agent() Agents
Use agent() to build either a short tool-using agent or a long-horizon RLM agent with a typed final response.
import { agent, ai, f, fn } from '@ax-llm/ax';
const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY! });
const search = fn('search')
.description('Search docs')
.arg('query', f.string('Search query'))
.returns(f.string('Search result text'))
.handler(async ({ query }) => `docs for ${query}`)
.build();
const helper = agent('question:string -> answer:string', { functions: [search] });
const out = await helper.forward(llm, { question: 'How do I tune a program?' });Agents coordinate tools, child agents, runtime sessions, memories, skills, context policies, discovery, recall, shared fields, traces, usage, and final typed responses.
Pick the path by task shape:
- Short agents: quick tool calls, small child-agent composition, and compact final responses.
- Long-horizon agents: RLM runtime execution, context policy, context maps, memory, skills, and optimizer artifacts.
See short agent examples and Advanced Start for the broader Ax path.
What It Does
agent() creates a structured agent program. The agent planner/executor/responder loop can call tools, delegate to child agents, inspect runtime state, ask for clarification, discover tools or skills, recall memory, and finish with a typed output object.
Core Call Shape
helper = agent(signature, options)
result = helper.forward(aiClient, inputs)Common Patterns
- Start with a signature that names the final answer fields.
- Add
fn()tools for host data and side effects. - Add child agents to the same callable list as tools.
- Use namespaces to keep tool calls readable.
- Enable discovery when available tools are too numerous to include in full.
- Save and restore state around clarification.
- Use context policies for long-running sessions.
Short agent
import { agent, ai, f, fn } from '@ax-llm/ax';
const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY! });
const lookupOrder = fn('lookupOrder')
.description('Fetch an order record by id')
.arg('orderId', f.string('Order id, e.g. ord-1042'))
.returns(f.json('Order record'))
.handler(async ({ orderId }) => orderStore.get(orderId))
.build();
const support = agent('ticket:string -> reply:string', {
functions: [lookupOrder],
});
const out = await support.forward(llm, {
ticket: 'Where is my order ord-1042?',
});Namespaced tools and discovery
Use a flat functions list for small stable sets: local fn() tools, child agents, MCP clients, and runtime providers can all live beside each other. The actor sees those callables directly.
import { agent, f, fn } from '@ax-llm/ax';
const findPolicy = fn('findPolicy')
.namespace('kb')
.description('Find internal policy snippets')
.arg('topic', f.string('Policy topic'))
.returns(f.string('Snippets').array())
.handler(async ({ topic }) => searchPolicyIndex(topic))
.build();
const writer = agent('draft:string -> revision:string', {
agentIdentity: { name: 'Writer', description: 'Polishes replies', namespace: 'team' },
contextFields: [],
});
const assistant = agent('message:string -> reply:string', {
functions: [findPolicy, writer],
contextFields: [],
});Use grouped functions when the catalog is large or easier to reason about by domain. Each group gives the actor a namespace plus module-level selection criteria; with functionDiscovery: true, concrete schemas are loaded only after the actor calls discover(...). You rarely need to set the flag yourself: autoUpgrade (ON by default) enables discovery automatically once the inline tool docs get large, and likewise keeps oversized input values runtime-only with a truncated prompt preview when they aren’t declared in contextFields. Explicit settings always win; pass autoUpgrade: false to opt out.
import { type AxAgentFunctionGroup, agent } from '@ax-llm/ax';
const groups: AxAgentFunctionGroup[] = [
{
namespace: 'crm',
title: 'Customer Records',
selectionCriteria: 'Accounts, contacts, and subscription lookups.',
functions: [findAccount, listSubscriptions],
},
{
namespace: 'billing',
title: 'Billing',
selectionCriteria: 'Charges, invoices, refunds, disputes.',
functions: [listCharges, issueRefund],
},
];
const assistant = agent('request:string -> resolution:string', {
functions: groups,
functionDiscovery: true,
});
// The actor sees a compact module index and calls discover(['billing'])
// to load full function docs only when that module is actually needed.
For the cross-language smart-default path, see the Smart Defaults Agent in the long-agent examples.
Grouped mode keeps big catalogs out of the prompt until needed. Keep the top-level list either flat or grouped. If a child agent belongs inside a group, pass childAgent.getFunction() inside the group’s functions list.
Memory, skills, and context policy
const assistant = agent('situation:string -> guidance:string', {
// Always-on guidance plus stores the agent searches on demand.
skills: [houseStyleSkill],
onSkillsSearch, // agent loads runbooks via await discover({ skills })
onMemoriesSearch, // agent recalls past facts via await recall([...])
onLoadedSkills: (loaded) =>
console.log('skills:', loaded.map((s) => s.id ?? s.name)),
onUsedMemories: (used) => console.log('memories used:', used),
});const analyst = agent(
'incidentLog:string, question:string -> findings:string',
{
contextFields: ['incidentLog'],
runtime: new AxJSRuntime(),
maxTurns: 8,
contextPolicy: {
preset: 'checkpointed', // full | checkpointed | adaptive | lean
budget: 'compact',
},
}
);Connect MCP servers
MCP clients can be passed as tool providers after initialization. Use the flat form when the server exposes a small, obvious tool set.
import { AxJSRuntime, AxMCPClient, agent } from '@ax-llm/ax';
const mcpClient = new AxMCPClient(transport);
await mcpClient.init();
const assistant = agent('request:string -> response:string', {
mcp: mcpClient,
functionDiscovery: true,
contextFields: [],
runtime: new AxJSRuntime(),
});Use grouped discovery when an MCP server has many tools, prompts, or resources. The group gives the actor a namespace and selection criteria before it asks to see detailed schemas.
const assistant = agent('request:string -> response:string', {
mcp: [memoryClient, searchClient],
functionDiscovery: true,
contextFields: [],
});Production Notes
Trace actor turns, tool calls, child-agent calls, clarification, discovery, recall, context growth, token usage, and final typed outputs. Keep host functions narrow and typed. Let fatal infrastructure errors bubble; let task uncertainty become clarification or a typed final answer.
See Tools, agent() API, and MCP.