/** * Surface 10 (V0.4) — `createTokenBudgetCallbacks(budget, onExceed)`. * * Production-pattern from the LangGraph TypeScript Production Guide * (langgraphjs.guide/production): a token budget enforced per-invocation * across ALL LLM calls inside a graph, throwing when the budget is * exceeded. Mirrors the canonical example with two differences: * * 1. Returned as a `BaseCallbackHandler` subclass so it composes with * {@link DarwinCallbackHandler} via the standard `{ callbacks: [...] }` * option — no model-side patching required, works against any * LangChain provider that emits `handleLLMEnd`. * 2. Throws a typed {@link DarwinTokenBudgetExceededError} so consumers * can `instanceof`-check without parsing message text. * * The handler tracks BOTH the LangChain-canonical `output.llmOutput.tokenUsage` * shape (used by `ChatOpenAI`, `ChatAnthropic`, etc.) AND the per-message * usage shape (`generations[0][0].message.usage_metadata`) some providers * emit. The total is monotonically non-decreasing across `handleLLMEnd` * events; once the budget is crossed the throw happens INSIDE * `handleLLMEnd`, which LangChain surfaces back to the caller of * `graph.invoke` / `graph.stream`. * * IMPORTANT: the throw is the only reliable abort signal — LangGraph's * node-level retry policy may still re-fire the budget-exceeded path. * The `onExceed` callback fires once per handler instance regardless of * how many times the throw is observed (use it for logging / alerting, * not retry). * * NEW V0.4 (S1235). */ import { BaseCallbackHandler } from "@langchain/core/callbacks/base"; import type { LLMResult } from "@langchain/core/outputs"; /** * Options accepted by {@link createTokenBudgetCallbacks}. */ export interface TokenBudgetOptions { /** * Per-handler-instance token ceiling. Counts the SUM of input + output * tokens across every `handleLLMEnd` event. Must be a finite positive * integer; invalid values throw `DarwinTokenBudgetExceededError` * eagerly on construction so misconfigured deployments fail loud. */ budget: number; /** * Fire-and-forget side-effect when the budget is exceeded. Receives the * cumulative total at the moment of breach, the configured budget, and * an optional `providerHint` extracted from the LLMResult (e.g. the * model name when emitted). Errors thrown inside this callback are * swallowed with a single warn so they cannot mask the budget throw. * * Use this for logging / metrics / alerting — not for retry. */ onExceed?: (info: TokenBudgetExceedInfo) => void; /** * Fire on every `handleLLMEnd` event with the running total. Useful for * dashboards or step-by-step budget consumption traces. Optional. */ onTick?: (info: TokenBudgetTickInfo) => void; } export interface TokenBudgetExceedInfo { budget: number; totalTokens: number; providerHint: string | undefined; } export interface TokenBudgetTickInfo { budget: number; totalTokens: number; deltaTokens: number; remainingTokens: number; providerHint: string | undefined; } /** * LangChain `BaseCallbackHandler` that enforces a hard token budget * across all LLM calls observed during its lifetime. * * Construct once per `graph.invoke` call (do NOT reuse across requests — * the running total is per-handler-instance). The * {@link createTokenBudgetCallbacks} factory makes the per-invocation * shape ergonomic. */ export declare class TokenBudgetCallbackHandler extends BaseCallbackHandler { readonly name = "DarwinTokenBudgetHandler"; /** * V0.4 R1 P2-3 fix (S1235): `awaitHandlers = true` is required so * LangChain's callback manager AWAITS this handler before continuing * — the synchronous `throw` from `handleLLMEnd` MUST reach the * `graph.invoke` caller. With `awaitHandlers = false` the throw may * surface as an unhandled rejection in some LangChain versions * rather than aborting the graph, which is the entire point of a * token budget. */ readonly awaitHandlers = true; private readonly budget; private readonly onExceed; private readonly onTick; private totalTokens; private exceedWarned; private exceedFired; private tickErrorWarned; constructor(opts: TokenBudgetOptions); handleLLMEnd(output: LLMResult): void; private warnTick; /** Helper for tests + debug introspection. */ getTotalTokens(): number; } /** * Factory that returns a single-element `BaseCallbackHandler[]` ready to * be passed via the standard LangGraph `{ callbacks: [...] }` option. * Returning an array is the ergonomic shape — most consumers spread it * into a larger callbacks array next to {@link DarwinCallbackHandler}. * * @example * ```ts * import { * DarwinCallbackHandler, * createTokenBudgetCallbacks, * DarwinTokenBudgetExceededError, * } from "darwin-langgraph"; * * try { * const result = await graph.invoke({ task: "..." }, { * callbacks: [ * new DarwinCallbackHandler({ nodeMap, onTrajectory }), * ...createTokenBudgetCallbacks({ * budget: 20_000, * onExceed: ({ totalTokens, providerHint }) => { * console.error(`Budget breach: ${totalTokens} tok (${providerHint})`); * }, * }), * ], * }); * } catch (err) { * if (err instanceof DarwinTokenBudgetExceededError) { * // ... graceful degradation, fallback model, etc. * } * } * ``` */ export declare function createTokenBudgetCallbacks(opts: TokenBudgetOptions): [TokenBudgetCallbackHandler]; //# sourceMappingURL=token-budget.d.ts.map