AgentExperience.MicrosoftAgentFramework 0.1.0-preview.8

This is a prerelease version of AgentExperience.MicrosoftAgentFramework.
dotnet add package AgentExperience.MicrosoftAgentFramework --version 0.1.0-preview.8
                    
NuGet\Install-Package AgentExperience.MicrosoftAgentFramework -Version 0.1.0-preview.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AgentExperience.MicrosoftAgentFramework" Version="0.1.0-preview.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AgentExperience.MicrosoftAgentFramework" Version="0.1.0-preview.8" />
                    
Directory.Packages.props
<PackageReference Include="AgentExperience.MicrosoftAgentFramework" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AgentExperience.MicrosoftAgentFramework --version 0.1.0-preview.8
                    
#r "nuget: AgentExperience.MicrosoftAgentFramework, 0.1.0-preview.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package AgentExperience.MicrosoftAgentFramework@0.1.0-preview.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=AgentExperience.MicrosoftAgentFramework&version=0.1.0-preview.8&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=AgentExperience.MicrosoftAgentFramework&version=0.1.0-preview.8&prerelease
                    
Install as a Cake Tool

AgentExperience.MicrosoftAgentFramework

Preview — not production ready. This is a 0.1.0-preview package, and it claims no production readiness. Public APIs may change between previews. Read Known limits and documented boundaries before you rely on it.

The Microsoft Agent Framework (MAF) adapter for AgentExperience.NET. It does two independent things; use either, or both (plus an opt-in model-backed reflector):

  • Capture. UseExperienceCapture records every MAF invocation — ordinary, streaming, failed, cancelled, or a stream the consumer stopped reading — and its tool calls as a sanitized Experience Run. It can finalize each run into a durable Experience Record, and record retries as attempts of one run.
  • Injection. ExperienceContextProvider retrieves applicable past experience before each invocation and adds it as one delimited, labeled Historical Reference message.
  • Model-backed reflection (optional, off by default). AddAgentExperienceChatClientReflector replaces the deterministic reflector with ChatClientExperienceReflector, which asks your IChatClient for the lesson text. It sends sanitized captured run content to your model provider — task text, tool names, clipped results and errors, check and evidence IDs. See Model-backed reflection.

Requires Microsoft.Agents.AI 1.22.0 or any later 1.x (declared [1.22.0, 2.0.0)). Targets net10.0. CI tests the floor and the newest 1.x on every change and on a weekly schedule. MAF 2.0 and later are outside the range, and NuGet warns (NU1608) when a host resolves one. Brings in AgentExperience.Core.

The one-call setup

services.AddAgentExperience(...) registers everything capture, injection and verification need, with safe defaults (no tool argument value is captured until you allowlist it, and secret-named fields are redacted). Choose the storage on the builder it returns, with .UseInMemoryStorageForDevelopment() (AgentExperience.Storage.InMemory) or .UsePostgres(connectionString) (AgentExperience.Storage.Postgres), then:

AIAgent agent = new ChatClientAgent(chatClient, new ChatClientAgentOptions
    {
        AIContextProviders = [provider.GetAgentExperienceContextProvider()],   // injection, before the model
    })
    .AsBuilder()
    .UseAgentExperience(provider)                                             // capture and verification, after
    .Build();

UseAgentExperience alone captures but injects nothing: the agent needs the provider in AIContextProviders too. options.ResolveIdentity (required) says who each invocation runs for, from your own authentication; options.Verify runs your own checks on each completed run, and without it nothing is stored. The README quick start shows it whole, and the deployment guide lists every option. The sections below are the explicit wiring, which keeps working unchanged.

Capture

using AgentExperience.Core.Capture;
using AgentExperience.Core.Sanitization;
using AgentExperience.MicrosoftAgentFramework;
using Microsoft.Agents.AI;

IExperienceCaptureService capture = new InMemoryExperienceCaptureService(
    new DefaultSanitizer(sanitizationOptions),
    captureLimits,
    TimeProvider.System);   // the clock completed-run retention is measured on (DI uses the registered one)

AIAgent agent = chatClientAgent
    .AsBuilder()
    .UseExperienceCapture(capture, new ExperienceCaptureOptions
    {
        ResolveRun = context => new ExperienceRunDescriptor(
            TaskId: "triage-ticket",
            Scope: hostScope,                  // established by the host, never taken from model output
            TaskDescription: context.DerivedTaskText),   // the user's own words, stored as written: redact first if needed
        OnCaptureFailure = failure => logger.LogWarning("Capture failed at {Stage}: {Reason}", failure.Stage, failure.Reason),
    })
    .Build();

var response = await agent.RunAsync("...", session);

Call UseExperienceCapture first on the builder so capture is the outermost layer. What to know:

  • Capture never changes what the caller sees. Responses, streaming updates and exceptions are exactly what the agent would produce without it, and capture failures are reported through OnCaptureFailure, never thrown.
  • Everything goes through the capture service's sanitizer and limits. Errors are recorded as the exception's type name only, never its message.
  • Tool calls need a ChatClientAgent (CaptureToolCalls, on by default). Other AIAgent types are captured with CaptureToolCalls = false.
  • Finalization is opt-in. Set FinalizationService and ResolveFinalizationAsync (or the synchronous ResolveFinalization), and each completed run is turned into a durable record inside FinalizationTimeout (5 s by default). That adds caller-visible latency; leave it unset to finalize out of band.
  • Retries can be one run. Return ContinuesRunId from ResolveRun and decide with ShouldCompleteRun, so a lesson sees the failure and the fix together. An open run is always bounded, by MaxAttemptsPerOpenRun (8) and MaxOpenRunDuration (5 minutes).
  • The run ID is written to the session under "AgentExperience.RunId", never into AdditionalProperties (MAF forwards those to the model provider).

Every option, the retry rules and bounds, the supported agent types, and MAF caveats are in Capturing runs with MAF and Finalization.

Injection

using AgentExperience.Core.Retrieval;
using AgentExperience.MicrosoftAgentFramework.Injection;

var provider = new ExperienceContextProvider(
    retrieval,                    // AgentExperience.Core.Retrieval.ExperienceRetrievalService
    recordStore,                  // IExperienceRecordStore: the final eligibility check re-reads through it
    new ExperienceInjectionOptions
    {
        // The user's latest words, bounded; with none (an image-only turn, say), return null to skip injection.
        // Awaited with the invocation's token, so the caller's authorization and scope can be looked up here.
        ResolveRequestAsync = (context, cancellationToken) => ValueTask.FromResult(context.DerivedTaskText is { } taskText
            ? new RetrieveExperienceRequest(
                Authorization: hostAuthorization,  // host-established; nothing in the invocation may widen it
                Scope: hostScope,
                TaskText: taskText)
            : null),
        DecideInjection = decision => riskPolicy.Allows(decision.Current)
            ? InjectionDecision.Permit
            : InjectionDecision.Deny("risk policy"),
    });

var agent = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
    ChatOptions = new ChatOptions { Tools = tools },
    AIContextProviders = [provider],
});

What to know:

  • The label is hygiene, not a security control. The block says it is untrusted reference material; your tool-approval boundary is what stops a harmful call. A test proves an obeyed injected instruction is still denied.
  • Raw payloads never appear. The block carries the lesson, guidance, provenance and, for a verified record, the ordered tool names the run called — never tool results, errors, evidence detail, or an argument value you did not allowlist in ApproachArguments.
  • Every record is re-checked immediately before injection, in one batched read, against every rule retrieval applies, and then offered to your DecideInjection (fail-closed).
  • A lesson the agent cannot act on is not injected, when you declare ReceivingAgent: its available tools and the highest tool risk class it may use. A record whose approach needs a missing tool, or a riskier one, is omitted with its own reason. Passing the gate grants no permission; your approval boundary still decides every call.
  • Limits drop whole records: 8 records and 16 KB per block, re-checked within 500 ms, by default.
  • Reused sessions are tracked by default: at most 32 records and 64 KB per session, no revision twice, and a fixed withdrawal notice when a record the session was given stops being valid. The notice is advisory: the earlier block stays in the history (the KL-12 boundary). SessionLimits = null turns tracking off; two providers on one agent need different SessionStateKeys.
  • It never throws into the invocation, except for the caller's own cancellation.
  • With capture on too, it records on the captured run which records it delivered, which is what lets confidence evidence about that run count.

The payload format, argument allowlists, grant disclosure levels, the session rules, and failure behaviour are in Injection into MAF.

Model-backed reflection

using AgentExperience.MicrosoftAgentFramework.Reflections;

services.AddSingleton<IChatClient>(chatClient);            // a singleton, without UseFunctionInvocation
services.AddAgentExperienceChatClientReflector(options => options.ModelName = "your-model");

What to know:

  • Privacy: it sends sanitized captured run content to your model provider. The task text (or task ID), each attempt's sequence number and ordered tool names, each tool call's and attempt's result and error clipped to 500 characters, and the verification status, check IDs and evidence IDs; never tool arguments, evidence detail, the environment or the scope. It is off unless you register it, and the decision is yours. BuildPrompt shows the exact message, and the system prompt is the public constant ChatClientExperienceReflector.SystemPrompt.
  • Your IChatClient middleware can record it. The library's own telemetry never carries the prompt or the answer, but UseOpenTelemetry with sensitive data enabled, or UseLogging, on the client you hand it does.
  • No tools. Every call offers none, whatever ConfigureChatOptions sets, and a client with UseFunctionInvocation in its pipeline is refused.
  • The model writes only free text. Every bound field is copied from the request, and finalization's binding check and screening apply unchanged. Extra members and reasoning content are ignored and never stored.
  • Failure quarantines. A throw, a timeout (30 s, enforced even on a client that ignores its token), a tool call, an oversized or unparseable answer, or an empty lesson throws ReflectionFailedException, with no model text in it; finalization keeps the record, quarantined.
  • Registration never evicts silently. It replaces the default reflector only; another registered reflector needs replaceExisting: true. A scoped IChatClient is refused, and a keyed client has no unkeyed fallback.
  • Not deterministic, and it costs a model call per verified run finalized. Verification never uses a model. Captured tool output can steer the lesson's text; your approval boundary still denies any call it induces.
  • Marked, filtered and labelled. Its reflections are ReflectionAuthorship.Model (a model-backed reflector of your own must set that itself). Finalization's content guard refuses one carrying a link the run never showed, instruction-override phrasing, credential-shaped text or a mixed-script word, but it is a best-effort filter, not a boundary: content echoed from the run, a poisoned tool result included, passes by design. The controls to rely on are injection's label around every model-written field and ModelAuthoredLessons = Exclude, plus your approval boundary. Its records written before 0.1.0-preview.5 read as deterministic; see the upgrade note in the guide.

Details: Model-backed reflection.

More

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.1.0-preview.8 35 10/9/2026
0.1.0-preview.7 174 10/5/2026
0.1.0-preview.6 55 10/1/2026
0.1.0-preview.5 58 10/1/2026
0.1.0-preview.4 53 9/29/2026
0.1.0-preview.3 56 9/29/2026
0.1.0-preview.2 58 9/26/2026
0.1.0-preview.1 53 9/24/2026

Preview release. Not production ready, and it claims no production readiness: the Known limits table lists every unresolved item, and any unresolved item blocks a production-readiness claim. The Documented boundaries table beside it states exactly what no code change can remove. Public APIs may change between previews. See https://github.com/fabbrik/AgentExperience.NET/blob/main/docs/known-limits.md