Skip to content

Chapter 7: Advanced Agent Patterns #7

@yagop

Description

@yagop

Part of the Build Your Own Coding Agent tutorial. One issue = one chapter (chapters/07-advanced-patterns.md) plus its examples/07-advanced-patterns/ samples.

Goal (1 sentence): Move from single tool calls to autonomous loops that plan, reason (extended thinking), self-critique, recover from errors, and produce structured output.

After this chapter you can

  • Run an autonomous tool_use loop that inspects stop_reason, enforces a maxSteps budget, and exits cleanly on end_turn or budget exhaustion.
  • Enable extended thinking and read thinking content blocks; apply a reflection pass and error recovery inside the loop; force structured output via tool_choice to a named tool.
  • Use a dedicated planning tool call to produce an explicit task list and iterate over subtasks in subsequent loop iterations.
  • Check usage.input_tokens and usage.output_tokens each step and stop the loop when token-budget thresholds are exceeded.

What to cover (ONE paragraph, not a list)

Introduce the anatomy of an autonomous loop: accumulating messages, inspecting stop_reason (tool_use vs end_turn vs max_tokens), and enforcing a maxSteps budget to prevent runaway execution. Next, enable extended thinking with thinking: { type: "adaptive" } (optionally output_config: { effort: "low" | "medium" | "high" }); on models 4.6 and earlier the deprecated thinking: { type: "enabled", budget_tokens: N } form applies - thinking tokens count toward usage so check the docs for your target model. Introduce multi-step planning: a dedicated planning tool call that produces an explicit task list, after which the loop iterates over each subtask in subsequent iterations. Then show a reflection pass: after the agent produces a draft, append it as a plain user turn (not a fabricated tool_result) so the model can identify flaws and improve before the loop exits. Cover error recovery - catching Anthropic.RateLimitError and Anthropic.APIError, surfacing tool failures as tool_result blocks with is_error: true, and deciding whether to retry or abort the step with backoff logic - then close with structured output via tool_choice: { type: "tool", name: "emit_result" } plus a tight input_schema, a lightweight subagent orchestration pattern where a coordinator issues high-level tool calls dispatched to helper functions each running their own client.messages.create, and guardrails that check usage.input_tokens and usage.output_tokens each step to stop the loop when thresholds are exceeded.

⚠️ The exact thinking parameter shape (adaptive vs budget_tokens) is past the drafting model's knowledge cutoff - confirm against current Anthropic docs before finalizing the code.

Going deeper (optional asides - keep OFF the main line)

  • Multi-step planning tool: deeper elaboration on the dedicated planning tool call pattern - producing an explicit task list, then iterating over subtasks in subsequent loop iterations.
  • Guardrails: deeper elaboration on checking usage.input_tokens and usage.output_tokens each step to detect token budget overruns and stop the loop when thresholds are exceeded.

Out of scope (defer - do NOT preview)

  • Full multi-agent frameworks and inter-agent communication protocols (a later chapter).

Code samples - examples/07-advanced-patterns/

  • autonomous-loop.ts - multi-step loop with maxSteps and clean end_turn exit.
  • extended-thinking.ts - enable thinking and print the thinking block separately.
  • reflection.ts - draft -> self-critique (user turn) -> revise.
  • structured-output.ts - tool_choice: { type: "tool", name } with a strict input_schema.
  • error-recovery.ts - try/catch per step, is_error results, backoff on RateLimitError.
  • orchestrator.ts - coordinator delegating subtasks to helper agents.

Must-keep for a beginner (floor - never cut for brevity)

  • The run command for the first sample.
  • "Never hardcode your key; it comes from the environment" (once, in prose).
  • Anything a beginner cannot infer from the code (e.g. Bun auto-loads .env, no loader).
  • The one genuinely non-obvious gotcha for this chapter: a reflection turn must be a plain user message, not a fabricated tool_result block.

Friendliness floor (never cut - terse is not friendly)

  • The chapter addresses the reader as "you", never "the user" or "one".
  • The intro AND at least one section open with a warm, second-person sentence.

Key APIs (flat list, reference only - NOT a coverage checklist)

client.messages.create, stop_reason, thinking parameter, thinking block, tool_use, tool_result, is_error, tool_choice, input_schema, usage, Anthropic.APIError, Anthropic.RateLimitError

Prerequisites

Chapters 5 and 6 (required).

Definition of done

  • Chapter at chapters/07-advanced-patterns.md, <=120 lines, <=4 main-line H2s plus an optional "What's next" closer (paste wc -l AND grep -c '^## ' in the PR).
  • Every sample runnable with bun run, imported via <<< @/examples/07-advanced-patterns/file.ts, <=35 lines, comment:code <=0.30.
  • One-home rule held: no prose sentence restates an inline code comment.
  • Friendliness floor held: reader addressed as "you"; intro + >=1 section open warm.
  • Samples use only real @anthropic-ai/sdk surface; ASCII punctuation only.
  • Optional material lives in Going-deeper asides, not main-line H2s.
  • Linked from README.md and the .vitepress/config.ts sidebar; bun x vitepress build passes.
  • thinking parameter shape verified against current Anthropic docs for the chosen model.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions