Ai.Tlbx.Inference
2.1.5
dotnet add package Ai.Tlbx.Inference --version 2.1.5
NuGet\Install-Package Ai.Tlbx.Inference -Version 2.1.5
<PackageReference Include="Ai.Tlbx.Inference" Version="2.1.5" />
<PackageVersion Include="Ai.Tlbx.Inference" Version="2.1.5" />
<PackageReference Include="Ai.Tlbx.Inference" />
paket add Ai.Tlbx.Inference --version 2.1.5
#r "nuget: Ai.Tlbx.Inference, 2.1.5"
#:package Ai.Tlbx.Inference@2.1.5
#addin nuget:?package=Ai.Tlbx.Inference&version=2.1.5
#tool nuget:?package=Ai.Tlbx.Inference&version=2.1.5
Ai.Tlbx.Inference
Trim-friendly .NET AI inference client for OpenAI, Anthropic, Google, and xAI, built around a single inference facade.
Features
- Multi-provider — OpenAI, Anthropic, Google (AI Studio + Vertex), xAI behind a single interface
- Streaming —
IAsyncEnumerable<string>across all supported providers with integration coverage - Document attachments — provider-aware document attachment support with live coverage for supported models
- Structured output —
CompleteAsync(..., JsonTypeInfo<T>)for trim- and AOT-safe typed results - Model registry — first-class
AiModelCatalogdescriptors with endpoint/capability metadata - Tool calling — unified tool loop with streaming support, lives once in the facade
- Embeddings — OpenAI and Google embedding models with batch support
- Image generation — Google Gemini image generation via
gemini-2.5-flash-image - Token metering —
TokenUsageon every response including cache and thinking tokens - Resilience — Polly v8 retry and timeout handling wired into provider HTTP execution
- Thinking budget — universal mapping across all providers that support reasoning
- Diagnostics —
CompletionDiagnosticsexposes endpoint family, stop reason, and truncation hints - AOT/trimming-first — manual provider JSON construction/parsing where it reduces reflection risk and wire bloat
Design Goals
- One public facade:
IAiInferenceClient - Internal provider implementations
- Shared
HttpClientper client instance - Explicit model capability metadata instead of implicit provider heuristics
- Sparse provider payloads: omit null/default fields unless the upstream API requires them
Supported Models
OpenAI
| Model | Enum | Context |
|---|---|---|
| GPT-5.2 | AiModel.Gpt52 |
400k |
| GPT-5.2 Pro | AiModel.Gpt52Pro |
400k |
| GPT-5.2 Chat | AiModel.Gpt52Chat |
128k |
| GPT-5.3 Chat | AiModel.Gpt53Chat |
128k |
| GPT-5.4 | AiModel.Gpt54 |
1.05M |
Anthropic
| Model | Enum | Context |
|---|---|---|
| Claude Opus 4.6 | AiModel.ClaudeOpus46 |
200k |
| Claude Sonnet 4.6 | AiModel.ClaudeSonnet46 |
200k |
| Claude Haiku 4.5 | AiModel.ClaudeHaiku45 |
200k |
| Model | Enum | Context |
|---|---|---|
| Gemini 3.5 Flash | AiModel.Gemini35Flash |
1M |
| Gemini 3 Flash Preview | AiModel.Gemini3FlashPreview |
1M |
| Gemini 3.1 Pro Preview | AiModel.Gemini31ProPreview |
1M |
| Gemini 3.1 Flash-Lite Preview | AiModel.Gemini31FlashLitePreview |
1M |
xAI
| Model | Enum | Context |
|---|---|---|
| Grok 4.1 Fast | AiModel.Grok41Fast |
2M |
| Grok 4 | AiModel.Grok4 |
256k |
Embeddings
| Model | Enum | Dimensions | Provider |
|---|---|---|---|
| text-embedding-3-large | EmbeddingModel.TextEmbedding3Large |
3072 | OpenAI |
| text-embedding-3-small | EmbeddingModel.TextEmbedding3Small |
1536 | OpenAI |
| gemini-embedding-001 | EmbeddingModel.GeminiEmbedding001 |
3072 |
Installation
dotnet add package Ai.Tlbx.Inference
Quick Start
Model Registry
var descriptor = AiModelCatalog.Get(AiModel.Gpt52Pro);
Console.WriteLine(descriptor.ApiName);
Console.WriteLine(descriptor.PreferredEndpoint);
Console.WriteLine(descriptor.Capabilities.SupportsResponsesApi);
DI Registration
services.AddAiInference(options =>
{
options.AddOpenAi("sk-...");
options.AddAnthropic("sk-ant-...");
options.AddGoogle("AIza...");
options.AddXai("xai-...");
});
Simple Completion
var response = await client.CompleteAsync(new CompletionRequest
{
Model = AiModel.ClaudeOpus46,
Messages = [new ChatMessage { Role = ChatRole.User, Content = "Hello!" }]
});
Console.WriteLine(response.Content);
Console.WriteLine($"Tokens: {response.Usage.TotalTokens}");
Console.WriteLine(response.Diagnostics?.EndpointFamily);
Console.WriteLine(response.Diagnostics?.Note);
Streaming
await foreach (var delta in client.StreamAsync(new CompletionRequest
{
Model = AiModel.Gpt52,
Messages = [new ChatMessage { Role = ChatRole.User, Content = "Write a haiku" }]
}))
{
Console.Write(delta);
}
Structured Output
public sealed record WeatherInfo
{
public required string City { get; init; }
public required double Temperature { get; init; }
public required string Condition { get; init; }
}
var response = await client.CompleteAsync(new CompletionRequest
{
Model = AiModel.Gemini31FlashLitePreview,
JsonSchema = """{"type":"object","properties":{"city":{"type":"string"},"temperature":{"type":"number"},"condition":{"type":"string"}},"required":["city","temperature","condition"]}""",
Messages = [new ChatMessage { Role = ChatRole.User, Content = "Weather in Berlin?" }]
}, MyJsonContext.Default.WeatherInfo);
Console.WriteLine($"{response.Content.City}: {response.Content.Temperature}°C, {response.Content.Condition}");
AiModel.Gemini35Flash maps to Google's gemini-3.5-flash Gemini API model and supports text,
PDF/document attachments, streaming, structured output, and function calling through the Google
GenerateContent endpoint.
Model Validation
var validation = AiModelValidator.ValidateForCompletion(
AiModel.Gpt52Pro,
streaming: false,
tools: false,
structuredOutput: false);
foreach (var warning in validation.Warnings)
{
Console.WriteLine(warning);
}
Document Attachments
var attachment = new DocumentAttachment
{
FileName = "brief.pdf",
MimeType = "application/pdf",
Content = File.ReadAllBytes("brief.pdf")
};
var response = await client.CompleteAsync(new CompletionRequest
{
Model = AiModel.Gemini31FlashLitePreview,
Messages =
[
new ChatMessage
{
Role = ChatRole.User,
Content = "Read the attached document and summarize it in three bullet points.",
Attachments = [attachment]
}
]
});
Console.WriteLine(response.Content);
Tool Calling
var tools = new List<ToolDefinition>
{
new()
{
Name = "get_weather",
Description = "Get current weather for a city",
ParametersSchema = JsonDocument.Parse(
"""{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}""").RootElement
}
};
var result = await client.CompleteWithToolsAsync(
new CompletionRequest
{
Model = AiModel.ClaudeSonnet46,
Messages = [new ChatMessage { Role = ChatRole.User, Content = "What's the weather in Tokyo?" }]
},
tools,
toolExecutor: async call =>
{
var weather = GetWeather(call.Arguments);
return new ToolCallResult
{
ToolCallId = call.Id,
Result = JsonSerializer.Serialize(weather)
};
});
Console.WriteLine(result.Content);
Console.WriteLine($"Tool iterations: {result.Iterations}, Total tokens: {result.Usage.TotalTokens}");
Embeddings
var embedding = await client.EmbedAsync(new EmbeddingRequest
{
Model = EmbeddingModel.TextEmbedding3Large,
Input = "The quick brown fox"
});
Console.WriteLine($"Dimensions: {embedding.Embedding.Length}");
Image Generation
var imageBytes = await client.GenerateImageAsync(new ImageGenerationRequest
{
Model = ImageGenerationModel.GptImage2,
Prompt = "A product photo of a matte black teapot on a concrete counter",
Size = "1536x1024",
Quality = "high"
});
await File.WriteAllBytesAsync("teapot.png", imageBytes);
ImageGenerationModel selects both the provider and the model. OpenAI image generation uses the Image API and
returns the decoded PNG bytes from data[0].b64_json; Size and Quality map directly to the request. Google
image generation remains available through the default Gemini25FlashImage model and returns the first inline
image bytes from Gemini's response.
Configuration
Logging
services.AddAiInference(options =>
{
options.AddOpenAi("sk-...");
options.WithLogging((level, message) =>
{
Console.WriteLine($"[{level}] {message}");
});
});
Custom Retry Policy
var customPipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddRetry(new RetryStrategyOptions<HttpResponseMessage>
{
MaxRetryAttempts = 2,
Delay = TimeSpan.FromSeconds(5)
})
.Build();
services.AddAiInference(options =>
{
options.AddOpenAi("sk-...");
options.WithRetryPolicy(customPipeline);
});
Google Vertex AI
services.AddAiInference(options =>
{
options.AddGoogle(
serviceAccountJson: File.ReadAllText("service-account.json"),
projectId: "my-project",
location: "us-central1");
});
Thinking Budget
var response = await client.CompleteAsync(new CompletionRequest
{
Model = AiModel.ClaudeOpus46,
ThinkingBudget = 10000,
Messages = [new ChatMessage { Role = ChatRole.User, Content = "Solve this complex problem..." }]
});
Console.WriteLine($"Thinking tokens used: {response.Usage.ThinkingTokens}");
Prompt Caching (Anthropic)
var response = await client.CompleteAsync(new CompletionRequest
{
Model = AiModel.ClaudeSonnet46,
EnableCache = true,
SystemMessage = longSystemPrompt,
Messages = [new ChatMessage { Role = ChatRole.User, Content = "Question..." }]
});
Console.WriteLine($"Cache read: {response.Usage.CacheReadTokens}, Cache write: {response.Usage.CacheWriteTokens}");
AOT / Trimming
The library is AOT and trimming compatible (IsAotCompatible, IsTrimmable).
For structured output and typed tool results, use the JsonTypeInfo<T> overloads and provide your schema explicitly:
[JsonSerializable(typeof(WeatherInfo))]
internal partial class MyJsonContext : JsonSerializerContext { }
var response = await client.CompleteAsync(
new CompletionRequest
{
Model = AiModel.Gemini31FlashLitePreview,
JsonSchema = """{"type":"object","properties":{"city":{"type":"string"},"temp":{"type":"number"}},"required":["city","temp"]}""",
Messages = [new ChatMessage { Role = ChatRole.User, Content = "Weather in Berlin?" }]
},
MyJsonContext.Default.WeatherInfo);
The non-generic methods (CompleteAsync, StreamAsync, EmbedAsync, etc.) are always AOT-safe.
Runtime Notes
- The library does not create ad hoc provider
HttpClientinstances. A single sharedHttpClientis supplied to eachAiInferenceClientinstance and reused by all configured providers for that client. - Provider request payloads are built manually with
JsonObject/JsonArrayso the library can omit unused fields and stay predictable under trimming/AOT. - A small shared JSON policy is used for serializer-based paths, and source-generated DTOs are used for a few stable internal envelopes such as embedding and upload responses.
Paid Integration Tests
Live provider integration tests cost money and are intended to run on demand only.
- Command:
dotnet test tests\Ai.Tlbx.Inference.IntegrationTests\Ai.Tlbx.Inference.IntegrationTests.csproj - Manifest: tests/Ai.Tlbx.Inference.IntegrationTests/live-test-manifest.json
- Source of truth for covered models:
AiModelCatalog - Smoke request helper:
CompletionRequestProfiles
Recommended environment variables:
OPENAI_API_KEYANTHROPIC_API_KEYGOOGLE_API_KEYXAI_API_KEY
The live suite includes:
- simple prompt smoke tests
- streaming tests that verify multi-chunk output
- document attachment tests for supported models
These tests are intentionally not run automatically.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
- Microsoft.Extensions.Http (>= 9.0.18)
- Polly.Core (>= 8.7.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
- Microsoft.Extensions.Http (>= 9.0.18)
- Polly.Core (>= 8.7.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.5 | 98 | 7/19/2026 |
| 2.1.4 | 99 | 7/18/2026 |
| 2.1.3 | 125 | 6/8/2026 |
| 2.1.2 | 109 | 6/4/2026 |
| 2.1.1 | 111 | 5/20/2026 |
| 2.1.0 | 259 | 3/24/2026 |
| 2.0.0 | 151 | 3/7/2026 |
| 1.5.0 | 117 | 2/16/2026 |
| 1.4.1 | 121 | 2/15/2026 |
| 1.4.0 | 135 | 2/15/2026 |
| 1.3.0 | 128 | 2/15/2026 |
| 1.2.0 | 134 | 2/6/2026 |
| 1.1.0 | 128 | 2/6/2026 |
| 1.0.0 | 125 | 2/6/2026 |
2.1.4: add typed image-model routing and OpenAI Image API generation, including GPT Image 2, while preserving Gemini image generation as the default.