chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<!--
Simulate an AOT / trim-aggressive deployment by disabling System.Text.Json's
implicit reflection fallback. When this flag is false, any JSON operation in
the process must resolve type info via a source-generated JsonSerializerContext
or fail at runtime (the checkpoint pipeline surfaces this as
InvalidOperationException: "No JSON type info is available for type 'X'").
This is the same constraint that 'dotnet publish -p:PublishAot=true' imposes,
observed without requiring a full AOT publish.
-->
<PropertyGroup>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
<PropertyGroup>
<InjectIsExternalInitOnLegacy>true</InjectIsExternalInitOnLegacy>
<InjectSharedFoundryAgents>true</InjectSharedFoundryAgents>
<InjectSharedWorkflowsSettings>true</InjectSharedWorkflowsSettings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Workflows.Declarative\Microsoft.Agents.AI.Workflows.Declarative.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Workflows.Declarative.Foundry\Microsoft.Agents.AI.Workflows.Declarative.Foundry.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="AotCheckpointing.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,38 @@
#
# This workflow has three discrete actions so each runs in a distinct
# superstep, making the checkpoint progression easy to follow.
#
# 1. SetVariable: capture the user input
# 2. InvokeAzureAgent: greet the user via an Azure agent (autoSend on)
# 3. SendActivity: emit a closing message
#
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_aot_demo
actions:
# Capture the user's input
- kind: SetVariable
id: set_input
variable: Local.UserInput
value: =System.LastMessage.Text
# Invoke the greeting agent and stream the response to the user
- kind: InvokeAzureAgent
id: invoke_greeter
conversationId: =System.ConversationId
agent:
name: GreeterAgent
input:
messages: =Local.UserInput
output:
messages: Local.GreeterResponse
autoSend: true
# Emit a closing activity so there is a clear final superstep
- kind: SendActivity
id: send_summary
activity: |-
[Sample] Workflow completed. Checkpoints persisted to disk.
@@ -0,0 +1,174 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Checkpointing;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Shared.Foundry;
using Shared.Workflows;
namespace Demo.Workflows.Declarative.AotCheckpointing;
/// <summary>
/// Demonstrates JSON checkpointing of a declarative workflow under reflection-disabled
/// <see cref="System.Text.Json.JsonSerializer"/> (the AOT / trim-aggressive constraint set
/// via <c>JsonSerializerIsReflectionEnabledByDefault=false</c> in the csproj).
/// </summary>
/// <remarks>
/// The key call is <see cref="CheckpointManager.CreateJson(ICheckpointStore{System.Text.Json.JsonElement}, System.Text.Json.JsonSerializerOptions?)"/>
/// with <see cref="DeclarativeWorkflowJsonOptions.Default"/>. Drop the options argument to observe the AOT failure. See README.
/// </remarks>
internal sealed class Program
{
public static async Task Main(string[] args)
{
IConfiguration configuration = Application.InitializeConfig();
Uri foundryEndpoint = new(configuration.GetValue(Application.Settings.FoundryEndpoint));
await CreateGreeterAgentAsync(foundryEndpoint, configuration);
string workflowInput = Application.GetInput(args);
Workflow CreateWorkflow()
{
AzureAgentProvider agentProvider = new(foundryEndpoint, new AzureCliCredential());
DeclarativeWorkflowOptions options = new(agentProvider) { Configuration = configuration };
string workflowPath = Path.Combine(AppContext.BaseDirectory, "AotCheckpointing.yaml");
return DeclarativeWorkflowBuilder.Build<string>(workflowPath, options);
}
DirectoryInfo checkpointFolder = Directory.CreateDirectory(Path.Combine(".", $"chk-{DateTime.Now:yyMMdd-HHmmss-ff}"));
try
{
using FileSystemJsonCheckpointStore store = new(checkpointFolder);
// KEY LINE: AOT-safe checkpoint manager. Drop the options argument to see the failure.
CheckpointManager checkpointManager = CheckpointManager.CreateJson(store, DeclarativeWorkflowJsonOptions.Default);
Console.WriteLine($"\nCheckpoint folder: {checkpointFolder.FullName}");
// Phase 1: run + drain. Every [checkpoint x<n>] line is a successful JSON WRITE.
List<CheckpointInfo> checkpoints = await RunAndStreamAsync(CreateWorkflow(), workflowInput, checkpointManager).ConfigureAwait(false);
// Phase 2: prove the JSON READ path. ResumeStreamingAsync deserializes the checkpoint
// inside the call; a clean return is the proof. We do not drain the resumed run because
// it parks in WaitForInputAsync without a pending external request.
if (checkpoints.Count > 0)
{
CheckpointInfo resumeFromCheckpoint = checkpoints[0];
Console.WriteLine($"\nWORKFLOW: Verifying read path by resuming from checkpoint {resumeFromCheckpoint.CheckpointId}");
StreamingRun resumed = await InProcessExecution.ResumeStreamingAsync(CreateWorkflow(), resumeFromCheckpoint, checkpointManager).ConfigureAwait(false);
await resumed.DisposeAsync().ConfigureAwait(false);
Console.WriteLine("WORKFLOW: Checkpoint deserialized successfully");
}
Console.WriteLine("\nWORKFLOW: Done!\n");
}
finally
{
TryDelete(checkpointFolder);
}
}
private static async Task<List<CheckpointInfo>> RunAndStreamAsync(Workflow workflow, string input, CheckpointManager checkpointManager)
{
StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input, checkpointManager).ConfigureAwait(false);
return await DrainAsync(run).ConfigureAwait(false);
}
private static async Task<List<CheckpointInfo>> DrainAsync(StreamingRun run)
{
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
await using IAsyncDisposable disposeRun = run;
#pragma warning restore CA2007
List<CheckpointInfo> checkpoints = [];
string? streamingMessageId = null;
await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync().ConfigureAwait(false))
{
switch (workflowEvent)
{
case WorkflowErrorEvent workflowError:
throw workflowError.Data as Exception ?? new InvalidOperationException("Unexpected workflow failure.");
case SuperStepCompletedEvent superStepCompleted:
CheckpointInfo? checkpoint = superStepCompleted.CompletionInfo?.Checkpoint;
if (checkpoint is not null)
{
checkpoints.Add(checkpoint);
}
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($"\n[checkpoint x{superStepCompleted.StepNumber}: {checkpoint?.CheckpointId ?? "(none)"}]");
Console.ResetColor();
break;
case MessageActivityEvent activityEvent:
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"\nACTIVITY: {activityEvent.Message.Trim()}");
Console.ResetColor();
break;
case AgentResponseUpdateEvent streamEvent:
if (!string.Equals(streamingMessageId, streamEvent.Update.MessageId, StringComparison.Ordinal))
{
streamingMessageId = streamEvent.Update.MessageId;
string agentName = streamEvent.Update.AuthorName ?? streamEvent.Update.AgentId ?? nameof(ChatRole.Assistant);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write($"\n{agentName.ToUpperInvariant()}: ");
Console.ResetColor();
}
Console.Write(streamEvent.Update.Text);
break;
}
}
return checkpoints;
}
private static async Task CreateGreeterAgentAsync(Uri foundryEndpoint, IConfiguration configuration)
{
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIProjectClient aiProjectClient = new(foundryEndpoint, new DefaultAzureCredential());
DeclarativeAgentDefinition definition =
new(configuration.GetValue(Application.Settings.FoundryModel))
{
Instructions =
"""
You are a warm and concise greeter. Reply to the user's message in
one or two short sentences. Always include the user's name if they
provided one, and end with a friendly question.
"""
};
await aiProjectClient.CreateAgentAsync(
agentName: "GreeterAgent",
agentDefinition: definition,
agentDescription: "Greeter agent for the AotCheckpointing sample.");
}
private static void TryDelete(DirectoryInfo directory)
{
try
{
directory.Refresh();
if (directory.Exists)
{
directory.Delete(recursive: true);
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($"\n(could not clean up '{directory.FullName}': {ex.Message})");
Console.ResetColor();
}
}
}
@@ -0,0 +1,107 @@
# AotCheckpointing sample
Demonstrates JSON checkpointing of a declarative workflow under
reflection-disabled `System.Text.Json` -- the same constraint imposed by
**AOT / trim-aggressive deployments**.
## What it shows
- A 3-action declarative workflow
(`SetVariable` -> `InvokeAzureAgent` -> `SendActivity`) checkpointed
after every superstep.
- The csproj sets
`<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>`.
Every JSON operation must resolve type info via a source-gen
`JsonSerializerContext` or fail with
`InvalidOperationException: No JSON type info is available for type 'X'`.
- The experimental
[`DeclarativeWorkflowJsonOptions.Default`](../../../../src/Microsoft.Agents.AI.Workflows.Declarative/DeclarativeWorkflowJsonOptions.cs)
`JsonSerializerOptions` instance covers every declarative-package
type that flows through the checkpoint pipeline. Pass it to
`CheckpointManager.CreateJson`.
- JSON round-trip is verified in two phases:
1. Run + drain -- every `[checkpoint x<n>]` line is a successful JSON **write**.
2. `ResumeStreamingAsync` on a fresh workflow instance -- a clean
return is the proof JSON **reads** round-trip too. The resumed run
is disposed immediately; without a pending external request it
would park in `WaitForInputAsync` indefinitely.
`DeclarativeWorkflowJsonOptions` is marked
`[Experimental("MAAI001")]`. Suppress that diagnostic in your csproj to
use it.
### Registering user-defined types
For workflows whose inputs or custom `ActionExecutorResult.Result`
payloads are user-defined, clone `Default` and append your own resolver:
```csharp
JsonSerializerOptions options = new(DeclarativeWorkflowJsonOptions.Default);
options.TypeInfoResolverChain.Add(MyAppJsonContext.Default);
options.MakeReadOnly();
CheckpointManager manager = CheckpointManager.CreateJson(store, options);
```
## Run
Prerequisites:
- Azure Foundry project with a deployed model.
- `az login`.
- Configuration (user secrets or env):
| Setting | Description |
| --- | --- |
| `AZURE_AI_PROJECT_ENDPOINT` | Foundry project endpoint URL. |
| `AZURE_AI_MODEL_DEPLOYMENT_NAME` | Model deployment name. |
See the [parent README](../README.md) for the full walkthrough.
```sh
cd dotnet/samples/03-workflows/Declarative/AotCheckpointing
dotnet run "Hello, my name is Ada."
```
Expected output:
1. `[checkpoint x<n>]` lines after each superstep.
2. The agent's streamed response.
3. `ACTIVITY: [Sample] Workflow completed. ...`
4. `WORKFLOW: Verifying read path by resuming from checkpoint <id>`
5. `WORKFLOW: Checkpoint deserialized successfully`
6. `WORKFLOW: Done!`
The `chk-*/` checkpoint folder is deleted at the end.
## Observe the failure mode
Drop the options argument:
```csharp
CheckpointManager checkpointManager = CheckpointManager.CreateJson(store, DeclarativeWorkflowJsonOptions.Default);
```
becomes
```csharp
CheckpointManager checkpointManager = CheckpointManager.CreateJson(store);
```
Clean rebuild, then re-run. Expected on the first checkpoint commit:
```
System.InvalidOperationException: No JSON type info is available for type
'Microsoft.Agents.AI.Workflows.Declarative.Kit.ActionExecutorResult'.
```
This is what `dotnet publish -p:PublishAot=true` would surface at runtime.
## Notes
- `PublishAot=true` is **not** set. The
`JsonSerializerIsReflectionEnabledByDefault=false` flag is the
minimum constraint that reproduces the AOT failure for JSON
checkpointing.
- JSON code paths inside transitive dependencies (e.g. Foundry SDK)
that rely on reflection would also fail under this flag; those are
outside the workflow framework's responsibility.