AxAgent Codegen Rules (@ax-llm/ax)
This skill helps an LLM generate correct core AxAgent code using @ax-llm/ax. Use when the user asks about agent(), child agents, namespaced functions, discovery mode, clarification, bubbleErrors, host-side final/clarification protocol, or ordinary agent runtime behavior. For MCP clients, native runtime modules, subscriptions, tasks, or authentication use ax-mcp alongside this skill. For RLM/code-runtime work use ax-agent-rlm; for callbacks and telemetry use ax-agent-observability; for recall/memory/skill loading use ax-agent-memory-skills; for agent.optimize(…) use ax-agent-optimize.
Install
Install only this skill for TypeScript:
npx skills add https://ax-llm.github.io/ax/typescript/ --skill 'ax-agent'Published skill file: ax-agent/SKILL.md.
Source
- Source: src/ax/skills/ax-agent.md
- Version:
23.0.5
Skill Instructions
Use this skill to generate small, correct AxAgent code. Prefer modern factory-style APIs and copyable patterns. Do not write tutorial prose unless the user explicitly asks for explanation.
Your job is to choose the smallest correct AxAgent shape for the user’s needs:
- If the user wants a normal tool-using assistant, keep the config minimal.
- If the user wants long-running code execution, use the
ax-agent-rlmskill. - If the user wants callbacks, logs, tracing, or usage data, use the
ax-agent-observabilityskill. - If the user wants dynamic memory retrieval or skill-guide loading, use the
ax-agent-memory-skillsskill. - If the user wants tuning or eval with
agent.optimize(...), use theax-agent-optimizeskill. - If the user wants MCP transports, authentication, catalogs, subscriptions,
tasks, Apps, or event-driven wake/resume, use the
ax-mcpskill.
Use These Defaults
- Use
agent(...), notnew AxAgent(...). - Prefer string signatures or
f()signatures over hand-written signature objects. - Put
ai,judgeAI, andagentIdentityon theagent(...)config when you want instance defaults or child-agent metadata. - Prefer
fn(...)for host-side function definitions instead of hand-writing JSON Schema objects. - Prefer namespaced functions such as
utils.search(...)orkb.find(...). - Pass child agents directly in
functions: [...]. They land under theiragentIdentity.namespace(orutilsif unset), exactly like afn()tool. - If discovery is enabled, call
discover(...)before using callables whose docs are not already in the prompt. - Use explicit child agents in
functions: [...]for specialist delegation; do not model that as recursivellmQuery(...). - Add
bubbleErrorsonly for fatal infrastructure errors that should abort.forward().
Decision Guide
Map user intent to agent shape before writing code:
- “Use tools and answer” -> plain
agent(...)with local functions, no extra observability. - “Need child agents with distinct responsibilities” -> add child agents to the parent’s
functions: [...]list and set each child’sagentIdentity.namespacewhen you want a specific runtime call site such asteam.writer(...). - “Need tool discovery because names/schemas are not stable” -> enable discovery and generate discovery-first actor code.
- “Need certain errors to escape the agent loop” -> add
bubbleErrorswith error classes; those errors propagate through function handlers, actor code, andllmQuery(...)sub-queries to.forward(). - “Inspect large context with code”, “RLM”, or “
llmQuery(...)” -> useax-agent-rlm. - “Need debugging, traces, progress updates, tool-call logs, chat logs, or usage” -> use
ax-agent-observability. - “Need memories, recall, dynamic skill guides,
discover({ skills }), or loaded/used tracking” -> useax-agent-memory-skills.
Critical Rules
- Use
agent(...)factory syntax for new code. - Add child agents to the parent’s
functions: [...]list. Each child’sagentIdentity.namespace(orutils, the default) determines the runtime call site, e.g.await team.writer({...}). - If discovery is enabled, call
discover(...)before using callables whose docs are not already in the prompt. autoUpgradeis ON by default: large tool catalogs auto-enable discovery, and oversized undeclared input values are auto-kept runtime-only with a truncated prompt preview. ExplicitfunctionDiscoveryand declaredcontextFieldsalways win; setautoUpgrade: falseto opt out.directResponseis ON by default ('auto'): when a task needs no user-provided functions, the distiller ends the run withrespond(task, evidence)and the executor stage is skipped (zero executor model calls). Function-less agents run respond-only every time; agents with functions offerrespondunder a conservative covenant (no live/fresh-state asks, no side effects, nothing a listed function/module domain covers). SetdirectResponse: 'off'to always run the executor.- If a host-side
AxAgentFunctionneeds to end the current actor turn, useextra.protocol.final(...)orextra.protocol.askClarification(...). - In public
forward()andstreamingForward()flows,askClarification(...)throwsAxAgentClarificationError; it does not go through the responder. - When resuming after clarification, prefer
error.getState()from the thrownAxAgentClarificationError, then callagent.setState(savedState)before the nextforward(...). - Errors listed in
bubbleErrorsbypass actor-loop catch blocks and propagate directly to the caller of.forward(). - Child agents receive only the arguments the actor passes. Pass parent fields explicitly via
inputs.<field>or useinputUpdateCallbackwhen many calls need the same value. - Audio input fields are transcribed before agent planner/executor/responder stages by default; internal agent stages receive text transcripts, not base64 audio.
Canonical Pattern
import { agent, ai, f } from '@ax-llm/ax';
const llm = ai({
name: 'openai',
apiKey: process.env.OPENAI_APIKEY!,
});
const assistant = agent(
f()
.input('query', f.string())
.output('answer', f.string())
.build(),
{
agentIdentity: {
name: 'Assistant',
description: 'Answers user questions',
},
contextFields: [],
}
);
const result = await assistant.forward(llm, { query: 'What is TypeScript?' });
console.log(result.answer);Audio Inputs And Speech Outputs
Agents can accept audio inputs and return scripted speech artifacts. The runtime transcribes audio input fields before internal stages run, then synthesizes :audio outputs after the final structured response is selected.
const voiceAgent = agent(
'recording:audio, question:string -> speech:audio, summary:string',
{
agentIdentity: {
name: 'Voice Assistant',
description: 'Answers spoken requests',
},
contextFields: [],
}
);
const result = await voiceAgent.forward(
llm,
{
recording: { data: base64Wav, format: 'wav' },
question: 'What should I do next?',
},
{
speech: {
transcribe: { model: 'gpt-4o-mini-transcribe' },
speak: { voice: 'alloy', format: 'mp3' },
},
}
);
console.log(result.summary);
console.log(result.speech.data);Use direct ax(...) or .chat() if the model should receive native audio instead of a transcript-first agent pipeline.
Child Agents As Tools
Child agents are passed in the parent’s functions list. There is no separate agents option for new code. Each child agent’s agentIdentity.namespace (or utils, the default) determines where it lands in the actor runtime. With AxJSRuntime, that produces JavaScript call sites such as team.writer(...):
const writer = agent('draft:string -> revision:string', {
agentIdentity: {
name: 'Writer',
description: 'Polishes drafts',
namespace: 'team',
},
contextFields: [],
});
const coordinator = agent('query:string -> answer:string', {
functions: [writer],
contextFields: [],
});Generated runtime call:
const result = await team.writer({ draft: '...' });Without agentIdentity.namespace, the child lands under utils.<name> like any other tool:
const result = await utils.writer({ draft: '...' });Rules:
- Add child agents to
functions: [...], the same array asfn(...)tools. - Set
agentIdentity.namespaceon the child to control its runtime call site. onFunctionCallobservers receivekind: 'internal'for agent-derived calls andkind: 'external'for user-registered tools.
Reserved namespace names
The agent runtime injects a fixed set of globals into the runtime session. These names cannot be used as agentIdentity.namespace values or as agent-function namespaces.
inputs
llmQuery
final
askClarification
reportSuccess
reportFailure
inspectRuntime
discover
recallPick any other lowercase identifier such as utils, kb, tools, team, or db.
Tool Functions And Namespaces
import { agent, f, fn } from '@ax-llm/ax';
const findSnippets = fn('findSnippets')
.description('Find handbook snippets by topic')
.namespace('kb')
.arg('topic', f.string('Topic keyword'))
.returns(f.string('Matching snippet').array())
.example({
title: 'Find severity guidance',
code: 'await kb.findSnippets({ topic: "severity" });',
})
.handler(async ({ topic }) => [])
.build();
const analyst = agent('query:string -> answer:string', {
functions: [findSnippets],
contextFields: [],
});Generated runtime call:
const snippets = await kb.findSnippets({ topic: 'severity' });Rules:
- Prefer namespaced functions.
- Default function namespace is
utilswhen no namespace is set. - With
AxJSRuntime, use the runtime call shapeawait <namespace>.<name>({...}). Custom runtimes should expose equivalent namespaced calls through their ownformatCallable()guidance. .arg()and.returns()can use Ax field helpers or any Standard Schema v1 validator directly.
Grouped Function Modules
For discovery mode, group functions into modules using the AxAgentFunctionGroup shape when you want a clean namespace tree such as kb.find(...) or metrics.score(...) without setting namespace on every individual fn(...):
const parent = agent('query:string -> answer:string', {
functions: [
{
namespace: 'kb',
title: 'Knowledge Base',
selectionCriteria: 'Use for handbook and documentation lookups.',
description: 'Knowledge base lookups',
functions: [findSnippetsFn, searchPagesFn],
},
{
namespace: 'workflow',
title: 'Workflow Controls',
description: 'Small control functions the actor should always see',
alwaysInclude: true,
functions: [completeFn],
},
],
functionDiscovery: true,
contextFields: [],
});Attach MCP/UCP clients through the native execution context. Ax initializes them once, exposes mcp.<namespace> / ucp.<namespace> runtime modules, and propagates them through actor stages, llmQuery, RLM, and child agents:
Use ax-mcp for constructing those clients, transport/authentication policy,
server-initiated handlers, resource subscriptions, task continuations, and
recording/replay. Keep this section focused on Agent attachment and discovery.
const parent = agent('query:string -> answer:string', {
mcp: [memoryClient, searchClient],
mcpInheritance: 'all',
functionDiscovery: true,
contextFields: [],
});
// A child can restrict inheritance to selected namespaces or `none`.
await parent.forward(llm, { query }, { mcpInheritance: ['memory'] });Rules:
- A group is
{ namespace, title, description, functions: [...] }. selectionCriteriais optional but useful in discovery mode; it tells the actor when to choose that module.- The group’s
namespace,title,selectionCriteria, anddescriptionshow up indiscover(...)module docs. relevanceRanking(default ON — setfalseto opt out): a deterministic local ranker that injects an advisory### Likely Relevantshortlist into the executor turn (dynamic, non-cached field — the cached prompt stays byte-stable). Enabled by default after its A/B gate passed on both small and frontier models and implemented in the generated language ports through AxIR Core. Details inax-agent-memory-skills; outcomes observable via therelevance_rankingcontext event (ax-agent-observability).- Add
alwaysInclude: trueto a group when discovery mode is on but the actor should always see that group’s full callable definitions inline in the prompt. - Keep
functions: [...]either flat or grouped. Runtime validation rejects mixed plain function entries and group objects. - In flat mode, pass
fn(...)tools and child agents directly. - In grouped mode, put callable entries inside groups. To expose a child agent inside a group, use
childAgent.getFunction(). - Do not place MCP clients in
functions; usemcpso tasks, resources, subscriptions, elicitation, sampling, authorization, cancellation, and protocol metadata remain available. - To wake an Agent from a resource subscription, use
AxMCPEventSourceand an explicit authenticatedwakeroute. MCP sessions are not tenant identity; supply identity from the application’s authenticated token mapping. - An endpoint does not imply a resource URI. Inspect
client.inspectCatalog()and choose an explicitresourceSubscriptionspolicy. Omission means none;'all'selects all discovered concrete resources; selectors can use names, descriptions, MIME types, URIs, and annotations. Templates are not expanded. - Map the event with a signature-aware
.wakeInput(...)plan, or reuse aneventInput()plan. CallbackmapInputis still signature-validated and cannot inject undeclared Agent fields. Use multiple matching routes to wake multiple Agents with independent state, authorization, retries, and runs. - To wake from a UCP lifecycle webhook, use
AxUCPWebhookEventSourceand map verified profile/account state to Ax tenant identity after request verification. Never derive tenant identity from the order payload.
Host-Side Completion From Functions
Use this pattern when the actor should call a namespaced function, but the host-side function implementation should decide to end the turn:
import { f, fn } from '@ax-llm/ax';
const finishReply = fn('finishReply')
.description('Complete the actor turn with the final reply text')
.namespace('workflow')
.arg('reply', f.string('Final reply text'))
.returns(f.string('Final reply text'))
.handler(async ({ reply }, extra) => {
extra?.protocol?.final(reply);
return reply;
})
.build();
const askForOrderId = fn('askForOrderId')
.description('Complete the actor turn by requesting clarification')
.namespace('workflow')
.arg('question', f.string('Clarification question'))
.returns(f.string('Clarification question'))
.handler(async ({ question }, extra) => {
extra?.protocol?.askClarification(question);
return question;
})
.build();Rules:
extra.protocolis only available when the function call comes from an active AxAgent actor runtime session.- Use
extra.protocol.final(...),extra.protocol.askClarification(...), orextra.protocol.guideAgent(...)only inside host-side function handlers. - Inside actor-authored runtime code, use the runtime globals
final(...)andaskClarification(...)with the syntax documented by the active runtime. extra.protocol.guideAgent(...)is handler-only internal control flow. It stops the current actor turn and appends trusted guidance toguidanceLogfor the next iteration.askClarification(...)accepts either a simple string or a structured object withquestionplus optional UI hints such astype: 'date' | 'number' | 'single_choice' | 'multiple_choice'andchoices.
Clarification And Resume State
Use this pattern when the actor should pause for user input and continue later from the same runtime state.
import {
AxAgentClarificationError,
AxJSRuntime,
agent,
ai,
} from '@ax-llm/ax';
const llm = ai({
name: 'openai',
apiKey: process.env.OPENAI_APIKEY!,
});
const tripAgent = agent('request:string, answer?:string -> reply:string', {
contextFields: [],
runtime: new AxJSRuntime(),
});
let savedState = tripAgent.getState();
try {
await tripAgent.forward(llm, {
request: 'Plan a Lisbon trip',
});
} catch (error) {
if (error instanceof AxAgentClarificationError) {
console.log(error.question);
savedState = error.getState();
} else {
throw error;
}
}
if (savedState) {
tripAgent.setState(savedState);
const resumed = await tripAgent.forward(llm, {
request: 'Plan a Lisbon trip',
answer: 'June 1-5',
});
console.log(resumed.reply);
}Public flow rules:
forward()andstreamingForward()throwAxAgentClarificationErrorwhen the actor callsaskClarification(...).- Successful
final(...)completions always continue through the responder in public flows. AxAgentClarificationError.questionis the user-facing question text.AxAgentClarificationError.clarificationis the normalized structured payload.AxAgentClarificationError.getState()returns the saved continuation state captured at throw time.agent.getState()andagent.setState(...)export or restore continuation state on the agent instance.test(...)is different: it returns structured completion payloads for harness/debug use instead of throwing clarification exceptions.
Structured clarification payloads:
- String shorthand is allowed:
askClarification("What dates should I use?"). - Structured form is preferred for richer chat UIs:
askClarification({
question: 'Which route should I use?',
type: 'single_choice',
choices: ['Fastest', 'Scenic'],
});- Supported
typevalues aretext,number,date,single_choice, andmultiple_choice. single_choicepayloads with missing, empty, or malformedchoicesare downgraded to a plain clarification question instead of failing the turn.multiple_choicepayloads must include at least two valid choices; otherwise the actor turn fails with a corrective runtime error.- Choice entries may be strings or
{ label, value? }objects. - Invalid clarification payloads such as a missing
questionare actor-turn runtime errors, not successful clarification completions.
State notes:
runtimeBindingsrestores execution state;runtimeEntries,actionLogEntries, andcheckpointStaterestore prompt context.- Resume does not create a fake rehydration action-log turn; provenance still points to the original actor code that set the value.
- Only serializable/structured-clone-friendly values are guaranteed to round-trip through
getState()/setState(...). - Reserved runtime globals such as
inputs, tools, and protocol helpers are rebuilt fresh and are not part of saved state. - Treat one agent instance as conversation-scoped when using
setState(...); do not share one mutable resumed instance across unrelated concurrent conversations.
Bubble Errors
Use bubbleErrors when certain exceptions thrown inside function handlers or llmQuery(...) sub-query calls should propagate all the way out to .forward() instead of being caught by the actor loop and returned as [ERROR] strings.
import { agent, f, fn } from '@ax-llm/ax';
class DatabaseError extends Error {
constructor(message: string) {
super(message);
this.name = 'DatabaseError';
}
}
const dbTool = fn('queryUsers')
.description('Query the user database')
.namespace('db')
.arg('filter', f.string('Filter expression'))
.returns(f.string('JSON result'))
.handler(async ({ filter }) => {
if (!isConnected()) throw new DatabaseError('DB connection refused');
return JSON.stringify(await db.query(filter));
})
.build();
const myAgent = agent('query:string -> answer:string', {
contextFields: [],
functions: [dbTool],
bubbleErrors: [DatabaseError],
});Rules:
bubbleErrorstakes an array of Error constructor classes, checked viainstanceof.- A matching error thrown inside a function handler, during actor code execution, or inside an
llmQuery(...)sub-query propagates immediately to.forward(). - Use
bubbleErrorsfor fatal infrastructure errors such as DB down, auth failure, or quota exceeded. - Do not use
bubbleErrorsfor expected recoverable errors; let those return as[ERROR] ...strings so the actor can handle them. AxAgentClarificationErrorandAxAIServiceAbortedErroralways bubble up unconditionally.
Unified Final Signal
There are two ways to end a successful run through the responder:
- In actor JS code, call
final(message)when no extra context object is needed, orfinal(task, context)when you gathered evidence. - In function handlers, use
extra.protocol.final(...)with the same one-arg or two-arg forms.
Rules:
- Use
final(message)when the actor already knows the answer and no extra context object is needed. - Use
final(task, context)when context was gathered and needs synthesis into output fields. - In function handlers, use
extra.protocol.final(...)instead of a separate respond API. - The responder still runs for both successful
final(...)forms. - Use
askClarification(...)when the user must provide more information to continue.
Discovery Mode
Enable discovery mode when you want the actor to discover modules and fetch callable definitions on demand:
const analyst = agent('context:string, query:string -> answer:string', {
agentIdentity: {
name: 'Analyst',
description: 'Analyzes long context',
namespace: 'team',
},
contextFields: ['context'],
functions: [writer, ...tools],
functionDiscovery: true,
});Discovery API:
await discover(item: string): voidawait discover(items: string[]): voidawait discover({ tools?: string | string[], skills?: string | string[] }): voidwhenonSkillsSearchis configured
Discovery returns void; fetched docs render in the next executor prompt.
Rules:
discover('kb')loads a module callable list whenkbis a discoverable module.discover('kb.findSnippets')loads a full callable definition.discover('lookup')resolves asutils.lookup.discover({ tools: ['kb'], skills: ['release-checklist'] })loads tool docs and skill bodies in one turn.- Call one batched
discover(...)with every module, callable, and skill you need. - Do not split discovery into separate calls or wrap discovery in
Promise.all(...). - Read the next prompt’s “Discovered Tool Docs” and “Loaded Skills” sections.
- If a guessed call fails, stop guessing nearby names. Run
discover(...)for that module or function and call only the exact discovered qualified name.
Threading Parent Fields Into Child Agents
If a child agent requires a parent field such as audience, declare it on the child’s signature and pass it explicitly when calling the child from the actor:
const writingCoach = agent('draft:string, audience:string -> revision:string', {
agentIdentity: {
name: 'Writing Coach',
description: 'Polishes summaries for a target audience',
namespace: 'team',
},
contextFields: [],
});
const analyst = agent('context:string, audience:string, query:string -> answer:string', {
functions: [writingCoach],
contextFields: ['context'],
});Generated runtime call:
const polished = await team.writingCoach({
draft: summary,
audience: inputs.audience,
});Rules:
- Pass parent fields explicitly via the call site.
- If many children need the same field on every call, use
inputUpdateCallbackto inject the value before each executor turn. - Do not assume auto-propagation; child agents receive only the args the actor passes.
Core API Reference
Factory shape:
agent(signature, {
ai,
judgeAI,
agentIdentity,
contextFields,
functions,
functionDiscovery,
autoUpgrade,
playbook,
citations,
...agentOptions,
});aiis an optional default service for the agent instance;.forward(ai, ...)can still pass the runtime service.judgeAIis the optional default judge/teacher service used by optimize flows.agentIdentitycontrols the user-facing agent identity and child-agent function metadata.
agentIdentity?: {
name: string;
description: string;
namespace?: string;
}nameis normalized to camelCase for child-agent function names.nameanddescriptionare included in the actor and responder prompts as the user-facing agent identity.namespacechanges the child-agent module from defaultutilsto a custom module such asteam.
Each contextFields entry is either a plain field name string or an object controlling how much of the value is inlined into the distiller prompt:
{ field, promptMaxChars: N }: inline only when the serialized value is at mostNchars; otherwise omit it from the prompt and keep it runtime-only.{ field, keepInPromptChars: N, reverseTruncate?: boolean }: always inline a truncated string excerpt;reverseTruncate: truekeeps the lastNchars.
Use promptMaxChars when partial data is worse than no data. Use keepInPromptChars when a prefix or suffix alone is useful. The two options are mutually exclusive on one field.
Auto-upgrade defaults
autoUpgrade is ON by default: the agent applies both knobs above on the user’s behalf based on character counts, so forgetting them no longer floods prompts.
- Function discovery: when
functionDiscoveryis left unset and the estimated inline docs of discoverable functions exceed ~10k chars, discovery is enabled automatically. An explicitfunctionDiscovery: true | falsealways wins. - Context fields: per run, an undeclared input value whose serialized size exceeds 8k chars is kept runtime-only like a declared context field — the prompt gets a 1,200-char truncated preview plus a
contextMetadataentry, while the full value stays addressable asinputs.<field>in the code runtime (the responder stage gets the same preview). Fields declared incontextFieldskeep their declared config.
autoUpgrade?: boolean | {
functionDiscovery?: boolean | { aboveFunctionDocChars?: number }; // default 10_000
contextFields?: boolean | { promoteAboveChars?: number; previewChars?: number }; // 8_000 / 1_200
}Rules:
- Set
autoUpgrade: false(or disable one side) to restore fully manual behavior. - Values in required non-string fields (arrays, objects, numbers, media) are never auto-promoted — declare those in
contextFieldsexplicitly when they can be large. - Each promotion emits a
field_auto_promotedcontext event (onContextEvent) with the field name, original size, and preview size; use it to observe what was kept out of the prompt.
Learning And Citations
These construction-time options are portable across TypeScript and the generated Python, Java, C++, Go, and Rust packages (both default off):
playbook: attach an ACE playbook at construction.learnis on by default — after each run that produced failure signals (error turns, dead-ends, failing tool calls) one bounded update curates durable avoidance rules that ride the next run’s actor prompt; zero LLM cost on clean runs. TypeScript seeds a prior session withplaybook: { playbook: snapshot }; generated packages accept their full{ playbook, artifact }snapshot underseed. Persist viaonUpdate, read the live handle withgetPlaybook()(or the language-shaped equivalent), gate withlearn: { minSignals, dedupe }, or disable withlearn: false. To grow the same playbook from a task set with a held-out verify gate, use the agent-bound playbook evolve method — seeax-playbook.citations: add an optionalevidenceCitations: string[]responder output listing which evidence entries (top-level keys of the curated evidence, plus memory ids) the answer relied on. Validated in-pipeline — the model cannot cite evidence it never collected (existence, not entailment). Passtrue, or{ field?, surface?: 'output' | 'hidden', includeMemoryIds?, onCitations? }.
Stage guidance is portable too. setInstruction replaces the stage-owned actor
instruction and addActorInstruction appends an additive rule. Both are real
optimization components; rebuilding the split programs no longer discards them.
Generated packages use their normal casing conventions (set_instruction in
Python/C++/Rust and SetInstruction in Go).
The generated-language observer and evolve spellings are:
| Language | Citations observer | Verified agent playbook evolve |
|---|---|---|
| Python | citations.onCitations | agent.playbook().evolve(dataset, options) |
| Java | citations.onCitations (Consumer) | agent.playbook(null).evolve(dataset, options) |
| C++ | set_citations_observer(...) | agent.get_playbook()->evolve(dataset, options) |
| Go | citations.onCitations (func([]Value)) | agent.GetPlaybook().EvolveAgent(ctx, dataset, options) |
| Rust | set_citations_observer(...) | playbook.evolve_agent(&mut agent, client, dataset, options) |
C++ and Rust use set_playbook_observer(...) for construction-time learning
updates; Python, Java, and Go accept the playbook.onUpdate callback in their
native configuration map.
Public Surface
Use these method groups as the compact AxAgent surface map:
- Running:
forward(ai, values, options?)andstreamingForward(ai, values, options?). - Forward-time agent options:
skills,onUsedMemories, andonUsedSkills; useax-agent-memory-skillsfor details. - State and control:
getState(),setState(state?),getContextMap(),setContextMap(map?),stop(),getSignature(),setSignature(signature),getFunction(),getId(), andsetId(id). Context-map evolve policy lives onAxAgentContextMap(infiniteEvolve,evolveSteps,maxChars), not on the agent config. Seesrc/examples/rlm-context-map-live.tsfor provider-backed persistence and finite-evolve usage. - Observability:
getChatLog(),getUsage(),getStagedUsage(),resetUsage(), andgetTraces(); useax-agent-observabilityfor details. - Demos and tuning:
setDemos(...),namedPrograms(),namedProgramInstances(),optimize(...),applyOptimization(...),getOptimizableComponents(), andapplyOptimizedComponents(...); useax-agent-optimizefor tuning details. - Learning:
playbook()returns an agent-aware playbook handle (update(...),render(), state/load methods, and verified dataset evolution);getPlaybook()reads the current handle. Generated packages expose the same behavior with language-shaped method names. Useax-playbookfor details.
Rules:
getFunction()requiresagentIdentitybecause the agent needs function metadata when used as a child tool.- Prefer
.forward(...)for normal runs and.streamingForward(...)only when the caller needs streamed responder output. setSignature(...)must preserve configuredcontextFields; it throws if a configured context field is missing from the new signature.- Treat low-level optimization component methods as advanced hooks; normal examples should use
agent.optimize(...)andagent.applyOptimization(...).
Tuning Hand-off
When the user wants agent.optimize(...), judge configuration, eval datasets, saved optimization artifacts, or optimization guidance, use ax-agent-optimize.
Keep this skill focused on building and running agents. For tuning work:
- use eval-safe tools
- treat
judgeOptionsas part of the optimize workflow - choose an objective
metricwhen scoring is mechanical; use the built-in judge only when run quality needs qualitative review - keep runtime authoring guidance here and optimization guidance in
ax-agent-optimize
Examples
Fetch these for full working code:
- Agent - basic agent
- Functions - function validation
- Food Search - API tools
- Smart Home - state management
- Customer Support - classification agent
- Abort Patterns - abort handling
- Smart Defaults Agent - auto-upgrade context promotion, relevance hints, and runtime tools
- Portable Playbook Evolve - Python construction-time learning, validated citations, stage guidance, and verified task-set evolution (parallel Java/C++/Go/Rust examples live beside it)
RLM examples are listed in ax-agent-rlm. Memory/skills examples are listed in ax-agent-memory-skills.
Event-Driven Agents
AxEventRuntime can wake or resume an Agent while preserving its logical
state. Use createProgram(instance) for multi-tenant Agents; one mutable Agent
object must not serve multiple instance keys concurrently. Clarification and
remote task completion are represented as owned continuations, not synthetic
user turns.
Declare the Agent signature on
eventTarget('id').createProgram(signature, factory) and map event values with
eventPath. The runtime verifies every created Agent against that signature
before invoking it. Fan-out uses multiple matching routes so each Agent keeps
its own authorization, instance serialization, retry policy, and run record.
Do Not Generate
- Do not use
new AxAgent(...)for new code unless explicitly required. - Do not assume child agents are always under
agents.*. - Do not guess function names in discovery mode.
- Do not write a full multi-step RLM actor program in one turn; use
ax-agent-rlm. - Do not combine
console.log(...)withfinal(...). - Do not add
bubbleErrorsfor ordinary recoverable tool errors. - Do not call
discover()from the distiller or responder stages. - Do not assign or inspect the return value of
await discover(...); read the next prompt instead. - Do not loop
discover()calls or wrap them inPromise.all.