Microsoft.Agents.Ai Hits 1.0 — What It Means for FabrCore
The Microsoft Agent Framework has shipped its 1.0.0 GA release of Microsoft.Agents.AI and Microsoft.Agents.AI.Abstractions. FabrCore has been tracking the RC builds since the early previews, and today we are pinned to the stable 1.0 packages. Here is what the framework provides, how FabrCore uses it, and what the GA milestone means for teams building production agents.
What Microsoft.Agents.AI Provides
The framework defines a small, focused set of abstractions for building LLM-powered agents. At the center is AIAgent — an abstract base class that handles session management, execution (both streaming and non-streaming), and service resolution. The concrete implementation that ships out of the box is ChatClientAgent, which wraps any IChatClient from Microsoft.Extensions.AI.
The key types across the two packages:
| Type | Package | Role |
|---|---|---|
AIAgent | Abstractions | Abstract base — session management, RunAsync, RunStreamingAsync |
AgentSession | Abstractions | Conversation state container with StateBag for arbitrary key-value data |
AgentResponse | Abstractions | Complete response from a non-streaming run |
AgentResponseUpdate | Abstractions | Individual chunk from a streaming run |
ChatClientAgent | Microsoft.Agents.AI | Sealed implementation wrapping IChatClient with instructions, tools, history |
ChatClientAgentOptions | Microsoft.Agents.AI | Configuration — name, description, chat options, history provider |
AIAgentBuilder | Microsoft.Agents.AI | Middleware pipeline for intercepting agent runs |
The framework intentionally stays thin. It does not prescribe how you host agents, how you persist sessions, or which LLM provider you use. That is where FabrCore steps in.
How FabrCore Uses the Framework
Every FabrCore agent extends FabrCoreAgentProxy, which provides a CreateChatClientAgent helper method. Under the hood, this method does three things: it creates an IChatClient for the configured model via FabrCoreChatClientService, wraps it in a ChatClientAgent with your system prompt and tools, and creates an AgentSession backed by FabrCoreChatHistoryProvider for automatic chat history persistence.
private AIAgent? _agent;
private AgentSession? _session;
public override async Task OnInitialize()
{
var tools = await ResolveConfiguredToolsAsync();
var result = await CreateChatClientAgent(
chatClientConfigName: config.Models ?? "default",
threadId: config.Handle ?? fabrcoreAgentHost.GetHandle(),
tools: tools);
_agent = result.Agent; // AIAgent (ChatClientAgent)
_session = result.Session; // AgentSession with auto-persisted history
}
Once initialized, your OnMessage handler calls either RunAsync for a complete response or RunStreamingAsync to stream tokens as they arrive:
public override async Task<AgentMessage> OnMessage(AgentMessage message)
{
var response = message.Response();
var chatMessage = new ChatMessage(ChatRole.User, message.Message);
var result = await _agent!.RunAsync(chatMessage, _session!);
response.Message = result.Text;
return response;
}
public override async Task<AgentMessage> OnMessage(AgentMessage message)
{
var response = message.Response();
var chatMessage = new ChatMessage(ChatRole.User, message.Message);
await foreach (var update in _agent!.RunStreamingAsync(chatMessage, _session!))
{
response.Message += update.Text;
}
return response;
}
FabrCore also automatically tracks LLM usage across all calls within a single OnMessage invocation — input tokens, output tokens, reasoning tokens, call count, and duration — attaching them to the response AgentMessage.Args without any extra code.
Session Management and Serialization
AgentSession holds the conversation state between agent runs. FabrCore backs each session with a FabrCoreChatHistoryProvider that automatically persists chat history to Orleans grain state, so sessions survive grain deactivation and reactivation without any manual save/load code.
The session also carries a StateBag for arbitrary key-value data that your agent can read and write during a conversation:
// Store custom state in the session
_session!.StateBag.SetValue("userPreferences", new UserPrefs { Theme = "dark" });
// Read it back in a later turn
var prefs = _session!.StateBag.GetValue<UserPrefs>("userPreferences");
For advanced scenarios, sessions can be serialized to JSON and restored later using SerializeSessionAsync and DeserializeSessionAsync on AIAgent. This is useful for migrating conversation state between agent instances or storing session snapshots externally.
What the 1.0 GA Release Means
Moving from RC to GA brings three practical benefits:
- Stable API surface. The core types —
AIAgent,AgentSession,ChatClientAgent,AgentResponse, andAgentResponseUpdate— are now under semantic versioning. Breaking changes require a major version bump, which means FabrCore agents built today will not need rewrites for framework updates. - Production-ready middleware. The
AIAgentBuildermiddleware pipeline is stable. You can intercept agent runs for logging, security checks, or response modification without worrying about the API changing under you. - Ecosystem alignment. With
Microsoft.Extensions.AIalready at GA andMicrosoft.Agents.AInow joining it, the full stack fromIChatClientup through agent orchestration is stable. FabrCore sits on top of both, and having stable foundations underneath means fewer dependency conflicts and smoother upgrades.
FabrCore's FabrCore.Sdk package includes Microsoft.Agents.AI and Microsoft.Agents.AI.Abstractions as transitive dependencies, so upgrading is automatic when you update the FabrCore NuGet packages.
Built with FabrCore on .NET 10.
Builder of FabrCore and OpenCaddis.