Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions AI.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Folder Name="/Sample/">
<Project Path="sample/Aspire/Aspire.csproj" Id="6166be22-a13f-4074-91a9-b0f3b3a6c4fe" />
<Project Path="sample/Client/Client.csproj" />
<Project Path="sample/Server/Server.csproj" Id="34619937-085f-453d-bc12-9ab2d4abccb7" />
</Folder>
<Project Path="src/Agents/Agents.csproj" Id="90827430-b415-47d6-aac9-2dbe4911b348" />
<Project Path="src/Extensions.CodeAnalysis/Extensions.CodeAnalysis.csproj" />
<Project Path="src/Extensions.Grok/Extensions.Grok.csproj" Id="3590dc05-72f0-4ada-823b-60cb7b5ea828" />
<Project Path="src/Extensions/Extensions.csproj" />
Expand Down
268 changes: 3 additions & 265 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black&color=C9FF30)](osmfeula.txt)
[![OSS](https://img.shields.io/github/license/devlooped/oss.svg?color=blue)](license.txt)
[![Version](https://img.shields.io/nuget/vpre/Devlooped.Extensions.AI.svg?color=royalblue)](https://www.nuget.org/packages/Devlooped.Extensions.AI)
[![Downloads](https://img.shields.io/nuget/dt/Devlooped.Extensions.AI.svg?color=green)](https://www.nuget.org/packages/Devlooped.Extensions.AI)

Extensions for Microsoft.Agents.AI and Microsoft.Extensions.AI.
Extensions for Microsoft.Extensions.AI.

<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
## Open Source Maintenance Fee
Expand All @@ -19,270 +21,6 @@ OSMF tier. A single fee covers all of [Devlooped packages](https://www.nuget.org

<!-- https://github.com/devlooped/.github/raw/main/osmf.md -->

# Devlooped.Agents.AI

[![Version](https://img.shields.io/nuget/vpre/Devlooped.Agents.AI.svg?color=royalblue)](https://www.nuget.org/packages/Devlooped.Agents.AI)
[![Downloads](https://img.shields.io/nuget/dt/Devlooped.Agents.AI.svg?color=green)](https://www.nuget.org/packages/Devlooped.Agents.AI)

<!-- #agents-title -->
Extensions for Microsoft.Agents.AI, such as configuration-driven auto-reloading agents.
<!-- #agents-title -->

<!-- #agents -->
## Overview

Microsoft.Agents.AI (aka [Agent Framework](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview)
is a comprehensive API for building AI agents. Its programatic model (which follows closely
the [Microsoft.Extensions.AI](https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai)
approach) provides maximum flexibility with little prescriptive structure.

This package provides additional extensions to make developing agents easier and more
declarative.

## Configurable Agents

Tweaking agent options such as description, instructions, chat client to use and its
options, etc. is very common during development/testing. This package provides the ability to
drive those settings from configuration (with auto-reload support). This makes it far easier
to experiment with various combinations of agent instructions, chat client providers and
options, and model parameters without changing code, recompiling or even restarting the application:

> [!NOTE]
> This example shows integration with configurable chat clients feature from the
> Devlooped.Extensions.AI package, but any `IChatClient` registered in the DI container
> with a matching key can be used.

```json
{
"AI": {
"Agents": {
"MyAgent": {
"Description": "An AI agent that helps with customer support.",
"Instructions": "You are a helpful assistant for customer support.",
"Client": "Grok",
"Options": {
"ModelId": "grok-4",
"Temperature": 0.5,
}
}
},
"Clients": {
"Grok": {
"Endpoint": "https://api.grok.ai/v1",
"ModelId": "grok-4-fast-non-reasoning",
"ApiKey": "xai-asdf"
}
}
}
}
````

```csharp
var host = new HostApplicationBuilder(args);
host.Configuration.AddJsonFile("appsettings.json, optional: false, reloadOnChange: true);

// 👇 implicitly calls AddChatClients
host.AddAIAgents();

var app = host.Build();
var agent = app.Services.GetRequiredKeyedService<AIAgent>("MyAgent");
```

Agents are also properly registered in the corresponding Microsoft Agent Framework
[AgentCatalog](https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.ai.hosting.agentcatalog):

```csharp
var catalog = app.Services.GetRequiredService<AgentCatalog>();
await foreach (AIAgent agent in catalog.GetAgentsAsync())
{
var metadata = agent.GetService<AIAgentMetadata>();
Console.WriteLine($"Agent: {agent.Name} by {metadata.ProviderName}");
}
```

You can of course use any config format supported by .NET configuration, such as
TOML which is arguably more human-friendly for hand-editing:

```toml
[ai.clients.openai]
modelid = "gpt-4.1"

[ai.clients.grok]
endpoint = "https://api.x.ai/v1"
modelid = "grok-4-fast-non-reasoning"

[ai.agents.orders]
description = "Manage orders using catalogs for food or any other item."
instructions = """
You are an AI agent responsible for processing orders for food or other items.
Your primary goals are to identify user intent, extract or request provider information, manage order data using tools and friendly responses to guide users through the ordering process.
"""

# ai.clients.openai, can omit the ai.clients prefix
client = "openai"

[ai.agents.orders.options]
modelid = "gpt-4o-mini"
```

This can be used by leveraging [Tomlyn.Extensions.Configuration](https://www.nuget.org/packages/Tomlyn.Extensions.Configuration).

> [!NOTE]
> This package will automatically dedent and trim start and end newlines from
> multi-line instructions and descriptions when applying the configuration,
> avoiding unnecessary tokens being used for indentation while allowing flexible
> formatting in the config file.

You can also leverage the format pioneered by [VS Code Chat Modes](https://code.visualstudio.com/docs/copilot/customization/custom-chat-modes),
(por "custom agents") by using markdown format plus YAML front-matter for better readability:

```yaml
---
id: ai.agents.notes
description: Provides free-form memory
client: grok
model: grok-4-fast
---
You organize and keep notes for the user.
# Some header
More content
```

Visual Studio Code will ignore the additional attributes used by this project. In particular, the `model`
property is a shorthand for setting the `options.modelid`, but in our implementation, the latter takes
precedence over the former, which allows you to rely on `model` to drive the VSCode testing, and the
longer form for run-time with the Agents Framework:

```yaml
---
id: ai.agents.notes
description: Provides free-form memory
model: Grok Code Fast 1 (copilot)
client: grok
options:
modelid: grok-code-fast-1
---
// Instructions
```

![agent model picker](assets/img/agent-model.png)

Use the provided `AddAgentMarkdown` extension method to load instructions from files as follows:

```csharp
var host = new HostApplicationBuilder(args);
host.Configuration.AddAgentMarkdown("notes.agent.md", optional: false, reloadOnChange: true);
```

The `id` field in the front-matter is required and specifies the configuration section name, and
all other fields are added as if they were specified under it in the configuration.

### Extensible AI Contexts

The Microsoft [agent framework](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview) allows extending
agents with dynamic context via [AIContextProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.ai.aicontextprovider)
and `AIContext`. This package supports dynamic extension of a configured agent in the following ways (in order of priority):

1. A keyed service `AIContextProviderFactory` with the same name as the agent will be set up just as if you had
set it manually as the [ChatClientAgentOptions.AIContextProviderFactory](https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.ai.chatclientagentoptions.aicontextproviderfactory)
in code.
2. Aggregate of AI contexts from:
a. Keyed service `AIContextProvider` with the same name as the agent.
b. Keyed service `AIContext` with the same name as the agent.
c. Other services pulled in via `use` setting for an agent registered as either `AIContextProvider` or `AIContext`
with a matching key.

The first option assumes you want full control of the context, so it does not allow futher composition.
The second alternative allows more declarative scenarios involving reusable and cross-cutting
context definitions.

For example, let's say you want to provide consistent tone for all your agents. It would be tedious, repetitive and harder
to maintain if you had to set that in each agent's instructions. Instead, you can define a reusable context named `tone` such as:

```toml
[ai.context.tone]
instructions = """\
Default to using spanish language, using argentinean "voseo" in your responses \
(unless the user explicitly talks in a different language). \
This means using "vos" instead of "tú" and conjugating verbs accordingly. \
Don't use the expression "pa'" instead of "para". Don't mention the word "voseo".
"""
```

Then, you can reference that context in any agent using the `use` setting:
```toml
[ai.agents.support]
description = "An AI agent that helps with customer support."
instructions = "..."
client = "grok"
use = ["tone"]

[ai.agents.sales]
description = "An AI agent that helps with sales inquiries."
instructions = "..."
client = "openai"
use = ["tone"]
```

Configured contexts can provide all three components of an `AIContext`: instructions, messages and tools, such as:

```toml
[ai.context.timezone]
instructions = "Always assume the user's timezone is America/Argentina/Buenos_Aires unless specified otherwise."
messages = [
{ system = "You are aware of the current date and time in America/Argentina/Buenos_Aires." }
]
tools = ["get_date"]
```

If multiple contexts are specified in `use`, they are applied in order, concatenating their instructions, messages and tools.

In addition to configured sections, the `use` property can also reference exported contexts as either `AIContext`
(for static context) or `AIContextProvider` (for dynamic context) registered in DI with a matching name.


### Extensible Tools

The `tools` section allows specifying tool names registered in the DI container, such as:

```csharp
services.AddKeyedSingleton("get_date", AIFunctionFactory.Create(() => DateTimeOffset.Now, "get_date"));
```

This tool will be automatically wired into any agent that uses the `timezone` context above.

Agents themselves can also add tools from DI into an agent's context without having to define an entire
section just for that, by specifying the tool name directly in the `tools` array:

```toml
[ai.agents.support]
description = "An AI agent that helps with customer support."
instructions = "..."
client = "grok"
use = ["tone"]
tools = ["get_date"]
```

This enables a flexible and convenient mix of static and dynamic context for agents, all driven
from configuration.

In addition to registering your own tools in DI, you can also use leverage the MCP C# SDK and reuse
the same tool declarations:

```csharp
builder.Services.AddMcpServer().WithTools<NotesTools>();

// 👇 Reuse same tool definitions in agents
builder.AddAIAgents().WithTools<NotesTools>();
```

<!-- #agents -->

# Devlooped.Extensions.AI

[![Version](https://img.shields.io/nuget/vpre/Devlooped.Extensions.AI.svg?color=royalblue)](https://www.nuget.org/packages/Devlooped.Extensions.AI)
[![Downloads](https://img.shields.io/nuget/dt/Devlooped.Extensions.AI.svg?color=green)](https://www.nuget.org/packages/Devlooped.Extensions.AI)

<!-- #extensions-title -->
Extensions for Microsoft.Extensions.AI
<!-- #extensions-title -->
Expand Down
15 changes: 0 additions & 15 deletions sample/Aspire/AppHost.cs

This file was deleted.

19 changes: 0 additions & 19 deletions sample/Aspire/Aspire.csproj

This file was deleted.

29 changes: 0 additions & 29 deletions sample/Aspire/Properties/launchSettings.json

This file was deleted.

8 changes: 0 additions & 8 deletions sample/Aspire/appsettings.Development.json

This file was deleted.

9 changes: 0 additions & 9 deletions sample/Aspire/appsettings.json

This file was deleted.

Loading
Loading