Skip to content

239573049/GearsAI

GearsAI

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

Why GearsAI

Most provider SDKs are good at exposing one API family well. GearsAI is aimed at the layer above that:

  • one AiClient for multiple providers
  • one AiRequest model for common prompting, tools, reasoning, and streaming
  • one AiResponse model 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

Current Project Shape

Repository layout:

  • src/GearsAI: library source
  • tests/GearsAI.Tests: MSTest unit tests with fake HTTP handlers
  • tests/GearsAI.AotSmoke: smoke test for AOT assumptions
  • examples: runnable provider examples

Core public pieces:

  • AiClient: unified entry point
  • AiClientOptions: provider, base URL, API key, auth mode, headers, timeout, endpoint paths
  • AiRequest: shared request object with provider-specific extensions
  • AiResponse: shared non-streaming response object
  • AiStreamEvent: shared base type for streaming events
  • JsonValues: helpers for raw JSON values and tool schemas

Supported provider enum values:

  • AiProvider.OpenAiChatCompletions
  • AiProvider.OpenAiResponses
  • AiProvider.ClaudeMessages

Features

  • 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

Installation

Once the package is published to NuGet.org, install it with:

dotnet add package GearsAI

If 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 Release

Then 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.

Quick Start

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);

Configuration

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 it
  • BaseUri: custom endpoint root for OpenAI-compatible or self-hosted gateways
  • ApiKey: shared credential input
  • ApiKeyHeaderName: custom header name for non-bearer auth setups
  • AuthenticationKind: Bearer, ApiKeyHeader, or None
  • AnthropicVersion: Claude API version header
  • DefaultHeaders: extra HTTP headers
  • EndpointPaths: per-provider path overrides
  • HttpClient: bring your own client/handler pipeline

Working with Requests

At minimum, an AiRequest needs a Model. You can provide either:

  • Messages for simple chat-style input
  • Items for 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 Tools and ToolChoice
  • 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")
};

Streaming

GearsAI exposes a unified stream of AiStreamEvent records. Provider-native SSE payloads are mapped into common events such as:

  • AiTextDelta
  • AiReasoningDelta
  • AiToolCallDelta
  • AiToolCallCompletedEvent
  • AiUsageEvent
  • AiCompletedEvent
  • AiErrorEvent
  • 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.

Provider Notes

OpenAI Chat Completions

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

OpenAI Responses

Use AiProvider.OpenAiResponses for the newer Responses API shape.

This path supports:

  • Instructions
  • PreviousResponseId
  • Conversation
  • Include
  • response stream events for output parts, reasoning, and function call arguments

Claude Messages

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

Provider-Specific Escape Hatches

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.

Examples

The repository includes ten runnable examples:

  • examples/OpenAi.Responses.Basic
  • examples/OpenAi.Responses.Streaming
  • examples/OpenAi.Responses.Tools
  • examples/OpenAi.ChatCompletions.Basic
  • examples/OpenAi.ChatCompletions.Streaming
  • examples/Claude.Messages.Basic
  • examples/Claude.Messages.Streaming
  • examples/DeepSeek.Chat.Basic
  • examples/DeepSeek.Reasoning.Streaming
  • examples/AlibabaCloud.Qwen.Thinking

Examples read credentials from OPENAI_API_KEY.

Run one:

$env:OPENAI_API_KEY = "..."
dotnet run --project examples/OpenAi.Responses.Basic

See examples/README.md for provider-focused walkthroughs.

Build and Test

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 Release

Optional formatting:

dotnet format GearsAI.slnx

Design Notes

From 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.

License

This project is licensed under the MIT License. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages