Agent patterns

Choose a proven Agent composition by the shape of the work, then implement it with the seven primitives and governed Resources.

Agent names describe a product; patterns describe its control flow. A legal assistant and a support assistant may share the same dialogue pattern. A research Agent and a coding Agent may both use planner–worker delegation. Choose the smallest structural pattern that matches the work, then add domain prompts, Resources, Memory, Channels, Credentials, and Policy.

Pattern catalog

FamilyPatternUse it whenCore composition
DialogueConversational assistantOne bounded answer depends on session historyledger → turn → commit
DialogueContent or generation AgentThe output is primarily a model-produced artifactturn → commit
DialogueRouter or triage AgentThe Agent classifies and hands work to a bounded destinationturn → commit or turn → spawn
DialogueCustomer-support AgentConversation may read systems, act, or escalateledger → turn → await? → commit
KnowledgeRetrieval or knowledge AgentAnswers must be grounded in governed recordsResource search → turn → commit
KnowledgeResearch AgentSeveral independent questions or sources must be investigatedturn → spawn* → turn → commit
KnowledgeDocument-intelligence AgentMany documents need extraction, comparison, or synthesismap → reduce → turn → commit
DataData analyst AgentA question requires governed queries and interpretationturn → Resource → turn → commit
DataBatch enrichment or transformation AgentThe same bounded operation applies across large volumemap → reduce? → commit
DataEvaluator or judge AgentOutputs need a rubric, score, gate, or comparisonturn(gate) → commit
ActionReAct AgentThe model must observe Tool results and continue until it can finishreact() from @constal/std
ActionTool-using operatorThe model chooses among bounded external operationsturn(Tools) → commit
ActionWorkflow automation AgentProgress crosses steps, retries, or invocationsdurable state → commit
ActionHuman-approval AgentAuthority must pause for a person or external decisionturn → await → commit
ActionBrowser or computer-use AgentA governed Resource exposes interactive operationsrepeated turn → Tool, then commit
EngineeringCoding AgentRepository inspection, edits, tests, and review form a loopturn → Resources → turn → commit
OperationsMonitoring or incident AgentEvents trigger diagnosis, mitigation, and escalationledger → turn → await? → commit
CoordinationPlanner–executor AgentPlanning and execution need separate durable workturn → spawn* → turn → commit
CoordinationSupervisor or multi-Agent systemSpecialized workers can proceed independentlyspawn* → derived join → turn → commit
AutonomyLong-horizon AgentWork must resume across time with explicit progressdurable state composed from all seven

These are structural archetypes, not an industry list. Sales, legal, healthcare, finance, education, and security Agents are domain applications of one or more rows. Combining patterns is normal; inventing a new runtime primitive for each label is not.

Start with the bounded core

ts
import { agent } from "@constal/sdk";

export default agent({
  id: "bounded-assistant", version: "1.0.0", model: "model",
  async onMessage(input, ctx) {
    const history = await ctx.ledger.view("history");
    const answer = await ctx.turn({
      system: "Complete one bounded objective and state uncertainty.",
      objective: input,
      context: { history },
    });
    await ctx.commit({ kind: "answer", text: answer.message.content });
    return answer.message.content;
  },
});

Add await only when time or authority crosses the invocation. Add spawn when child work needs an independent durable identity. Add map and reduce when the cardinality is data volume rather than a bounded worker set. External search, databases, browsers, repositories, ticketing systems, and Memory stay Resources; they do not become primitives.

Build a ReAct Agent with the library

ReAct is a standard-library composition, not another Agent primitive. react() from @constal/std supplies the durable state machine, transcript handling, Tool loop, steering intake, and explicit final Tool. The Agent definition only adds its identity, Model binding, instructions, and offered Tools.

ts
import { agent } from "@constal/sdk";
import { react, type ReactState } from "@constal/std";

const behavior = react({
  system: "Research the request with the offered Tools. Call final only when the answer is supported.",
  tools: ["search", "read_page"],
  window: 40,
});

export default agent<ReactState>({
  id: "research-assistant",
  version: "1.0.0",
  model: "model",
  ...behavior,
});

search and read_page must be registered Tools exposed by the Agent deployment; react() does not create those capabilities or bypass their Resource and Policy boundaries.

Use window to bound the messages sent to each Model turn. Windowing does not rewrite the durable transcript. For long-running Agents, provide fold to compact older working context into a serializable summary while retaining the recent messages that still matter:

ts
const behavior = react({
  system: "Investigate the objective and call final with a supported answer.",
  tools: ["search", "read_page"],
  window: 40,
  async fold(recent, summary, ctx) {
    if (recent.length < 32) return { context: recent, summary };

    const compacted = await ctx.turn({
      system: "Preserve decisions, evidence, open questions, and source references. Remove repetition.",
      objective: { previousSummary: summary, messages: recent },
    });

    return {
      context: recent.slice(-12),
      summary: compacted.message.content,
    };
  },
});

Compaction changes the context prepared for later turns, not the Run's recorded history. Keep the fold deterministic in structure, treat its summary as model-generated context rather than business truth, and use commit for facts that must become authoritative.

Implementation guides