From 6655118d6fdf1c0b5fe584e478e2bfdf64fb7098 Mon Sep 17 00:00:00 2001
From: UniversePeak <113168673+UniversePeak@users.noreply.github.com>
Date: Fri, 4 Sep 2026 08:29:16 +0800
Subject: [PATCH 1/2] docs: clarify declarative workflow input serialization
---
.../Declarative/AotCheckpointing/Program.cs | 22 +++++++---
.../Declarative/AotCheckpointing/README.md | 44 +++++++++++++++++--
2 files changed, 57 insertions(+), 9 deletions(-)
diff --git a/dotnet/samples/03-workflows/Declarative/AotCheckpointing/Program.cs b/dotnet/samples/03-workflows/Declarative/AotCheckpointing/Program.cs
index 2bfd6d51d72..8f515b7d866 100644
--- a/dotnet/samples/03-workflows/Declarative/AotCheckpointing/Program.cs
+++ b/dotnet/samples/03-workflows/Declarative/AotCheckpointing/Program.cs
@@ -1,5 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
+using System.Text.Json;
+using System.Text.Json.Serialization;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
@@ -15,12 +17,12 @@ namespace Demo.Workflows.Declarative.AotCheckpointing;
///
/// Demonstrates JSON checkpointing of a declarative workflow under reflection-disabled
-/// (the AOT / trim-aggressive constraint set
+/// (the AOT / trim-aggressive constraint set
/// via JsonSerializerIsReflectionEnabledByDefault=false in the csproj).
///
///
-/// The key call is
-/// with . Drop the options argument to observe the AOT failure. See README.
+/// The key call is with
+/// . Drop the options argument to observe the AOT failure. See README.
///
internal sealed class Program
{
@@ -31,14 +33,14 @@ public static async Task Main(string[] args)
await CreateGreeterAgentAsync(foundryEndpoint, configuration);
- string workflowInput = Application.GetInput(args);
+ WorkflowInput workflowInput = new(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(workflowPath, options);
+ return DeclarativeWorkflowBuilder.Build(workflowPath, options, TransformInput);
}
DirectoryInfo checkpointFolder = Directory.CreateDirectory(Path.Combine(".", $"chk-{DateTime.Now:yyMMdd-HHmmss-ff}"));
@@ -74,7 +76,10 @@ Workflow CreateWorkflow()
}
}
- private static async Task> RunAndStreamAsync(Workflow workflow, string input, CheckpointManager checkpointManager)
+ private static ChatMessage TransformInput(WorkflowInput input) =>
+ new(ChatRole.User, JsonSerializer.Serialize(input, AotCheckpointingJsonContext.Default.WorkflowInput));
+
+ private static async Task> RunAndStreamAsync(Workflow workflow, WorkflowInput input, CheckpointManager checkpointManager)
{
StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input, checkpointManager).ConfigureAwait(false);
return await DrainAsync(run).ConfigureAwait(false);
@@ -172,3 +177,8 @@ private static void TryDelete(DirectoryInfo directory)
}
}
}
+
+internal sealed record WorkflowInput(string Message);
+
+[JsonSerializable(typeof(WorkflowInput))]
+internal sealed partial class AotCheckpointingJsonContext : JsonSerializerContext;
diff --git a/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md b/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md
index 9856274bfc8..421e39b91b5 100644
--- a/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md
+++ b/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md
@@ -25,15 +25,53 @@ reflection-disabled `System.Text.Json` -- the same constraint imposed by
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.
+- The initial workflow input is a `WorkflowInput` record. `TransformInput` uses the
+ source-generated `AotCheckpointingJsonContext` to serialize it into a
+ `ChatMessage` before the declarative workflow runs.
`DeclarativeWorkflowJsonOptions` is marked
`[Experimental("MAAI001")]`. Suppress that diagnostic in your csproj to
use it.
-### Registering user-defined types
+### Initial input and checkpoint serialization are separate
-For workflows whose inputs or custom `ActionExecutorResult.Result`
-payloads are user-defined, clone `Default` and append your own resolver:
+`DeclarativeWorkflowBuilder.Build` accepts an optional `inputTransform` delegate.
+For a non-`ChatMessage` input, the default behavior is to call `ToString()`; the
+checkpoint serializer is not involved in this conversion. Use a source-generated
+context (or your own `JsonSerializerOptions`) in the delegate when the workflow
+should receive a JSON representation of a typed input:
+
+```csharp
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.Agents.AI.Workflows.Declarative;
+using Microsoft.Extensions.AI;
+
+internal sealed record WorkflowInput(string Message);
+
+[JsonSerializable(typeof(WorkflowInput))]
+internal sealed partial class AppJsonContext : JsonSerializerContext;
+
+Workflow workflow = DeclarativeWorkflowBuilder.Build(
+ workflowPath,
+ options,
+ input => new ChatMessage(
+ ChatRole.User,
+ JsonSerializer.Serialize(input, AppJsonContext.Default.WorkflowInput)));
+```
+
+This sample uses `AotCheckpointingJsonContext` for that initial-input transform.
+The separate `DeclarativeWorkflowJsonOptions.Default` passed to
+`CheckpointManager.CreateJson` supplies type information for declarative workflow
+checkpoint state. If checkpoint state also contains application-defined payloads,
+clone those options and append the application's resolver as shown below; adding
+the resolver to checkpoint options does not automatically change the initial input.
+
+### Registering user-defined checkpoint types
+
+For custom `ActionExecutorResult.Result` payloads or other user-defined values
+that are persisted in workflow checkpoint state, clone `Default` and append your
+own resolver:
```csharp
JsonSerializerOptions options = new(DeclarativeWorkflowJsonOptions.Default);
From d5edf334f4e27b76ef0dc133f076bd8226dde34c Mon Sep 17 00:00:00 2001
From: UniversePeak <113168673+UniversePeak@users.noreply.github.com>
Date: Sat, 5 Sep 2026 01:57:10 +0800
Subject: [PATCH 2/2] docs: add workflows namespace to serialization snippet
---
.../samples/03-workflows/Declarative/AotCheckpointing/README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md b/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md
index 421e39b91b5..b601f40299d 100644
--- a/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md
+++ b/dotnet/samples/03-workflows/Declarative/AotCheckpointing/README.md
@@ -44,6 +44,7 @@ should receive a JSON representation of a typed input:
```csharp
using System.Text.Json;
using System.Text.Json.Serialization;
+using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Extensions.AI;