import type { CostEstimate, MessageJSON, ModelName, PromptResult, TokenUsage, ToolCallJSON, UserContentInput } from "smoltalk"; import type { LLMRetryReason } from "./llmRetry.js"; import { type Run } from "./asyncContext.js"; import type { RuntimeContext } from "./state/context.js"; import type { StateStack } from "./state/stateStack.js"; import type { CheckpointJSON, TraceEvent } from "./trace/types.js"; import type { RunNodeResult } from "./types.js"; export type CallbackMap = { onAgentStart: { nodeName: string; args: Record; messages: MessageJSON[]; cancel: (reason?: string) => void; }; onAgentEnd: { nodeName: string; result: RunNodeResult; }; onNodeStart: { nodeName: string; }; onNodeEnd: { nodeName: string; data: any; }; onLLMCallStart: { prompt: string | UserContentInput; tools: { name: string; description?: string; schema: any; }[]; model: ModelName | undefined; messages: MessageJSON[]; }; onLLMCallEnd: { model: string; result: PromptResult; usage: TokenUsage | undefined; cost: CostEstimate | undefined; timeTaken: number; messages: MessageJSON[]; }; onFunctionStart: { functionName: string; args: Record; moduleId: string; }; onFunctionEnd: { functionName: string; timeTaken: number; }; onToolCallStart: { toolName: string; args: Record; }; onToolCallEnd: { toolName: string; /** The call's named arguments, the same object `onToolCallStart` got. */ args: Record; result: any; timeTaken: number; }; onLLMRetry: { attempt: number; maxRetries: number; delayMs: number; reason: LLMRetryReason; detail: string; }; onLLMTimeout: { limitMs: number; attempt: number; }; onStream: { type: "text"; text: string; } | { type: "tool_call"; toolCall: ToolCallJSON; } | { type: "done"; result: PromptResult; } | { type: "error"; error: any; }; onTrace: TraceEvent; /** One statement checkpoint on the top-level stack, fired from `debugStep` * whenever a consumer is registered. `checkpoint` is plain JSON (function * refs encoded, as in a pause result); `{ type: "paused", checkpoint, * runId }` resumes through `resumeFromCheckpoint`. Never forwarded from * a subprocess. */ onCheckpoint: { runId: string; checkpoint: CheckpointJSON; }; onOAuthRequired: { serverName: string; authUrl: string; complete: Promise; cancel: () => void; }; onEmit: unknown; onThreadStart: { threadId: string; threadType: "thread" | "subthread"; parentThreadId?: string; label?: string; isResumption?: boolean; }; onThreadEnd: { threadId: string; label?: string; eagerSummarize: boolean; messages: MessageJSON[]; }; }; /** All callbacks (scoped + top-level + TS-passed) return `void`. Callback * bodies cannot raise interrupts — that is enforced statically by the * typechecker (see `checkCallbackBodyInterrupts`). A callback that * throws a JS error is caught and logged by `fireWithGuard`. */ export type CallbackReturn = void; export type AgencyCallbacks = { [K in keyof CallbackMap]?: (data: CallbackMap[K]) => void | Promise; }; /** One callbacks object that calls `first`'s hook and then `second`'s for * every event either has a hook for. An attached debugger uses it to add * its own hooks to a caller's on a resume, which takes one object and * would otherwise replace the caller's. */ export declare function composeCallbacks(first: AgencyCallbacks | undefined, second: AgencyCallbacks | undefined): AgencyCallbacks; /** True while a callback body is executing on this async path. The runner * defers an external pause here, because a checkpoint taken inside a * callback dispatch is not a place a resume can re-enter. */ export declare function isInsideCallback(run: Run): boolean; export declare function registerGlobalHook(name: K, fn: (data: CallbackMap[K]) => void | Promise): void; /** Gather every callback registered for `name`, in fire order. `stack` is * the stack to walk for scoped callbacks — pass `ctx.stateStack` from * top-level call sites, or a branch's own stack from inside a fork branch * (otherwise scoped callbacks registered inside the branch's frame chain * are missed). */ export declare function gatherCallbacks(ctx: RuntimeContext, name: K, stack: StateStack): any[]; /** Whether any consumer is registered for `name` across all sources a fire * would reach: global hooks, scoped callbacks on `stack`, top-level * registrations, and a TS-passed callback. Mirrors what `invokeCallbacks` * actually fires, so callers can branch on "is anyone listening?" without * reaching into `ctx.callbacks` directly (which only sees the TS-passed * slot — the bug that made streaming ignore `callback("onStream")`). */ export declare function hasCallbackConsumer(ctx: RuntimeContext, name: K, stateStack?: StateStack): boolean; /** Fire every callback registered for `name`, sequentially. When * `stateStack` is supplied, callbacks run on that stack (so scoped * callbacks registered inside a branch's frame chain are found). When * `stateStack` is omitted, behaviour is identical to today's `callHook`: * scoped callbacks are walked from `ctx.stateStack` and the callback * frame pushes onto `ctx.stateStack`. * * Used directly by sites that fire inside a fork/tool branch (e.g. the * per-tool `onToolCallStart` / `onToolCallEnd` in `prompt.ts`). The * public `callHook` is now a thin wrapper that omits `stateStack`. * * The caller passes the run the callbacks fire under. `fireWithGuard` * keeps its recursion guard on that run. */ export declare function invokeCallbacks(run: Run, args: { name: K; data: CallbackMap[K]; stateStack?: StateStack; }): Promise; /** Today's call sites that fire on the top-level stack. Thin wrapper over * `invokeCallbacks` with no `stateStack` override. */ export declare function callHook(run: Run, args: { name: K; data: CallbackMap[K]; }): Promise;