Graph
Run agents as nodes in a directed acyclic graph (DAG). Independent nodes execute in parallel; dependent nodes wait for their inputs automatically. All agents run in the same app process on the same device.
When to Use Graph
- You know all the analysis steps before execution starts
- Some steps are independent and can run concurrently on device
- You want predictable, auditable execution order
- Downstream agents need the results of upstream agents as context
How It Works
Each node is an agent with an ID and an optional dependencies list. Nodes with no unsatisfied dependencies run immediately; nodes with dependencies wait until all their inputs are ready. The orchestrator handles scheduling automatically.
Basic Example
A writing assistant on macOS or iOS: a grammar agent and a tone agent analyze the user's draft in parallel. Once both finish, an editor agent synthesizes their feedback into actionable suggestions.
import StrandsAgents
let grammarAgent = Agent(
model: provider,
systemPrompt: "You are a grammar expert. Review the draft for grammar and spelling errors. Return a concise list of specific corrections."
)
let toneAgent = Agent(
model: provider,
systemPrompt: "You are a writing coach. Review the draft's tone and voice. Return concrete suggestions for making it clearer and more engaging."
)
let editorAgent = Agent(
model: provider,
systemPrompt: "You are a senior editor. You will receive grammar feedback and tone feedback for a draft. Synthesize them into a short, prioritized list of actionable improvements."
)
let graph = GraphOrchestrator(nodes: [
GraphNode(id: "grammar", agent: grammarAgent),
GraphNode(id: "tone", agent: toneAgent),
// editor waits for both grammar and tone to finish
GraphNode(id: "editor", agent: editorAgent, dependencies: ["grammar", "tone"]),
])
let result = try await graph.run("Review this draft: \(userDraft)")
print(result.output) // editor's synthesized feedback
Chaining Stages
Stages chain by declaring dependencies. Each node's output is forwarded automatically as context to every node that lists it as a dependency. No manual wiring needed.
A full writing pipeline shows this clearly: three analysis agents run in parallel, then an editor synthesizes their findings, and subsequent stages refine and finalize the document.
let graph = GraphOrchestrator(nodes: [
// Stage 1: three independent analysis agents run concurrently
GraphNode(id: "grammar", agent: grammarAgent),
GraphNode(id: "tone", agent: toneAgent),
GraphNode(id: "clarity", agent: clarityAgent),
// Stage 2: editor synthesizes all three analyses
GraphNode(id: "editor", agent: editorAgent, dependencies: ["grammar", "tone", "clarity"]),
// Stage 3: polish agent refines the edited draft
GraphNode(id: "polish", agent: polishAgent, dependencies: ["editor"]),
// Stage 4: export agent formats the final document
GraphNode(id: "export", agent: exportAgent, dependencies: ["polish"]),
])
let result = try await graph.run("Analyze and improve this draft: \(userDraft)")
print(result.output)
Parallel Execution
The orchestrator resolves the dependency graph at runtime. In the pipeline above, grammar, tone, and clarity all start at the same moment and run without waiting for each other. This is the main performance benefit over running agents sequentially, especially on device where inference time matters.
Nodes are declared in any order. The dependency list, not the declaration order, determines execution. Add as many independent analysis nodes as you like; they all run concurrently in the same process.
Accessing Intermediate Results
GraphResult contains the output of every node, keyed by ID. Useful for logging, debugging, or surfacing individual analyses in your UI alongside the final synthesis:
let result = try await graph.run("Analyze and improve this draft: \(userDraft)")
print(result.output) // final node's output (export summary)
// Surface individual analyses in the UI
print(result.nodeOutputs["grammar"] ?? "") // grammar corrections
print(result.nodeOutputs["tone"] ?? "") // tone suggestions
print(result.nodeOutputs["editor"] ?? "") // synthesized edits