A flexible .NET plugin toolkit for AI model function calling and tool integration. This toolkit provides a unified way to create and manage plugins that can be used with various AI models including OpenAI, Claude, Qwen, Mistral, and Gemini.
- 🔌 Declarative plugin registration using attributes
- đź“Š Automatic schema generation for different AI model formats
- âś… Type-safe parameter validation
- đź“ť Built-in plugin registry and execution system
- 🔄 Extensible plugin architecture with async support
- 🛡️ Comprehensive error handling and logging
- 🤖 Model-specific request formatting for major AI providers
Install the package via NuGet:
dotnet add package MarketAlly.AIPlugin
Create a new plugin by implementing the IAIPlugin
interface and decorating it with the appropriate attributes:
[AIPlugin("Calculator", "Performs basic arithmetic operations")]
public class CalculatorPlugin : IAIPlugin
{
[AIParameter("First number", required: true)]
public double Number1 { get; set; }
[AIParameter("Second number", required: true)]
public double Number2 { get; set; }
[AIParameter("Operation to perform (add, subtract, multiply, divide)", required: true)]
public string Operation { get; set; }
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
{
["number1"] = typeof(double),
["number2"] = typeof(double),
["operation"] = typeof(string)
};
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
{
double n1 = Convert.ToDouble(parameters["number1"]);
double n2 = Convert.ToDouble(parameters["number2"]);
string op = parameters["operation"].ToString().ToLower();
double result = op switch
{
"add" => n1 + n2,
"subtract" => n1 - n2,
"multiply" => n1 * n2,
"divide" => n2 != 0 ? n1 / n2 : throw new DivideByZeroException(),
_ => throw new ArgumentException($"Unknown operation: {op}")
};
return new AIPluginResult(result);
}
}
Register your plugins with the plugin registry:
var logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger<AIPluginRegistry>();
var registry = new AIPluginRegistry(logger);
// Register plugins
registry.RegisterPlugin(new CalculatorPlugin());
registry.RegisterPlugin(new StringManipulatorPlugin());
Generate the appropriate schema for your AI model:
// Generate schema for OpenAI
string openAiSchema = AIPluginHelper.GenerateSchema(AIPluginHelper.AIModel.OpenAI);
// Generate schema for Claude
string claudeSchema = AIPluginHelper.GenerateSchema(AIPluginHelper.AIModel.Claude);
You can easily prepare API requests for different AI providers using the helper methods:
// Your messages
var messages = new List<ChatMessage>
{
new ChatMessage { Role = "system", Content = "You are a helpful assistant." },
new ChatMessage { Role = "user", Content = "Calculate 25 * 48" }
};
// Get function definitions from the registry
var functionDefinitions = registry.GetAllPluginSchemas();
// For OpenAI
var openAiRequest = AIPluginHelper.SerializeRequestWithTools(
AIPluginHelper.AIModel.OpenAI,
messages,
functionDefinitions,
"gpt-4",
temperature: 0.7,
maxTokens: 1024
);
// For Claude (handles system message and input_schema correctly)
var claudeRequest = AIPluginHelper.SerializeRequestWithTools(
AIPluginHelper.AIModel.Claude,
messages,
functionDefinitions,
"claude-3-opus-20240229",
temperature: 0.7,
maxTokens: 4096
);
Execute plugin functions:
var parameters = new Dictionary<string, object>
{
["number1"] = 10,
["number2"] = 5,
["operation"] = "multiply"
};
var result = await registry.CallFunctionAsync("Calculator", parameters);
if (result.Success)
{
Console.WriteLine($"Result: {result.Data}");
}
else
{
Console.WriteLine($"Error: {result.Message}");
}
The toolkit comes with several built-in plugins:
- StringManipulator: Performs string operations (reverse, uppercase, lowercase, trim)
- SystemInfo: Retrieves current system information
- UrlValidator: Validates and parses URLs
- FileInfo: Gets metadata about files
- GenerateRandomNumber: Generates random numbers within a specified range
- GetDateTime: Retrieves formatted date and time
- Create a class that implements
IAIPlugin
- Decorate the class with
[AIPlugin]
attribute - Add properties with
[AIParameter]
attributes - Implement the
SupportedParameters
property - Implement the
ExecuteAsync
method
AIPluginAttribute
: Defines plugin name and descriptionAIParameterAttribute
: Defines parameter properties and requirements
The toolkit automatically validates:
- Required parameters
- Parameter types
- Parameter presence
Use AIPluginResult
to return results:
// Success case
return new AIPluginResult(data, "Operation successful");
// Error case
return new AIPluginResult(exception, "Operation failed");
The toolkit supports the following AI models:
- OpenAI: Full support for function calling and tools
- Claude: Handles the unique system message and input_schema requirements
- Qwen: Supports the Qwen API format
- Mistral: Compatible with Mistral's tools implementation
- Gemini: Supports Google's Gemini model format
Each model has its own format requirements, which are automatically handled by the SerializeRequestWithTools
method.
The toolkit handles provider-specific formatting requirements:
// The helper handles differences between providers automatically
AIPluginHelper.PrepareRequestWithTools(
modelType, // AI model type (OpenAI, Claude, etc.)
messages, // Your chat messages
functionDefs, // Function definitions from your registry
modelName, // Model name (e.g., "gpt-4", "claude-3-opus")
temperature, // Temperature setting
maxTokens // Max tokens for response
);
Key differences that are automatically handled:
- OpenAI/Gemini: Uses
tools
array withtype: "function"
wrapper - Claude: Places system messages in a separate field and uses
input_schema
- Mistral: Follows a similar format to Claude with minor differences
- Qwen: Uses
apis
instead oftools
for function definitions
The toolkit supports dependency injection through the AIPluginRegistry
:
services.AddSingleton<AIPluginRegistry>();
services.AddTransient<CalculatorPlugin>();
The toolkit uses Microsoft.Extensions.Logging
for comprehensive logging:
services.AddLogging(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Debug);
});
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
For support, please open an issue in the GitHub repository.