AI.Dial.Sharp.Auth
1.0.0-preview.260615.26.1
dotnet add package AI.Dial.Sharp.Auth --version 1.0.0-preview.260615.26.1
NuGet\Install-Package AI.Dial.Sharp.Auth -Version 1.0.0-preview.260615.26.1
<PackageReference Include="AI.Dial.Sharp.Auth" Version="1.0.0-preview.260615.26.1" />
<PackageVersion Include="AI.Dial.Sharp.Auth" Version="1.0.0-preview.260615.26.1" />
<PackageReference Include="AI.Dial.Sharp.Auth" />
paket add AI.Dial.Sharp.Auth --version 1.0.0-preview.260615.26.1
#r "nuget: AI.Dial.Sharp.Auth, 1.0.0-preview.260615.26.1"
#:package AI.Dial.Sharp.Auth@1.0.0-preview.260615.26.1
#addin nuget:?package=AI.Dial.Sharp.Auth&version=1.0.0-preview.260615.26.1&prerelease
#tool nuget:?package=AI.Dial.Sharp.Auth&version=1.0.0-preview.260615.26.1&prerelease
Dial.Sharp
DIAL (Deterministic Integrator of Applications and Language Models) is EPAM’s open-source AI orchestration platform for building and operating enterprise GenAI applications. It provides a unified, model-agnostic Core API (OpenAI-compatible for chat and embeddings) plus services for applications, files, tools, access control, and rate limits — so teams can use many LLMs and DIAL apps through one integration layer instead of separate provider SDKs.
Dial.Sharp is a .NET package that connects that API to Microsoft.Extensions.AI: IChatClient, IEmbeddingGenerator, and ISpeechToTextClient for OpenAI-compatible deployments, plus DialClient for DIAL-native REST endpoints (catalog, tokenize, MCP, and more). The same IChatClient works with Microsoft Agent Framework (ChatClientAgent).
Install the package
NuGet package ID: AI.Dial.Sharp. C# namespace and assembly: Dial.Sharp.
From the command-line:
dotnet add package AI.Dial.Sharp
Or directly in the C# project file:
<ItemGroup>
<PackageReference Include="AI.Dial.Sharp" Version="[CURRENTVERSION]" />
</ItemGroup>
ChatClientBuilder, hosting extensions, caching, and OpenTelemetry middleware require the Microsoft.Extensions.AI package (and related hosting/cache/telemetry packages as needed). For agents, add Microsoft.Agents.AI separately (not a dependency of AI.Dial.Sharp).
Usage Examples
Set DIAL_ENDPOINT and DIAL_API_KEY (or use DialClient.WithBearerToken for OIDC). The deployment name is the model id configured in DIAL (examples use gpt-4o-mini).
Chat
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
IChatClient client =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
Console.WriteLine(await client.GetResponseAsync("What is AI?"));
Chat + Conversation History
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
IChatClient client =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
Console.WriteLine(await client.GetResponseAsync(
[
new ChatMessage(ChatRole.System, "You are a helpful AI assistant"),
new ChatMessage(ChatRole.User, "What is AI?"),
]));
Chat streaming
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
IChatClient client =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
await foreach (var update in client.GetStreamingResponseAsync("What is AI?"))
{
Console.Write(update);
}
Microsoft Agent Framework
Wrap the DIAL-backed IChatClient with AsAIAgent:
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
IChatClient chatClient =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
ChatClientAgent agent = chatClient.AsAIAgent(
instructions: "You are a helpful assistant.",
name: "DialAgent");
AgentResponse response = await agent.RunAsync("What is AI?");
Console.WriteLine(response.Text);
dotnet add package Microsoft.Agents.AI
Agent Framework provider support matrix
Dial.Sharp exposes DIAL deployments through IChatClient on the OpenAI Chat Completions API. The matrix below follows the Agent Framework tools overview and shows which tool types work with ChatClientAgent backed by DialClient.
| Tool Type | Dial (Chat Completions) |
|---|---|
| Function Tools | ✅ |
| Code Interpreter | ❌ |
| File Search | ❌ |
| Web Search | ✅ |
| Hosted MCP Tools | ❌ |
| Local MCP Tools | ✅ |
This matches the Chat Completion column in the Agent Framework provider support matrix: hosted tools such as code interpreter, file search, and hosted MCP require the OpenAI Responses API, which Dial.Sharp does not use today.
Notes
- Function tools and local MCP tools need
ChatClientBuilder.UseFunctionInvocation()(or equivalent agent middleware) so tool calls are executed and results are sent back to the model. - Web search requires
HostedWebSearchToolinChatOptions.Tools/AsAIAgent(..., tools: ...)and a DIAL deployment whose upstream model supports web search. - Tool approval is an Agent Framework feature (not provider-specific) and works with Dial when function invocation runs locally via
Microsoft.Extensions.AI. - DIAL also exposes separate REST endpoints —
DialClient.CodeInterpreter,DialClient.Mcp,DialClient.Files— that are outside this Agent Framework tool matrix. See DIAL Core API.
Runnable samples for supported tool types and speech-to-text: src/examples/ (including SpeechToText for real-time microphone dictation).
DIAL thinking models
using System.ClientModel;
using Dial.Sharp;
using Dial.Sharp.Inference;
using Microsoft.Extensions.AI;
IChatClient client =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
DialChatOptions options = new()
{
EnableThinking = true,
Reasoning = new ReasoningOptions
{
Effort = ReasoningEffort.Medium,
Output = ReasoningOutput.Full,
},
};
Console.WriteLine(await client.GetResponseAsync("Explain recursion briefly.", options));
Arbitrary DIAL request fields
For DIAL fields that have no typed option, set them directly on the underlying ChatCompletionOptions.Patch via RawRepresentationFactory. Use the raw-JSON Patch.Set(path, ReadOnlySpan<byte>) overload for object/array values (the string overload writes a JSON string):
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
using OpenAI.Chat;
IChatClient client =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
ChatOptions options = new()
{
RawRepresentationFactory = _ =>
{
ChatCompletionOptions raw = new();
raw.Patch.Set("$.chat_template_kwargs.enable_thinking"u8, true);
raw.Patch.Set("$.custom_fields"u8, """{"key":"value"}"""u8); // raw-JSON overload
return raw;
},
};
Console.WriteLine(await client.GetResponseAsync("What is AI?", options));
Tool calling
using System.ComponentModel;
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
IChatClient dialClient =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
IChatClient client = new ChatClientBuilder(dialClient)
.UseFunctionInvocation()
.Build();
ChatOptions chatOptions = new()
{
Tools = [AIFunctionFactory.Create(GetWeather)],
};
await foreach (var message in client.GetStreamingResponseAsync("Do I need an umbrella?", chatOptions))
{
Console.Write(message);
}
[Description("Gets the weather")]
static string GetWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";
Caching
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
IDistributedCache cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions()));
IChatClient dialClient =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
IChatClient client = new ChatClientBuilder(dialClient)
.UseDistributedCache(cache)
.Build();
for (int i = 0; i < 3; i++)
{
await foreach (var message in client.GetStreamingResponseAsync("In less than 100 words, what is AI?"))
{
Console.Write(message);
}
Console.WriteLine();
Console.WriteLine();
}
Telemetry
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
using OpenTelemetry.Trace;
var sourceName = Guid.NewGuid().ToString();
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
.AddConsoleExporter()
.Build();
IChatClient dialClient =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
IChatClient client = new ChatClientBuilder(dialClient)
.UseOpenTelemetry(sourceName: sourceName, configure: c => c.EnableSensitiveData = true)
.Build();
Console.WriteLine(await client.GetResponseAsync("What is AI?"));
Telemetry, Caching, and Tool Calling
using System.ComponentModel;
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenTelemetry.Trace;
var sourceName = Guid.NewGuid().ToString();
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
.AddConsoleExporter()
.Build();
IDistributedCache cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions()));
var chatOptions = new ChatOptions
{
Tools = [AIFunctionFactory.Create(GetPersonAge)],
};
IChatClient dialClient =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIChatClient("gpt-4o-mini");
IChatClient client = new ChatClientBuilder(dialClient)
.UseDistributedCache(cache)
.UseFunctionInvocation()
.UseOpenTelemetry(sourceName: sourceName, configure: c => c.EnableSensitiveData = true)
.Build();
for (int i = 0; i < 3; i++)
{
Console.WriteLine(await client.GetResponseAsync("How much older is Alice than Bob?", chatOptions));
}
[Description("Gets the age of a person specified by name.")]
static int GetPersonAge(string personName) =>
personName switch
{
"Alice" => 42,
"Bob" => 35,
_ => 26,
};
Text embedding generation
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
IEmbeddingGenerator<string, Embedding<float>> generator =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIEmbeddingGenerator("text-embedding-3-small");
var embeddings = await generator.GenerateAsync("What is AI?");
Console.WriteLine(string.Join(", ", embeddings[0].Vector.ToArray()));
Text embedding generation with caching
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
IDistributedCache cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions()));
IEmbeddingGenerator<string, Embedding<float>> dialGenerator =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetIEmbeddingGenerator("text-embedding-3-small");
IEmbeddingGenerator<string, Embedding<float>> generator =
new EmbeddingGeneratorBuilder<string, Embedding<float>>(dialGenerator)
.UseDistributedCache(cache)
.Build();
foreach (var prompt in new[] { "What is AI?", "What is .NET?", "What is AI?" })
{
var embeddings = await generator.GenerateAsync(prompt);
Console.WriteLine(string.Join(", ", embeddings[0].Vector.ToArray()));
}
Dependency Injection
AddDialClient registers a singleton DialClient and requires authentication up front:
- Api-Key:
AddDialClient(endpoint, apiKey) - Bearer:
AddDialClient(endpoint, DialBearerToken.From(token)) - OIDC (
AI.Dial.Sharp.Auth):AddDialClient(endpoint)— interactive sign-in with Dynamic Client Registration whenClientIdis not set; passoidcOptions => { ... }only to override defaults
AddDialChatClient and AddDialEmbeddingGenerator return the Microsoft.Extensions.AI ChatClientBuilder / EmbeddingGeneratorBuilder, so you can chain middleware:
using Dial.Sharp;
using Dial.Sharp.DependencyInjection;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder();
builder.Services.AddDistributedMemoryCache();
builder.Services
.AddDialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
Environment.GetEnvironmentVariable("DIAL_API_KEY")!);
builder.Services.AddDialChatClient("gpt-4o-mini")
.UseDistributedCache()
.UseFunctionInvocation();
builder.Services.AddDialEmbeddingGenerator("text-embedding-3-small");
var app = builder.Build();
var chatClient = app.Services.GetRequiredService<IChatClient>();
Console.WriteLine(await chatClient.GetResponseAsync("What is AI?"));
OIDC sign-in (Dial.Sharp.Auth)
The optional AI.Dial.Sharp.Auth package adds interactive OIDC sign-in (Authorization Code + PKCE, automatic refresh, and Dynamic Client Registration when no ClientId is configured). The system browser opens lazily on the first request:
dotnet add package AI.Dial.Sharp.Auth
using Dial.Sharp;
using Dial.Sharp.Auth;
using Dial.Sharp.DependencyInjection;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
Uri endpoint = new(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!);
var services = new ServiceCollection();
services.AddDialClient(endpoint);
services.AddDialChatClient("gpt-4o-mini");
using var provider = services.BuildServiceProvider();
var chatClient = provider.GetRequiredService<IChatClient>();
Console.WriteLine(await chatClient.GetResponseAsync("What is AI?"));
To use a pre-registered client instead of Dynamic Client Registration:
services.AddDialClient(endpoint, o =>
{
o.ClientId = Environment.GetEnvironmentVariable("DIAL_OIDC_CLIENT_ID");
});
Tokens are kept by IDialTokenStore (default: in-memory). Register your own implementation to persist them (for example, in an OS keychain). Without DI, call DialOidcSession.Create(options).CreateDialClient() to get a DialClient whose requests carry the refreshing token. Run the Oidc example:
dotnet run --project src/examples/Oidc
Minimal Web API
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
var builder = WebApplication.CreateBuilder(args);
Uri endpoint = new(builder.Configuration["DIAL:Endpoint"]!);
ApiKeyCredential credential = new(builder.Configuration["DIAL:ApiKey"]!);
builder.Services.AddSingleton(_ => new DialClient(endpoint, credential));
builder.Services.AddChatClient(services =>
services.GetRequiredService<DialClient>().GetIChatClient(builder.Configuration["DIAL:ChatDeployment"]!));
builder.Services.AddEmbeddingGenerator(services =>
services.GetRequiredService<DialClient>().GetIEmbeddingGenerator(builder.Configuration["DIAL:EmbeddingDeployment"]!));
var app = builder.Build();
app.MapPost("/chat", async (IChatClient client, string message) =>
{
var response = await client.GetResponseAsync(message);
return response.Text;
});
app.MapPost("/embedding", async (IEmbeddingGenerator<string, Embedding<float>> client, string message) =>
{
var response = await client.GenerateAsync(message);
return response[0].Vector;
});
app.Run();
Speech-to-text (DIAL ASR)
DIAL ASR deployments (for example qwen3-asr) transcribe audio through chat completions with custom_content.attachments, not the OpenAI /audio/transcriptions endpoint. Dial.Sharp maps them to ISpeechToTextClient:
using System.ClientModel;
using Dial.Sharp;
using Microsoft.Extensions.AI;
using OpenAI.Audio;
ISpeechToTextClient speechToText =
new DialClient(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!))
.GetISpeechToTextClient("qwen3-asr");
await using var audio = File.OpenRead("sample.wav");
var response = await speechToText.GetTextAsync(audio, new SpeechToTextOptions
{
RawRepresentationFactory = _ => new AudioTranscriptionOptions
{
Prompt = "Transcribe this audio.",
},
});
Console.WriteLine(response.Text);
For real-time dictation from the microphone (cross-platform via PortAudio), run the SpeechToText example:
dotnet run --project src/examples/SpeechToText
DIAL REST APIs
DialClient also exposes deployment catalog, files, tokenize, MCP, and related DIAL endpoints:
using System.ClientModel;
using Dial.Sharp;
using Dial.Sharp.Tokenization;
using DialClient dial = new(
new Uri(Environment.GetEnvironmentVariable("DIAL_ENDPOINT")!),
new ApiKeyCredential(Environment.GetEnvironmentVariable("DIAL_API_KEY")!));
var catalog = await dial.DeploymentCatalog.GetAsync();
var counter = dial.GetTokenCounter("gpt-4o-mini");
int tokens = await counter.CountStringAsync("hello");
Documentation
- DIAL Core API
- Microsoft.Extensions.AI
- Microsoft Agent Framework
- Quickstart - Build an AI chat app with .NET — follow the guide and replace the sample provider with
DialClientas shown above
Building this repository
dotnet build Dial.Sharp.slnx
dotnet test Dial.Sharp.slnx
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- AI.Dial.Sharp (>= 1.0.0-preview.260615.26.1)
- Microsoft.Extensions.Http (>= 10.0.8)
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 |
|---|---|---|
| 1.0.0-preview.260615.26.1 | 79 | 6/15/2026 |
| 1.0.0-preview.260615.25.1 | 69 | 6/15/2026 |
| 1.0.0-preview.260615.23.1 | 68 | 6/15/2026 |
| 1.0.0-preview.260613.21.1 | 70 | 6/13/2026 |
| 1.0.0-preview.260608.19.1 | 70 | 6/8/2026 |