Callbacks
Agency exposes a number of hooks. It's possible to write callbacks for these hooks in Agency files or pass them in when you run the node through TypeScript. Here are both options.
Callbacks in Agency files
import { callback } from "std::agency"
callback("onNodeStart") as data {
print(`Node ${data.nodeName} started.`)
}Callbacks registered with callback(name, fn) are scoped to the dynamic extent of the function or node that calls callback(...). When that function or node returns, the callback is automatically unregistered. Callbacks registered at module top-level (outside any function or node) are active for the entire run.
Callbacks in TypeScript
import { main } from "agency"
const callbacks = {
onNodeStart: (data) => {
console.log(`Node ${data.node.id} started.`)
}
}
const result = main(param1, param2, { callbacks })interrupt is not allowed inside a callback body
Callback bodies cannot raise interrupts. The typechecker rejects any interrupt(...) call (direct or transitive) inside a callback(...) { ... } body with an error like:
interruptis not allowed inside a callback body. Callbacks fire as side effects; their body cannot pause execution to ask the user a question. Move theinterruptinto the calling node/function instead, or use a runtime guard if you wanted budget enforcement.
Callbacks fire as side effects: they run, they may throw a JS error (which is caught and logged by the runtime), and that is it. If you need to pause the agent for user input, put the interrupt(...) in the node or function that contains the work, not in a hook callback.
List of hooks
Here are all the hooks that Agency provides.
onAgentStart
Called when an agent (graph) starts executing.
nodeName: the name of the entry nodeargs: the arguments passed to the agentmessages: the initial message historycancel(reason?): call this to cancel the agent before it runs
onAgentEnd
Called when an agent finishes executing.
nodeName: the name of the entry noderesult: the result of running the agent
onNodeStart
Called when a graph node begins executing.
nodeName: the name of the node
onNodeEnd
Called when a graph node finishes executing.
nodeName: the name of the nodedata: the data returned by the node
onLLMCallStart
Called before an LLM call is made. You can return a MessageJSON[] array to override the messages sent to the LLM.
prompt: the prompt stringtools: the tools available to the LLM, each withname,description, andschemamodel: the model being usedmessages: the messages that will be sent
onLLMCallEnd
Called after an LLM call completes. You can return a MessageJSON[] array to override the messages stored in the thread.
model: the model that was usedresult: the full prompt result from the LLMusage: token usage statistics (if available)cost: estimated cost (if available)timeTaken: how long the call took in millisecondsmessages: the messages that were sent
onFunctionStart
Called when a function (tool) begins executing.
functionName: the name of the functionargs: the arguments passed to the functionisBuiltin: whether this is a built-in functionmoduleId: the module the function belongs to
onFunctionEnd
Called when a function (tool) finishes executing.
functionName: the name of the functiontimeTaken: how long the function took in milliseconds
onEmit
Called when agency code invokes emit(...). Receives whatever value was passed to emit.
onToolCallStart
Called when the LLM invokes a tool call.
toolName: the name of the tool being calledargs: the arguments passed to the tool
onToolCallEnd
Called when a tool call finishes.
toolName: the name of the toolresult: the result returned by the tooltimeTaken: how long the tool call took in milliseconds
onStream
Called during streaming LLM responses. The data is a tagged union with one of these types:
{ type: "text", text }— a chunk of streamed text{ type: "tool_call", toolCall }— a streamed tool call{ type: "done", result }— streaming is complete{ type: "error", error }— an error occurred during streaming
onTrace
Called for each trace line emitted during execution. Providing this callback automatically activates tracing for the execution. Receives a TraceEvent object:
runId: a unique id identifying this run (useful for distinguishing concurrent requests)line: the trace line, one of:{ type: "header", ... }— trace metadata (first line){ type: "chunk", hash, data }— content-addressed data block{ type: "manifest", ... }— checkpoint reference (one per step){ type: "footer", checkpointCount, chunkCount, timestamp }— emitted when execution completes