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.

ANALYZE runs in parallel SYNTHESIZE waits for both grammar tone editor

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.

writing_assistant.swiftSwift
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.

ANALYZE 3 parallel checks EDIT waits for all POLISH waits for edit EXPORT waits for polish grammar tone clarity editor polish export
Full writing pipelineSwift
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:

Swift
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