MICROSOFT AGENT FRAMEWORK · 0.16.0-rc.1
Demo420 — Safe Telemetry
Observe safe spans and distinguish deterministic mode from actual requests.
Objectives
- Correlate safe native and HTTP spans and record nullable measured usage.
Prepare an isolated experiment
From BaseTechnique or the extracted repository root, build the Release solution. The App project calls ObservabilityDemo in Maf.Observability; Demo420 and Demo430 share this implementation. Documented --deterministic mode loads no model, embeddings or collector. A fresh database distinguishes this experiment’s actions.
dotnet build BaseTechnique.slnx -m:1 -c ReleaseRun without a model
$journal = Join-Path $env:TEMP ("maf-lot012-" + [guid]::NewGuid().ToString("N") + ".db")dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --deterministic --db $journalRecord ExecutionId, TraceId and Database. Expect an accepted workflow followed by ActionCommitted and ExecutionSucceeded. Trace: lines contain SafeSpan JSON; Workflow event: lines describe progress. No model consumption is measured in this mode. Identifiers and durations change on every execution.
public static SafeSpan Project(Activity activity) => new(
activity.Source.Name == Source.Name ? "host" : activity.Source.Name.StartsWith("System.Net.Http", StringComparison.Ordinal)
? "http" : activity.Source.Name.StartsWith("Microsoft.Agents.AI.Workflows", StringComparison.Ordinal)
? "maf.workflow" : activity.Source.Name.StartsWith("Microsoft.Extensions.AI", StringComparison.Ordinal)
? "maf.model" : "maf.agent",
activity.Source.Name == Source.Name && activity.OperationName is "execution" or "tool" or "workflow" or "model"
? activity.OperationName : "operation",
activity.TraceId.ToString(), activity.SpanId.ToString(), activity.ParentSpanId.ToString(),
activity.Duration.TotalMilliseconds, activity.Status.ToString());
Inject a failure and read back
dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --deterministic --fail --db $journalThis new execution has another GUID. --fail interrupts immediately before CommitReview: exit 1, Intention then ExecutionFailed, no ActionCommitted for this GUID. Earlier actions remain. --read expects an existing GUID; enter the execution identifier to inspect.
$executionId = Read-Host 'ExecutionId to inspect'dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --db $journal --read $executionIdWithout --deterministic, the program loads the common connection and calls a real agent with get_review_policy followed by a native reviewer. The required tool call is checked; failure triggers no generated fallback decision. Run only with the configured provider available; request counters can remain null.
dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --db $journalCheck evidence beyond the exit code
In a new process, read the successful execution and verify ActionId with HasAction. Also read the failed execution: readback can exit 0 despite no action, because every present action was verified and none exists. Inspect Kind and ActionId. Tests cover restart, replay of the same GUID, native correlation, excluded secrets and missing usage.
dotnet test tests/Maf.Observability.Tests/Maf.Observability.Tests.csproj -m:1 -c Release --no-build --no-restorevar input = usage?.InputTokenCount;
var output = usage?.OutputTokenCount;
long? derived = input.HasValue && output.HasValue ? checked(input.Value + output.Value) : null;
decimal? cost = rate is not null && input.HasValue && output.HasValue
? (input.Value * rate.InputPerMillion + output.Value * rate.OutputPerMillion) / 1_000_000m : null;
return new(input, output, usage?.TotalTokenCount, derived,
contextCharacters.HasValue ? ((long)contextCharacters.Value + 3) / 4 : null,
cost, rate?.Currency, rate?.Version);
Preserve local scope
The local commit records ReviewRequested; it performs no remote deletion, refund or other remote effect. --erase deletes only the chosen execution’s metadata and is not a business undo. The journal is not immutable. Redirected console output is its owner’s responsibility; no raw file is published on the site.
Follow shared code
public static TracerProvider CreateProvider(Action<SafeSpan> write) => Sdk.CreateTracerProviderBuilder()
.AddSource("Maf.Renovation", "Maf.NativeAgent", "Microsoft.Agents.AI*", "Microsoft.Extensions.AI*")
.AddHttpClientInstrumentation()
.AddProcessor(new SimpleActivityExportProcessor(new SafeExporter(write))).Build();
/// <summary>Adds the native MAF decorator with sensitive data explicitly disabled.</summary>
public static AIAgent Instrument(AIAgent agent) => agent.AsBuilder()
.UseOpenTelemetry(sourceName: "Maf.NativeAgent", configure: options => options.EnableSensitiveData = false).Build();
