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.
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:
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 schemaOptions
| Field | Purpose | Default |
|---|---|---|
id | Unique identifier (used in devtools and swarm routing) | Required |
description | Human-readable description (used in swarm transfer tool descriptions) | undefined |
prompt | The prompt this agent executes | Required |
model | Model override (takes precedence over composition-level model) | undefined |
tools | Agent-specific tools | undefined |
handoffs | Agent IDs or { id, when } objects for swarm routing | [] |
swarmTools | Tool name whitelist for swarm context | All 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:
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:
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 responsePlain 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
}