Plugin Development
This is an advanced developer document, designed for those who wish to creat their own NVIGI plugins. Before reading this document please read the architecture document. While writing a plugin only requires a copy of the NVIGI Core PDK (Plugin Development Kit), most of the plugins of interest are a part of the overall main SDK. As a result, this document will make frequent reference to plugins from the main SDK when discussing concrete examples.
Breaking ABI
In terminology below, “Breaking ABI” or “ABI-Breaking” means that a change is made that causes a compiled object with an understanding of the object’s binary layout before the change will no longer work correctly after the change.
Non-exhaustive examples of changes that break ABI (expounded further below):
Function calling convention
Function return type or parameters (including changing pass-by-value to pass-by-reference)
Ordering of members within a
structorclassType of a member (i.e. changing
size_ttounsigned)Offset or alignment (such as by inserting a member)
Size of a member (i.e. changing
char buffer[128]tochar buffer[256])Using nested structures (i.e. struct B { A a}, any change in size for struct A breaks the expected offsets and/or alignment for struct B)
Making these types of changes is acceptable only when working on the plugin’s INTERNAL data structures and APIs which are NOT shared across plugin boundaries or across the plugin/app boundary.
Implementing a Plugin
IMPORTANT: There should be no need to edit any core source code outside of
source/plugins/nvigi.mypluginandsource/tests/ai/main.cpp, if changes are needed in the In-Game Inferencing core components please ask for assistance from your NVIDIA Developer Relations Manager (see below). Modifying core APIs or behaviors innvigi.core.frameworkin any way can (and likely will) make the modified core malfunction or even fail to load standard NVIGI plugins.
Kinds of Plugins
Technically, NVIGI plugins are simply dynamic link libraries that export a set of interfaces, and may have a set of plugin-specific structs that are used as inputs and outputs. But in most IGI use cases, plugins fall into one of two categories:
Utility Plugins: These plugins do not tend to follow any specific interface standards, other than the basic functions required of all plugins for loading, unloading, and interface discovery. There are several such plugins in the NVIGICore itself, specifically the
nvigi.plugin.hwi.*plugins, which provide interfaces for connecting NVIGI and it plugins to the various hardware and rendering APIs. The standard NVIGI SDK includes a utility plugin for network behavior. Note that not all utility plugins are designed to be used by the application. Some utility plugins, like the main SDK’s networking plguin, does not export any app-facing interfaces; it is designed to have its interfaces loaded and used only by other plugins.Inference Plugins: These plugins are designed specifically for some form of AI inference, and follow a more specific standard set of interfaces. Creating inference plugins that follow these standards (discussed below) will allow you plugin to be more easily integrated into applications and into “parent” plugins, such as the main SDK’s AI Pipeline plugin.
Critical Reminders
Do NOT break C ABI compatibility
Use
NVIGI_UIDandNVIGI_VALIDATE_STRUCTfor all shared structures!Never use virtual functions, volatile members or STL types (
std::vectoretc.) in shared interfacesNever change or reorder existing members in any shared data or interfaces
Never use nested structures, always use pointer members
Do NOT forget to clearly mark your exported methods as thread safe or not - this is normally done in the comment section above the function declaration.
Do NOT duplicate interface or plugin GUIDs - always create new GUID when cloning an existing interface or data structure
Do NOT ship plugins unless they are PRODUCTION builds, DIGITALLY SIGNED and packaged on GitLab or TeamCity
Shipping non production builds or any builds from someones local machine is strictly forbidden
Do NOT break other plugins or add unnecessary dependencies between your plugin and others
Do NOT include internal headers in plugin’s public header(s) - only public headers are allowed
Public headers are always in format
nvigi_xxxx.hand can only include other public headers or standard C/C++ headers as needed.All public headers are located in
_sdk\includeafter NVIGI SDK is packaged
Always use
NVIGI_CATCH_EXCEPTIONmacro when implementing custom interfacesThis allows us to catch any exceptions out in the wild and produce mini-dumps for debugging
If your plugin has custom error codes make sure to follow the guidelines provided in
nvigi_result.hIf a large memory allocation needs to cross plugin (NOT host) boundaries you must use
nvigi::types::string or vectorThis ensures C ABI compatibility and consistent memory allocation and de-allocation (see below for assistance if new data type needs to be implemented)
When accessing shared data or interfaces which are version 2 or higher always check the version before accessing any members
It is worth noting that there are some exceptions when it comes to C ABI compatibility compliance and rules. They apply only to the NON SHIPPING / NON-PRODUCTION plugins which are designed to be used internal to NVIDIA or internal to the app developer only as helpers or debugging tools. It is perfectly fine to use STL std::function and lambdas to provide UI rendering functions for internal, non-end-user plugin(s) as long as these code sections are compiled out in production builds.
Thread Safety
Unless explicitly stated otherwise, NVIGI has no built-in thread safety. Each method exported by NVIGI SDK must be clearly marked as thread safe or unsafe depending on the implementation. Here is an example from the CORE API:
//! Shuts down the NVIGI module
//!
//! Call this method when your application is shutting down.
//!
//! @returns IResult interface with code nvigi::kResultOk if successful, error code otherwise (see nvigi_result.h for details)
//!
Note the following statement just before the API declaration:
//! This method is NOT thread safe.
NVIGI_API nvigi::Result nvigiShutdown();
IMPORTANT: When implementing interface(s) for your plugin always make sure to state thread safety clearly.
Plugin Naming
All plugins must follow the following naming nomenclature nvigi.plugin.$name.{$backend.$api} where $backend and $api are optional unless there are multiple backends and/or APIs used by the same backend. Here are some examples:
nvigi.plugin.hwi.d3d12
nvigi.plugin.hwi.cuda
nvigi.plugin.gpt.ggml.cpu
nvigi.plugin.gpt.ggml.cuda
nvigi.plugin.tts.asqflow-trt
nvigi.plugin.net
NOTE: NVIGI core components are named
nvigi.core.$namelike for examplenvigi.core.framework
GUID Creation for Interfaces and Plugins
For creating IDs for plugins the easiest way is to use built in tool (packaged in any SDK [sdk], including a pre-packaged one as [root] or a locally-packaged one as [root]/_sdk) as follows:
[sdk]/bin/x64/nvigi.tool.utils.exe --plugin nvigi.plugin.$name.$backend.$api
which then outputs:
namespace nvigi::plugin::$name::$backend::$api
{
constexpr PluginID kId = {{0x9be1b413, 0xda31, 0x445b,{0xbe, 0x1b, 0x20, 0x30, 0x7f, 0x4f, 0x0c, 0x00}}, 0x4dc06d};
//{9BE1B413-DA31-445B-BE1B-20307F4F0C00} [nvigi.plugin.$name.$backend.$api]
}
When it comes to the interfaces the approach is very similar:
[sdk]/bin/x64/nvigi.tool.utils.exe --interface MyInterface
which generates unique GUID and new interface that looks like this:
//! Interface MyInterface
//!
//! {41021ED0-1BB2-4255-9545-AD5C902017E0}
struct alignas(8) MyInterface
{
MyInterface(){}
NVIGI_UID(UID({0x41021ed0, 0x1bb2, 0x4255,{0x95, 0x45, 0xad, 0x5c, 0x90, 0x20, 0x17, 0xe0}}), kStructVersion1);
//! v1 members go here, please do NOT break the C ABI compatibility:
//! * do not use virtual functions, volatile, STL (e.g. std::vector) or any other C++ high level functionality
//! * do not use nested structures, always use pointer members
//! * do not use internal types in _public_ interfaces (like for example 'nvigi::types::vector' etc.)
//! * do not change or move any existing members once interface has shipped
//! v2+ members go here, remember to update the kStructVersionN in the above NVIGI_UID macro!
};
NOTE: The above generated code is automatically copied to the clipboard for easy pasting into your public header
nvigi_$name.h
Files and Folders
Most plugins have the following file structure:
source/plugins/nvigi.$name/
├── nvigi_$name.h <- public header, must NOT include any internal headers
├── $backendA
│ ├── internal headers, source, version, resources
│ └── $3rdparty <- optional, only if not on packman and cannot be under 'external'
│ └── 3rd party includes, source, libs
├── $backendB
│ ├── internal headers, source, version, resources
│ └── $3rdparty <- optional, only if not on packman and cannot be under 'external'
│ └── 3rd party includes, source, libs
IMPORTANT: If having a backend makes no sense for your plugin there is no need to have the subfolder for it.
New Plugin Setup
Inference Plugins
Here are the basic steps for setting up a new plugin performing AI inference tasks:
Clone
nvigi.template.inferencefolder and rename it to your plugin’s nameRename public header
nvigi_template.hto match your nameSearch for “tmpl”, “template”, “Template” and “TEMPLATE” and replace with your name
Run
[sdk]/bin/x64/nvigi.tool.utils.exe --plugin nvigi.plugin.$name.$backend{.$api}to obtain UID and crc24 and paste that in the public headernvigi_$name.hundernamespace nvigi::$mynamespaceRename folder
backendto match target backend you are using (ggml,cuda,trt,vketc.)Add more backends as needed if your plugin supports more than one (see gpt plugin for details)
Ideally, all backends should implement the same interface declared in
nvigi_myplugin.h
In addition, the public git source is also available for many of the shipping plugins as a part of the public GitHub Plugins source repo.
IMPORTANT: All inference plugins are expected to implement the same interface and follow the same execution flow as defined in
source/utils/nvigi.ai
Generic Plugins
Here are the basic steps for setting up a new plugin performing completely generic and custom tasks:
Clone
nvigi.template.genericfolder and rename it to your plugin’s nameRename public header
nvigi_template.hto match your nameSearch for “tmpl”, “template”, “Template” and “TEMPLATE” and replace with your name
Run
[sdk]/bin/x64/nvigi.tool.utils.exe --plugin nvigi.plugin.$name.$backend{.$api}to obtain UID and crc24 and paste that in the public headernvigi_$name.hundernamespace nvigi::$mynamespace
Some examples, nvigi.plugin.hwi.cuda, nvigi.plugin.gpt.ggml.d3d12 etc.
NOTE: Generic plugins can do rendering, networking or any other custom tasks. If backends make no sense there is no need to use the subfolder.
Common Steps
Modify
package.pyto add your project to the build system (again clone from template or any other plugin as needed). Here is a snapshot from the file showing various components:
components = {
'core': {
'platforms': all_plat,
'externals': [coresdk_ext, cuda_ext, nlohmann_json_ext]
},
'ai.pipeline' : {
'platforms': win_plat,
'sharedlib': ['nvigi.plugin.ai.pipeline'],
'includes': ['source/plugins/nvigi.aip/nvigi_aip.h'],
'sources': ['plugins/nvigi.aip', 'shared'],
'premake': 'source/plugins/nvigi.aip/premake.lua'
},
'asr.ggml.cpu' : {
'platforms': win_plat,
'sharedlib': ['nvigi.plugin.asr.ggml.cpu'],
'docs': ['ProgrammingGuideASRWhisper.md'],
'includes': ['source/plugins/nvigi.asr/nvigi_asr_whisper.h'],
'sources': ['plugins/nvigi.asr/nvigi_asr_whisper.h', 'plugins/nvigi.asr/ggml', 'shared'],
'externals': [nlohmann_json_ext, whispercpp_ext],
'premake': 'source/plugins/nvigi.asr/ggml/premake.lua',
'models': ['nvigi.plugin.asr.ggml'],
'data': ['nvigi.asr']
},
....
Update
premake.luain your plugin’s directory to include everything your project needs and make sure path to it is listed correctly in yourcomponentsection, an example:
'premake': 'source/plugins/nvigi.asr/ggml/premake.lua',
Run
setup.bat vs20xx
NOTE: If
setup.batfails with an error from thepackmanpackage downloader, please re-runsetup.batagain as there are rare but possible issues with link-creation on initial run.
NOTE: If it makes things easier it is totally fine to clone and modify any existing plugin (gpt, asr etc.) to speed up development.
Building and Code Modifications
Modify source code (add new headers or cpp files as needed) to perform actions you need for your plugin
If adding new files make sure to update
premakeand re-runsetup.xx
Make sure NOT to include internal headers in your public
nvigi_$name.hheaderWhen adding new data structures/interfaces which are shared either publicly or internally you must use the
nvigi.tool.utilsas described in GUID creationWhen modifying an existing shared data or interfaces always follow the “do not break C ABI compatibility” guidelines
Wrap all you externally exposed functions with
NVIGI_CATCH_EXCEPTIONBuild your plugin using
_project/vs20xx/nvigi.sln
Packaging
Modify
package.pyto include your plugin(s) in the final SDKMake sure to include ONLY the public header(s), DLL and symbols for each plugin
Run
package.bat -{debug, release, develop, production}to package SDK locally under_sdkfolder
Using Interfaces
All interfaces in NVIGI are typed and versioned structures
If multiple versions of an interface are available, it is mandatory to check the version before accessing members v2 or higher+.
IMPORTANT: Always keep in mind that plugins can be updated individually so at any point in time, plugin code can be handed an interface or data structure from another plugin that is older or newer than the one used at the compile time.
//! Obtain interfaces from other plugins or core (if needed)
//!
//! For example, here we use our internal helper function to obtain networking interface.
//!
//! NOTE: This will trigger loading of the 'nvigi.plugin.net' if it wasn't loaded already
//!
net::INet* net{};
if (!framework::getInterface(framework, nvigi::plugin::net::kId, &net))
{
NVIGI_LOG_ERROR("Failed to obtain interface");
}
else
{
if(isOlderStruct(net))
{
//! Our plugin is coming from a newer SDK, INet interface is older so we can NOT access latest members or API(s) in net::INet
if(net->getVersion() == 1)
{
// ONLY access members from v1
}
else if(net->getVersion() == 2)
{
// ONLY access members from v2
}
// and so on
}
else // same version or newer
{
// our plugin is coming from an older or identical SDK as plugin::net::kId, we can access all members and API(s) in net::INet known to us at the compile time
}
}
IMPORTANT: Always check versions or interfaces or data structures received from other plugins, they could be older or newer since plugins can be updated independently
Exception Handling
When implementing custom APIs in your exported interface always make sure to wrap your functions using the NVIGI_CATCH_EXCEPTION macro. Here is an example on an interface implementation:
//! Example interface implementation
//!
nvigi::Result tmplCreateInstance(const nvigi::NVIGIParameter* params, nvigi::InferenceInstance** instance)
{
//! An example showing how to obtain an optional chained parameters
//!
//! User can chain extra structure(s) using the params._next
//!
auto extraParams = findStruct<nvigi::TemplateCreationParametersEx>(*params);
if (extraParams)
{
//! User provided extra parameters!
}
return kResultOk;
}
nvigi::Result tmplDestroyInstance(const nvigi::InferenceInstance* instance)
{
return kResultOk;
}
nvigi::Result tmplGetCapsAndRequirements(nvigi::TemplateCapabilitiesAndRequirements* modelInfo, const nvigi::TemplateCreationParameters* params)
{
return kResultOk;
}
Here is how one would wrap this implementation to make sure we catch any exceptions:
//! Making sure our implementation is covered with our exception handler
//!
namespace tmpl
{
nvigi::Result createInstance(const nvigi::NVIGIParameter* params, nvigi::InferenceInstance** instance)
{
NVIGI_CATCH_EXCEPTION(tmplCreateInstance(params, instance));
}
nvigi::Result destroyInstance(const nvigi::InferenceInstance* instance)
{
NVIGI_CATCH_EXCEPTION(tmplDestroyInstance(instance));
}
nvigi::Result getCapsAndRequirements(nvigi::TemplateCapabilitiesAndRequirements* modelInfo, const nvigi::TemplateCreationParameters* params)
{
NVIGI_CATCH_EXCEPTION(tmplGetCapsAndRequirements(modelInfo, params));
}
} // namespace tmpl
Finally, here is how our interface is shared with the host application or other plugins:
//! Main entry point - starting our plugin
//!
Result nvigiPluginRegister(framework::IFramework* framework)
{
if (!plugin::internalPluginSetup(framework)) return ResultInvalidState;
auto& ctx = (*tmpl::getContext());
//! Add your interface(s) to the framework
//!
//! NOTE: We are exporting functions with the exception handler enabled
ctx.api.createInstance = tmpl::createInstance;
ctx.api.destroyInstance = tmpl::destroyInstance;
ctx.api.getCapsAndRequirements = tmpl::getCapsAndRequirements;
framework->addInterface(plugin::tmpl::kIdBackendApi, &ctx.api);
...
}
NOTE: Logs and mini-dumps from any exception caught by NVIGI can be found in
%PROGRAM_DATA%\NVIDIA\NVIGI\{APP_NAME}\{UNIQUE_ID}
Input Parameters and Chained Data Structures
NVIGI data structures can be chained together for convenience. For example, host application can provide mandatory creation parameters to the createInstance API in an interface but it can also add an optional input(s) as needed. Here is an example:
nvigi::Result llama2CreateInstance(const nvigi::NVIGIParameters* params, nvigi::InferenceInstance** _instance)
{
//! Look for an optional input parameter(s) chained using params._next
auto cugfxCreate = findStruct<GPTcugfxCreationParameters>(*params);
if (cugfxCreate)
{
//! User provided optional cuGfx creation parameters!
}
...
}
IMPORTANT: If you add new NVIGI data structures for your plugin make sure to use utils library as shown here
Hybrid AI plugins
This section provides more information about developing hybrid AI (local and cloud inference) plugins
Inference API
All hybrid AI plugins should implement similar APIs based on what is described in the hybrid AI guide and implemented in nvigi_ai.h
AI Model File Structure
For consistency, all NVIGI AI inference plugins are expected to store their models using the following directory structure:
nvigi.models/
├── nvigi.plugin.$name.$backend
└── {MODEL_GUID}
├── files
Here is an example structure for the existing NVIGI plugins and models:
nvigi.models/
├── nvigi.plugin.gpt.cloud
│ └── {{01F43B70-CE23-42CA-9606-74E80C5ED0B6}}
│ └── nvigi.model.config.json
├── nvigi.plugin.gpt.ggml
│ └── {175C5C5D-E978-41AF-8F11-880D0517C524}
│ └── gpt-7b-chat-q4.gguf
│ └── nvigi.model.config.json
└── nvigi.plugin.asr.ggml
└── {5CAD3A03-1272-4D43-9F3D-655417526170}
└── ggml-asr-small.gguf
│ └── nvigi.model.config.json
Each model must provide an nvigi.model.config.json file containing the model’s name, vram consumption and other model specific information. Here is an example from nvigi.plugin.gpt.ggml:
{
"name": "Qwen3-8B",
"vram": 5280,
"n_layers": 37,
"prompt_template_think": [
"<|im_start|>system\n",
"$system",
"<|im_end|>",
"<|im_start|>user\n",
"$user",
"<|im_end|>",
"<|im_start|>assistant\n"
],
"turn_template_think": [
"<|im_start|>user\n",
"$user",
"<|im_end|>",
"<|im_start|>assistant\n"
],
"prompt_template": [
"<|im_start|>system\n",
"$system",
"<|im_end|>",
"<|im_start|>user\n",
"$user",
" /no_think <|im_end|>",
"<|im_start|>assistant\n"
],
"turn_template": [
"<|im_start|>user\n",
"$user",
" /no_think <|im_end|>",
"<|im_start|>assistant\n"
],
"model":
{
"ext" : "gguf",
"notes": "Must use .gguf extension and format, model(s) can be obtained for free on huggingface",
"file":
{
"command": "curl -L -o Qwen3-8B-Q4_K_M.gguf 'https://huggingface.co/Qwen/Qwen3-8B-GGUF/resolve/main/Qwen3-8B-Q4_K_M.gguf?download=true'"
}
}
}
An optional configs subfolder, with the identical folder structure, can be added under nvigi.models to provide nvigi.model.config.json overrides as shown below:
nvigi.models/
├── configs
├── nvigi.plugin.$name.$backend
└── {MODEL_GUID}
├── nvigi.model.config.json
| etc
├── nvigi.plugin.$name.$backend
└── {MODEL_GUID}
├── files
NOTE: This allows quick way of modifying only model config settings in JSON without having to reupload the entire model which can be GBs in size
Various helper methods are available in source/utils/nvigi.ai/ai.h allowing easy model enumeration and filtering with custom extension support. Example usage can be found in any existing AI plugin (gpt, asr etc.)
Creating a Customized Plugin from An Existing Plugin
This document guides you through the process of creating a customized NVIGI GPT plugin, based on the original GPT plugin from the SDK.
> IMPORTANT: Although the document uses the GPT plugin as an example, the high-level steps also apply to other plugins.
Steps
This section presents one recommended approach to creating a new GPT plugin. Once you understand the project setup process, you can freely make customized changes without strictly following all the steps.
In the following instructions, we follow the directory setup described here.
<SDK_PLUGINS>should be replaced with the full path to your NVIGI SDK directory (the path of this README).
Add a New Plugin Project
Choose a name for your new plugin, such as
mygpt.Prepare the source files for the new plugin by copying from an existing project.
Duplicate the folder containing the source code of the original plugin (
<SDK_PLUGINS>/source/plugins/nvigi.gpt) and rename it to<SDK_PLUGINS>/source/plugins/nvigi.mygpt.(Optional) Enter the new source folder and remove unused backend code (e.g.
rest).(Optional) Rename the source files with your new plugin name by replacing
gptwithmygpt.For example, assuming that we want to modify the GGML backend, the source tree should now have the following structure:
<SDK_PLUGINS>/source/plugins |-- nvigi.mygpt | |-- ggml | | |-- premake.lua | | |-- mygpt.h | | |-- mygpt.cpp | | |-- ... // Other source files | |-- nvigi_mygpt.h | |-- // "rest" is removed |-- ... // Other plugins
Update the setup scripts to include the new source files.
Update
NVIGI-Plugins/source/plugins/nvigi.mygpt/ggml/premake.luaby renaming it with the new plugin name (e.g., renamegroup "plugins/gpt"togroup "plugins/mygpt"andproject "nvigi.plugin.gpt.ggml.$backend"toproject "nvigi.plugin.mygpt.ggml.$backend").Update
NVIGI-Plugins/premake.luato include the project premake file by addinginclude("source/plugins/nvigi.mygpt/ggml/premake.lua")at the end.
Run
setup.batto reflect the changes.Open
NVIGI-Plugins/_project/vs2022/nvigi.slnand check the Solution Explorer - a new projectnvigi.plugin.mygpt.ggml.{$backend}should be added underplugins.mygpt.
Update Names and GUIDs in Source Files
Find the NVIGI utility
nvigi.tool.utils.exelocated inNVIGI-Core\bin\Release_x64Open terminal and run
nvigi.tool.utils.exe --plugin nvigi.plugin.mygpt.ggml.$backend(make sure to replacemygptand$backendaccordingly)Open
nvigi_mygpt.h. This is a public header and will be provided to apps.Remove the namespaces of unused backends (e.g.,
namespace cloud::rest).Update the plugin GUIDs in this file by pasting the code provided by the NVIGI utilities tool:
// Before // constexpr PluginID kId = { {0x54bbefba, 0x535f, 0x4d77,{0x9c, 0x3f, 0x46, 0x38, 0x39, 0x2d, 0x23, 0xac}}, 0x4b9ee9 }; // {54BBEFBA-535F-4D77-9C3F-4638392D23AC} [nvigi.plugin.gpt.ggml.$backend] // After constexpr PluginID kId = { 0x576e1145, 0xf790, 0x46b4, { 0xbf, 0x9a, 0xde, 0x88, 0x9, 0x46, 0x3a, 0x15 } }; // {576E1145-F790-46B4-BF9A-DE8809463A15} [nvigi.plugin.mygpt.ggml.$backend]
Open
mygpt.cpp.Include the new headers.
// Before #include "source/plugins/nvigi.gpt/nvigi_gpt.h" #include "source/plugins/nvigi.gpt/ggml/gpt.h" // After #include "source/plugins/nvigi.mygpt/nvigi_mygpt.h" #include "source/plugins/nvigi.mygpt/ggml/mygpt.h"
Update function
getFeatureId()to return the new plugin IDreturn plugin::mygpt::ggml::$backend::kId;.
(Optional) Rename namespaces and variables in
mygpt.h/cpp. These source files will not be visible to apps.
(Optional) Update Your App to Use the New Plugin
If you already have an app using the original GPT plugin “nvigi.plugin.gpt.ggml.cuda”, follow these steps to replace it with the new plugin.
Replace the public header
#include "nvigi_gpt.h"with#include "nvigi_mygpt.h".Replace the plugin ID
nvigi::plugin::gpt::ggml::$backend::kIdwithnvigi::plugin::mygpt::ggml::$backend::kIdwhen getting the interface.Rename the model folder from
nvigi.models\nvigi.plugin.gpt.ggmltonvigi.models\nvigi.plugin.mygpt.ggmlso the new plugin can find and load models.(Troubleshooting) If the new plugin DLL fails to load, start with checking if you are using the correct set of dependent DLLs, like ggml and llama.cpp and CUDA runtime.
Customize Your Plugin!
You have completed the setup and can now start modifying the plugin if you have plans in mind. If not, the example below shows how to add a new parameter grammar to GPTSamplerParameters.
The example demonstrates the steps to add the grammar parameter. Note that this parameter may be added in future versions. Similar steps can be applied to other parameters like GPTRuntimeParameters.
Open
nvigi_mygpt.hand navigate toGPTSamplerParameters, then add the parameter at the end and update the version.// Before struct alignas(8) GPTSamplerParameters { NVIGI_UID(UID({ 0xfd183aa9, 0x6e50, 0x4021,{0x9b, 0x0e, 0xa7, 0xae, 0xab, 0x6e, 0xef, 0x49} }), kStructVersion1) // ... v1 parameters //! v2+ members go here, remember to update the kStructVersionN in the above NVIGI_UID macro! }; // After struct alignas(8) GPTSamplerParameters { NVIGI_UID(UID({ 0xfd183aa9, 0x6e50, 0x4021,{0x9b, 0x0e, 0xa7, 0xae, 0xab, 0x6e, 0xef, 0x49} }), kStructVersion2) // ... v1 parameters //! v2+ members go here, remember to update the kStructVersionN in the above NVIGI_UID macro! const char* grammar{}; };
Open
mygpt.cppand navigate to functionggmlEvaluate().// Before instance->params.sparams.ignore_eos = sampler->ignoreEOS; // After instance->params.sparams.ignore_eos = sampler->ignoreEOS; if (sampler->getVersion() >= 2) { instance->params.sparams.grammar = sampler->grammar ? sampler->grammar : ""; }
Update your app to set the new parameter.
Adding New Structures Or Interfaces
If you need to add completely new structure or new interface (structure with functions defining an API) please follow these steps:
Find the NVIGI utility
nvigi.tool.utils.exelocated inNVIGI-Core\bin\Release_x64Open terminal and run
nvigi.tool.utils.exe --interface MyData(make sure to replaceMyDataaccordingly)Paste the provided code into your
nvigi_mygpt.hheader like for example:
NOTE: Same command is used for data and interfaces since they are simply typed and versioned structures in NVIGI terminology
//! Interface 'MyData'
//!
//! {45DF99CE-F5B8-4D66-90EE-FADEEFBBF713}
struct alignas(8) MyData
{
MyData() { };
NVIGI_UID(UID({0x45df99ce, 0xf5b8, 0x4d66,{0x90, 0xee, 0xfa, 0xde, 0xef, 0xbb, 0xf7, 0x13}}), kStructVersion1)
//! v1 members go here, please do NOT break the C ABI compatibility:
//! * do not use virtual functions, volatile, STL (e.g. std::vector) or any other C++ high level functionality
//! * do not use nested structures, always use pointer members
//! * do not use internal types in _public_ interfaces (like for example 'nvigi::types::vector' etc.)
//! * do not change or move any existing members once interface has shipped
//! v2+ members go here, remember to update the kStructVersionN in the above NVIGI_UID macro!
};
NVIGI_VALIDATE_STRUCT(MyData)
Add new data members to your structure
Using New Structures Or Interfaces
Data Structures
If your new structure contains only data simply chain it to the creation or runtime properties and then use findStruct in either createInstance or evaluate calls.
host app
// Default GPT creation parameters
GPTCreationParameters creationParams{};
// Fill in the creation params
MyData myData{};
// Fill in your data
myData.someData = 1;
// Chain it to the creation parameters
if(NVIGI_FAILED(error,creationParams.chain(myData)))
{
// handle error
}
mygpt.cpp
nvigi::Result ggmlCreateInstance(const nvigi::NVIGIParameter* _params, nvigi::InferenceInstance** _instance)
{
auto myData = findStruct<MyData>(_params);
if(myData)
{
// Do something with v1 data
// If you modify your structure after having shipped your app, make sure to bump the version and check
if(myData->getVersion() >= kStructVersion2)
{
// Do something with v2 data
}
// And so on ...
}
...
}
Interface Structures
If your new structure contains and API then this new interface must be exported by your modified plugin in order to be used on the host side. Here is an example:
nvigi_mygpt.h
//! Interface 'IMyInterface'
//!
//! {45DF99CE-F5B8-4D66-90EE-FADEEFBBF713}
struct alignas(8) IMyInterface
{
IMyInterface() { };
NVIGI_UID(UID({0x45df99ce, 0xf5b8, 0x4d66,{0x90, 0xee, 0xfa, 0xde, 0xef, 0xbb, 0xf7, 0x13}}), kStructVersion1)
//! v1 members go here, please do NOT break the C ABI compatibility:
nvigi::Result (*someFunction)();
//! * do not use virtual functions, volatile, STL (e.g. std::vector) or any other C++ high level functionality
//! * do not use nested structures, always use pointer members
//! * do not use internal types in _public_ interfaces (like for example 'nvigi::types::vector' etc.)
//! * do not change or move any existing members once interface has shipped
//! v2+ members go here, remember to update the kStructVersionN in the above NVIGI_UID macro!
};
NVIGI_VALIDATE_STRUCT(IMyInterface)
mygpt.cpp
// Add new API to the context
struct GPTContext
{
NVIGI_PLUGIN_CONTEXT_CREATE_DESTROY(GPTContext);
void onCreateContext() {};
void onDestroyContext() {};
IMyInterface myapi{};
// other bits
};
namespace mygpt
{
nvigi::Result someFunction()
{
// Implement your function!
}
}
// Now export the API
Result nvigiPluginRegister(framework::IFramework* framework)
{
if (!plugin::internalPluginSetup(framework)) return kResultInvalidState;
auto& ctx = (*mygpt::getContext());
ctx.feature = mygpt::getFeatureId(nullptr);
ctx.myapi.someFunction = mygpt::someFunction;
framework->addInterface(ctx.feature, &ctx.myapi, 0);
...
}
host app
nvigi::mygpt::IMyInterface* iMyApi{};
if(NVIGI_FAILED(error,nvigiGetInterface("nvigi::plugin::mygpt::ggml::$backend::kId", &iMyApi)))
{
// handle error
}
// use your interface v1
iMyApi->someFunction();
// If interface changed and your app can load both old and new plugins always check the version
if(iMyApi->getVersion() >= kStructureVersion2)
{
// safe to use v2 interface members
iMyApi->someFunction2();
}
Assistance
For any assistance or for questions regarding ANY changes to NVIGI Core, please contact your NVIDIA Developer Relations Manager