Crux
GuidesAgents

Agent

Bundle a prompt with optional model and tools into a reusable agent primitive for composition utilities.

Compositions need the same prompt+model+tools bundle everywhere: define it once with agent(). An agent wraps a prompt with optional execution config: a default model, tools, and handoff targets. Agents are the building blocks for all composition patterns: parallel, pipeline, consensus, and swarm.

agents.ts
import { agent } from "@use-crux/core/agent";

const reviewer = agent({
  id: "content-reviewer",
  description: "Reviews content for quality and accuracy",
  prompt: reviewPrompt,
  model: gpt4mini, // optional: overrides composition-level model
  tools: [searchTool], // optional: agent-specific tools
  handoffs: ["editor"], // optional: agents this agent can route to in a swarm
  swarmTools: ["search"], // optional: tool whitelist for swarm context
});

Why agent?

Composition patterns need to know what to execute (prompt), how to execute it (model), and what tools are available. agent() bundles these into a single, frozen, typed object.

Without agent(), you'd pass these separately to every composition call. With it, you define once and reuse across compositions:

composition.ts
import { parallel } from "@use-crux/ai";

const { results } = await parallel({
  id: "agent-parallel-1",
  agents: { reviewer, factChecker, seoAnalyzer },
  context: { content: articleDraft },
  model: claude35, // shared default, reviewer's gpt4mini overrides this
});

results.reviewer.output; // typed from reviewer's output schema
results.factChecker.output; // typed from factChecker's output schema

Options

FieldPurposeDefault
idUnique identifier (used in devtools and swarm routing)Required
descriptionHuman-readable description (used in swarm transfer tool descriptions)undefined
promptThe prompt this agent executesRequired
modelModel override (takes precedence over composition-level model)undefined
toolsAgent-specific toolsundefined
handoffsAgent IDs or { id, when } objects for swarm routing[]
swarmToolsTool name whitelist for swarm contextAll tools

Per-agent model overrides

When an agent has a model, it takes precedence over the composition's shared model. This lets you use cheap models for simple tasks and expensive models for complex ones:

cost-optimization.ts
const classifier = agent({
  id: "classifier",
  prompt: classifyPrompt,
  model: gpt4mini, // cheap model for classification
});

const writer = agent({
  id: "writer",
  prompt: writePrompt,
  // no model, uses composition-level default
});

await pipeline({
  id: "agent-pipeline-1",
  steps: [
    { agent: classifier, name: "classify" },
    {
      agent: writer,
      name: "write",
      input: (ctx) => ({ topic: ctx.classify.output.category }),
    },
  ],
  model: claude35, // writer uses this; classifier uses gpt4mini
  context: { text: userMessage },
});

Escape hatch: plain functions

Composition utilities also accept plain async functions alongside agents. Use this for custom logic, external API calls, or wrapping delegates:

escape-hatch.ts
const { results } = await parallel({
  id: "agent-parallel-2",
  agents: {
    reviewer: reviewerAgent,
    external: async (ctx) => {
      const resp = await fetch("https://api.example.com/review", {
        method: "POST",
        body: JSON.stringify(ctx),
      });
      return resp.json();
    },
  },
  context: { content: draft },
});

results.reviewer.output; // typed AgentResult
results.external.output; // external API response

Plain functions skip devtools agent tracing but still appear as flow steps.

Type guard

Use isAgent() to distinguish agents from plain functions at runtime:

import { isAgent } from "@use-crux/core/agent";

if (isAgent(entry)) {
  // entry is Agent, has .id, .prompt, .model, .tools, .handoffs
} else {
  // entry is a plain async function
}

On this page