# Microsoft Agent Framework - Workflow Orchestration Patterns

> **Scope:** universal
> **Layer:** 0 (always load)
> **Keywords:** workflow, orchestration, sequential, parallel, conditional
> **Load When:** always

**Ref:** `setup.md` — Core setup guide (packages, ChatClientAgent, tools)

Workflows compose multiple agents and executors into coordinated pipelines using `AgentWorkflowBuilder`.

---

## Core Concepts

| Concept | Description |
|---------|-------------|
| **Executor** | Base processing unit. Implements `IMessageHandler<T>`. Agents are executors. |
| **Edge** | Typed connection between executors defining message flow |
| **Workflow** | Composition of executors + edges forming a processing graph |
| **AIAgent** | Chat-based executor (most common type) |

### Packages

```xml
<PackageReference Include="Microsoft.Agents.AI" Version="1.0.0-preview.*" />
<PackageReference Include="Microsoft.Agents.AI.Workflows" Version="1.0.0-preview.*" />
```

---

## 5 Orchestration Patterns

| Pattern | Topology | Use Case | Coordination |
|---------|----------|----------|--------------|
| **Sequential** | Linear chain | Pipelines, multi-stage processing | Ordered, dependent |
| **Concurrent** | Broadcast | Parallel analysis, ensemble | Independent, aggregated |
| **GroupChat** | Star (manager hub) | Iterative refinement, review | Manager-controlled |
| **Handoff** | Mesh | Dynamic routing, escalation | Agent-decided |
| **Magentic** | Star (planner) | Complex generalist collaboration | Planner-based |

---

## 1. Sequential Workflow

Agents execute in order — each agent receives the output of the previous one.

```
[Writer] → [Editor] → [Output]
```

```csharp
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;

AIAgent writer = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
    Name = "Writer",
    Instructions = "Write stories that are engaging and creative."
});

AIAgent editor = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
    Name = "Editor",
    Instructions = "Make the story more engaging, fix grammar, and enhance plot."
});

Workflow workflow = AgentWorkflowBuilder.BuildSequential(writer, editor);

AIAgent workflowAgent = await workflow.AsAgentAsync();
AgentRunResponse response = await workflowAgent.RunAsync(
    "Write a short story about a haunted house.");

Console.WriteLine(response.Text);
```

---

## 2. Concurrent Workflow (Fan-Out / Fan-In)

Same input sent to multiple agents in parallel, results aggregated.

```
           ┌→ [Agent B1] →┐
[Input] → Fan-Out → [Agent B2] → Fan-In → [Aggregator]
           └→ [Agent B3] →┘
```

```csharp
// Create specialized analysis agents
AIAgent securityAnalyst = chatClient.AsAIAgent(
    instructions: "Analyze code for security vulnerabilities.",
    name: "SecurityAnalyst");

AIAgent performanceAnalyst = chatClient.AsAIAgent(
    instructions: "Analyze code for performance issues.",
    name: "PerformanceAnalyst");

AIAgent readabilityAnalyst = chatClient.AsAIAgent(
    instructions: "Analyze code for readability and maintainability.",
    name: "ReadabilityAnalyst");

// Fan-out to all analysts, fan-in results
// Use AddFanOutEdge / AddFanInEdge for custom executors
```

**Note:** All executors in the same superstep must complete before downstream executors begin.

---

## 3. GroupChat Workflow

Manager-controlled round-robin conversation between agents.

```csharp
Workflow workflow = AgentWorkflowBuilder
    .CreateGroupChatBuilderWith(agents =>
        new AgentWorkflowBuilder.RoundRobinGroupChatManager(agents)
        {
            MaximumIterationCount = 2  // Max rounds
        })
    .AddParticipants(writer, editor)
    .Build();

AIAgent workflowAgent = await workflow.AsAgentAsync();
AgentRunResponse response = await workflowAgent.RunAsync(prompt);
```

---

## 4. Handoff Workflow

Agents dynamically pass control based on routing rules. Mesh topology — no central orchestrator.

```
[Triage] ──┬→ [Math Tutor] ──→ [Triage]
           └→ [History Tutor] → [Triage]
```

```csharp
// Define specialized agents
ChatClientAgent historyTutor = new(chatClient,
    "You provide help with historical queries. Only respond about history.",
    "history_tutor",
    "Specialist agent for historical questions");

ChatClientAgent mathTutor = new(chatClient,
    "You provide help with math problems. Only respond about math.",
    "math_tutor",
    "Specialist agent for math questions");

ChatClientAgent triageAgent = new(chatClient,
    "You determine which agent to use. ALWAYS handoff to another agent.",
    "triage_agent",
    "Routes messages to the appropriate specialist");

// Build handoff workflow
var workflow = AgentWorkflowBuilder.StartHandoffWith(triageAgent)
    .WithHandoffs(triageAgent, [mathTutor, historyTutor])
    .WithHandoff(mathTutor, triageAgent)
    .WithHandoff(historyTutor, triageAgent)
    .Build();
```

### Running Handoff with Streaming Events

```csharp
List<ChatMessage> messages = new();
messages.Add(new(ChatRole.User, "What is the derivative of x^2?"));

StreamingRun run = await InProcessExecution.StreamAsync(workflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));

await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
    if (evt is AgentResponseUpdateEvent e)
        Console.WriteLine($"{e.ExecutorId}: {e.Data}");
    else if (evt is WorkflowOutputEvent outputEvt)
    {
        messages.AddRange(((List<ChatMessage>)outputEvt.Data!).Skip(messages.Count));
        break;
    }
}
```

**Handoff characteristics:**
- Receiving agent takes full task ownership
- Full conversation history passed to receiving agent
- Only supports `ChatAgent` with local tool execution

---

## 5. Magentic Workflow

Planner-based variant of GroupChat. A manager agent dynamically selects which agent acts next based on planning.

| Aspect | GroupChat | Magentic |
|--------|-----------|----------|
| Turn order | Fixed (round-robin) | Dynamic (planner decides) |
| Manager | Simple rotation | LLM-based planner |
| Best for | Predictable workflows | Complex, adaptive tasks |

---

## Workflow-as-Agent

Any workflow can be encapsulated as a single agent for composition:

```csharp
Workflow workflow = AgentWorkflowBuilder.BuildSequential(writer, editor);
AIAgent workflowAgent = await workflow.AsAgentAsync();

// Use like any other agent
var response = await workflowAgent.RunAsync("Write a report.");

// Can be composed into larger workflows
Workflow outerWorkflow = AgentWorkflowBuilder.BuildSequential(workflowAgent, reviewer);
```

---

## Web API Integration

```csharp
// Program.cs
builder.AddAIAgent("Writer", (sp, key) =>
{
    var chatClient = sp.GetRequiredService<IChatClient>();
    return new ChatClientAgent(chatClient, name: key,
        instructions: "You are a creative writing assistant.");
});

builder.AddAIAgent("Editor",
    instructions: "You improve a writer's draft.");

app.MapGet("/agent/chat", async (
    [FromKeyedServices("Writer")] AIAgent writer,
    [FromKeyedServices("Editor")] AIAgent editor,
    string prompt) =>
{
    Workflow workflow = AgentWorkflowBuilder.BuildSequential(writer, editor);
    AIAgent workflowAgent = await workflow.AsAgentAsync();
    var response = await workflowAgent.RunAsync(prompt);
    return Results.Ok(response.Text);
});
```

---

## Custom Executors

For non-agent processing steps (data transformation, external API calls):

```csharp
public class PhotoCritiqueExecutor : BaseExecutor, IMessageHandler<WorkflowMessage>
{
    public async Task HandleAsync(
        WorkflowMessage message,
        WorkflowContext context,
        CancellationToken cancellationToken)
    {
        var client = GetVisionClient();
        var prompt = await GetPromptAsync("critique-prompt.md");

        var dataContent = new DataContent(
            await File.ReadAllBytesAsync(message.ImagePath),
            "image/jpeg");

        var fullPrompt = new PromptBuilder()
            .AddText(prompt)
            .AddImage(dataContent)
            .Build();

        var response = await client.GetResponseAsync(fullPrompt);
        await context.SendAsync(new CritiqueResult(response));
    }
}
```

---

## Client Types

| Type | Method | Input / Output | Use Case |
|------|--------|---------------|----------|
| Conversational | `GetConversationalClient()` | Text → Text | Chat, analysis, generation |
| Vision | `GetVisionClient()` | Image → Text | Image analysis, OCR |
| Image Generation | `GetImageClient()` | Text → Image | Mockups, visualizations |

---

## Prompt Engineering for Workflows

Store prompts in external markdown files for:
- Versioning without recompilation
- Independent iteration and testing
- Reuse across agents

```csharp
var prompt = await File.ReadAllTextAsync("prompts/analysis.md");
var agent = chatClient.AsAIAgent(instructions: prompt, name: "Analyst");
```

---

## When to Use Which Pattern

| Scenario | Pattern | Why |
|----------|---------|-----|
| ETL / data pipeline | Sequential | Each step depends on previous |
| Code review (security + perf + style) | Concurrent | Independent analyses |
| Content creation + editing | GroupChat | Iterative refinement |
| Customer support routing | Handoff | Dynamic expert selection |
| Complex research tasks | Magentic | Adaptive planning |
| Composing sub-workflows | Workflow-as-Agent | Abstraction |

---

## Development Tools

| Tool | Purpose |
|------|---------|
| Mermaid diagrams | Auto-generated workflow visualization |
| Aspire Dashboard | Trace inter-agent calls and performance |
| `dotnet new webapi-ai` | Template: Web API with Agent Framework |
| `dotnet new mcp-server` | Template: MCP Server |

---

## Checklist

- [ ] `Microsoft.Agents.AI.Workflows` package installed
- [ ] Orchestration pattern selected and justified
- [ ] Agents have clear, single responsibilities
- [ ] Workflow built with `AgentWorkflowBuilder`
- [ ] Streaming events handled for real-time UI
- [ ] OpenTelemetry enabled for workflow tracing
- [ ] Prompts stored externally (markdown files)
- [ ] Error handling defined per executor

---

## References

- [Workflow Orchestrations Overview](https://learn.microsoft.com/agent-framework/user-guide/workflows/orchestrations/overview)
- [Handoff Pattern](https://learn.microsoft.com/agent-framework/user-guide/workflows/orchestrations/handoff)
- [Agents in Workflows](https://learn.microsoft.com/agent-framework/tutorials/workflows/agents-in-workflows)
- [GitHub Samples: Workflows](https://github.com/microsoft/agent-framework/tree/main/dotnet/samples/GettingStarted/Workflows)
- `setup.md` — Core setup
- `production.md` — Middleware, A2A, MCP

---

*MORPH-SPEC by Polymorphism Tech*
