This skill helps an LLM generate correct AxAgent observability code using @ax-llm/ax. Use when the user asks about axGlobals.onUsage, usageContext, centralized or multi-tenant usage accounting, actorTurnCallback, onContextEvent, agentStatusCallback, onFunctionCall, reportSuccess, reportFailure, getChatLog(), getUsage(), resetUsage(), debug traces, progress updates, or telemetry for AxAgent runs.
68
83%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Use this skill when an agent needs runtime visibility, progress reporting, tracing, usage accounting, or chat-log access. For ordinary agent setup use ax-agent. For RLM runtime policy use ax-agent-rlm. For memories and dynamic skill loading use ax-agent-memory-skills.
debug: true.actorTurnCallback.onContextEvent.agentStatusCallback.onFunctionCall.getChatLog().axGlobals.onUsage plus usageContext.getUsage() and resetUsage().getStagedUsage().getTraces().OpenTelemetry and debug defaults come from the shared Ax runtime surface:
import { axGlobals, axCreateDefaultColorLogger } from '@ax-llm/ax';
import { trace } from '@opentelemetry/api';
axGlobals.tracer = trace.getTracer('agent-app');
axGlobals.debug = true;
axGlobals.logger = axCreateDefaultColorLogger();
axGlobals.onUsage = (event) => usageQueue.enqueue(event);These globals are live defaults for future AI, AxGen, AxFlow, and agent-internal model calls. Per-call or explicitly configured options still override axGlobals. Use AxAgent callbacks below when the caller needs structured agent-turn events rather than OpenTelemetry spans or debug logs.
Use the process-wide usage observer for application accounting across many agents, API routes, tenants, and users. Keep getUsage() for inspecting one agent instance after a run.
import { axGlobals } from '@ax-llm/ax';
axGlobals.onUsage = (event) => {
usageQueue.enqueue(event); // Must return immediately.
};
await supportAgent.forward(
llm,
{ query: request.body.query },
{
usageContext: {
tenantId: auth.tenantId,
userId: auth.userId,
requestId: request.id,
runId: crypto.randomUUID(),
feature: 'support-chat',
attributes: { environment: 'production' },
},
}
);Rules:
operation, ai, model, normalized tokens, streaming, optional context, and available session or remote request IDs.usageContext. Put tenant, user, request, run, and feature attribution in per-call or per-forward usageContext.attributes are shallow-merged.axGlobals.onUsage = undefined during test teardown or shutdown when appropriate.For direct AI calls and the complete event shape, also read ax-ai.
Use actorTurnCallback when the caller needs structured telemetry for each actor turn.
What it gives you:
code: the normalized JavaScript code the actor producedstage: which actor produced the turn (distiller or executor)result: the raw untruncated runtime return value from executing that codeoutput: the formatted action-log output string after Ax normalizes and truncates it for prompt replaythought: the actor model's thought field when showThoughts is enabled and the provider returns oneexecutorResult: the full actor payload returned by the current actor stage, kept under this historical field name for compatibilityisError: whether the execution path for that turn was treated as an errorusage: token usage for this actor turn onlymodel: model used for this turn when explicitly set through executorModelPolicychatLogMessages: raw ChatML conversation for this turn, populated only when an actor turn callback is setUse it for:
thought for internal diagnostics when supported by the providerImportant:
output is not raw stdout; it is the formatted replay string used in the action log.result is the raw runtime result before Ax applies type-aware serialization and budget-proportional truncation.thought is optional and only appears when the underlying AxGen call had showThoughts enabled and the provider actually returned a thought field.actionLogEntryCount and guidanceLogEntryCount reflect the live log sizes after the turn is processed, including resumed runs.actorTurnCallback fires for the configured agent instance. Child agents passed through functions: [...] should define their own callback if you need their internal actor turns; use onFunctionCall on the parent to observe the parent-side child-agent invocation.Good pattern:
const supportAgent = agent('query:string -> answer:string', {
contextFields: ['query'],
runtime,
actorTurnCallback: ({
stage,
turn,
actionLogEntryCount,
guidanceLogEntryCount,
code,
result,
output,
thought,
isError,
usage,
model,
}) => {
console.log({
turn,
stage,
model,
actionLogEntryCount,
guidanceLogEntryCount,
isError,
code,
rawResult: result,
replayOutput: output,
thought,
usage,
});
},
executorOptions: {
model: 'gpt-5.4-mini',
showThoughts: true,
},
});Callback type:
actorTurnCallback?: (turn: {
stage: 'distiller' | 'executor';
turn: number;
actionLogEntryCount: number;
guidanceLogEntryCount: number;
executorResult: Record<string, unknown>;
code: string;
result: unknown;
output: string;
isError: boolean;
thought?: string;
usage?: AxProgramUsage[];
model?: string;
chatLogMessages?: ReadonlyArray<{ role: string; content: string }>;
}) => void | Promise<void>;
actorTurnCallback?: (turn: {
stage: 'distiller' | 'executor';
turn: number;
actionLogEntryCount: number;
guidanceLogEntryCount: number;
executorResult: Record<string, unknown>;
code: string;
result: unknown;
output: string;
isError: boolean;
thought?: string;
usage?: AxProgramUsage[];
model?: string;
chatLogMessages?: ReadonlyArray<{ role: string; content: string }>;
}) => void | Promise<void>; // deprecated aliasUse onContextEvent when the caller needs structured telemetry about prompt pressure and compaction. It does not change model behavior directly; it is for logs, evals, and dashboards.
Events:
budget_check: character-based prompt pressure before an actor turn, with detailed metrics kept out of the actor promptcheckpoint_created / checkpoint_cleared: checkpoint lifecycle events with covered turns and reasontombstone_created: compact resolved-error summary creationrelevance_ranking: emitted once per ranked domain per forward when relevanceRanking is enabled; carries domain ('modules' | 'skills' | 'memories'), the shortlist ({ id, score }[], most relevant first), and suppressed (true when the low-confidence guard emitted no hint)field_auto_promoted: emitted once per field per run when autoUpgrade keeps an oversized undeclared input value runtime-only; carries fieldName, originalChars, and promptPreviewChars (undefined when no inline preview was kept)To measure whether the advisory hint helps, join per forward: relevance_ranking.shortlist ids against what the actor then loaded — for modules the internal discover calls (onFunctionCall with kind: 'internal', name: 'discover', args.request) plus the module part of external qualifiedNames; for skills onLoadedSkills / used(id); for memories onLoadedMemories / used(id).
Rules:
contextPressure in the actor prompt is intentionally compact (ok, watch, critical plus one short instruction).onContextEvent, not the actor prompt.const supportAgent = agent('query:string -> answer:string', {
contextFields: ['query'],
runtime,
contextPolicy: { preset: 'checkpointed', budget: 'balanced' },
onContextEvent: (event) => {
if (event.kind === 'budget_check') {
console.log(event.pressure, event.mutablePromptChars);
}
},
});Type:
onContextEvent?: (event: AxAgentContextEvent) => void | Promise<void>;Use agentStatusCallback when the caller wants real-time progress updates from the actor. When set, the actor can call await reportSuccess(message) and await reportFailure(message) in its JavaScript turns.
const supportAgent = agent('query:string -> answer:string', {
contextFields: ['query'],
runtime,
agentStatusCallback: (message, status) => {
console.log(`[${status}] ${message}`);
},
});Rules:
agentStatusCallback receives (message: string, status: 'success' | 'failed').reportSuccess(message) and reportFailure(message) as available runtime functions.reportSuccess and reportFailure are reserved runtime names when the callback is configured.Type:
agentStatusCallback?: (
message: string,
status: 'success' | 'failed'
) => void | Promise<void>;Use onFunctionCall when the caller wants to observe every function call the actor makes from the JS runtime. It fires before the underlying function runs.
const supportAgent = agent('query:string -> answer:string', {
contextFields: ['query'],
runtime,
functions: [helperAgent, lookupOrderTool],
onFunctionCall: ({ name, qualifiedName, args, kind }) => {
console.log(`[${kind}] ${qualifiedName}`, args);
},
});Rules:
{ name, qualifiedName, args, kind }.name is the bare function name, e.g. 'lookupOrder'.qualifiedName is the namespaced name as the actor sees it, e.g. 'tools.lookupOrder'; for un-namespaced runtime globals it equals name.args is the resolved positional/named arguments object (Record<string, unknown>).kind is 'external' for caller-registered functions.kind is 'internal' for agent-injected globals: child agents, discover, recall, and used.onFunctionCall on AxProgramForwardOptions; that hook is for LLM tool-calls and never fires under AxAgent because AxAgent injects functions as runtime globals.Type:
onFunctionCall?: (call: {
name: string;
qualifiedName: string;
args: Record<string, unknown>;
kind: 'internal' | 'external';
}) => void | Promise<void>;AxAgent exposes actor and responder sub-programs. getChatLog() returns the same flat AxChatLogEntry[] shape as AxGen and AxFlow; use each entry's optional name field to distinguish distiller, executor, and responder. getUsage() returns token usage split by actor/responder.
Returns the full normalized chat history after any .forward() call. Each entry is one ai.chat() round-trip. Actor stages accumulate one entry per turn; the responder typically has one entry.
const log = myAgent.getChatLog();
for (const entry of log) {
console.log(entry.name, entry.model);
for (const msg of entry.messages) {
console.log(`[${msg.role}]`, msg.content);
}
}Each AxChatLogEntry captures the full prompt sent to the model and its response:
type AxChatLogMessage =
| { role: 'system'; content: string }
| { role: 'user'; content: string }
| { role: 'assistant'; content: string }
| { role: 'tool'; name: string; content: string };
type AxChatLogEntry = {
name?: string; // e.g. "distiller", "executor", "responder"
model: string;
messages: AxChatLogMessage[];
modelUsage?: AxProgramUsage;
stage?: 'ctx' | 'task';
};Returns token usage split by actor/responder. Each sub-array contains one AxProgramUsage entry per model/run, merged by (ai, model) key.
const usage = myAgent.getUsage();
// { actor: AxProgramUsage[], responder: AxProgramUsage[] }
console.log('Actor tokens:', usage.actor[0]?.tokens);
console.log('Responder tokens:', usage.responder[0]?.tokens);Returns usage split by pipeline stage. The ctx stage has the distiller actor only; the task stage has the executor actor plus responder.
const staged = myAgent.getStagedUsage();
console.log(staged.ctx?.actor);
console.log(staged.task.actor);
console.log(staged.task.responder);Returns Ax program traces for the agent pipeline. Use it when the caller needs trace data rather than chat messages or token summaries.
const traces = myAgent.getTraces();Resets both actor and responder usage at once:
myAgent.resetUsage();Type signatures:
// AxAgent
agent.getChatLog(): readonly AxChatLogEntry[]
agent.getUsage(): { actor: AxProgramUsage[]; responder: AxProgramUsage[] }
agent.getStagedUsage(): { ctx?: AxAgentUsage; task: AxAgentUsage }
agent.getTraces(): AxProgramTrace[]
agent.resetUsage(): void
// AxGen / AxFlow
gen.getChatLog(): readonly AxChatLogEntry[]
gen.getUsage(): AxProgramUsage[]debug: true and actorTurnCallback unless the user wants both unstructured prompt/runtime visibility and structured telemetry.onFunctionCall when the user wants AxAgent runtime function calls.showThoughts unless the user needs provider thought diagnostics and the provider supports it.getUsage() as the centralized source of truth across shared agents or processes.axGlobals.onUsage; enqueue and return.If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.