GearsAI is a lightweight .NET library for calling multiple AI providers through one request/response model.
It currently unifies:
- OpenAI Chat Completions
- OpenAI Responses
- Claude Messages
- OpenAI-compatible providers such as DeepSeek and DashScope
The project targets net8.0, net9.0, and net10.0, uses System.Text.Json source generation, and is designed to stay trimming- and AOT-friendly.
中文文档: README.zh-CN.md
Most provider SDKs are good at exposing one API family well. GearsAI is aimed at the layer above that:
- one
AiClientfor multiple providers - one
AiRequestmodel for common prompting, tools, reasoning, and streaming - one
AiResponsemodel for text, reasoning output, tool calls, and usage - one stream event model across OpenAI and Claude style SSE protocols
- escape hatches for provider-specific request fields when compatibility matters
That makes it useful when you want to:
- switch providers without rewriting application code
- support OpenAI-compatible endpoints behind a custom base URL
- consume streaming output through a single event pipeline
- keep low-level JSON control without dropping into handwritten payload strings
Repository layout:
src/GearsAI: library sourcetests/GearsAI.Tests: MSTest unit tests with fake HTTP handlerstests/GearsAI.AotSmoke: smoke test for AOT assumptionsexamples: runnable provider examples
Core public pieces:
AiClient: unified entry pointAiClientOptions: provider, base URL, API key, auth mode, headers, timeout, endpoint pathsAiRequest: shared request object with provider-specific extensionsAiResponse: shared non-streaming response objectAiStreamEvent: shared base type for streaming eventsJsonValues: helpers for raw JSON values and tool schemas
Supported provider enum values:
AiProvider.OpenAiChatCompletionsAiProvider.OpenAiResponsesAiProvider.ClaudeMessages
- Sync and async request execution
- Sync and async streaming
- OpenAI Chat Completions support
- OpenAI Responses support
- Claude Messages support
- Tool definitions and tool call normalization
- Reasoning/thinking field support across providers
- Usage normalization, including OpenAI reasoning token extraction when available
- Custom headers, auth modes, endpoint overrides, and raw extra request fields
- Trimming and AOT-minded implementation
Once the package is published to NuGet.org, install it with:
dotnet add package GearsAIIf you are working from source before the first public release, clone the repo and build it:
git clone <your-fork-or-this-repo-url>
cd GearsAI
dotnet restore GearsAI.slnx
dotnet build GearsAI.slnx -c ReleaseThen reference src/GearsAI/GearsAI.csproj from your solution or pack it for internal distribution.
NuGet publishing is automated through GitHub Actions. Repository setup details are documented in docs/publishing.md.
using GearsAI;
using var client = new AiClient(new AiClientOptions
{
Provider = AiProvider.OpenAiResponses,
ApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
});
var response = await client.CreateAsync(new AiRequest
{
Model = "gpt-5.4-mini",
Instructions = "Answer concisely.",
Messages =
{
AiMessage.User("Give one practical use for a unified AI client abstraction.")
},
MaxOutputTokens = 300
});
Console.WriteLine(response.Text);AiClientOptions supports the usual transport and compatibility controls:
var options = new AiClientOptions
{
Provider = AiProvider.OpenAiChatCompletions,
BaseUri = new Uri("https://api.deepseek.com"),
ApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY"),
Timeout = TimeSpan.FromMinutes(10),
DefaultHeaders = new Dictionary<string, string>
{
["x-test-header"] = "test-value"
}
};Notable options:
Provider: default provider used when a request does not override itBaseUri: custom endpoint root for OpenAI-compatible or self-hosted gatewaysApiKey: shared credential inputApiKeyHeaderName: custom header name for non-bearer auth setupsAuthenticationKind:Bearer,ApiKeyHeader, orNoneAnthropicVersion: Claude API version headerDefaultHeaders: extra HTTP headersEndpointPaths: per-provider path overridesHttpClient: bring your own client/handler pipeline
At minimum, an AiRequest needs a Model. You can provide either:
Messagesfor simple chat-style inputItemsfor richer mixed conversation state such as tool calls, tool results, reasoning items, or raw provider payload fragments
High-level request features include:
Instructions- sampling controls such as
Temperature,TopP - token controls such as
MaxTokens,MaxOutputTokens,MaxCompletionTokens - tools via
ToolsandToolChoice - provider-specific reasoning controls
- metadata and provider-specific top-level fields
Example with tools:
var request = new AiRequest
{
Model = "gpt-5.4-mini",
Messages =
{
AiMessage.User("Use lookup_ticket to inspect ticket GRS-101.")
},
Tools =
{
AiTool.Function(
"lookup_ticket",
JsonValues.StrictToolSchemaObject(("ticket_id", "string", "Ticket id such as GRS-101")),
"Look up an engineering ticket.",
strict: true)
},
ToolChoice = JsonValues.FromString("auto")
};GearsAI exposes a unified stream of AiStreamEvent records. Provider-native SSE payloads are mapped into common events such as:
AiTextDeltaAiReasoningDeltaAiToolCallDeltaAiToolCallCompletedEventAiUsageEventAiCompletedEventAiErrorEvent- raw lifecycle/content-part events when the provider exposes them
Example:
await foreach (var streamEvent in client.StreamAsync(new AiRequest
{
Model = "gpt-5.4-mini",
Messages = { AiMessage.User("Stream three short bullet points.") },
ChatStreamOptions = new OpenAiChatStreamOptions { IncludeUsage = true },
MaxCompletionTokens = 300
}))
{
switch (streamEvent)
{
case AiReasoningDelta reasoning:
Console.Write(reasoning.Text);
break;
case AiTextDelta text:
Console.Write(text.Text);
break;
case AiToolCallCompletedEvent toolCall:
Console.WriteLine(toolCall.ToolCall.Name);
break;
}
}AiStreamAccumulator is also included to help reconstruct completed state from deltas.
Use AiProvider.OpenAiChatCompletions when you want compatibility with chat-completions style APIs, including OpenAI-compatible vendors.
This path supports:
- chat messages
- tools
- reasoning content mapping
- usage mapping
- streaming chunk normalization
Use AiProvider.OpenAiResponses for the newer Responses API shape.
This path supports:
InstructionsPreviousResponseIdConversationInclude- response stream events for output parts, reasoning, and function call arguments
Use AiProvider.ClaudeMessages for Anthropic-compatible Messages APIs.
This path supports:
- system/instruction mapping
- Claude tool use and tool result content blocks
- thinking blocks and signatures
- Claude streaming event normalization
The library intentionally keeps escape hatches because AI provider compatibility layers move fast.
Use Thinking when a provider accepts a raw top-level thinking object:
var request = new AiRequest
{
Model = "provider-model",
Messages = { AiMessage.User("hello") },
Thinking = JsonValues.FromRaw("""{"type":"enabled","vendor_mode":"deep"}""")
};Use ExtraBody / ProviderOptions for arbitrary provider fields:
var request = new AiRequest
{
Model = "provider-model",
Messages = { AiMessage.User("hello") },
ExtraBody =
{
["enable_thinking"] = JsonValues.FromRaw("true"),
["thinking_budget"] = JsonValues.FromRaw("2048")
}
};This is especially useful for OpenAI-compatible vendors like DeepSeek or DashScope that add custom flags on top of the shared protocol.
The repository includes ten runnable examples:
examples/OpenAi.Responses.Basicexamples/OpenAi.Responses.Streamingexamples/OpenAi.Responses.Toolsexamples/OpenAi.ChatCompletions.Basicexamples/OpenAi.ChatCompletions.Streamingexamples/Claude.Messages.Basicexamples/Claude.Messages.Streamingexamples/DeepSeek.Chat.Basicexamples/DeepSeek.Reasoning.Streamingexamples/AlibabaCloud.Qwen.Thinking
Examples read credentials from OPENAI_API_KEY.
Run one:
$env:OPENAI_API_KEY = "..."
dotnet run --project examples/OpenAi.Responses.BasicSee examples/README.md for provider-focused walkthroughs.
dotnet restore GearsAI.slnx
dotnet build GearsAI.slnx -c Release
dotnet test tests/GearsAI.Tests/GearsAI.Tests.csproj -c Release
dotnet run --project tests/GearsAI.AotSmoke/GearsAI.AotSmoke.csproj -c ReleaseOptional formatting:
dotnet format GearsAI.slnxFrom the code and tests, a few project priorities are clear:
- keep the public API small and explicit
- favor typed request/response models over ad hoc JSON strings
- still allow raw JSON where provider divergence requires it
- normalize streaming rather than hiding it
- keep tests offline and deterministic
- stay compatible with trimming and AOT scenarios
That combination gives the project a nice niche: it is not trying to be the largest AI SDK, but a portable interoperability layer for modern .NET applications.
This project is licensed under the MIT License. See LICENSE.