/** * Event bridge: maps pi-agent-core events to normalized consumer events. * * Pi-agent-core emits 10 events across 4 scopes (agent, turn, message, tool). * The event bridge normalizes these into a consumer-facing event stream for * logging, monitoring, and lifecycle hooks. * * Key mappings: * agent_start -> loop_start * agent_end -> loop_end (onLoopComplete fires here) * turn_start -> turn_start * turn_end -> turn_end + AgentTextOutput (parse working tags) * message_start -> response_start * message_update -> response_chunk * message_end -> response_end * tool_execution_start -> tool_call_start * tool_execution_update -> tool_call_update * tool_execution_end -> tool_call_end * * Child event forwarding: * forwardFrom(childBridge, childTaskId) subscribes to a child agent's * event bridge and re-emits events on this bridge with childTaskId set. * Consumers use event.childTaskId to distinguish parent vs child events. * * Reference: cortex-architecture.md (Event Bridge section) */ import type { AgentTextOutput, CortexLogger, CortexUsage, ToolCallStartPayload, ToolCallUpdatePayload, ToolCallEndPayload } from './types.js'; export type CortexEventType = 'loop_start' | 'loop_end' | 'turn_start' | 'turn_end' | 'response_start' | 'response_chunk' | 'response_end' | 'tool_call_start' | 'tool_call_update' | 'tool_call_end'; /** * Normalized event data emitted by the event bridge. */ export interface CortexEvent { type: CortexEventType; /** The original pi-agent-core event data (opaque to the bridge). */ data?: unknown; /** Parsed text output, present only for turn_end events. */ textOutput?: AgentTextOutput; /** * Typed payload for tool events (tool_call_start, tool_call_update, tool_call_end). * Provides typed access to tool event data without casting `data`. */ payload?: ToolCallStartPayload | ToolCallUpdatePayload | ToolCallEndPayload; /** * Extracted usage data from the LLM response, present on turn_end events. * Centralizes extraction from pi-ai's AssistantMessage.usage structure so * subscribers (BudgetGuard, CortexAgent, consumers) read typed data instead * of parsing the opaque `data` field themselves. */ usage?: CortexUsage; /** * Present when this event originates from a child (sub-agent) event bridge. * The value is the sub-agent's task ID, allowing consumers to route events * to the correct UI component. Absent for parent agent events. */ childTaskId?: string; } /** * Callback type for event listeners. */ export type CortexEventListener = (event: CortexEvent) => void; export type PiEventType = 'agent_start' | 'agent_end' | 'turn_start' | 'turn_end' | 'message_start' | 'message_update' | 'message_end' | 'tool_execution_start' | 'tool_execution_update' | 'tool_execution_end'; export interface PiEvent { type: PiEventType; [key: string]: unknown; } /** * Minimal interface for pi-agent-core's Agent.subscribe(). * Returns an unsubscribe function. */ export interface PiEventSource { subscribe(handler: (event: PiEvent) => void): () => void; } export declare class EventBridge { private readonly listeners; private readonly allListeners; private unsubscribeFromPi; private workingTagsEnabled; private readonly logger; /** * Create an EventBridge. * * @param workingTagsEnabled - Whether to parse working tags on turn_end * @param logger - Optional logger for diagnostics (defaults to silent no-op) */ constructor(workingTagsEnabled?: boolean, logger?: CortexLogger); /** * Wire the bridge to a pi-agent-core Agent's event stream. * Stores the unsubscribe function for cleanup. * * @param source - The pi-agent-core Agent (or any PiEventSource) */ wire(source: PiEventSource): void; /** * Disconnect from the pi-agent-core event stream. */ unwire(): void; /** * Register a listener for a specific event type. * * @param type - The event type to listen for * @param listener - The callback function * @returns An unsubscribe function */ on(type: CortexEventType, listener: CortexEventListener): () => void; /** * Register a listener for all event types. * * @param listener - The callback function * @returns An unsubscribe function */ onAll(listener: CortexEventListener): () => void; /** * Forward all events from a child agent's event bridge onto this bridge. * * Each forwarded event gets `childTaskId` set so consumers can distinguish * parent events from child events. Returns an unsubscribe function that * stops forwarding (call when the child agent completes or is destroyed). * * @param childBridge - The child agent's EventBridge * @param childTaskId - The sub-agent task ID to tag forwarded events with * @returns An unsubscribe function */ forwardFrom(childBridge: EventBridge, childTaskId: string): () => void; /** * Update whether working tags parsing is enabled. */ setWorkingTagsEnabled(enabled: boolean): void; /** * Clean up all listeners and disconnect from the pi-agent-core event stream. */ destroy(): void; /** * Handle a pi-agent-core event by mapping and emitting to consumers. */ private handlePiEvent; /** * Extract a typed payload from a pi-agent-core tool event. * Returns undefined for non-tool events. */ private extractToolPayload; /** * Extract the text content from a turn_end event. * Pi-agent-core's turn_end event carries the assistant message for that turn. */ private extractTurnText; /** * Extract typed CortexUsage from a turn_end event. * * Pi-ai's AssistantMessage carries usage at message.usage with a nested * cost object. This method navigates the opaque event data once so all * subscribers receive clean, typed usage without duplicating extraction. */ private extractUsage; /** * Build a CortexUsage from a raw usage-shaped object. * Returns null if the object is not a valid usage structure. */ private buildUsageFromObject; /** * Emit a normalized event to all matching listeners. * Each listener is wrapped in try/catch so a throwing listener * does not prevent subsequent listeners from receiving the event. */ private emit; } //# sourceMappingURL=event-bridge.d.ts.map