Callbacks & Events
Centralized event handling for LLM, tools, agents, and chains for responsive AI applications.
OrkaJS provides a powerful CallbackManager for centralized event handling across your entire application. Track token streaming, tool execution, agent actions, and more with a unified API.
Key Features
- Centralized event management across all components
- Token-level callbacks (onTokenStart, onToken, onTokenEnd)
- Tool execution tracking (onToolStart, onToolEnd, onToolError)
- Agent lifecycle events (onAgentAction, onAgentFinish)
- Chain and retrieval events
- Async callback support with error isolation
- Event filtering by type
Quick Start
Create a callback handler and add it to the global manager:
import { getCallbackManager, createCallbackHandler } from '@orka-js/core'; // Create a handler with shortcut callbacksconst myHandler = createCallbackHandler('my-handler', { onToken: (token, index, content) => { process.stdout.write(token); }, onToolStart: (event) => { console.log(`Tool ${event.toolName} started`); }, onToolEnd: (event) => { console.log(`Tool ${event.toolName} completed in ${event.durationMs}ms`); }, onAgentAction: (event) => { console.log(`Agent action: ${event.action}`); }, onAgentFinish: (event) => { console.log(`Agent finished in ${event.durationMs}ms`); },}); // Add to global managerconst manager = getCallbackManager();manager.addHandler(myHandler);#CallbackManager
The CallbackManager is the central hub for all events:
import { CallbackManager } from '@orka-js/core'; // Create a new managerconst manager = new CallbackManager({ asyncMode: true, // Fire-and-forget callbacks (default) verbose: false, // Log event emissions}); // Add handlersmanager.addHandler({ name: 'logger', eventTypes: ['tool_start', 'tool_end'], // Only these events handleEvent(event) { console.log(`[${event.type}]`, event); },}); // Emit events programmaticallyconst runId = await manager.emitToolStart('search', { query: 'test' });await manager.emitToolEnd(runId, 'search', { query: 'test' }, { results: [] }, 150); // Remove handlermanager.removeHandler('logger'); // Clear all handlersmanager.clearHandlers();Event Types
Available callback event types:
| System Domain | Monitoring Context | Event Hooks |
|---|---|---|
Token | Real-time generation & latency | token_starttokentoken_end |
Tool | External function execution | tool_starttool_endtool_error |
Agent | High-level reasoning & decisions | agent_actionagent_finishagent_error |
Chain | Workflow orchestration | chain_startchain_endchain_error |
LLM | Model inference cycles | llm_startllm_endllm_error |
Retrieval | Vector search & context injection | retrieval_startretrieval_end |
// Token/Streaming eventstype TokenEvents = 'token_start' | 'token' | 'token_end'; // Tool eventstype ToolEvents = 'tool_start' | 'tool_end' | 'tool_error'; // Agent events type AgentEvents = 'agent_action' | 'agent_observation' | 'agent_finish' | 'agent_error'; // Chain eventstype ChainEvents = 'chain_start' | 'chain_end' | 'chain_error'; // LLM eventstype LLMEvents = 'llm_start' | 'llm_end' | 'llm_error'; // Retrieval eventstype RetrievalEvents = 'retrieval_start' | 'retrieval_end'; // All eventstype CallbackEventType = | TokenEvents | ToolEvents | AgentEvents | ChainEvents | LLMEvents | RetrievalEvents;#Creating Handlers
Use createCallbackHandler for a simpler API:
import { createCallbackHandler } from '@orka-js/core'; const handler = createCallbackHandler('analytics', { // Token events onTokenStart: (event) => { console.log('Generation started for:', event.prompt.slice(0, 50)); }, onToken: (token, index, content) => { // Track token count }, onTokenEnd: (event) => { console.log(`Generated ${event.tokenCount} tokens in ${event.durationMs}ms`); }, // Tool events onToolStart: (event) => { analytics.track('tool_invoked', { tool: event.toolName }); }, onToolEnd: (event) => { analytics.track('tool_completed', { tool: event.toolName, duration: event.durationMs }); }, onToolError: (event) => { analytics.track('tool_error', { tool: event.toolName, error: event.error.message }); }, // Agent events onAgentAction: (event) => { console.log(`Agent thinking: ${event.thought}`); console.log(`Action: ${event.action}`); }, onAgentFinish: (event) => { console.log(`Agent completed in ${event.durationMs}ms`); }, // LLM events onLLMStart: (event) => { console.log(`Calling ${event.model}...`); }, onLLMEnd: (event) => { console.log(`LLM used ${event.usage.totalTokens} tokens`); },});#Agent Integration
Agents automatically emit events to the CallbackManager:
import { ReActAgent } from '@orka-js/agent';import { OpenAIAdapter } from '@orka-js/openai';import { getCallbackManager, createCallbackHandler } from '@orka-js/core'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); // Set up callback handlerconst manager = getCallbackManager();manager.addHandler(createCallbackHandler('agent-monitor', { onToolStart: (event) => { console.log(`🔧 Tool: ${event.toolName}`); }, onAgentAction: (event) => { console.log(`🤔 Thought: ${event.thought}`); console.log(`⚡ Action: ${event.action}`); }, onAgentFinish: (event) => { console.log(`✅ Completed in ${event.durationMs}ms`); },})); // Create agent - it automatically uses the global CallbackManagerconst agent = new ReActAgent( { goal: 'Help users with calculations', tools: [ { name: 'calculate', description: 'Perform math calculations', execute: async ({ expression }) => ({ output: eval(expression) }), }, ], }, llm); // Or pass a specific CallbackManagerconst customManager = new CallbackManager();const agentWithCustomManager = new ReActAgent( { goal: 'Help users', tools: [], callbackManager: customManager, // Use custom manager }, llm); // Run agent - events are automatically emittedconst result = await agent.run('What is 25 * 4?');Console Handler
Use the built-in console handler for debugging:
import { getCallbackManager, consoleCallbackHandler } from '@orka-js/core'; // Add built-in console handler for debuggingconst manager = getCallbackManager();manager.addHandler(consoleCallbackHandler); // Now all events will be logged to console:// [2024-01-15T10:30:00.000Z] [token_start] Starting generation...// hello world// [2024-01-15T10:30:01.000Z] [token_end] Completed in 1000ms (15 tokens)// [2024-01-15T10:30:01.100Z] [tool_start] Tool: search// [2024-01-15T10:30:01.500Z] [tool_end] Tool search completed in 400msGlobal vs Local Managers
You can use the global manager or create local instances:
import { CallbackManager, getCallbackManager, setCallbackManager, resetCallbackManager } from '@orka-js/core'; // Get the global singletonconst global = getCallbackManager(); // Replace global managerconst custom = new CallbackManager({ verbose: true });setCallbackManager(custom); // Reset to a fresh global managerresetCallbackManager(); // Create child manager (inherits parent handlers)const parent = getCallbackManager();parent.addHandler({ name: 'parent', handleEvent: () => {} }); const child = parent.createChild();child.addHandler({ name: 'child', handleEvent: () => {} }); // child has both 'parent' and 'child' handlers// parent only has 'parent' handlerBest Practices
- Use async mode (default) for non-blocking callbacks
- Filter events by type to reduce overhead
- Handle errors in callbacks to prevent silent failures
- Use child managers for isolated scopes