defineAgent declares an agent: which model answers, what it is told, which tools it may call, how long its memory is, and how many steps it may take. One file per agent under functions/_agents/, default-exporting the definition. The dev server and the deploy build load every file in that directory, so you never import an agent yourself; functions reach it by name through ctx.agent(name).
A complete definition
// functions/_agents/support-agent.ts
import { defineAgent } from '@trayai/helix-sdk';
import lookupOrder from '../_shared/tools/lookup-order';
import issueRefund from '../_shared/tools/issue-refund';
export default defineAgent({
name: 'support-agent',
description: 'Resolves order and refund questions for a signed-in customer.',
model: 'claude-sonnet-4-5',
auth: 'anthropicKey',
fallbacks: [{ model: 'gpt-4o', auth: 'openaiKey' }],
instructionsFile: './support-agent.md',
tools: [lookupOrder, issueRefund],
agents: ['shipping-agent'],
memory: {
scope: 'user',
maxSessionMessages: 100,
ttl: 60 * 60 * 24 * 7,
},
limits: {
maxIterations: 15,
maxToolCalls: 30,
},
});
| Field | Required | Default | What it does |
|---|---|---|---|
name | Yes | Kebab case, starting with a letter, up to 64 characters. What ctx.agent(name) and helix agent chat <name> use | |
description | Yes | One or two sentences. Shown by helix agent list, and read by other agents that delegate to this one | |
model | Yes | A model id for the provider behind auth, the same string you would pass to ctx.ai(auth) | |
auth | Yes | An authentication alias with an aiProviders entry in helix.config.ts | |
fallbacks | No | none | Models to try, in order, when the primary throws |
instructions | One of the two | The system prompt, inline | |
instructionsFile | One of the two | Path to a text or Markdown file, relative to the agent file | |
tools | No | none | defineTool definitions the model may call |
agents | No | none | Names of other agents this one may delegate to |
memory.scope | No | 'project' | 'project' shares sessions across the project; 'user' keys them to the signed-in user |
memory.maxSessionMessages | No | 200 | Most recent messages the model is sent each turn. Does not limit what is stored |
memory.ttl | No | none | Seconds of inactivity before a session expires. Omit it and sessions are kept |
limits.maxIterations | No | 25 | Model steps per call |
limits.maxToolCalls | No | 50 | Tool executions per call, across all steps |
The definition is validated when the file loads. A missing field, a badly formed name, two tools with the same name, or both instructions and instructionsFile set at once throws an error that names the field, so a broken agent fails at helix dev startup rather than on first use.
Model, auth, and fallbacks
model and auth together are one ctx.ai(auth) model: the alias names the provider, the id names the model. Declare the alias in helix.config.ts under both authentications and aiProviders exactly as you would for a direct ctx.ai call. See calling AI models.
fallbacks is an ordered list of further model and alias pairs, as in the complete definition above. When the primary model throws, the runtime retries the same step on the next entry, then the next. A fallback is never used after the caller aborts the request. Because any step of a run may be answered by a fallback, result.helix.model names the model that produced the final answer and result.helix.cost prices each step at the rate of the model that answered it. The cost covers this agent’s own model calls. A run it delegates to another agent is priced on that agent’s own result, not added here.
Instructions
Short instructions fit inline:
instructions: 'You are a billing assistant. Answer only billing questions. Use lookup_invoice before quoting any amount.',
Longer prompts go in a file next to the agent so you can edit them without touching code. The path is relative to the agent file:
instructionsFile: './support-agent.md',
<!-- functions/_agents/support-agent.md -->
You are the support assistant for Acme.
Rules:
- Always call lookup_order before discussing an order.
- Never promise a refund; call issue_refund, which may require approval.
- If you cannot resolve the issue, say so and offer to open a ticket.
Exactly one of instructions and instructionsFile must be set. The file is read when the agent is first used in helix dev, and bundled into the deployment at build time. The path is relative to the agent file and must point inside the project. The file can be up to 256 KB.
Tools and delegates
tools takes defineTool definitions, covered in defining tools. agents takes the names of other agents. Each one becomes a tool called agent_<name> (hyphens become underscores) whose description is the target agent’s description, so write descriptions that tell a calling agent when to hand off. Delegation patterns, depth limits, and what a delegate can and cannot do are in agent architecture and patterns.
References under agents are checked the first time the agent runs, not when the file loads, because two agents may legitimately refer to each other.
Memory
memory configures the session every conversation gets. scope: 'user' makes sessions private to the signed-in user who invoked the function, and lets you call agent.sessions() to list that user’s conversations. The default 'project' scope shares sessions across the project, which suits a schedule or a back-office function. The message window and retention are in agent sessions.
Limits
A call stops when the model gives a final answer, or when either limit is reached. maxIterations counts model steps; maxToolCalls counts tool executions across the whole call. When a limit stops the run, result.text is whatever the model had produced by then and result.finishReason reports why it stopped. result.status is still 'completed': status only tells you whether the run is waiting on an approval, so check finishReason when you need to know the answer is finished. Override both per call with stopWhen:
import { stepCountIs, totalToolCallsIs } from '@trayai/helix-sdk';
const result = await ctx.agent('support-agent').generate({
prompt: ctx.input.question,
stopWhen: [stepCountIs(5), totalToolCallsIs(10)],
});
Running an agent
ctx.agent(name) returns a client with generate and stream. Both take a prompt or a messages array, an optional sessionId, and per-call overrides:
const agent = ctx.agent('support-agent');
const result = await agent.generate({ prompt: 'Where is order 1042?' });
result.text; // the final answer
result.sessionId; // pass back to continue the conversation
result.status; // 'completed' | 'awaiting-approval'
result.steps.length; // model steps taken
result.helix.cost.amount; // estimated USD for the whole call
result.helix.model; // model that produced the final answer
stream resolves to the AI SDK stream result with sessionId added. Prior history is loaded before the stream starts, which is why it returns a promise. The turn is saved to the session when the stream finishes. If that save fails, or the stream is aborted, the turn is not saved and nothing is thrown, because your function has already returned the stream:
const stream = await agent.stream({ prompt: ctx.input.question, sessionId: ctx.input.sessionId });
return stream.toUIMessageStreamResponse();
Per-call options: activeTools narrows the tool list for one call, toolChoice forces or forbids tool use, prepareStep adjusts settings before each step, and providerOptions passes provider-specific settings through. All are the AI SDK’s own options. Full shapes are in the ctx.agent() reference.
What you see in the logs
Every call opens a span named agent.generate or agent.stream carrying the agent name, session id, step count, and outcome. Tool calls nest under it. In helix dev with pretty logs that renders as:
AGENT support-agent
TOOL lookup_order success 212ms
TOOL issue_refund success 380ms
AGENT support-agent → completed 3 steps 4520ms
The closing line is yellow when the run paused for approval and red when it failed. In production, the same spans appear in the execution’s trace on the project’s Logs tab. Use the Uses AI filter to find them. See observability.
Full option list with types: agent definition reference.