Skip to content
Helix Docs

Building agents

Define tools and agents in code, run them from any function with ctx.agent(), pause for human approval, and keep conversation history in sessions.

For developers Updated Oct 20, 2026
View as Markdown

An agent in Helix is a model, a set of tools, and instructions, defined in one file under functions/_agents/ and run from any function with ctx.agent(name). The runtime drives the model loop, runs each tool with the caller’s ctx, pauses when a tool needs a human to approve it, and keeps the conversation in a session so the next call continues where the last one stopped.

What an agent is made of

PartDefined withLives inDoes
TooldefineToolAny shared module, for example functions/_shared/tools/One capability the model can call: a name, a description, a Zod input schema, and a handler
AgentdefineAgentfunctions/_agents/<name>.tsThe model, its instructions, the tools it may call, and its limits and memory settings
Callerctx.agent(name)Any function or scheduleStarts or continues a conversation and gets a result back
SessionCreated for youManaged by the platformThe message history for one conversation, plus any approvals waiting on a human

Every model call an agent makes goes through ctx.ai, so the model provider’s key is injected by the platform and never appears in your code. Every tool call runs with the same ctx the calling function has, so tools reach connected services, the key-value store, and logging the way any function does.

Your first agent

Three files and one config entry. Start with the provider the agent will use:

// helix.config.ts
import { defineConfig } from '@trayai/helix-sdk';

export default defineConfig({
  name: 'support',
  workspaceId: '<your-workspace-uuid>',
  authentications: {
    anthropicKey: '<your-anthropic-auth-uuid>',
  },
  aiProviders: {
    anthropicKey: 'anthropic',
  },
});

Define a tool. The handler gets the caller’s ctx with input already validated against the schema:

// functions/_shared/tools/lookup-order.ts
import { z } from 'zod';
import { defineTool } from '@trayai/helix-sdk';

export default defineTool({
  name: 'lookup_order',
  description: 'Look up an order by its id and return its status and line items.',
  input: z.object({
    orderId: z.string().min(1),
  }),
  handler: async (ctx) => {
    const order = await ctx.kv().getItem(`order:${ctx.input.orderId}`);
    if (!order) return { found: false };
    return { found: true, order };
  },
});

Define the agent. The file name is yours to choose; the name field is what callers use:

// functions/_agents/support-agent.ts
import { defineAgent } from '@trayai/helix-sdk';
import lookupOrder from '../_shared/tools/lookup-order';

export default defineAgent({
  name: 'support-agent',
  description: 'Answers questions about a customer order.',
  model: 'claude-sonnet-4-5',
  auth: 'anthropicKey',
  instructions: `You are a support assistant. Use lookup_order to check an order
before answering. If the order is not found, say so and ask for the id again.`,
  tools: [lookupOrder],
});

Run it from a function:

// functions/api/v1/support.post.ts
import { z } from 'zod';
import { defineFunction } from '@trayai/helix-sdk';

export const input = z.object({
  question: z.string().min(1),
  sessionId: z.string().optional(),
});

export default defineFunction<typeof input>(async (ctx) => {
  const result = await ctx.agent('support-agent').generate({
    prompt: ctx.input.question,
    sessionId: ctx.input.sessionId,
  });

  return {
    answer: result.text,
    sessionId: result.sessionId,
    cost: result.helix.cost.amount,
  };
});

The first call creates a session and returns its id. Pass that id back on the next call and the agent sees the earlier turns.

Try it locally

helix dev loads every file under functions/_agents/ and lists what it found:

  Agents (1): support-agent
    chat: helix agent chat support-agent

helix agent chat <name> opens a terminal conversation with the agent through the running dev server, one session per chat. When a tool needs approval, the chat prompts you inline. See the agent commands reference.

Adding or removing an agent file needs a dev server restart. Edits to an existing agent file hot-reload like any other function.

What the runtime does for you

  • Runs the loop. The model answers, calls tools, reads the results, and continues until it has a final answer or hits a limit. Defaults are 25 steps and 50 tool calls per call.
  • Falls back between models. Declare fallbacks and a provider error moves the call to the next model in the chain.
  • Pauses for approval. A tool marked needsApproval stops the loop before it runs. You get the pending request back, show it to a person, and resume with their decision. See tool approval.
  • Keeps history. Each conversation is a session that stores every message. The model is sent a window of the most recent ones, always a valid history. See agent sessions.
  • Delegates. An agent can hand a sub-task to another agent by listing it under agents. See agent architecture and patterns.
  • Reports cost. result.helix.cost is the estimated spend for the agent’s own model calls in that run, priced per step at the rate of the model that answered that step. Runs it delegates to another agent are not included.
  • Traces every run. helix dev prints an AGENT line when a run starts and finishes, with a TOOL line under it for each tool call. The same spans reach the execution logs in production.

After you deploy

The project’s Agents tab in the dashboard lists every agent in the live deployment, with its model, tools, and memory scope. Switch to Tools to see which tools need approval and which agents use them. The tab is read-only; it updates when you deploy.

Runs appear on the project’s Logs tab. The Uses AI filter finds executions that ran an agent or called a model. Open one to see the agent run and each tool call in its trace.

Every deployment that adds, removes, or changes an agent, or changes whether a tool needs approval, is recorded in the organization’s activity trail.

Where to go next

GuideCovers
Defining toolsInput schemas, handlers, calling a tool directly, testing
Defining agentsEvery defineAgent option, instructions files, fallbacks, limits
Agent architecture and patternsThe built-in loop, chains of calls, delegation, and writing your own loop
Tool approvalPausing for a human and resuming with their decision
Agent sessionsProject and user scoped sessions, the model window, retention
Bring your own session storageStoring history in your own table, or managing it yourself
Building a chat UI for an agentExposing an agent over HTTP and rendering a chat in your app

Loading search…

Jump to a section

tab to move · esc to close