Skip to content

Commit f2ffe94

Browse files
authored
Merge pull request #782 from MicrosoftDocs/main
Merge main to live
2 parents 192c2fc + c14650f commit f2ffe94

13 files changed

Lines changed: 272 additions & 463 deletions

.openpublishing.redirection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,11 @@
824824
"source_path": "semantic-kernel/Frameworks/agent/examples/example-agent-collaboration.md",
825825
"redirect_url": "/semantic-kernel/support/archive/agent-chat-example",
826826
"redirect_document_id": false
827+
},
828+
{
829+
"source_path": "agent-framework/tutorials/workflows/visualization.md",
830+
"redirect_url": "/agent-framework/user-guide/workflows/visualization",
831+
"redirect_document_id": true
827832
}
828833
]
829834
}

agent-framework/tutorials/workflows/TOC.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@
99
- name: Handle requests and responses in workflows
1010
href: requests-and-responses.md
1111
- name: Checkpointing and resuming workflows
12-
href: checkpointing-and-resuming.md
13-
- name: Visualizing workflows
14-
href: visualization.md
12+
href: checkpointing-and-resuming.md

agent-framework/tutorials/workflows/agents-in-workflows.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ You'll create a workflow that:
2727
- Streams real-time updates as agents process requests
2828
- Demonstrates proper resource cleanup for Azure Foundry agents
2929

30+
### Concepts Covered
31+
32+
- [Agents in Workflows](../../user-guide/workflows/using-agents.md)
33+
- [Direct Edges](../../user-guide/workflows/core-concepts/edges.md#direct-edges)
34+
- [Workflow Builder](../../user-guide/workflows/core-concepts/workflows.md)
35+
3036
## Prerequisites
3137

3238
- [.NET 8.0 SDK or later](https://dotnet.microsoft.com/download)
@@ -68,18 +74,7 @@ public static class Program
6874
var persistentAgentsClient = new PersistentAgentsClient(endpoint, new AzureCliCredential());
6975
```
7076

71-
## Step 3: Create Specialized Azure Foundry Agents
72-
73-
Create three translation agents using the helper method:
74-
75-
```csharp
76-
// Create agents
77-
AIAgent frenchAgent = await GetTranslationAgentAsync("French", persistentAgentsClient, model);
78-
AIAgent spanishAgent = await GetTranslationAgentAsync("Spanish", persistentAgentsClient, model);
79-
AIAgent englishAgent = await GetTranslationAgentAsync("English", persistentAgentsClient, model);
80-
```
81-
82-
## Step 4: Create Agent Factory Method
77+
## Step 3: Create Agent Factory Method
8378

8479
Implement a helper method to create Azure Foundry agents with specific instructions:
8580

@@ -106,6 +101,17 @@ Implement a helper method to create Azure Foundry agents with specific instructi
106101
}
107102
```
108103

104+
## Step 4: Create Specialized Azure Foundry Agents
105+
106+
Create three translation agents using the helper method:
107+
108+
```csharp
109+
// Create agents
110+
AIAgent frenchAgent = await GetTranslationAgentAsync("French", persistentAgentsClient, model);
111+
AIAgent spanishAgent = await GetTranslationAgentAsync("Spanish", persistentAgentsClient, model);
112+
AIAgent englishAgent = await GetTranslationAgentAsync("English", persistentAgentsClient, model);
113+
```
114+
109115
## Step 5: Build the Workflow
110116

111117
Connect the agents in a sequential workflow using the WorkflowBuilder:
@@ -187,6 +193,12 @@ You'll create a workflow that:
187193
- Streams real-time updates as agents process requests
188194
- Demonstrates proper async context management for Azure AI clients
189195

196+
### Concepts Covered
197+
198+
- [Agents in Workflows](../../user-guide/workflows/using-agents.md)
199+
- [Direct Edges](../../user-guide/workflows/core-concepts/edges.md#direct-edges)
200+
- [Workflow Builder](../../user-guide/workflows/core-concepts/workflows.md)
201+
190202
## Prerequisites
191203

192204
- Python 3.10 or later

agent-framework/tutorials/workflows/checkpointing-and-resuming.md

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ ms.service: agent-framework
1313

1414
Checkpointing allows workflows to save their state at specific points and resume execution later, even after process restarts. This is crucial for long-running workflows, error recovery, and human-in-the-loop scenarios.
1515

16+
### Concepts Covered
17+
18+
- [Checkpoints](../../user-guide/workflows/checkpoints.md)
19+
1620
::: zone pivot="programming-language-csharp"
1721

1822
## Prerequisites
@@ -67,14 +71,14 @@ await using Checkpointed<StreamingRun> checkpointedRun = await InProcessExecutio
6771
Executors can persist local state that survives checkpoints using the `Executor<T>` base class:
6872

6973
```csharp
70-
internal sealed class GuessNumberExecutor : Executor<NumberSignal>
74+
internal sealed class GuessNumberExecutor : Executor<NumberSignal>("Guess")
7175
{
7276
private const string StateKey = "GuessNumberExecutor.State";
7377

7478
public int LowerBound { get; private set; }
7579
public int UpperBound { get; private set; }
7680

77-
public GuessNumberExecutor() : base("GuessNumber")
81+
public GuessNumberExecutor() : this()
7882
{
7983
}
8084

@@ -446,37 +450,45 @@ Executors can persist local state that survives checkpoints:
446450
```python
447451
from agent_framework import Executor, WorkflowContext, handler
448452

449-
class UpperCaseExecutor(Executor):
450-
@handler
451-
async def to_upper_case(self, text: str, ctx: WorkflowContext[str]) -> None:
452-
result = text.upper()
453-
454-
# Persist executor-local state for checkpoints
455-
prev = await ctx.get_executor_state() or {}
456-
count = int(prev.get("count", 0)) + 1
457-
await ctx.set_executor_state({
458-
"count": count,
459-
"last_input": text,
460-
"last_output": result,
461-
})
462-
463-
# Send result to next executor
464-
await ctx.send_message(result)
465-
```
466-
467-
### Shared State
453+
class WorkerExecutor(Executor):
454+
"""Processes numbers to compute their factor pairs and manages executor state for checkpointing."""
468455

469-
Use shared state for data that multiple executors need to access:
456+
def __init__(self, id: str) -> None:
457+
super().__init__(id=id)
458+
self._composite_number_pairs: dict[int, list[tuple[int, int]]] = {}
470459

471-
```python
472-
class ProcessorExecutor(Executor):
473460
@handler
474-
async def process(self, text: str, ctx: WorkflowContext[str]) -> None:
475-
# Write to shared state for cross-executor visibility
476-
await ctx.set_shared_state("original_input", text)
477-
await ctx.set_shared_state("processed_output", text.upper())
478-
479-
await ctx.send_message(text.upper())
461+
async def compute(
462+
self,
463+
task: ComputeTask,
464+
ctx: WorkflowContext[ComputeTask, dict[int, list[tuple[int, int]]]],
465+
) -> None:
466+
"""Process the next number in the task, computing its factor pairs."""
467+
next_number = task.remaining_numbers.pop(0)
468+
469+
print(f"WorkerExecutor: Computing factor pairs for {next_number}")
470+
pairs: list[tuple[int, int]] = []
471+
for i in range(1, next_number):
472+
if next_number % i == 0:
473+
pairs.append((i, next_number // i))
474+
self._composite_number_pairs[next_number] = pairs
475+
476+
if not task.remaining_numbers:
477+
# All numbers processed - output the results
478+
await ctx.yield_output(self._composite_number_pairs)
479+
else:
480+
# More numbers to process - continue with remaining task
481+
await ctx.send_message(task)
482+
483+
@override
484+
async def on_checkpoint_save(self) -> dict[str, Any]:
485+
"""Save the executor's internal state for checkpointing."""
486+
return {"composite_number_pairs": self._composite_number_pairs}
487+
488+
@override
489+
async def on_checkpoint_restore(self, state: dict[str, Any]) -> None:
490+
"""Restore the executor's internal state from a checkpoint."""
491+
self._composite_number_pairs = state.get("composite_number_pairs", {})
480492
```
481493

482494
## Working with Checkpoints
@@ -496,24 +508,6 @@ workflow_checkpoints = await checkpoint_storage.list_checkpoints(workflow_id="my
496508
sorted_checkpoints = sorted(all_checkpoints, key=lambda cp: cp.timestamp)
497509
```
498510

499-
### Checkpoint Information
500-
501-
Access checkpoint metadata and state:
502-
503-
```python
504-
from agent_framework import get_checkpoint_summary
505-
506-
for checkpoint in checkpoints:
507-
# Get human-readable summary
508-
summary = get_checkpoint_summary(checkpoint)
509-
510-
print(f"Checkpoint: {summary.checkpoint_id}")
511-
print(f"Iteration: {summary.iteration_count}")
512-
print(f"Status: {summary.status}")
513-
print(f"Messages: {len(checkpoint.messages)}")
514-
print(f"Shared State: {checkpoint.shared_state}")
515-
```
516-
517511
## Resuming from Checkpoints
518512

519513
### Streaming Resume
@@ -682,8 +676,3 @@ if __name__ == "__main__":
682676
For the complete working implementation, see the [Checkpoint with Resume sample](https://github.com/microsoft/agent-framework/blob/main/python/samples/getting_started/workflows/checkpoint/checkpoint_with_resume.py).
683677

684678
::: zone-end
685-
686-
## Next Steps
687-
688-
> [!div class="nextstepaction"]
689-
> [Learn about Workflow Visualization](visualization.md)

agent-framework/tutorials/workflows/requests-and-responses.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ ms.service: agent-framework
1313

1414
This tutorial demonstrates how to handle requests and responses in workflows using Agent Framework Workflows. You'll learn how to create interactive workflows that can pause execution to request input from external sources (like humans or other systems) and then resume once a response is provided.
1515

16+
## Concepts Covered
17+
18+
- [Requests and Responses](../../user-guide/workflows/requests-and-responses.md)
19+
1620
::: zone pivot="programming-language-csharp"
1721

1822
In .NET, human-in-the-loop workflows use `RequestPort` and external request handling to pause execution and gather user input. This pattern enables interactive workflows where the system can request information from external sources during execution.
@@ -68,12 +72,12 @@ Create executors that process user input and provide feedback:
6872
/// <summary>
6973
/// Executor that judges the guess and provides feedback.
7074
/// </summary>
71-
internal sealed class JudgeExecutor : Executor<int>, IMessageHandler<int>
75+
internal sealed class JudgeExecutor : Executor<int>("Judge")
7276
{
7377
private readonly int _targetNumber;
7478
private int _tries;
7579

76-
public JudgeExecutor(int targetNumber) : base("Judge")
80+
public JudgeExecutor(int targetNumber) : this()
7781
{
7882
_targetNumber = targetNumber;
7983
}

agent-framework/tutorials/workflows/simple-concurrent-workflow.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ You'll create a workflow that:
2424
- Collects and combines responses from both agents into a single output
2525
- Demonstrates concurrent execution with AI agents using fan-out/fan-in patterns
2626

27+
### Concepts Covered
28+
29+
- [Executors](../../user-guide/workflows/core-concepts/executors.md)
30+
- [Fan-out Edges](../../user-guide/workflows/core-concepts/edges.md#fan-out-edges)
31+
- [Fan-in Edges](../../user-guide/workflows/core-concepts/edges.md#fan-in-edges)
32+
- [Workflow Builder](../../user-guide/workflows/core-concepts/workflows.md)
33+
- [Events](../../user-guide/workflows/core-concepts/events.md)
34+
2735
## Prerequisites
2836

2937
- [.NET 8.0 SDK or later](https://dotnet.microsoft.com/download)
@@ -101,8 +109,7 @@ The `ConcurrentStartExecutor` implementation:
101109
/// <summary>
102110
/// Executor that starts the concurrent processing by sending messages to the agents.
103111
/// </summary>
104-
internal sealed class ConcurrentStartExecutor() :
105-
Executor<string>("ConcurrentStartExecutor")
112+
internal sealed class ConcurrentStartExecutor() : Executor<string>("ConcurrentStartExecutor")
106113
{
107114
/// <summary>
108115
/// Starts the concurrent processing by sending messages to the agents.
@@ -139,7 +146,7 @@ The `ConcurrentAggregationExecutor` implementation:
139146
/// Executor that aggregates the results from the concurrent agents.
140147
/// </summary>
141148
internal sealed class ConcurrentAggregationExecutor() :
142-
Executor<ChatMessage>("ConcurrentAggregationExecutor")
149+
Executor<List<ChatMessage>>("ConcurrentAggregationExecutor")
143150
{
144151
private readonly List<ChatMessage> _messages = [];
145152

@@ -151,9 +158,9 @@ internal sealed class ConcurrentAggregationExecutor() :
151158
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
152159
/// The default is <see cref="CancellationToken.None"/>.</param>
153160
/// <returns>A task representing the asynchronous operation</returns>
154-
public override async ValueTask HandleAsync(ChatMessage message, IWorkflowContext context, CancellationToken cancellationToken = default)
161+
public override async ValueTask HandleAsync(List<ChatMessage> message, IWorkflowContext context, CancellationToken cancellationToken = default)
155162
{
156-
this._messages.Add(message);
163+
this._messages.AddRange(message);
157164

158165
if (this._messages.Count == 2)
159166
{
@@ -231,6 +238,14 @@ You'll create a workflow that:
231238
- Aggregates the different result types (float and int) into a final output
232239
- Demonstrates how the framework handles different result types from concurrent executors
233240

241+
### Concepts Covered
242+
243+
- [Executors](../../user-guide/workflows/core-concepts/executors.md)
244+
- [Fan-out Edges](../../user-guide/workflows/core-concepts/edges.md#fan-out-edges)
245+
- [Fan-in Edges](../../user-guide/workflows/core-concepts/edges.md#fan-in-edges)
246+
- [Workflow Builder](../../user-guide/workflows/core-concepts/workflows.md)
247+
- [Events](../../user-guide/workflows/core-concepts/events.md)
248+
234249
## Prerequisites
235250

236251
- Python 3.10 or later

0 commit comments

Comments
 (0)