Skip to content

devlooped/Extensions.AI

Devlooped AI Extensions

Icon Devlooped AI Extensions

Version Downloads EULA OSS

Extensions for Microsoft.Extensions.AI

Overview

This package adds configuration-driven client registration, provider resolution, tool helpers, OpenAI-specific extensions, and observability helpers for Microsoft.Extensions.AI.

It is split into two packages:

Package Purpose
Devlooped.Extensions.AI Configuration, providers, chat helpers, tools, OpenAI extras, and pipeline observability
Devlooped.Extensions.AI.Console Rich JSON console logging for chat and HTTP pipeline messages

Configuration-driven clients

Register clients from configuration with AddAIClients:

var builder = Host.CreateApplicationBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.AddAIClients();

var app = builder.Build();
var chat = app.Services.GetChatClient("AI:Clients:Grok");

The default configuration prefix is ai:clients. A minimal configuration section looks like this:

{
  "AI": {
    "Clients": {
      "Grok": {
        "provider": "xai",
        "apikey": "xai-...",
        "modelid": "grok-4-fast"
      }
    }
  }
}

Useful rules:

Config shape Registration
section has apikey keyed IClientFactory
section has modelid keyed IChatClient
section has id adds an extra lookup key
section has lifetime controls the chat client lifetime

IChatClient and IClientFactory registrations are keyed by their full configuration section path. An optional id adds a secondary lookup key without replacing the section-path key. IChatClient registrations are reloadable. IClientFactory registrations stay valid across configuration changes and create fresh clients each time you call CreateChatClient, CreateSpeechToTextClient, or CreateTextToSpeechClient.

Built-in provider support:

Provider Name Chat Speech-to-text Text-to-speech Match
OpenAI openai yes yes yes explicit provider, or https://api.openai.com/
Azure OpenAI azure.openai yes yes yes explicit provider, or *.openai.azure.com
Azure AI Inference azure.inference yes no no explicit provider, or https://ai.azure.com/
xAI / Grok xai yes yes yes explicit provider, or https://api.x.ai/

When provider is omitted, endpoint-based matching is used. If no endpoint is provided at all, OpenAI is the default provider.

You can also register your own provider:

builder.Services.AddAIClientProvider<MyClientProvider>();
// or
builder.Services.AddAIClientProvider(sp => new MyClientProvider(sp));

Use useDefaultProviders: false if you want only your own providers:

builder.AddAIClients(useDefaultProviders: false);

Section-bound clients expose the provider options they were created with. Most callers can request the provider options type directly, for example:

var options = chat.GetService<OpenAIClientOptions>();

For keyed lookup, use GetChatClient, GetSpeechToTextClient, and GetTextToSpeechClient.

Client defaults

Use the Configure*ClientDefaults methods to apply shared pipelines without touching each registration site.

builder
    .ConfigureChatClientDefaults(b => b.UseLogging())
    .ConfigureChatClientDefaults("AI:Clients:Grok", b => b.UseLogging())
    .ConfigureSpeechToTextClientDefaults(b => b.UseLogging())
    .ConfigureTextToSpeechClientDefaults(b => b.UseLogging())
    .AddAIClients();

Behavior:

Rule Meaning
Global defaults apply to every client of that modality
Section-specific defaults match the exact configuration section path, case-insensitively
Section paths use : separators, not .
Order registrations run in the order they were added

Chat defaults survive reloads because they are applied outside the reloadable chat wrapper. Factory-created speech/chat clients get defaults applied on each Create* call.

Chat helpers

Chat is a convenient IList<ChatMessage> implementation with factory helpers:

var messages = new Chat
{
    Chat.System("You are a helpful assistant."),
    Chat.User("What is 101 * 3?")
};

var options = new ChatOptions
{
    EndUserId = "user-123"
};

Chat also supports collection initializer syntax with string roles:

var chat = new Chat
{
    { "system", "You are concise." },
    { "user", "Say hello." }
};

Chat.Developer(...) is also available for developer-role messages.

For source-generated serialization, use ChatJsonContext.DefaultOptions.

Tool calling helpers

ToolFactory.Create turns a delegate into an AIFunction with safe, snake_case tool names:

static MyResult RunTool(string name, string description, string content) => new(name, description, content);

AIFunction tool = ToolFactory.Create(RunTool);

ToolExtensions.FindCalls locates tool invocations and their results in ChatResponse or message histories:

var response = await client.GetResponseAsync(messages, options);
var call = response.FindCalls<MyResult>(tool).FirstOrDefault();

if (call is not null)
{
    Console.WriteLine(call.Result);
}

If you only need the raw call/result pair, use the untyped FindCalls overload and inspect Outcome.Exception.

ToolJsonOptions.Default provides the serializer settings used by the tool helpers.

OpenAI extras

The Devlooped.Extensions.AI.OpenAI namespace adds OpenAI-specific helpers on top of ChatOptions.

Verbosity

Verbosity is available as an extension property on ChatOptions:

using Devlooped.Extensions.AI.OpenAI;

var options = new ChatOptions
{
    Verbosity = Verbosity.Low
};

Verbosity is supported by GPT-5+ models. Setting it automatically configures the raw response factory, so do not set a custom RawRepresentationFactory yourself when using it.

If you want a bindable options type, use OpenAIChatOptions.

Web search

WebSearchTool wraps the OpenAI Responses API web search tool with typed location and domain controls:

var options = new ChatOptions
{
    Tools =
    [
        new WebSearchTool("AR")
        {
            Region = "Bariloche",
            TimeZone = "America/Argentina/Buenos_Aires",
            AllowedDomains = ["catedralaltapatagonia.com"]
        }
    ]
};

Supported properties:

Property Meaning
Country ISO alpha-2 country code
Region Free-text region
City Free-text city
TimeZone IANA time zone
AllowedDomains Domain allow-list for search results

Observability

ClientPipelineExtensions adds low-level request/response observation for any ClientPipelineOptions-derived type:

var requests = new List<JsonNode>();
var responses = new List<JsonNode>();

var options = OpenAIClientOptions.Observable(requests.Add, responses.Add);

Observe adds the pipeline policy to an existing options instance; Observable creates a configured instance in one call. Non-JSON payloads are ignored.

Console logging

Install Devlooped.Extensions.AI.Console to get rich JSON console logging.

Chat pipeline logging

using Devlooped.Extensions.AI;
using Microsoft.Extensions.AI;

var chat = someChatClient
    .AsBuilder()
    .UseJsonConsoleLogging(new JsonConsoleOptions
    {
        InteractiveOnly = false,
        TruncateLength = 200
    })
    .Build();

HTTP pipeline logging

var client = new OpenAIClient(
    apiKey,
    new OpenAIClientOptions().UseJsonConsoleLogging());

JsonConsoleOptions lets you control:

Option Meaning
Border / BorderStyle panel appearance
IncludeAdditionalProperties include extra message/response data
InteractiveConfirm ask before enabling logging in interactive consoles
InteractiveOnly suppress output when the console is not interactive
TruncateLength trim long text
WrapLength wrap long text

The default settings favor interactive development sessions and keep non-interactive output quiet.

Open Source Maintenance Fee

To ensure the long-term sustainability of this project, users of this package who generate revenue must pay an Open Source Maintenance Fee. While the source code is freely available under the terms of the License, this package and other aspects of the project require adherence to the Maintenance Fee.

To pay the Maintenance Fee, become a Sponsor at the proper OSMF tier. A single fee covers all of Devlooped packages.

Sponsors

Clarius Org MFB Technologies, Inc. SandRock DRIVE.NET, Inc. Keith Pickford Thomas Bolon Kori Francis Reuben Swartz Jacob Foshee Eric Johnson Jonathan Ken Bonny Simon Cropp agileworks-eu Zheyu Shen Vezel ChilliCream 4OTC domischell Adrian Alonso torutek Ryan McCaffery Seika Logiciel Andrew Grant eska-gmbh

Sponsor this project

Learn more about GitHub Sponsors

About

Extensions for Microsoft.Extensions.AI

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors