Common builder stacks
Use this page to assemble realistic builder chains. For every method, default, and env var, see the authoritative references:
- Builder API — signatures, option types,
ReactiveAgentmethods, events, andAgentResult. - Configuration — grouped checklist of builder methods and high-level defaults.
For a first end-to-end walkthrough, see Quickstart and Your first agent.
Patterns that stay true across stacks
Section titled “Patterns that stay true across stacks”- Start from
ReactiveAgents.create()— default name is"agent", default provider is"test"until you call.withProvider(...). - Finish with
.build()(async) or.buildEffect()(Effect) — see Effect-TS primer. - Dispose agents that use MCP stdio or other subprocess tools: prefer
await using,runOnce(), ordispose()— Resource management. - Custom tools and hooks return Effect —
import { Effect } from "effect"and useEffect.succeed/Effect.fail/Effect.genas needed.
Stack A — Direct LLM (no reasoning loop)
Section titled “Stack A — Direct LLM (no reasoning loop)”Single-shot Q&A; no tools, no multi-step loop. Smallest surface area.
import { ReactiveAgents } from "reactive-agents";
await using agent = await ReactiveAgents.create() .withName("qa-bot") .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .build();
const result = await agent.run("Explain what a functor is in one paragraph.");console.log(result.output);Stack B — ReAct + built-in tools
Section titled “Stack B — ReAct + built-in tools”Enables the reasoning kernel and the default tool registry (file I/O, web search when keys exist, etc.). With .withTools(), Conductor meta-tools (brief, find, pulse, recall) default on unless you pass .withMetaTools(false) — see Tools and Builder API — MetaToolsConfig.
import { ReactiveAgents } from "reactive-agents";
await using agent = await ReactiveAgents.create() .withName("tool-agent") .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .withReasoning() .withTools() .build();
const result = await agent.run("Use web-search to find today's date in UTC and reply with one sentence.");console.log(result.output);Stack C — Memory + reasoning + debrief context
Section titled “Stack C — Memory + reasoning + debrief context”.withMemory() uses the standard tier by default (SQLite + FTS5; no embedding API required). Use { tier: "enhanced" } when you want vector similarity (embedding provider + env). Debrief-style artifacts are tied to memory + reasoning — details in Debrief & chat and Memory.
import { ReactiveAgents } from "reactive-agents";
await using agent = await ReactiveAgents.create() .withName("researcher") .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .withMemory() // or .withMemory({ tier: "enhanced" }) .withReasoning() .withTools() .build();
const result = await agent.run("Summarize the project goals in three bullets.");if (result.debrief) console.log(result.debrief.summary);Stack D — Safer, observable runs
Section titled “Stack D — Safer, observable runs”Guardrails toggle injection / PII / toxicity detectors (all default on when guardrails are enabled). Observability drives the metrics dashboard at normal+ verbosity. Cost tracking enforces USD budgets when you pass limits.
import { ReactiveAgents } from "reactive-agents";
await using agent = await ReactiveAgents.create() .withName("production-shape") .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .withReasoning() .withTools() .withGuardrails({ toxicity: true, injection: true, pii: true }) .withObservability({ verbosity: "normal", live: false }) .withCostTracking({ perRequest: 0.25, daily: 10 }) .build();
await agent.run("Draft a short status update for the team.");Stack E — Token streaming
Section titled “Stack E — Token streaming”.withStreaming() sets the default density for agent.runStream() (tokens vs full). You can override per call. See Streaming and Streaming responses.
import { ReactiveAgents } from "reactive-agents";
await using agent = await ReactiveAgents.create() .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .withReasoning() .withStreaming({ density: "tokens" }) .build();
for await (const event of agent.runStream("Write a haiku about TypeScript.")) { if (event._tag === "TextDelta") process.stdout.write(event.text); if (event._tag === "StreamCompleted") console.log("\nDone.");}Stack F — Agent as Data (serialize / restore)
Section titled “Stack F — Agent as Data (serialize / restore)”toConfig() captures the builder state as AgentConfig. Use agentConfigToJSON / agentConfigFromJSON (from reactive-agents) for strings. Some runtime-only fields (e.g. custom ICS functions) are not round-tripped — see Builder API — Agent as Data.
import { ReactiveAgents, agentConfigToJSON, agentConfigFromJSON,} from "reactive-agents";
const builder = ReactiveAgents.create() .withName("saved-agent") .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .withReasoning() .withTools();
const json = agentConfigToJSON(builder.toConfig());const restored = await ReactiveAgents.fromJSON(json);await using agent = await restored.build();await agent.run("Ping.");Stack G — Adaptive strategy
Section titled “Stack G — Adaptive strategy”If defaultStrategy is "adaptive", you must set adaptive: { enabled: true } — Reasoning, Builder API — ReasoningOptions.
import { ReactiveAgents } from "reactive-agents";
await using agent = await ReactiveAgents.create() .withProvider("anthropic") .withModel("claude-sonnet-4-20250514") .withReasoning({ defaultStrategy: "adaptive", adaptive: { enabled: true }, }) .withTools() .build();
await agent.run("Plan then execute: list two pros and two cons of serverless agents.");Related cookbook pages
Section titled “Related cookbook pages”| Topic | Page |
|---|---|
| Custom tools | Building tools |
| Streaming details | Streaming responses |
| Tests | Testing agents |
| Multi-agent | Multi-agent patterns |
More guides
Section titled “More guides”| Goal | Guide or reference |
|---|---|
| Lifecycle hooks | Hooks |
| MCP servers | Builder API — MCP |
| Sub-agents | Sub-agents |
| Effect composition | Effect-TS primer |