@ai-sdk/harness-deepagents 1.0.133 → 1.0.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/bridge/index.mjs +1343 -2393
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +131 -129
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +758 -932
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/bridge/index.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/index.ts","../../../harness/src/bridge/index.ts","../../../harness/src/bridge/harness-bridge-capability-unsupported-error.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/chat_models/universal.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/errors.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/model.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/responses.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/types.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware.ts","../../../../node_modules/.pnpm/@langchain+langgraph-checkpoint@1.1.5_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@_ff898d037cda6bb5f88aa9c9d1caaf93/node_modules/@langchain/langgraph-checkpoint/src/serde/types.ts","../../../../node_modules/.pnpm/@langchain+langgraph-checkpoint@1.1.5_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@_ff898d037cda6bb5f88aa9c9d1caaf93/node_modules/@langchain/langgraph-checkpoint/src/base.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/hitl.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/constants.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/summarization.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/llmToolSelector.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/pii.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/piiRedaction.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/toolCallLimit.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/todoListMiddleware.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/modelCallLimit.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/modelRetry.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/toolRetry.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/provider/anthropic/promptCaching.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/src/agents/middleware/provider/aws/promptCaching.ts","../../../../node_modules/.pnpm/langchain@1.5.11_@langchain+core@1.2.11_@opentelemetry+api@1.9.1_@opentelemetry+exporte_f5289af23b1dceae16b2f90e7460a344/node_modules/langchain/dist/index.js","../../src/bridge/approvals.ts","../../src/bridge/create-emit-stream-event.ts","../../src/bridge/json-schema-to-zod.ts","../../src/bridge/local-shell-backend.ts","../../src/bridge/persistent-memory-saver.ts","../../src/bridge/tool-filtering.ts"],"sourcesContent":["// In-sandbox turn driver on `@ai-sdk/harness/bridge`; third-party imports stay external (tsup) and install in-sandbox from src/bridge/package.json — keep import/externals/deps in sync.\n\nimport { randomUUID } from 'node:crypto';\nimport { argv, env as procEnv } from 'node:process';\nimport {\n runBridge,\n type BridgeEvent,\n type BridgeTurn,\n} from '@ai-sdk/harness/bridge';\nimport { ChatAnthropic } from '@langchain/anthropic';\nimport { tool } from '@langchain/core/tools';\nimport { Command, MemorySaver, Overwrite } from '@langchain/langgraph';\nimport {\n MultiServerMCPClient,\n type ClientConfig,\n} from '@langchain/mcp-adapters';\nimport { createDeepAgent } from 'deepagents';\nimport { createMiddleware, toolStrategy } from 'langchain';\nimport type { StartMessage } from '../deepagents-bridge-protocol';\nimport { buildInterruptOn, collectActionRequests } from './approvals';\nimport {\n createDeepAgentsStreamEventState,\n createEmitStreamEvent,\n endReasoningBlock,\n endTextBlock,\n flushStep,\n toCommonName,\n type DeepAgentsStreamEvent,\n} from './create-emit-stream-event';\nimport { jsonSchemaToZodObject } from './json-schema-to-zod';\nimport { createLocalShellBackend } from './local-shell-backend';\nimport {\n loadMemorySaver,\n removeMemorySaverSnapshot,\n saveMemorySaver,\n} from './persistent-memory-saver';\nimport { createBuiltinToolFilteringMiddleware } from './tool-filtering';\n\nconst HARNESS_CLIENT_APP = procEnv.AI_SDK_HARNESS_CLIENT_APP;\n\nfunction parseArgs(rawArgs: string[]): Record<string, string> {\n const out: Record<string, string> = {};\n for (let i = 0; i < rawArgs.length; i++) {\n const arg = rawArgs[i];\n if (arg.startsWith('--')) {\n const key = arg\n .slice(2)\n .replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n out[key] = rawArgs[i + 1];\n i++;\n }\n }\n return out;\n}\n\n// Always drive the Anthropic client. Through the gateway, models keep their\n// `creator/model` slug (gateway translates); direct Anthropic wants the bare id.\nfunction buildModel({\n rawModel,\n thinking,\n effort,\n headers,\n}: {\n rawModel: string | undefined;\n thinking: StartMessage['thinking'];\n effort: StartMessage['effort'];\n headers: StartMessage['headers'];\n}) {\n if (!rawModel) return undefined;\n const baseUrl = procEnv.ANTHROPIC_BASE_URL;\n const model = baseUrl ? rawModel : rawModel.replace(/^anthropic[/:]/, '');\n return new ChatAnthropic({\n model,\n ...(thinking ? { thinking } : {}),\n ...(effort ? { outputConfig: { effort } } : {}),\n ...(procEnv.ANTHROPIC_API_KEY ? { apiKey: procEnv.ANTHROPIC_API_KEY } : {}),\n ...(baseUrl ? { anthropicApiUrl: baseUrl } : {}),\n ...(headers != null || procEnv.AI_GATEWAY_API_KEY\n ? {\n clientOptions: {\n defaultHeaders: {\n ...headers,\n ...(procEnv.AI_GATEWAY_API_KEY && HARNESS_CLIENT_APP\n ? {\n 'User-Agent': HARNESS_CLIENT_APP,\n 'x-client-app': HARNESS_CLIENT_APP,\n }\n : {}),\n },\n },\n }\n : {}),\n });\n}\n\nfunction createModelMiddleware() {\n return createMiddleware({\n name: 'harnessModel',\n wrapModelCall: async (request, handler) => {\n if (!activeModel && !activeThinking && !activeEffort && !activeHeaders) {\n return handler(request);\n }\n\n if (activeModel) {\n const configuredModel = buildModel({\n rawModel: activeModel,\n thinking: activeThinking,\n effort: activeEffort,\n headers: activeHeaders,\n });\n if (!configuredModel) throw new Error('Deep Agents model is missing');\n return handler({ ...request, model: configuredModel });\n }\n\n let model = request.model;\n if (\n '_getModelInstance' in model &&\n typeof model._getModelInstance === 'function'\n ) {\n model = await model._getModelInstance();\n }\n\n if (!(model instanceof ChatAnthropic)) {\n throw new Error('Deep Agents reasoning requires ChatAnthropic');\n }\n\n const configuredModel = buildModel({\n rawModel: model.model,\n thinking: activeThinking,\n effort: activeEffort,\n headers: activeHeaders,\n });\n if (!configuredModel) throw new Error('Deep Agents model is missing');\n\n return handler({ ...request, model: configuredModel });\n },\n });\n}\n\nconst args = parseArgs(argv.slice(2));\nconst workdir = args.workdir;\nconst bridgeStateDir = args.bridgeStateDir;\nif (!workdir || !bridgeStateDir) {\n // eslint-disable-next-line no-console\n console.error('deepagents bridge: missing --workdir / --bridge-state-dir');\n process.exit(1);\n}\nconst conversationCheckpointPath = `${bridgeStateDir}/conversation.checkpoint`;\n\n// One agent per bridge process, reused across turns; host tools read the live turn via `currentTurn`.\nlet agent: ReturnType<typeof createDeepAgent> | undefined;\nlet currentTurn: BridgeTurn | undefined;\nlet mcpClient: MultiServerMCPClient | undefined;\nlet mcpToolNames = new Set<string>();\nlet currentResponseFormat: ReturnType<typeof toolStrategy> | undefined;\nconst checkpointer = new MemorySaver();\nif (args.resume === 'true') {\n await loadMemorySaver({\n path: conversationCheckpointPath,\n saver: checkpointer,\n });\n} else {\n await removeMemorySaverSnapshot(conversationCheckpointPath);\n}\nlet agentConfigurationSignature: string | undefined;\nlet activeModel: string | undefined;\nlet activeThinking: StartMessage['thinking'];\nlet activeEffort: StartMessage['effort'];\nlet activeHeaders: StartMessage['headers'];\nconst modelMiddleware = createModelMiddleware();\n\ntype DeepAgentsJsonSchema = Record<string, unknown> & {\n type:\n | 'null'\n | 'boolean'\n | 'object'\n | 'array'\n | 'number'\n | 'string'\n | 'integer';\n};\n\nconst responseFormatMiddleware = createMiddleware({\n name: 'HarnessResponseFormat',\n wrapModelCall(request, handler) {\n return handler({\n ...request,\n ...(currentResponseFormat == null\n ? {}\n : { responseFormat: currentResponseFormat }),\n });\n },\n});\n\n// Host tools become LangChain tools that emit a `tool-call` and block on the host's `tool-result`.\nfunction buildHostTools(toolSchemas: StartMessage['tools']) {\n return (toolSchemas ?? []).map(schema =>\n tool(\n async (input: Record<string, unknown>) => {\n const turn = currentTurn;\n if (!turn) throw new Error('no active turn');\n const toolCallId = `${schema.name}-${randomUUID()}`;\n turn.emit({\n type: 'tool-call',\n toolCallId,\n toolName: schema.name,\n input: JSON.stringify(input),\n providerExecuted: false,\n } as BridgeEvent);\n const { output, isError } = await turn.requestToolResult(toolCallId);\n turn.emit({\n type: 'tool-result',\n toolCallId,\n toolName: schema.name,\n result: output ?? null,\n ...(isError !== undefined ? { isError } : {}),\n });\n return typeof output === 'string' ? output : JSON.stringify(output);\n },\n {\n name: schema.name,\n description: schema.description ?? '',\n schema: jsonSchemaToZodObject(schema.inputSchema),\n },\n ),\n );\n}\n\nasync function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {\n currentTurn = turn;\n if (start.model) activeModel = start.model;\n activeThinking = start.thinking;\n activeEffort = start.effort;\n activeHeaders = start.headers;\n currentResponseFormat =\n start.responseFormat?.type === 'json' && start.responseFormat.schema != null\n ? toolStrategy(start.responseFormat.schema as DeepAgentsJsonSchema)\n : undefined;\n const emit = (event: Record<string, unknown>) =>\n turn.emit(event as BridgeEvent);\n\n const interruptOn = buildInterruptOn(\n start.permissionMode,\n start.builtinToolFiltering,\n );\n const config = {\n version: 'v2' as const,\n configurable: { thread_id: 'bridge-session' },\n ...(start.recursionLimit != null\n ? { recursionLimit: start.recursionLimit }\n : {}),\n signal: turn.abortSignal,\n };\n const nextAgentConfigurationSignature = JSON.stringify({\n instructions: start.instructions,\n tools: start.tools,\n skillsPaths: start.skillsPaths,\n });\n const rebuildAgent =\n agent == null ||\n agentConfigurationSignature !== nextAgentConfigurationSignature ||\n start.skillsChanged === true;\n if (rebuildAgent) {\n if (agent != null && start.skillsChanged === true) {\n await agent.updateState(config, {\n skillsMetadata: new Overwrite([]),\n } as never);\n }\n await closeMcpClient();\n const builtinToolFilteringMiddleware = createBuiltinToolFilteringMiddleware(\n {\n builtinToolFiltering: start.builtinToolFiltering,\n emit: event => {\n const turn = currentTurn;\n if (!turn) throw new Error('no active turn');\n turn.emit(event as BridgeEvent);\n },\n },\n );\n const middleware = [\n responseFormatMiddleware,\n modelMiddleware,\n ...(builtinToolFilteringMiddleware\n ? [builtinToolFilteringMiddleware]\n : []),\n ];\n const hostTools = buildHostTools(start.tools);\n const hostToolNames = new Set(hostTools.map(hostTool => hostTool.name));\n const externalTools = await loadMcpTools({\n mcpServers: start.mcpServers,\n });\n const mcpTools = externalTools.filter(\n externalTool => !hostToolNames.has(externalTool.name),\n );\n mcpToolNames = new Set(mcpTools.map(mcpTool => mcpTool.name));\n agent = createDeepAgent({\n tools: [...mcpTools, ...hostTools],\n backend: createLocalShellBackend({ rootDir: workdir }),\n systemPrompt: start.instructions\n ? { suffix: start.instructions }\n : undefined,\n // Native skills loaded from the source dirs ($HOME-materialized + <workDir> for repo-provided skills).\n ...(start.skillsPaths?.length ? { skills: start.skillsPaths } : {}),\n ...(middleware.length > 0 ? { middleware } : {}),\n // Gate built-in tools behind HITL approval when the permission mode requires it.\n ...(interruptOn ? { interruptOn } : {}),\n // Real instance (LangGraph rejects `true` for root graphs); gives multi-turn memory.\n checkpointer,\n });\n agentConfigurationSignature = nextAgentConfigurationSignature;\n }\n const activeAgent = agent;\n if (activeAgent == null) {\n throw new Error('Deep Agents runtime was not initialized');\n }\n\n const hostToolNames = new Set((start.tools ?? []).map(t => t.name));\n const streamEventState = createDeepAgentsStreamEventState();\n const emitStreamEvent = createEmitStreamEvent({\n state: streamEventState,\n configuredModel: activeModel,\n hostToolNames,\n mcpToolNames,\n structuredOutputToolNames: new Set(\n currentResponseFormat?.map(format => format.name),\n ),\n emit,\n });\n\n // After a stream segment ends, return the tool calls paused by HITL interrupts (empty when the turn is truly done).\n const readPendingApprovals = async () => {\n try {\n const state = (await activeAgent.getState({\n configurable: { thread_id: 'bridge-session' },\n })) as { tasks?: Array<{ interrupts?: Array<{ value?: unknown }> }> };\n return collectActionRequests(\n (state.tasks ?? []).flatMap(t => t.interrupts ?? []),\n );\n } catch {\n return [];\n }\n };\n\n let resumeInput: unknown = {\n messages: [{ role: 'user', content: start.prompt }],\n };\n let emittedStructuredOutput = false;\n\n while (true) {\n const stream = await activeAgent.streamEvents(resumeInput as never, config);\n\n for await (const event of stream) {\n emitStreamEvent(event as DeepAgentsStreamEvent);\n const streamEvent = event as DeepAgentsStreamEvent;\n const namespace = streamEvent.metadata?.langgraph_checkpoint_ns ?? '';\n const output = (streamEvent.data as { output?: unknown } | undefined)\n ?.output as { structuredResponse?: unknown } | undefined;\n if (\n !emittedStructuredOutput &&\n streamEvent.event === 'on_chain_end' &&\n !namespace.includes('|') &&\n output?.structuredResponse !== undefined\n ) {\n const id = `structured-output-${randomUUID()}`;\n emit({ type: 'text-start', id });\n emit({\n type: 'text-delta',\n id,\n delta: JSON.stringify(output.structuredResponse),\n });\n emit({ type: 'text-end', id });\n emittedStructuredOutput = true;\n }\n }\n\n const actionRequests = await readPendingApprovals();\n if (actionRequests.length === 0) break;\n\n // HITL paused the run: announce each gated call, collect host decisions, then resume.\n const decisions: Array<\n { type: 'approve' } | { type: 'reject'; message?: string }\n > = [];\n for (const action of actionRequests) {\n const approvalId = `approval-${randomUUID()}`;\n endTextBlock({ state: streamEventState, emit });\n endReasoningBlock({ state: streamEventState, emit });\n emit({\n type: 'tool-call',\n toolCallId: approvalId,\n toolName: toCommonName(action.name),\n input: JSON.stringify(action.args ?? {}),\n providerExecuted: true,\n nativeName: action.name,\n });\n emit({\n type: 'tool-approval-request',\n approvalId,\n toolCallId: approvalId,\n });\n flushStep({ state: streamEventState, emit });\n const decision = await turn.requestToolApproval(approvalId);\n if (decision.approved) {\n const queue = streamEventState.approvedToolQueue.get(action.name) ?? [];\n queue.push(approvalId);\n streamEventState.approvedToolQueue.set(action.name, queue);\n decisions.push({ type: 'approve' });\n } else {\n // Rejected tools never execute, so surface the outcome as the result now.\n emit({\n type: 'tool-result',\n toolCallId: approvalId,\n toolName: toCommonName(action.name),\n result: decision.reason ?? 'Rejected by user.',\n });\n decisions.push({\n type: 'reject',\n ...(decision.reason ? { message: decision.reason } : {}),\n });\n }\n }\n\n resumeInput = new Command({ resume: { decisions } });\n }\n\n endTextBlock({ state: streamEventState, emit });\n endReasoningBlock({ state: streamEventState, emit });\n flushStep({ state: streamEventState, emit });\n emit({\n type: 'finish',\n finishReason: { unified: 'stop' },\n totalUsage: {\n inputTokens: { total: streamEventState.inputTokens },\n outputTokens: { total: streamEventState.outputTokens },\n },\n });\n}\n\nawait runBridge<StartMessage>({\n bridgeType: 'deepagents',\n bridgeStateDir: bridgeStateDir!,\n onStart: runTurn,\n onStop: async () => {\n await closeMcpClient();\n await saveMemorySaver({\n path: conversationCheckpointPath,\n saver: checkpointer,\n });\n return {};\n },\n onDestroy: async () => {\n await closeMcpClient();\n await removeMemorySaverSnapshot(conversationCheckpointPath);\n },\n});\n\nasync function loadMcpTools({\n mcpServers,\n}: {\n mcpServers: Record<string, unknown> | undefined;\n}) {\n if (mcpServers == null || Object.keys(mcpServers).length === 0) return [];\n for (const [name, value] of Object.entries(mcpServers)) {\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(\n `DeepAgents MCP server ${JSON.stringify(name)} must be configured with an object value.`,\n );\n }\n }\n mcpClient = new MultiServerMCPClient({\n mcpServers: mcpServers as ClientConfig['mcpServers'],\n prefixToolNameWithServerName: true,\n additionalToolNamePrefix: 'mcp',\n });\n return mcpClient.getTools();\n}\n\nasync function closeMcpClient(): Promise<void> {\n const client = mcpClient;\n mcpClient = undefined;\n mcpToolNames = new Set();\n await client?.close();\n}\n","// Shared in-sandbox bridge runtime. Adapter `bridge.mjs` bundles re-bundle\n// this module (tsup inlines it; `ws` stays external and resolves from the\n// sandbox-installed node_modules). It owns everything generic to the bridge\n// transport — the WebSocket server, token auth, the in-memory event log +\n// monotonic `seq`, resume replay, and the lifecycle/meta files. Any number of\n// hosts may be connected; exactly one of them owns the event stream, and\n// `start`/`resume` transfer that ownership. The adapter supplies only `onStart`\n// (drive its CLI/SDK and translate to wire events) and lifecycle cleanup hooks.\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport type { ToolResultPart } from '@ai-sdk/provider-utils';\nimport { WebSocketServer, type WebSocket } from 'ws';\n\nexport { HarnessBridgeCapabilityUnsupportedError } from './harness-bridge-capability-unsupported-error';\n\nexport type BridgeState = 'init' | 'waiting' | 'running' | 'draining' | 'done';\n\n/** Outbound turn event the adapter emits. `seq` is added by the runtime. */\nexport type BridgeEvent = Record<string, unknown> & { type: string };\n\nexport type BridgeDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface Experimental_BridgeUserMessage {\n readonly messageId: string;\n readonly text: string;\n accept(): void;\n reject(error: unknown): void;\n}\n\nexport interface Experimental_BridgeUserMessageQueue extends AsyncIterable<Experimental_BridgeUserMessage> {\n readonly pendingCount: number;\n close(error?: unknown): void;\n}\n\ntype InternalBridgeUserMessageQueue = Experimental_BridgeUserMessageQueue & {\n enqueue(input: { messageId: string; text: string }): void;\n};\n\ntype BridgeUserMessageResponse = {\n type: 'user-message-response';\n messageId: string;\n accepted: boolean;\n error?: { message: string };\n};\n\n/**\n * Per-session diagnostics config. The host resolves it from settings +\n * env and sends it on `start.debug`; the bridge gates console capture and\n * structured `debug-event`s on it. When disabled, nothing is captured or\n * emitted and no `seq` is consumed.\n */\nexport interface BridgeDebugConfig {\n enabled?: boolean;\n level?: BridgeDebugLevel;\n subsystems?: string[];\n}\n\nconst DEBUG_LEVEL_WEIGHT: Record<BridgeDebugLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\n/** Exact-or-dotted-prefix subsystem match (`'bridge'` matches `'bridge.turn'`). */\nfunction subsystemMatches(\n filters: string[] | undefined,\n subsystem: string,\n): boolean {\n if (!filters || filters.length === 0) return true;\n return filters.some(\n filter => subsystem === filter || subsystem.startsWith(`${filter}.`),\n );\n}\n\nfunction formatBridgeError(err: unknown): {\n name?: string;\n message: string;\n stack?: string;\n} {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n if (typeof err === 'string') {\n return { message: err };\n }\n if (err !== null && typeof err === 'object') {\n try {\n return { message: JSON.stringify(err) };\n } catch {}\n }\n return { message: String(err) };\n}\n\nfunction createBridgeUserMessageQueue(options: {\n respond(response: BridgeUserMessageResponse): void;\n}): InternalBridgeUserMessageQueue {\n const messages: Experimental_BridgeUserMessage[] = [];\n const waiters: Array<\n (result: IteratorResult<Experimental_BridgeUserMessage>) => void\n > = [];\n const entries = new Map<\n string,\n {\n response?: BridgeUserMessageResponse;\n reject(error: unknown): void;\n }\n >();\n let closed = false;\n let pendingCount = 0;\n\n const enqueue = (input: { messageId: string; text: string }): void => {\n const existing = entries.get(input.messageId);\n if (existing != null) {\n if (existing.response != null) {\n options.respond(existing.response);\n }\n return;\n }\n\n let settled = false;\n const settle = (response: BridgeUserMessageResponse): void => {\n if (settled) return;\n settled = true;\n pendingCount--;\n const entry = entries.get(input.messageId);\n if (entry != null) entry.response = response;\n options.respond(response);\n };\n const message: Experimental_BridgeUserMessage = {\n messageId: input.messageId,\n text: input.text,\n accept: () => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: true,\n });\n },\n reject: error => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: false,\n error: { message: formatBridgeError(error).message },\n });\n },\n };\n entries.set(input.messageId, {\n reject: message.reject,\n });\n pendingCount++;\n\n if (closed) {\n message.reject(\n new Error('The bridge turn is no longer accepting user messages.'),\n );\n return;\n }\n\n const waiter = waiters.shift();\n if (waiter != null) {\n waiter({ done: false, value: message });\n } else {\n messages.push(message);\n }\n };\n\n const close = (error?: unknown): void => {\n if (closed) return;\n closed = true;\n const reason =\n error ??\n new Error('The bridge turn ended before accepting the user message.');\n for (const entry of entries.values()) {\n if (entry.response == null) entry.reject(reason);\n }\n messages.length = 0;\n while (waiters.length > 0) {\n waiters.shift()!({ done: true, value: undefined });\n }\n };\n\n return {\n get pendingCount() {\n return pendingCount;\n },\n enqueue,\n close,\n [Symbol.asyncIterator]() {\n return {\n next: () => {\n const message = messages.shift();\n if (message != null) {\n return Promise.resolve({ done: false as const, value: message });\n }\n if (closed) {\n return Promise.resolve({\n done: true as const,\n value: undefined,\n });\n }\n return new Promise<IteratorResult<Experimental_BridgeUserMessage>>(\n resolve => {\n waiters.push(resolve);\n },\n );\n },\n };\n },\n };\n}\n\nfunction parseEnvList(value: string | undefined): string[] | undefined {\n if (!value) return undefined;\n const items = value\n .split(',')\n .map(item => item.trim())\n .filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\nconst ENV_TRUTHY = new Set(['1', 'true', 'yes', 'on']);\n\n/**\n * Per-turn surface handed to {@link RunBridgeOptions.onStart}. The adapter\n * drives its runtime against these primitives; the runtime owns the transport.\n */\nexport interface BridgeTurn {\n /**\n * Emit a turn event to the host. Stamps a monotonic `seq`, appends to the\n * in-memory replay log, and sends to the live socket (best-effort — if the\n * host is mid-reconnect the event waits in the log and is replayed on\n * resume).\n */\n emit(event: BridgeEvent): void;\n\n /**\n * Register interest in a host-executed tool result and resolve when the\n * matching `tool-result` arrives. The adapter emits the `tool-call` event\n * itself (via {@link emit}) using the same `toolCallId`.\n */\n requestToolResult(\n input:\n | string\n | {\n toolCallId: string;\n matches?: (result: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }) => boolean;\n },\n ): Promise<{\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }>;\n\n /**\n * Register interest in a host approval decision and resolve when the matching\n * `tool-approval-response` arrives. The adapter emits the\n * `tool-approval-request` event itself using the same `approvalId`.\n */\n requestToolApproval(\n approvalId: string,\n ): Promise<{ approved: boolean; reason?: string }>;\n\n readonly experimental_userMessages: Experimental_BridgeUserMessageQueue;\n\n /** Aborts when the host sends `abort`. */\n readonly abortSignal: AbortSignal;\n\n /** True for the first turn since this bridge process started. */\n readonly firstTurn: boolean;\n\n /**\n * Emit a structured diagnostic. Gated by the session's debug level +\n * subsystem filter; a no-op when diagnostics are disabled. Adapters use this\n * for runtime-level instrumentation; raw `console.*` output is captured and\n * forwarded automatically.\n */\n bridgeLog(input: {\n level?: BridgeDebugLevel;\n subsystem: string;\n message: string;\n attrs?: Record<string, unknown>;\n error?: unknown;\n }): void;\n\n /**\n * Emit a non-fatal bridge warning to stderr using the runtime's harness\n * prefix. This is diagnostic-only: it does not emit a stream event, does not\n * consume a `seq`, and does not fail the turn.\n */\n emitWarning(input: { message: string }): void;\n\n emitError(input: { error: unknown; message?: string }): void;\n}\n\nexport interface RunBridgeOptions<TStart extends { type: 'start' }> {\n /** Identifier written into `bridge-meta.json` (`'claude-code'` / `'codex'`). */\n bridgeType: string;\n /** Directory for `bridge-meta.json` / `start-config.json`. Created if absent. */\n bridgeStateDir: string;\n /**\n * Drive one prompt turn. Rejections surface to the host as an `error`\n * event.\n *\n * Contract: once `turn.abortSignal` fires, wind down promptly — turns are\n * serialized, and a replacement `start` waits up to\n * {@link turnTeardownGraceMs} for this promise to settle before it\n * proceeds anyway.\n */\n onStart(start: TStart, turn: BridgeTurn): Promise<void>;\n /**\n * How long a replacement `start` waits for the previous turn's teardown\n * after aborting it, in milliseconds. Turns are serialized so an aborted\n * turn cannot emit into its replacement's event log or overlap its runtime\n * process — but only within this bound: an adapter that does not settle\n * `onStart` after its abort signal fires forfeits the protection for that\n * boundary, and the new turn proceeds anyway rather than blocking forever.\n * The default of ten seconds exceeds the Claude bridge's five-second\n * hard-abort fallback.\n */\n turnTeardownGraceMs?: number;\n /**\n * Produce the adapter-defined runtime resume data for `stop`. Defaults to\n * `{}`.\n */\n onStop?(): unknown | Promise<unknown>;\n /**\n * Perform adapter-defined destruction before the bridge exits.\n */\n onDestroy?(): void | Promise<void>;\n /** WS port. Defaults to `BRIDGE_WS_PORT` env (0 = OS-assigned). */\n port?: number;\n /** Auth token. Defaults to `BRIDGE_CHANNEL_TOKEN` env. */\n token?: string;\n /** Called with the bound port once the server is listening. */\n onListening?(port: number): void;\n /**\n * Tear the process down after `stop` / `destroy`. Defaults to closing\n * the server and calling `process.exit(0)`. Overridable for tests.\n */\n onExit?(): void;\n}\n\ntype InboundControl =\n | {\n type: 'tool-result';\n toolCallId: string;\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }\n | {\n type: 'tool-approval-response';\n approvalId: string;\n approved: boolean;\n reason?: string;\n }\n | { type: 'user-message'; messageId?: string; text: string }\n | { type: 'abort' }\n | { type: 'stop' }\n | { type: 'destroy' }\n | { type: 'resume'; lastSeenEventId: number };\n\nconst WS_OPEN = 1;\n\n/**\n * Boot the bridge: bind the WebSocket server, announce `bridge-ready`, and\n * service host connections for the lifetime of the process. Resolves once the\n * server is listening; the process then stays alive on the server until a\n * `stop` / `destroy` exits it.\n */\nexport interface BridgeHandle {\n /** The port the WebSocket server bound to. */\n readonly port: number;\n /** Close the WebSocket server. Does not call `process.exit`. */\n close(): Promise<void>;\n}\n\nexport async function runBridge<TStart extends { type: 'start' }>(\n options: RunBridgeOptions<TStart>,\n): Promise<BridgeHandle> {\n const { bridgeType, bridgeStateDir, onStart, onStop, onDestroy } = options;\n const teardownGraceMs = options.turnTeardownGraceMs ?? 10_000;\n const expectedToken = options.token ?? procEnv.BRIDGE_CHANNEL_TOKEN ?? '';\n const bridgeWsPort =\n options.port ?? parseInt(procEnv.BRIDGE_WS_PORT ?? '0', 10);\n\n const bridgeMetaPath = `${bridgeStateDir}/bridge-meta.json`;\n const startConfigPath = `${bridgeStateDir}/start-config.json`;\n const rerunStartConfigPath = `${bridgeStateDir}/rerun-start-config.json`;\n const eventLogPath = `${bridgeStateDir}/event-log.ndjson`;\n\n try {\n await mkdir(bridgeStateDir, { recursive: true });\n } catch {\n // Best-effort; the bridge still runs without its state files.\n }\n\n // ─── mutable runtime state ──────────────────────────────────────────\n let currentBoundPort = 0;\n let currentTurnState: BridgeState = 'init';\n /*\n * The one connection turn events stream to. A socket claims it by asking for\n * work — `start` (a turn) or `resume` (a catch-up) — never by connecting:\n * every event goes here alone, so claiming on connect would silence a turn\n * already streaming to someone else. Any number of sockets may be connected;\n * the others still exchange control frames, they just get no events.\n */\n let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: InternalBridgeUserMessageQueue | undefined;\n /**\n * Settles when the in-flight turn has fully wound down — `onStart`\n * returned or threw AND its completion state was recorded. `undefined`\n * between turns. A new `start` fences on this so turns never overlap.\n */\n let activeTurn: Promise<void> | undefined;\n\n // Diagnostics. Resolved per turn from `start.debug` with a sandbox-side\n // env fallback; gates console capture + structured `debug-event`s.\n let debugConfig: BridgeDebugConfig | undefined;\n let consoleCaptureInstalled = false;\n const envDebugEnabled = ENV_TRUTHY.has(\n (procEnv.HARNESS_DEBUG ?? '').toLowerCase(),\n );\n\n // Replay log. `seq` is monotonic across the whole process — never reset —\n // because the host's `SandboxChannel` cursor (`lastSeenEventId`) lives across\n // turns. The log *contents* are cleared at the start of each turn to bound\n // memory; the just-finished turn stays replayable until the next `start`.\n let seqCounter = 0;\n let eventLog: Array<{ seq: number; line: string }> = [];\n\n /*\n * Disk mirror of the in-memory replay log. The in-memory log is lost when the\n * bridge process dies; the on-disk `event-log.ndjson` survives in the sandbox\n * filesystem so a respawned bridge (started with `BRIDGE_REPLAY_FROM_DISK=1`)\n * can reload the in-flight turn and serve a host's resume cursor —\n * `replay` recovery. Writes are batched on `setImmediate` (single-flight via\n * `flushPromise`) to keep `emit` off the disk hot path.\n */\n let diskBuffer = '';\n let flushPromise: Promise<void> | null = null;\n\n const flushEventsToDisk = async (): Promise<void> => {\n while (diskBuffer.length > 0) {\n const buf = diskBuffer;\n diskBuffer = '';\n await appendFile(eventLogPath, buf).catch(() => {\n // Best-effort crash-recovery mirror; the in-memory log is the source of\n // truth for the live connection.\n });\n }\n };\n\n const scheduleEventFlush = (): void => {\n if (flushPromise) return;\n flushPromise = new Promise<void>(resolve => {\n setImmediate(() => {\n void flushEventsToDisk().finally(resolve);\n });\n }).finally(() => {\n flushPromise = null;\n if (diskBuffer.length > 0) {\n scheduleEventFlush();\n }\n });\n };\n\n const flushPendingEventsToDisk = async (): Promise<void> => {\n if (diskBuffer.length > 0 && !flushPromise) {\n scheduleEventFlush();\n }\n // Await each in-flight flush, re-reading `flushPromise` after every await\n // since a fresh flush may have been scheduled for buffer that arrived while\n // we waited.\n let inFlight = flushPromise;\n while (inFlight) {\n await inFlight;\n inFlight = flushPromise;\n }\n };\n\n /*\n * When respawned for `replay`, reload the previous turn's log from disk before\n * accepting any connection so the very first `resume{lastSeenEventId}` can be\n * served the tail (including the terminal `finish`). The seq counter is\n * restored to the last persisted seq so it stays aligned with the host's\n * long-lived cursor. The file is NOT truncated in this mode — only a fresh\n * `start` (next turn) clears it.\n */\n const replayFromDisk = procEnv.BRIDGE_REPLAY_FROM_DISK === '1';\n if (replayFromDisk && existsSync(eventLogPath)) {\n try {\n const lines = readFileSync(eventLogPath, 'utf8')\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean);\n eventLog = lines.map(line => ({\n seq: (JSON.parse(line) as { seq: number }).seq,\n line,\n }));\n seqCounter = eventLog.at(-1)?.seq ?? 0;\n } catch {\n // Corrupt/partial log: fall back to an empty log; the host then degrades\n // to `rerun` instead of replaying a malformed tail.\n eventLog = [];\n seqCounter = 0;\n }\n }\n\n const pendingToolResults = new Map<\n string,\n {\n resolve: (output: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }) => void;\n matches?: (output: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }) => boolean;\n }\n >();\n const bufferedToolResults: Array<{\n toolCallId: string;\n result: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n };\n }> = [];\n const pendingToolApprovals = new Map<\n string,\n (response: { approved: boolean; reason?: string }) => void\n >();\n\n // ─── persistence (best-effort meta + start config) ──────────────────\n const writeBridgeMeta = async (state: BridgeState): Promise<void> => {\n try {\n await writeFile(\n bridgeMetaPath,\n JSON.stringify({\n type: bridgeType,\n port: currentBoundPort,\n state,\n pid,\n }),\n );\n } catch {\n // Best-effort resilience metadata; not load-bearing for the active turn.\n }\n };\n\n const writeStartConfig = async (start: unknown): Promise<void> => {\n try {\n const serialized = JSON.stringify(start);\n await writeFile(startConfigPath, serialized);\n // Frozen copy: written once, restored over start-config.json by future\n // rerun-mode recovery to re-run the original turn from scratch.\n if (!existsSync(rerunStartConfigPath)) {\n await writeFile(rerunStartConfigPath, serialized);\n }\n } catch {\n // Best-effort.\n }\n };\n\n // ─── wire send + replay ─────────────────────────────────────────────\n const emit = (event: BridgeEvent): void => {\n const seq = ++seqCounter;\n const line = JSON.stringify({ ...event, seq });\n eventLog.push({ seq, line });\n diskBuffer += `${line}\\n`;\n scheduleEventFlush();\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(line);\n } catch {\n // Send is best-effort: a dropped socket leaves the event in the log,\n // replayed once the host reconnects and sends `resume`.\n }\n }\n };\n\n const replay = (ws: WebSocket, afterSeq: number): void => {\n for (const entry of eventLog) {\n if (entry.seq > afterSeq && ws.readyState === WS_OPEN) {\n ws.send(entry.line);\n }\n }\n };\n\n // ─── diagnostics ──────────────────────────────────────────────\n const shouldEmitDebugEvent = (\n level: BridgeDebugLevel,\n subsystem: string,\n ): boolean => {\n if (!debugConfig?.enabled) return false;\n const threshold = debugConfig.level ?? 'debug';\n if (DEBUG_LEVEL_WEIGHT[level] > DEBUG_LEVEL_WEIGHT[threshold]) return false;\n return subsystemMatches(debugConfig.subsystems, subsystem);\n };\n\n /*\n * Forward sandbox console output. We line-buffer the original writers (kept so\n * output still reaches the real fds) and emit one `sandbox-log` per complete\n * line. `emit` never writes to stdout/stderr, so there is no recursion.\n * Installed lazily the first time a turn enables diagnostics; once installed,\n * capture is gated per-write on `debugConfig.enabled` so a later turn can\n * disable it. Console capture is independent of the subsystem/level filter.\n */\n const rawStdoutWrite = process.stdout.write.bind(process.stdout);\n const rawStderrWrite = process.stderr.write.bind(process.stderr);\n\n const writeErrorToStderr = (input: {\n message: string;\n error: unknown;\n }): void => {\n try {\n const formatted = formatBridgeError(input.error);\n rawStderrWrite(\n `[harness:${bridgeType}:error] ${input.message}: ${formatted.message}\\n`,\n );\n if (formatted.stack) {\n rawStderrWrite(`${formatted.stack}\\n`);\n }\n } catch {}\n };\n\n const emitWarning = (input: { message: string }): void => {\n try {\n for (const line of input.message.split('\\n')) {\n if (line.trim().length > 0) {\n rawStderrWrite(`[harness:${bridgeType}:warn] ${line}\\n`);\n }\n }\n } catch {}\n };\n\n const emitError = (input: { error: unknown; message?: string }): void => {\n writeErrorToStderr({\n message: input.message ?? 'bridge error',\n error: input.error,\n });\n emit({ type: 'error', error: serialiseError(input.error) });\n };\n\n const installConsoleCapture = (): void => {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n const buffers: { stdout: string; stderr: string } = {\n stdout: '',\n stderr: '',\n };\n const patch =\n (stream: 'stdout' | 'stderr', raw: typeof process.stdout.write) =>\n (chunk: unknown, encoding?: unknown, cb?: unknown): boolean => {\n if (debugConfig?.enabled) {\n try {\n const enc = typeof encoding === 'string' ? encoding : 'utf8';\n const text =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk as Uint8Array).toString(\n enc as BufferEncoding,\n );\n const combined = buffers[stream] + text.replace(/\\r\\n/g, '\\n');\n const parts = combined.split('\\n');\n buffers[stream] = parts.pop() ?? '';\n for (const line of parts) {\n const trimmed = line.replace(/\\s+$/, '');\n if (trimmed) {\n emit({\n type: 'sandbox-log',\n source: bridgeType,\n stream,\n line: trimmed,\n });\n }\n }\n } catch {\n // Never let capture break real output.\n }\n }\n return (raw as (c: unknown, e?: unknown, cb?: unknown) => boolean)(\n chunk,\n encoding,\n cb,\n );\n };\n process.stdout.write = patch(\n 'stdout',\n rawStdoutWrite,\n ) as typeof process.stdout.write;\n process.stderr.write = patch(\n 'stderr',\n rawStderrWrite,\n ) as typeof process.stderr.write;\n };\n\n // ─── inbound routing ────────────────────────────────────────────────\n const handleInbound = async (\n msg: TStart | InboundControl,\n ws: WebSocket,\n ): Promise<void> => {\n switch (msg.type) {\n case 'start': {\n /*\n * A new turn replaces the active one — but only after the active one\n * has fully wound down. Inbound frames are dispatched concurrently,\n * and the host settles a caller abort immediately, so a retry's\n * `start` can arrive while the aborted turn is still tearing down\n * (e.g. a graceful interrupt). Without this fence the old turn would\n * keep emitting into the new turn's cleared event log, two runtime\n * processes would run side by side, and the old turn's completion\n * would mark the bridge `waiting` underneath the new turn. Abort the\n * old turn to hasten its teardown; adapters are expected to bound\n * that teardown themselves (e.g. a hard-abort fallback), but the\n * runtime does not rely on it: the wait is capped by the teardown\n * grace period, after which the new turn proceeds anyway — the\n * pre-fence overlapping behavior — rather than hanging behind a\n * teardown that never settles.\n */\n for (;;) {\n const pendingTurn = activeTurn;\n if (pendingTurn == null) break;\n turnAbort?.abort();\n currentUserMessages?.close(\n new Error('A new bridge turn replaced the active turn.'),\n );\n let graceTimer: ReturnType<typeof setTimeout> | undefined;\n const settled = await Promise.race([\n pendingTurn.then(() => true as const),\n new Promise<false>(resolve => {\n graceTimer = setTimeout(() => resolve(false), teardownGraceMs);\n graceTimer.unref?.();\n }),\n ]);\n clearTimeout(graceTimer);\n if (!settled) break;\n }\n let turnFinished!: () => void;\n const thisTurn = new Promise<void>(resolve => (turnFinished = resolve));\n activeTurn = thisTurn;\n activeSocket = ws; // asking for a turn claims the event stream\n const firstTurn = isFirstTurn;\n isFirstTurn = false;\n eventLog = []; // clear previous turn; keep seqCounter monotonic\n // Mirror the in-memory clear to disk: the log tracks only the current\n // turn. Discard any unflushed tail from the prior turn first.\n diskBuffer = '';\n void writeFile(eventLogPath, '').catch(() => {});\n turnAbort = new AbortController();\n currentTurnState = 'running';\n void writeStartConfig(msg);\n void writeBridgeMeta('running');\n const startDebug = (msg as { debug?: BridgeDebugConfig }).debug;\n debugConfig = {\n enabled: startDebug?.enabled ?? envDebugEnabled,\n level:\n startDebug?.level ??\n (procEnv.HARNESS_DEBUG_LEVEL as BridgeDebugLevel | undefined),\n subsystems:\n startDebug?.subsystems ??\n parseEnvList(procEnv.HARNESS_DEBUG_SUBSYSTEMS),\n };\n if (debugConfig.enabled) {\n installConsoleCapture();\n }\n const userMessages = createBridgeUserMessageQueue({ respond: emit });\n const turn: BridgeTurn = {\n emit,\n requestToolResult: requestInput => {\n const request =\n typeof requestInput === 'string'\n ? { toolCallId: requestInput }\n : requestInput;\n const bufferedIndex = bufferedToolResults.findIndex(\n buffered =>\n buffered.toolCallId === request.toolCallId ||\n request.matches?.(buffered.result) === true,\n );\n if (bufferedIndex >= 0) {\n return Promise.resolve(\n bufferedToolResults.splice(bufferedIndex, 1)[0].result,\n );\n }\n return new Promise(resolve => {\n pendingToolResults.set(request.toolCallId, {\n resolve,\n matches: request.matches,\n });\n });\n },\n requestToolApproval: approvalId =>\n new Promise(resolve => {\n pendingToolApprovals.set(approvalId, resolve);\n }),\n experimental_userMessages: userMessages,\n abortSignal: turnAbort.signal,\n firstTurn,\n bridgeLog: input => {\n const level = input.level ?? 'debug';\n if (!shouldEmitDebugEvent(level, input.subsystem)) return;\n emit({\n type: 'debug-event',\n level,\n subsystem: input.subsystem,\n message: input.message,\n ...(input.attrs ? { attrs: input.attrs } : {}),\n ...(input.error !== undefined\n ? { error: formatBridgeError(input.error) }\n : {}),\n });\n },\n emitWarning,\n emitError,\n };\n currentUserMessages = userMessages;\n try {\n await onStart(msg as TStart, turn);\n } catch (err) {\n emitError({ error: err, message: 'bridge turn failed' });\n } finally {\n userMessages.close();\n if (currentUserMessages === userMessages) {\n currentUserMessages = undefined;\n }\n // Only the still-active turn records completion: after a fence\n // timeout a replacement turn is already running, and this stale\n // completion must not mark the bridge waiting underneath it.\n if (activeTurn === thisTurn) {\n activeTurn = undefined;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n }\n turnFinished();\n }\n return;\n }\n case 'tool-result': {\n const result = {\n output: msg.output,\n isError: msg.isError,\n toolResult: msg.toolResult,\n };\n const exactPending = pendingToolResults.get(msg.toolCallId);\n const matchingPending =\n exactPending == null\n ? Array.from(pendingToolResults.entries()).find(\n ([, pending]) => pending.matches?.(result) === true,\n )\n : undefined;\n const pending = exactPending ?? matchingPending?.[1];\n const pendingId =\n exactPending != null ? msg.toolCallId : matchingPending?.[0];\n if (pending != null && pendingId != null) {\n pendingToolResults.delete(pendingId);\n pending.resolve(result);\n } else {\n bufferedToolResults.push({\n toolCallId: msg.toolCallId,\n result,\n });\n }\n return;\n }\n case 'tool-approval-response': {\n const resolver = pendingToolApprovals.get(msg.approvalId);\n if (resolver) {\n pendingToolApprovals.delete(msg.approvalId);\n resolver({ approved: msg.approved, reason: msg.reason });\n }\n return;\n }\n case 'user-message': {\n const messageId = msg.messageId ?? randomUUID();\n if (currentUserMessages == null) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: { message: 'The bridge has no active turn to steer.' },\n });\n return;\n }\n if (ws !== activeSocket) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: {\n message: 'The connection does not own the active bridge turn.',\n },\n });\n return;\n }\n currentUserMessages.enqueue({\n messageId,\n text: msg.text,\n });\n return;\n }\n case 'abort':\n turnAbort?.abort();\n return;\n case 'resume':\n activeSocket = ws; // asking for a catch-up claims it too\n // Synchronous, so no event can slip out live ahead of the replayed tail.\n replay(ws, msg.lastSeenEventId);\n return;\n case 'destroy':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n await onDestroy?.();\n drainThenExit(ws, 1000, 'destroy');\n return;\n case 'stop': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onStop?.()) ?? {};\n sendControl(ws, { type: 'bridge-stop', data });\n drainThenExit(ws, 1000, 'stop');\n }\n }\n };\n\n // ─── server ─────────────────────────────────────────────────────────\n void writeBridgeMeta('init');\n\n const wss = new WebSocketServer({ port: bridgeWsPort, host: '0.0.0.0' });\n\n const exit = (): void => {\n if (options.onExit) {\n options.onExit();\n return;\n }\n wss.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 1000).unref();\n };\n\n const drainThenExit = (ws: WebSocket, code: number, reason: string): void => {\n const start = Date.now();\n const tick = (): void => {\n const drained = ws.bufferedAmount === 0 || ws.readyState !== WS_OPEN;\n if (drained || Date.now() - start >= 5_000) {\n // Flush the on-disk log so a clean stop/destroy leaves a complete\n // event-log.ndjson for any later replay recovery.\n void flushPendingEventsToDisk().finally(() => {\n try {\n ws.close(code, reason);\n } finally {\n exit();\n }\n });\n return;\n }\n setTimeout(tick, 10).unref();\n };\n tick();\n };\n\n wss.on('listening', () => {\n const addr = wss.address();\n currentBoundPort = typeof addr === 'object' && addr ? addr.port : 0;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n stdout.write(\n JSON.stringify({\n type: 'bridge-ready',\n port: currentBoundPort,\n }) + '\\n',\n );\n options.onListening?.(currentBoundPort);\n });\n\n wss.on('connection', (ws: WebSocket, req: { url?: string }) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n if (url.searchParams.get('agent_bridge_token') !== expectedToken) {\n ws.close(1008, 'unauthorized');\n return;\n }\n\n // Announce liveness the instant we accept. Some sandbox runtimes complete\n // the host-side WS handshake before the connection is forwarded here; the\n // host waits for this frame before sending `start`/`resume`.\n sendControl(ws, {\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\n capabilities: { experimental_userMessageResponses: true },\n });\n\n ws.on('message', (raw: ArrayBufferLike | string) => {\n let parsed: TStart | InboundControl;\n try {\n const text =\n typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf8');\n parsed = JSON.parse(text) as TStart | InboundControl;\n } catch (err) {\n sendControl(ws, {\n type: 'error',\n error: `protocol parse error: ${(err as Error).message}`,\n });\n return;\n }\n void handleInbound(parsed, ws);\n });\n\n ws.on('close', () => {\n // Only the stream owner's close matters; a socket that never claimed it,\n // or that a later `start`/`resume` displaced, closes as a no-op.\n // Crucially we do NOT abort the in-flight turn: it keeps running and its\n // events accumulate in the log for replay on reconnect.\n if (activeSocket === ws) {\n activeSocket = undefined;\n }\n });\n\n ws.on('error', () => {\n // 'close' follows; nothing to do beyond keeping the process alive.\n });\n });\n\n // Surface bridge-internal crashes to the host instead of dying silently.\n process.on('uncaughtException', err => {\n emitError({ error: err, message: 'uncaught exception' });\n });\n process.on('unhandledRejection', err => {\n emitError({ error: err, message: 'unhandled rejection' });\n });\n\n await new Promise<void>((resolve, reject) => {\n if (wss.address() != null) {\n resolve();\n return;\n }\n\n wss.once('listening', resolve);\n wss.once('error', reject);\n });\n\n return {\n port: currentBoundPort,\n close: () =>\n new Promise<void>(resolve => {\n wss.close(() => resolve());\n }),\n };\n}\n\n/*\n * Control frames answer the socket that sent the frame they reply to, so the\n * target is always explicit. Event streaming is the separate, stateful path\n * (`emit` → `activeSocket`); this one carries no state at all.\n */\nfunction sendControl(\n socket: WebSocket | undefined,\n message: Record<string, unknown>,\n): void {\n if (socket?.readyState === WS_OPEN) {\n try {\n socket.send(JSON.stringify(message));\n } catch {\n // best-effort\n }\n }\n}\n\nfunction serialiseError(err: unknown): unknown {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n return err;\n}\n","const name = 'AI_HarnessBridgeCapabilityUnsupportedError';\n\n/**\n * Signals an unsupported capability discovered inside a sandbox bridge.\n * `isInstance` also recognizes the serialized error shape received by the\n * host, where it can be translated to `HarnessCapabilityUnsupportedError`.\n */\nexport class HarnessBridgeCapabilityUnsupportedError extends Error {\n readonly harnessId?: string;\n readonly cause?: unknown;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super(message);\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n this.cause = cause;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessBridgeCapabilityUnsupportedError {\n return (\n error != null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === name &&\n 'message' in error &&\n typeof error.message === 'string'\n );\n }\n}\n","import {\n BaseLanguageModelInput,\n ToolDefinition,\n} from \"@langchain/core/language_models/base\";\nimport {\n BaseChatModel,\n BaseChatModelParams,\n BindToolsInput,\n type BaseChatModelCallOptions,\n} from \"@langchain/core/language_models/chat_models\";\nimport {\n BaseMessage,\n type AIMessageChunk,\n MessageStructure,\n} from \"@langchain/core/messages\";\nimport {\n type RunnableBatchOptions,\n RunnableBinding,\n type RunnableConfig,\n type RunnableToolLike,\n ensureConfig,\n} from \"@langchain/core/runnables\";\nimport {\n AsyncGeneratorWithSetup,\n IterableReadableStream,\n} from \"@langchain/core/utils/stream\";\nimport {\n type LogStreamCallbackHandlerInput,\n type RunLogPatch,\n type StreamEvent,\n} from \"@langchain/core/tracers/log_stream\";\nimport { type StructuredToolInterface } from \"@langchain/core/tools\";\nimport { CallbackManagerForLLMRun } from \"@langchain/core/callbacks/manager\";\nimport { ChatResult } from \"@langchain/core/outputs\";\nimport { ModelProfile } from \"@langchain/core/language_models/profile\";\nimport { ChatModelStream } from \"@langchain/core/language_models/stream\";\nimport {\n DEFAULT_LANGSMITH_GATEWAY,\n resolveLangSmithGatewayConfig,\n} from \"@langchain/core/utils/gateway\";\nimport { getEnvironmentVariable } from \"@langchain/core/utils/env\";\n\nfunction getLangSmithChatModelParams({\n apiKey,\n configuration = {},\n}: {\n apiKey?: unknown;\n configuration?: { apiKey?: unknown; baseURL?: string };\n}) {\n const gatewayConfig = resolveLangSmithGatewayConfig({\n baseURL: configuration.baseURL,\n providerPath: \"v1\",\n });\n\n return {\n apiKey:\n apiKey ??\n configuration.apiKey ??\n gatewayConfig.apiKey ??\n (getEnvironmentVariable(\"LANGSMITH_GATEWAY_API_KEY\") ||\n getEnvironmentVariable(\"LANGSMITH_API_KEY\")),\n configuration: {\n ...configuration,\n baseURL: gatewayConfig.baseURL ?? `${DEFAULT_LANGSMITH_GATEWAY}/v1`,\n },\n useResponsesApi: true,\n };\n}\n\n// TODO: remove once `EventStreamCallbackHandlerInput` is exposed in core\ninterface EventStreamCallbackHandlerInput extends Omit<\n LogStreamCallbackHandlerInput,\n \"_schemaFormat\"\n> {}\n\nexport interface ConfigurableChatModelCallOptions extends BaseChatModelCallOptions {\n tools?: (\n | StructuredToolInterface\n | Record<string, unknown>\n | ToolDefinition\n | RunnableToolLike\n )[];\n}\n\n// Configuration map for model providers\nexport const MODEL_PROVIDER_CONFIG = {\n openai: {\n package: \"@langchain/openai\",\n className: \"ChatOpenAI\",\n },\n anthropic: {\n package: \"@langchain/anthropic\",\n className: \"ChatAnthropic\",\n },\n azure_openai: {\n package: \"@langchain/openai\",\n className: \"AzureChatOpenAI\",\n },\n langsmith: {\n package: \"@langchain/openai\",\n className: \"ChatOpenAI\",\n },\n cohere: {\n package: \"@langchain/cohere\",\n className: \"ChatCohere\",\n },\n google: {\n package: \"@langchain/google\",\n className: \"ChatGoogle\",\n },\n \"google-vertexai\": {\n package: \"@langchain/google-vertexai\",\n className: \"ChatVertexAI\",\n },\n \"google-vertexai-web\": {\n package: \"@langchain/google-vertexai-web\",\n className: \"ChatVertexAI\",\n },\n \"google-genai\": {\n package: \"@langchain/google-genai\",\n className: \"ChatGoogleGenerativeAI\",\n },\n ollama: {\n package: \"@langchain/ollama\",\n className: \"ChatOllama\",\n },\n mistralai: {\n package: \"@langchain/mistralai\",\n className: \"ChatMistralAI\",\n },\n mistral: {\n package: \"@langchain/mistralai\",\n className: \"ChatMistralAI\",\n },\n groq: {\n package: \"@langchain/groq\",\n className: \"ChatGroq\",\n },\n bedrock: {\n package: \"@langchain/aws\",\n className: \"ChatBedrockConverse\",\n },\n aws: {\n package: \"@langchain/aws\",\n className: \"ChatBedrockConverse\",\n },\n deepseek: {\n package: \"@langchain/deepseek\",\n className: \"ChatDeepSeek\",\n },\n xai: {\n package: \"@langchain/xai\",\n className: \"ChatXAI\",\n },\n cerebras: {\n package: \"@langchain/cerebras\",\n className: \"ChatCerebras\",\n },\n fireworks: {\n package: \"@langchain/fireworks\",\n className: \"ChatFireworks\",\n },\n together: {\n package: \"@langchain/together-ai\",\n className: \"ChatTogetherAI\",\n hasCircularDependency: true,\n },\n perplexity: {\n package: \"@langchain/perplexity\",\n className: \"ChatPerplexity\",\n },\n} as const;\n\nconst SUPPORTED_PROVIDERS = Object.keys(\n MODEL_PROVIDER_CONFIG\n) as (keyof typeof MODEL_PROVIDER_CONFIG)[];\nexport type ChatModelProvider = keyof typeof MODEL_PROVIDER_CONFIG;\ntype ModelProviderConfig = {\n package: string;\n className: string;\n hasCircularDependency?: boolean;\n};\n\n/**\n * Helper function to get a chat model class by its class name or model provider.\n * @param className The class name (e.g., \"ChatOpenAI\", \"ChatAnthropic\")\n * @param modelProvider Optional model provider key for direct lookup (e.g., \"google-vertexai-web\").\n * When provided, uses direct lookup to avoid className collision issues.\n * @returns The imported model class or undefined if not found\n */\nexport async function getChatModelByClassName(\n className: string,\n modelProvider?: string\n) {\n let config: ModelProviderConfig | undefined;\n\n if (modelProvider) {\n // Direct lookup by modelProvider key - avoids className collision\n // (e.g., google-vertexai and google-vertexai-web both use \"ChatVertexAI\")\n config = MODEL_PROVIDER_CONFIG[\n modelProvider as keyof typeof MODEL_PROVIDER_CONFIG\n ] as ModelProviderConfig | undefined;\n } else {\n // Fallback to className lookup for backward compatibility\n const providerEntry = Object.entries(MODEL_PROVIDER_CONFIG).find(\n ([, c]) => c.className === className\n );\n config = providerEntry\n ? (providerEntry[1] as ModelProviderConfig)\n : undefined;\n }\n\n if (!config) {\n return undefined;\n }\n\n try {\n const module = await import(config.package);\n return module[config.className];\n } catch (e: unknown) {\n const err = e as Error;\n if (\n \"code\" in err &&\n err.code?.toString().includes(\"ERR_MODULE_NOT_FOUND\") &&\n \"message\" in err &&\n typeof err.message === \"string\"\n ) {\n const msg = err.message.startsWith(\"Error: \")\n ? err.message.slice(\"Error: \".length)\n : err.message;\n const attemptedPackage = msg\n .split(\"Cannot find package '\")[1]\n .split(\"'\")[0];\n throw new Error(\n `Unable to import ${attemptedPackage}. Please install with ` +\n `\\`npm install ${attemptedPackage}\\` or \\`pnpm install ${attemptedPackage}\\``\n );\n }\n throw e;\n }\n}\n\nasync function _initChatModelHelper(\n model: string,\n modelProvider?: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n params: Record<string, any> = {}\n): Promise<BaseChatModel> {\n const modelProviderCopy = modelProvider || _inferModelProvider(model);\n if (!modelProviderCopy) {\n throw new Error(\n `Unable to infer model provider for { model: ${model} }, please specify modelProvider directly.`\n );\n }\n\n const config = MODEL_PROVIDER_CONFIG[\n modelProviderCopy as keyof typeof MODEL_PROVIDER_CONFIG\n ] as ModelProviderConfig;\n if (!config) {\n const supported = SUPPORTED_PROVIDERS.join(\", \");\n throw new Error(\n `Unsupported { modelProvider: ${modelProviderCopy} }.\\n\\nSupported model providers are: ${supported}`\n );\n }\n\n const { modelProvider: _unused, ...passedParams } = params;\n // Pass modelProviderCopy to use direct lookup and avoid className collision\n const ProviderClass = await getChatModelByClassName(\n config.className,\n modelProviderCopy\n );\n return new ProviderClass({\n model,\n ...passedParams,\n ...(modelProviderCopy === \"langsmith\"\n ? getLangSmithChatModelParams(passedParams)\n : {}),\n });\n}\n\n/**\n * Attempts to infer the model provider based on the given model name.\n *\n * @param {string} modelName - The name of the model to infer the provider for.\n * @returns {string | undefined} The inferred model provider name, or undefined if unable to infer.\n *\n * @example\n * _inferModelProvider(\"gpt-4\"); // returns \"openai\"\n * _inferModelProvider(\"claude-2\"); // returns \"anthropic\"\n * _inferModelProvider(\"unknown-model\"); // returns undefined\n */\nexport function _inferModelProvider(modelName: string): string | undefined {\n if (\n modelName.startsWith(\"gpt-3\") ||\n modelName.startsWith(\"gpt-4\") ||\n modelName.startsWith(\"gpt-5\") ||\n modelName.startsWith(\"o1\") ||\n modelName.startsWith(\"o3\") ||\n modelName.startsWith(\"o4\")\n ) {\n return \"openai\";\n } else if (modelName.startsWith(\"claude\")) {\n return \"anthropic\";\n } else if (modelName.startsWith(\"command\")) {\n return \"cohere\";\n } else if (modelName.startsWith(\"accounts/fireworks\")) {\n return \"fireworks\";\n } else if (modelName.startsWith(\"gemini\")) {\n return \"google-vertexai\";\n } else if (modelName.startsWith(\"amazon.\")) {\n return \"bedrock\";\n } else if (modelName.startsWith(\"mistral\")) {\n return \"mistralai\";\n } else if (modelName.startsWith(\"sonar\") || modelName.startsWith(\"pplx\")) {\n return \"perplexity\";\n } else {\n return undefined;\n }\n}\n\ninterface ConfigurableModelFields extends BaseChatModelParams {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n defaultConfig?: Record<string, any>;\n /**\n * @default \"any\"\n */\n configurableFields?: string[] | \"any\";\n /**\n * @default \"\"\n */\n configPrefix?: string;\n /**\n * Methods which should be called after the model is initialized.\n * The key will be the method name, and the value will be the arguments.\n */\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n queuedMethodOperations?: Record<string, any>;\n /**\n * Overrides the profiling information for the model. If not provided,\n * the profile will be inferred from the inner model instance.\n */\n profile?: ModelProfile;\n}\n\n/**\n * Internal class used to create chat models.\n *\n * @internal\n */\nexport class ConfigurableModel<\n RunInput extends BaseLanguageModelInput = BaseLanguageModelInput,\n CallOptions extends ConfigurableChatModelCallOptions =\n ConfigurableChatModelCallOptions,\n> extends BaseChatModel<CallOptions, AIMessageChunk> {\n _llmType(): string {\n return \"chat_model\";\n }\n\n lc_namespace = [\"langchain\", \"chat_models\"];\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n _defaultConfig?: Record<string, any> = {};\n\n /**\n * @default \"any\"\n */\n _configurableFields: string[] | \"any\" = \"any\";\n\n /**\n * @default \"\"\n */\n _configPrefix: string;\n\n /**\n * Methods which should be called after the model is initialized.\n * The key will be the method name, and the value will be the arguments.\n */\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n _queuedMethodOperations: Record<string, any> = {};\n\n /** @internal */\n private _modelInstanceCache = new Map<\n string,\n BaseChatModel<BaseChatModelCallOptions, AIMessageChunk<MessageStructure>>\n >();\n\n /** @internal */\n private _profile?: ModelProfile;\n\n constructor(fields: ConfigurableModelFields) {\n super(fields);\n this._defaultConfig = fields.defaultConfig ?? {};\n\n if (fields.configurableFields === \"any\") {\n this._configurableFields = \"any\";\n } else {\n this._configurableFields = fields.configurableFields ?? [\n \"model\",\n \"modelProvider\",\n ];\n }\n\n if (fields.configPrefix) {\n this._configPrefix = fields.configPrefix.endsWith(\"_\")\n ? fields.configPrefix\n : `${fields.configPrefix}_`;\n } else {\n this._configPrefix = \"\";\n }\n\n this._queuedMethodOperations =\n fields.queuedMethodOperations ?? this._queuedMethodOperations;\n\n this._profile = fields.profile ?? undefined;\n\n this.metadata = {\n ...this.metadata,\n ls_integration: \"langchain_init_chat_model\",\n };\n }\n\n async _getModelInstance(\n config?: RunnableConfig\n ): Promise<\n BaseChatModel<BaseChatModelCallOptions, AIMessageChunk<MessageStructure>>\n > {\n // Check cache first\n const cacheKey = this._getCacheKey(config);\n const cachedModel = this._modelInstanceCache.get(cacheKey);\n if (cachedModel) {\n return cachedModel;\n }\n\n // Initialize model with merged params\n const params = { ...this._defaultConfig, ...this._modelParams(config) };\n let initializedModel = await _initChatModelHelper(\n params.model,\n params.modelProvider,\n params\n );\n\n // Apply queued method operations in sequence\n for (const [method, args] of Object.entries(this._queuedMethodOperations)) {\n if (\n method in initializedModel &&\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (initializedModel as any)[method] === \"function\"\n ) {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n initializedModel = await (initializedModel as any)[method](...args);\n }\n }\n\n // Cache and return the initialized model\n this._modelInstanceCache.set(cacheKey, initializedModel);\n return initializedModel;\n }\n\n async _generate(\n messages: BaseMessage[],\n options?: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const model = await this._getModelInstance(options);\n return model._generate(messages, options ?? {}, runManager);\n }\n\n override bindTools(\n tools: BindToolsInput[],\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n params?: Record<string, any>\n ): ConfigurableModel<RunInput, CallOptions> {\n const newQueuedOperations = { ...this._queuedMethodOperations };\n newQueuedOperations.bindTools = [tools, params];\n return new ConfigurableModel<RunInput, CallOptions>({\n defaultConfig: this._defaultConfig,\n configurableFields: this._configurableFields,\n configPrefix: this._configPrefix,\n queuedMethodOperations: newQueuedOperations,\n });\n }\n\n // Extract the input types from the `BaseModel` class.\n withStructuredOutput: BaseChatModel[\"withStructuredOutput\"] = (\n schema,\n ...args\n ): ReturnType<BaseChatModel[\"withStructuredOutput\"]> => {\n const newQueuedOperations = { ...this._queuedMethodOperations };\n newQueuedOperations.withStructuredOutput = [schema, ...args];\n return new ConfigurableModel<RunInput, CallOptions>({\n defaultConfig: this._defaultConfig,\n configurableFields: this._configurableFields,\n configPrefix: this._configPrefix,\n queuedMethodOperations: newQueuedOperations,\n }) as unknown as ReturnType<BaseChatModel[\"withStructuredOutput\"]>;\n };\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n _modelParams(config?: RunnableConfig): Record<string, any> {\n const configurable = config?.configurable ?? {};\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n let modelParams: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(configurable)) {\n if (key.startsWith(this._configPrefix)) {\n const strippedKey = this._removePrefix(key, this._configPrefix);\n modelParams[strippedKey] = value;\n }\n }\n\n if (this._configurableFields !== \"any\") {\n modelParams = Object.fromEntries(\n Object.entries(modelParams).filter(([key]) =>\n this._configurableFields.includes(key)\n )\n );\n }\n\n return modelParams;\n }\n\n _removePrefix(str: string, prefix: string): string {\n return str.startsWith(prefix) ? str.slice(prefix.length) : str;\n }\n\n /**\n * Bind config to a Runnable, returning a new Runnable.\n * @param {RunnableConfig | undefined} [config] - The config to bind.\n * @returns {RunnableBinding<RunInput, RunOutput, CallOptions>} A new RunnableBinding with the bound config.\n */\n withConfig(\n config?: RunnableConfig\n ): RunnableBinding<RunInput, AIMessageChunk, CallOptions> {\n const mergedConfig: RunnableConfig = { ...(config || {}) };\n const modelParams = this._modelParams(mergedConfig);\n\n const remainingConfig: RunnableConfig = Object.fromEntries(\n Object.entries(mergedConfig).filter(([k]) => k !== \"configurable\")\n );\n\n remainingConfig.configurable = Object.fromEntries(\n Object.entries(mergedConfig.configurable || {}).filter(\n ([k]) =>\n this._configPrefix &&\n !Object.keys(modelParams).includes(\n this._removePrefix(k, this._configPrefix)\n )\n )\n );\n\n const newConfigurableModel = new ConfigurableModel<RunInput, CallOptions>({\n defaultConfig: { ...this._defaultConfig, ...modelParams },\n configurableFields: Array.isArray(this._configurableFields)\n ? [...this._configurableFields]\n : this._configurableFields,\n configPrefix: this._configPrefix,\n queuedMethodOperations: this._queuedMethodOperations,\n });\n\n return new RunnableBinding<RunInput, AIMessageChunk, CallOptions>({\n config: mergedConfig,\n bound: newConfigurableModel,\n });\n }\n\n async invoke(\n input: RunInput,\n options?: CallOptions\n ): Promise<AIMessageChunk> {\n const model = await this._getModelInstance(options);\n const config = ensureConfig(options);\n return model.invoke(input, config);\n }\n\n async stream(\n input: RunInput,\n options?: CallOptions\n ): Promise<IterableReadableStream<AIMessageChunk>> {\n const model = await this._getModelInstance(options);\n const wrappedGenerator = new AsyncGeneratorWithSetup({\n generator: await model.stream(input, options),\n config: options,\n });\n await wrappedGenerator.setup;\n return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);\n }\n\n async batch(\n inputs: RunInput[],\n options?: Partial<CallOptions> | Partial<CallOptions>[],\n batchOptions?: RunnableBatchOptions & { returnExceptions?: false }\n ): Promise<AIMessageChunk[]>;\n\n async batch(\n inputs: RunInput[],\n options?: Partial<CallOptions> | Partial<CallOptions>[],\n batchOptions?: RunnableBatchOptions & { returnExceptions: true }\n ): Promise<(AIMessageChunk | Error)[]>;\n\n async batch(\n inputs: RunInput[],\n options?: Partial<CallOptions> | Partial<CallOptions>[],\n batchOptions?: RunnableBatchOptions\n ): Promise<(AIMessageChunk | Error)[]>;\n\n async batch(\n inputs: RunInput[],\n options?: Partial<CallOptions> | Partial<CallOptions>[],\n batchOptions?: RunnableBatchOptions\n ): Promise<(AIMessageChunk | Error)[]> {\n // We can super this since the base runnable implementation of\n // `.batch` will call `.invoke` on each input.\n return super.batch(inputs, options, batchOptions);\n }\n\n async *transform(\n generator: AsyncGenerator<RunInput>,\n options: CallOptions\n ): AsyncGenerator<AIMessageChunk> {\n const model = await this._getModelInstance(options);\n const config = ensureConfig(options);\n\n yield* model.transform(generator, config);\n }\n\n async *streamLog(\n input: RunInput,\n options?: Partial<CallOptions>,\n streamOptions?: Omit<LogStreamCallbackHandlerInput, \"autoClose\">\n ): AsyncGenerator<RunLogPatch> {\n const model = await this._getModelInstance(options);\n const config = ensureConfig(options);\n\n yield* model.streamLog(input, config, {\n ...streamOptions,\n _schemaFormat: \"original\",\n includeNames: streamOptions?.includeNames,\n includeTypes: streamOptions?.includeTypes,\n includeTags: streamOptions?.includeTags,\n excludeNames: streamOptions?.excludeNames,\n excludeTypes: streamOptions?.excludeTypes,\n excludeTags: streamOptions?.excludeTags,\n });\n }\n\n /**\n * @deprecated Use {@link BaseChatModel.streamEvents} without a `version`\n * option for content-block streaming instead.\n */\n streamEvents(\n input: RunInput,\n options: Partial<CallOptions> & { version: \"v2\" },\n streamOptions?: Omit<EventStreamCallbackHandlerInput, \"autoClose\">\n ): IterableReadableStream<StreamEvent>;\n\n /**\n * @deprecated Use {@link BaseChatModel.streamEvents} without a `version`\n * option for content-block streaming instead.\n */\n streamEvents(\n input: RunInput,\n options: Partial<CallOptions> & {\n version: \"v2\";\n encoding: \"text/event-stream\";\n },\n streamOptions?: Omit<EventStreamCallbackHandlerInput, \"autoClose\">\n ): IterableReadableStream<Uint8Array>;\n\n /**\n * @deprecated Use {@link BaseChatModel.streamEvents} without a `version`\n * option for content-block streaming instead.\n */\n streamEvents(\n input: RunInput,\n options: Partial<CallOptions> & { version: \"v1\" },\n streamOptions?: Omit<EventStreamCallbackHandlerInput, \"autoClose\">\n ): IterableReadableStream<StreamEvent>;\n\n /**\n * @deprecated Use {@link BaseChatModel.streamEvents} without a `version`\n * option for content-block streaming instead.\n */\n streamEvents(\n input: RunInput,\n options: Partial<CallOptions> & {\n version: \"v1\";\n encoding: \"text/event-stream\";\n },\n streamOptions?: Omit<EventStreamCallbackHandlerInput, \"autoClose\">\n ): IterableReadableStream<Uint8Array>;\n\n streamEvents(\n input: RunInput,\n options?: Partial<CallOptions>\n ): ChatModelStream;\n\n streamEvents(\n input: RunInput,\n options?: Partial<CallOptions> & {\n version?: \"v1\" | \"v2\";\n encoding?: \"text/event-stream\" | undefined;\n },\n streamOptions?: Omit<EventStreamCallbackHandlerInput, \"autoClose\">\n ): ChatModelStream | IterableReadableStream<StreamEvent | Uint8Array> {\n if (options?.version === \"v1\" || options?.version === \"v2\") {\n const outerThis = this;\n const tracingCallOptions = options;\n async function* wrappedGenerator() {\n const model = await outerThis._getModelInstance(tracingCallOptions);\n const config = ensureConfig(tracingCallOptions);\n const tracingOptions = {\n ...config,\n version: tracingCallOptions.version,\n ...(tracingCallOptions.encoding !== undefined\n ? { encoding: tracingCallOptions.encoding }\n : {}),\n };\n let eventStream: IterableReadableStream<StreamEvent | Uint8Array>;\n if (\n tracingCallOptions.version === \"v1\" &&\n tracingCallOptions.encoding === \"text/event-stream\"\n ) {\n eventStream = model.streamEvents(\n input,\n tracingOptions as Partial<CallOptions> & {\n version: \"v1\";\n encoding: \"text/event-stream\";\n },\n streamOptions\n );\n } else if (tracingCallOptions.version === \"v1\") {\n eventStream = model.streamEvents(\n input,\n tracingOptions as Partial<CallOptions> & { version: \"v1\" },\n streamOptions\n );\n } else if (\n tracingCallOptions.version === \"v2\" &&\n tracingCallOptions.encoding === \"text/event-stream\"\n ) {\n eventStream = model.streamEvents(\n input,\n tracingOptions as Partial<CallOptions> & {\n version: \"v2\";\n encoding: \"text/event-stream\";\n },\n streamOptions\n );\n } else {\n eventStream = model.streamEvents(\n input,\n tracingOptions as Partial<CallOptions> & { version: \"v2\" },\n streamOptions\n );\n }\n\n for await (const chunk of eventStream) {\n yield chunk;\n }\n }\n return IterableReadableStream.fromAsyncGenerator(wrappedGenerator());\n }\n\n const outerThis = this;\n async function* deferredEvents() {\n const model = await outerThis._getModelInstance(options);\n const config = ensureConfig(options);\n yield* model.streamEvents(input, config);\n }\n return new ChatModelStream(deferredEvents());\n }\n\n /**\n * Return profiling information for the model.\n *\n * @returns {ModelProfile} An object describing the model's capabilities and constraints\n */\n get profile(): ModelProfile {\n if (this._profile) {\n return this._profile;\n }\n const cacheKey = this._getCacheKey({});\n const instance = this._modelInstanceCache.get(cacheKey);\n return instance?.profile ?? {};\n }\n\n /** @internal */\n _getCacheKey(config?: RunnableConfig): string {\n let toStringify = config ?? {};\n if (toStringify.configurable) {\n const { configurable } = toStringify;\n const filtered: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(configurable)) {\n if (!k.startsWith(\"__pregel_\")) {\n filtered[k] = v;\n }\n }\n toStringify = { ...toStringify, configurable: filtered };\n }\n return JSON.stringify(toStringify);\n }\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface InitChatModelFields extends Partial<Record<string, any>> {\n modelProvider?: string;\n configurableFields?: string[] | \"any\";\n configPrefix?: string;\n}\n\nexport type ConfigurableFields = \"any\" | string[];\n\nexport async function initChatModel<\n RunInput extends BaseLanguageModelInput = BaseLanguageModelInput,\n CallOptions extends ConfigurableChatModelCallOptions =\n ConfigurableChatModelCallOptions,\n>(\n model: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n fields?: Partial<Record<string, any>> & {\n modelProvider?: string;\n configurableFields?: never;\n configPrefix?: string;\n }\n): Promise<ConfigurableModel<RunInput, CallOptions>>;\n\nexport async function initChatModel<\n RunInput extends BaseLanguageModelInput = BaseLanguageModelInput,\n CallOptions extends ConfigurableChatModelCallOptions =\n ConfigurableChatModelCallOptions,\n>(\n model: never,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n options?: Partial<Record<string, any>> & {\n modelProvider?: string;\n configurableFields?: never;\n configPrefix?: string;\n profile?: ModelProfile;\n }\n): Promise<ConfigurableModel<RunInput, CallOptions>>;\n\nexport async function initChatModel<\n RunInput extends BaseLanguageModelInput = BaseLanguageModelInput,\n CallOptions extends ConfigurableChatModelCallOptions =\n ConfigurableChatModelCallOptions,\n>(\n model?: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n options?: Partial<Record<string, any>> & {\n modelProvider?: string;\n configurableFields?: ConfigurableFields;\n configPrefix?: string;\n profile?: ModelProfile;\n }\n): Promise<ConfigurableModel<RunInput, CallOptions>>;\n\n// ################################# FOR CONTRIBUTORS #################################\n//\n// If adding support for a new provider, please append the provider\n// name to the supported list in the docstring below.\n//\n// ####################################################################################\n\n/**\n * Initialize a ChatModel from the model name and provider.\n * Must have the integration package corresponding to the model provider installed.\n *\n * @template {extends BaseLanguageModelInput = BaseLanguageModelInput} RunInput - The input type for the model.\n * @template {extends ConfigurableChatModelCallOptions = ConfigurableChatModelCallOptions} CallOptions - Call options for the model.\n *\n * @param {string | ChatModelProvider} [model] - The name of the model, e.g. \"gpt-4\", \"claude-3-opus-20240229\".\n * Can be prefixed with the model provider, e.g. \"openai:gpt-4\", \"anthropic:claude-3-opus-20240229\".\n * @param {Object} [fields] - Additional configuration options.\n * @param {string} [fields.modelProvider] - The model provider. Supported values include:\n * - openai (@langchain/openai)\n * - langsmith (@langchain/openai, via the [LangSmith LLM Gateway](https://docs.langchain.com/langsmith/llm-gateway))\n * - anthropic (@langchain/anthropic)\n * - azure_openai (@langchain/openai)\n * - google-vertexai (@langchain/google-vertexai)\n * - google-vertexai-web (@langchain/google-vertexai-web)\n * - google-genai (@langchain/google-genai)\n * - bedrock (@langchain/aws)\n * - cohere (@langchain/cohere)\n * - fireworks (@langchain/fireworks)\n * - together (@langchain/together-ai)\n * - mistralai (@langchain/mistralai)\n * - groq (@langchain/groq)\n * - ollama (@langchain/ollama)\n * - perplexity (@langchain/perplexity)\n * - cerebras (@langchain/cerebras)\n * - deepseek (@langchain/deepseek)\n * - xai (@langchain/xai)\n * @param {string[] | \"any\"} [fields.configurableFields] - Which model parameters are configurable:\n * - undefined: No configurable fields.\n * - \"any\": All fields are configurable. (See Security Note in description)\n * - string[]: Specified fields are configurable.\n * @param {string} [fields.configPrefix] - Prefix for configurable fields at runtime.\n * @param {ModelProfile} [fields.profile] - Overrides the profiling information for the model. If not provided,\n * the profile will be inferred from the inner model instance.\n * @param {Record<string, any>} [fields.params] - Additional keyword args to pass to the ChatModel constructor.\n * @returns {Promise<ConfigurableModel<RunInput, CallOptions>>} A class which extends BaseChatModel.\n * @throws {Error} If modelProvider cannot be inferred or isn't supported.\n * @throws {Error} If the model provider integration package is not installed.\n *\n * @example Initialize non-configurable models\n * ```typescript\n * import { initChatModel } from \"langchain/chat_models/universal\";\n *\n * const gpt4 = await initChatModel(\"openai:gpt-4\", {\n * temperature: 0.25,\n * });\n * const gpt4Result = await gpt4.invoke(\"what's your name\");\n *\n * const claude = await initChatModel(\"anthropic:claude-3-opus-20240229\", {\n * temperature: 0.25,\n * });\n * const claudeResult = await claude.invoke(\"what's your name\");\n *\n * const gemini = await initChatModel(\"gemini-1.5-pro\", {\n * modelProvider: \"google-vertexai\",\n * temperature: 0.25,\n * });\n * const geminiResult = await gemini.invoke(\"what's your name\");\n * ```\n *\n * @example Create a partially configurable model with no default model\n * ```typescript\n * import { initChatModel } from \"langchain/chat_models/universal\";\n *\n * const configurableModel = await initChatModel(undefined, {\n * temperature: 0,\n * configurableFields: [\"model\", \"apiKey\"],\n * });\n *\n * const gpt4Result = await configurableModel.invoke(\"what's your name\", {\n * configurable: {\n * model: \"gpt-4\",\n * },\n * });\n *\n * const claudeResult = await configurableModel.invoke(\"what's your name\", {\n * configurable: {\n * model: \"claude-sonnet-4-5-20250929\",\n * },\n * });\n * ```\n *\n * @example Create a fully configurable model with a default model and a config prefix\n * ```typescript\n * import { initChatModel } from \"langchain/chat_models/universal\";\n *\n * const configurableModelWithDefault = await initChatModel(\"gpt-4\", {\n * modelProvider: \"openai\",\n * configurableFields: \"any\",\n * configPrefix: \"foo\",\n * temperature: 0,\n * });\n *\n * const openaiResult = await configurableModelWithDefault.invoke(\n * \"what's your name\",\n * {\n * configurable: {\n * foo_apiKey: process.env.OPENAI_API_KEY,\n * },\n * }\n * );\n *\n * const claudeResult = await configurableModelWithDefault.invoke(\n * \"what's your name\",\n * {\n * configurable: {\n * foo_model: \"claude-sonnet-4-5-20250929\",\n * foo_modelProvider: \"anthropic\",\n * foo_temperature: 0.6,\n * foo_apiKey: process.env.ANTHROPIC_API_KEY,\n * },\n * }\n * );\n * ```\n *\n * @example Bind tools to a configurable model:\n * ```typescript\n * import { initChatModel } from \"langchain/chat_models/universal\";\n * import { z } from \"zod/v3\";\n * import { tool } from \"@langchain/core/tools\";\n *\n * const getWeatherTool = tool(\n * (input) => {\n * // Do something with the input\n * return JSON.stringify(input);\n * },\n * {\n * schema: z\n * .object({\n * location: z\n * .string()\n * .describe(\"The city and state, e.g. San Francisco, CA\"),\n * })\n * .describe(\"Get the current weather in a given location\"),\n * name: \"GetWeather\",\n * description: \"Get the current weather in a given location\",\n * }\n * );\n *\n * const getPopulationTool = tool(\n * (input) => {\n * // Do something with the input\n * return JSON.stringify(input);\n * },\n * {\n * schema: z\n * .object({\n * location: z\n * .string()\n * .describe(\"The city and state, e.g. San Francisco, CA\"),\n * })\n * .describe(\"Get the current population in a given location\"),\n * name: \"GetPopulation\",\n * description: \"Get the current population in a given location\",\n * }\n * );\n *\n * const configurableModel = await initChatModel(\"gpt-4\", {\n * configurableFields: [\"model\", \"modelProvider\", \"apiKey\"],\n * temperature: 0,\n * });\n *\n * const configurableModelWithTools = configurableModel.bindTools([\n * getWeatherTool,\n * getPopulationTool,\n * ]);\n *\n * const configurableToolResult = await configurableModelWithTools.invoke(\n * \"Which city is hotter today and which is bigger: LA or NY?\",\n * {\n * configurable: {\n * apiKey: process.env.OPENAI_API_KEY,\n * },\n * }\n * );\n *\n * const configurableToolResult2 = await configurableModelWithTools.invoke(\n * \"Which city is hotter today and which is bigger: LA or NY?\",\n * {\n * configurable: {\n * model: \"claude-sonnet-4-5-20250929\",\n * apiKey: process.env.ANTHROPIC_API_KEY,\n * },\n * }\n * );\n * ```\n *\n * @example Initialize a model with a custom profile\n * ```typescript\n * import { initChatModel } from \"langchain/chat_models/universal\";\n *\n * const model = await initChatModel(\"gpt-4o-mini\", {\n * profile: {\n * maxInputTokens: 100000,\n * },\n * });\n *\n * @description\n * This function initializes a ChatModel based on the provided model name and provider.\n * It supports various model providers and allows for runtime configuration of model parameters.\n *\n * Security Note: Setting `configurableFields` to \"any\" means fields like apiKey, baseUrl, etc.\n * can be altered at runtime, potentially redirecting model requests to a different service/user.\n * Make sure that if you're accepting untrusted configurations, you enumerate the\n * `configurableFields` explicitly.\n *\n * The function will attempt to infer the model provider from the model name if not specified.\n * Certain model name prefixes are associated with specific providers:\n * - gpt-3... or gpt-4... -> openai\n * - claude... -> anthropic\n * - amazon.... -> bedrock\n * - gemini... -> google-vertexai\n * - command... -> cohere\n * - accounts/fireworks... -> fireworks\n *\n * @since 0.2.11\n * @version 0.2.11\n */\nexport async function initChatModel<\n RunInput extends BaseLanguageModelInput = BaseLanguageModelInput,\n CallOptions extends ConfigurableChatModelCallOptions =\n ConfigurableChatModelCallOptions,\n>(\n model?: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n fields?: Partial<Record<string, any>> & {\n modelProvider?: string;\n configurableFields?: string[] | \"any\";\n configPrefix?: string;\n profile?: ModelProfile;\n }\n): Promise<ConfigurableModel<RunInput, CallOptions>> {\n // oxlint-disable-next-line prefer-const\n let { configurableFields, configPrefix, modelProvider, profile, ...params } =\n {\n configPrefix: \"\",\n ...(fields ?? {}),\n };\n if (modelProvider === undefined && model?.includes(\":\")) {\n const [provider, ...remainingParts] = model.split(\":\");\n const modelComponents =\n remainingParts.length === 0\n ? [provider]\n : [provider, remainingParts.join(\":\")];\n if (SUPPORTED_PROVIDERS.includes(modelComponents[0] as ChatModelProvider)) {\n // oxlint-disable-next-line no-param-reassign\n [modelProvider, model] = modelComponents;\n }\n }\n let configurableFieldsCopy = Array.isArray(configurableFields)\n ? [...configurableFields]\n : configurableFields;\n\n if (!model && configurableFieldsCopy === undefined) {\n configurableFieldsCopy = [\"model\", \"modelProvider\"];\n }\n if (configPrefix && configurableFieldsCopy === undefined) {\n console.warn(\n `{ configPrefix: ${configPrefix} } has been set but no fields are configurable. Set ` +\n `{ configurableFields: [...] } to specify the model params that are ` +\n `configurable.`\n );\n }\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const paramsCopy: Record<string, any> = { ...params };\n\n let configurableModel: ConfigurableModel<RunInput, CallOptions>;\n\n if (configurableFieldsCopy === undefined) {\n configurableModel = new ConfigurableModel<RunInput, CallOptions>({\n defaultConfig: {\n ...paramsCopy,\n model,\n modelProvider,\n },\n configPrefix,\n profile,\n });\n } else {\n if (model) {\n paramsCopy.model = model;\n }\n if (modelProvider) {\n paramsCopy.modelProvider = modelProvider;\n }\n configurableModel = new ConfigurableModel<RunInput, CallOptions>({\n defaultConfig: paramsCopy,\n configPrefix,\n configurableFields: configurableFieldsCopy,\n profile,\n });\n }\n\n // Initialize the model instance to make sure a profile is available\n await configurableModel._getModelInstance();\n return configurableModel;\n}\n","/* oxlint-disable no-instanceof/no-instanceof */\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport { isGraphBubbleUp } from \"@langchain/langgraph\";\n\nexport class MultipleToolsBoundError extends Error {\n constructor() {\n super(\n \"The provided LLM already has bound tools. \" +\n \"Please provide an LLM without bound tools to createAgent. \" +\n \"The agent will bind the tools provided in the 'tools' parameter.\"\n );\n }\n}\n\n/**\n * Raised when model returns multiple structured output tool calls when only one is expected.\n */\nexport class MultipleStructuredOutputsError extends Error {\n public readonly toolNames: string[];\n\n constructor(toolNames: string[]) {\n super(\n `The model has called multiple tools: ${toolNames.join(\n \", \"\n )} to return a structured output. ` +\n \"This is not supported. Please provide a single structured output.\"\n );\n this.toolNames = toolNames;\n }\n}\n\n/**\n * Raised when structured output tool call arguments fail to parse according to the schema.\n */\nexport class StructuredOutputParsingError extends Error {\n public readonly toolName: string;\n\n public readonly errors: string[];\n\n constructor(toolName: string, errors: string[]) {\n super(\n `Failed to parse structured output for tool '${toolName}':${errors\n .map((e) => `\\n - ${e}`)\n .join(\"\")}.`\n );\n this.toolName = toolName;\n this.errors = errors;\n }\n}\n\n/**\n * Raised when a tool call is throwing an error.\n */\nexport class ToolInvocationError extends Error {\n readonly \"~brand\" = \"ToolInvocationError\";\n\n public readonly toolCall: ToolCall;\n\n public readonly toolError: Error;\n\n constructor(toolError: unknown, toolCall: ToolCall) {\n const error =\n toolError instanceof Error ? toolError : new Error(String(toolError));\n const toolArgs = JSON.stringify(toolCall.args);\n super(\n `Error invoking tool '${toolCall.name}' with kwargs ${toolArgs} with error: ${error.stack}\\n Please fix the error and try again.`\n );\n\n this.toolCall = toolCall;\n this.toolError = error;\n }\n\n /**\n * Check if the error is a ToolInvocationError.\n * @param error - The error to check\n * @returns Whether the error is a ToolInvocationError\n */\n static isInstance(error: unknown): error is ToolInvocationError {\n return (\n error instanceof Error &&\n \"~brand\" in error &&\n error[\"~brand\"] === \"ToolInvocationError\"\n );\n }\n\n static [Symbol.hasInstance](obj: unknown) {\n return this.isInstance(obj);\n }\n}\n\n/**\n * Error thrown when a middleware fails.\n *\n * Use `MiddlewareError.wrap()` to create instances. The constructor is private\n * to ensure that GraphBubbleUp errors (like GraphInterrupt) are never wrapped.\n */\nexport class MiddlewareError extends Error {\n readonly \"~brand\" = \"MiddlewareError\";\n\n private constructor(error: unknown, middlewareName: string) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n super(errorMessage);\n this.name =\n error instanceof Error\n ? error.name\n : `${middlewareName[0].toUpperCase() + middlewareName.slice(1)}Error`;\n\n if (error instanceof Error) {\n this.cause = error;\n }\n }\n\n /**\n * Wrap an error in a MiddlewareError, unless it's a GraphBubbleUp error\n * (like GraphInterrupt) which should propagate unchanged.\n *\n * @param error - The error to wrap\n * @param middlewareName - The name of the middleware that threw the error\n * @returns The original error if it's a GraphBubbleUp, otherwise a new MiddlewareError\n */\n static wrap(error: unknown, middlewareName: string): Error {\n // Don't wrap GraphBubbleUp errors (GraphInterrupt, NodeInterrupt, etc.)\n // These are control flow mechanisms that need to bubble up unchanged\n if (isGraphBubbleUp(error)) {\n return error;\n }\n return new MiddlewareError(error, middlewareName);\n }\n\n /**\n * Check if the error is a MiddlewareError.\n * @param error - The error to check\n * @returns Whether the error is a MiddlewareError\n */\n static isInstance(error: unknown): error is MiddlewareError {\n return (\n error instanceof Error &&\n \"~brand\" in error &&\n error[\"~brand\"] === \"MiddlewareError\"\n );\n }\n\n static [Symbol.hasInstance](obj: unknown) {\n return this.isInstance(obj);\n }\n}\n","import type {\n BaseLanguageModelInput,\n LanguageModelOutput,\n} from \"@langchain/core/language_models/base\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport type { RunnableInterface } from \"@langchain/core/runnables\";\n\nexport type AgentLanguageModelLike = RunnableInterface<\n BaseLanguageModelInput,\n LanguageModelOutput\n>;\n\nexport interface ConfigurableModelInterface {\n _queuedMethodOperations: Record<string, unknown>;\n _getModelInstance: () => Promise<BaseChatModel>;\n}\n\nexport function isBaseChatModel(\n model: AgentLanguageModelLike\n): model is BaseChatModel {\n return (\n \"invoke\" in model &&\n typeof model.invoke === \"function\" &&\n \"_streamResponseChunks\" in model\n );\n}\n\nexport function isConfigurableModel(\n model: unknown\n): model is ConfigurableModelInterface {\n return (\n typeof model === \"object\" &&\n model != null &&\n \"_queuedMethodOperations\" in model &&\n \"_getModelInstance\" in model &&\n typeof (model as { _getModelInstance: unknown })._getModelInstance ===\n \"function\"\n );\n}\n","/* oxlint-disable @typescript-eslint/no-explicit-any */\n/* oxlint-disable no-instanceof/no-instanceof */\nimport {\n InteropZodObject,\n isInteropZodSchema,\n InteropZodType,\n isInteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport { type AIMessage } from \"@langchain/core/messages\";\nimport { toJsonSchema, Validator } from \"@langchain/core/utils/json_schema\";\nimport { type FunctionDefinition } from \"@langchain/core/language_models/base\";\nimport {\n type SerializableSchema,\n isSerializableSchema,\n} from \"@langchain/core/utils/standard_schema\";\n\nimport {\n StructuredOutputParsingError,\n MultipleStructuredOutputsError,\n} from \"./errors.js\";\nimport { isBaseChatModel } from \"./model.js\";\nimport type { AgentLanguageModelLike as LanguageModelLike } from \"./model.js\";\n\n/**\n * Special type to indicate that no response format is provided.\n * When this type is used, the structuredResponse property should not be present in the result.\n */\nexport type ResponseFormatUndefined = {\n __responseFormatUndefined: true;\n};\n\n/**\n * Default value for strict mode in providerStrategy.\n *\n * When using providerStrategy with json_schema response format, OpenAI's parse() method\n * requires all function tools to have strict: true. This ensures the model's output\n * exactly matches the provided JSON schema.\n *\n * @see https://platform.openai.com/docs/guides/structured-outputs\n */\nconst PROVIDER_STRATEGY_DEFAULT_STRICT = true;\n\n/**\n * This is a global counter for generating unique names for tools.\n */\nlet bindingIdentifier = 0;\n\n/**\n * Information for tracking structured output tool metadata.\n * This contains all necessary information to handle structured responses generated\n * via tool calls, including the original schema, its type classification, and the\n * corresponding tool implementation used by the tools strategy.\n */\nexport class ToolStrategy<_T = unknown> {\n private constructor(\n /**\n * The original JSON Schema provided for structured output\n */\n public readonly schema: Record<string, unknown>,\n\n /**\n * The tool that will be used to parse the tool call arguments.\n */\n public readonly tool: {\n type: \"function\";\n function: FunctionDefinition;\n },\n\n /**\n * The options to use for the tool output.\n */\n public readonly options?: ToolStrategyOptions\n ) {}\n\n get name() {\n return this.tool.function.name;\n }\n\n static fromSchema<S extends InteropZodObject>(\n schema: S,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<S extends InteropZodType<infer U> ? U : unknown>;\n\n static fromSchema(\n schema: SerializableSchema,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: InteropZodObject | SerializableSchema | Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<any> {\n /**\n * It is required for tools to have a name so we can map the tool call to the correct tool\n * when parsing the response.\n */\n function getFunctionName(name?: string) {\n return name ?? `extract-${++bindingIdentifier}`;\n }\n\n if (isSerializableSchema(schema) || isInteropZodSchema(schema)) {\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: {\n name: getFunctionName(asJsonSchema.title),\n strict: false,\n description:\n asJsonSchema.description ??\n \"Tool for extracting structured output from the model's response.\",\n parameters: asJsonSchema,\n },\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n let functionDefinition: FunctionDefinition;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n functionDefinition = schema as unknown as FunctionDefinition;\n } else {\n functionDefinition = {\n name: getFunctionName(schema.title as string),\n description: (schema.description as string) ?? \"\",\n parameters: schema.schema || (schema as Record<string, unknown>),\n };\n }\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: functionDefinition,\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n /**\n * Parse tool arguments according to the schema.\n *\n * @throws {StructuredOutputParsingError} if the response is not valid\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(toolArgs: Record<string, unknown>): Record<string, unknown> {\n const validator = new Validator(this.schema);\n const result = validator.validate(toolArgs);\n if (!result.valid) {\n throw new StructuredOutputParsingError(\n this.name,\n result.errors.map((e) => e.error)\n );\n }\n return toolArgs;\n }\n}\n\nexport class ProviderStrategy<T = unknown> {\n // @ts-expect-error - _schemaType is used only for type inference\n private _schemaType?: T;\n\n /**\n * The schema to use for the provider strategy\n */\n public readonly schema: Record<string, unknown>;\n\n /**\n * Whether to use strict mode for the provider strategy\n */\n public readonly strict: boolean;\n\n private constructor(options: {\n schema: Record<string, unknown>;\n strict?: boolean;\n });\n private constructor(schema: Record<string, unknown>, strict?: boolean);\n private constructor(\n schemaOrOptions:\n | Record<string, unknown>\n | { schema: Record<string, unknown>; strict?: boolean },\n strict?: boolean\n ) {\n if (\n \"schema\" in schemaOrOptions &&\n typeof schemaOrOptions.schema === \"object\" &&\n schemaOrOptions.schema !== null &&\n !(\"type\" in schemaOrOptions)\n ) {\n const options = schemaOrOptions as {\n schema: Record<string, unknown>;\n strict?: boolean;\n };\n this.schema = options.schema;\n this.strict = options.strict ?? PROVIDER_STRATEGY_DEFAULT_STRICT;\n } else {\n this.schema = schemaOrOptions as Record<string, unknown>;\n this.strict = strict ?? PROVIDER_STRATEGY_DEFAULT_STRICT;\n }\n }\n\n static fromSchema<T>(\n schema: InteropZodType<T>,\n strict?: boolean\n ): ProviderStrategy<T>;\n\n static fromSchema(\n schema: SerializableSchema,\n strict?: boolean\n ): ProviderStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: Record<string, unknown>,\n strict?: boolean\n ): ProviderStrategy<Record<string, unknown>>;\n\n static fromSchema<T = unknown>(\n schema: InteropZodType<T> | SerializableSchema | Record<string, unknown>,\n strict?: boolean\n ): ProviderStrategy<T> | ProviderStrategy<Record<string, unknown>> {\n const asJsonSchema = toJsonSchema(schema);\n return new ProviderStrategy(asJsonSchema, strict) as\n | ProviderStrategy<T>\n | ProviderStrategy<Record<string, unknown>>;\n }\n\n /**\n * Parse tool arguments according to the schema. If the response is not valid, return undefined.\n *\n * @param response - The AI message response to parse\n * @returns The parsed response according to the schema type\n */\n parse(response: AIMessage) {\n /**\n * Extract text content from the response.\n * Handles both string content and array content (e.g., from thinking models).\n */\n let textContent: string | undefined;\n\n if (typeof response.content === \"string\") {\n textContent = response.content;\n } else if (Array.isArray(response.content)) {\n /**\n * For thinking models, content is an array with thinking blocks and text blocks.\n * Extract the text from text blocks.\n */\n for (const block of response.content) {\n if (\n typeof block === \"object\" &&\n block !== null &&\n \"type\" in block &&\n block.type === \"text\" &&\n // Skip reasoning/thought summaries (e.g. Gemini represents these as\n // `{ type: \"text\", thought: true }`), which are not the structured\n // response and would otherwise fail JSON parsing.\n !(\"thought\" in block && block.thought === true) &&\n \"text\" in block &&\n typeof block.text === \"string\"\n ) {\n textContent = block.text;\n break; // Use the first non-thought text block found\n }\n }\n }\n\n // Return if no valid text content found\n if (!textContent || textContent === \"\") {\n return;\n }\n\n try {\n const content = JSON.parse(textContent);\n const validator = new Validator(this.schema);\n const result = validator.validate(content);\n if (!result.valid) {\n return;\n }\n\n return content;\n } catch {\n // no-op\n }\n }\n}\n\nexport type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;\n\nexport type ResponseFormatInput<\n StructuredResponseType extends Record<string, any> = Record<string, any>,\n> =\n | InteropZodType<StructuredResponseType>\n | InteropZodType<unknown>[]\n | SerializableSchema<StructuredResponseType>\n | SerializableSchema[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ResponseFormat[]\n | TypedToolStrategy<StructuredResponseType>\n | ToolStrategy<StructuredResponseType>\n | ProviderStrategy<StructuredResponseType>\n | ResponseFormatUndefined;\n\n/**\n * Handle user input for `responseFormat` parameter of `CreateAgentParams`.\n * This function defines the default behavior for the `responseFormat` parameter, which is:\n *\n * - if value is a Zod schema, default to structured output via tool calling\n * - if value is a JSON schema, default to structured output via tool calling\n * - if value is a custom response format, return it as is\n * - if value is an array, ensure all array elements are instance of `ToolStrategy`\n * @param responseFormat - The response format to transform, provided by the user\n * @param options - The response format options for tool strategy\n * @param model - The model to check if it supports JSON schema output\n * @returns\n */\nexport function transformResponseFormat(\n responseFormat?: ResponseFormatInput,\n options?: ToolStrategyOptions,\n model?: LanguageModelLike\n): ResponseFormat[] {\n if (!responseFormat) {\n return [];\n }\n\n // Handle ResponseFormatUndefined case\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"__responseFormatUndefined\" in responseFormat\n ) {\n return [];\n }\n\n /**\n * If users provide an array, it should only contain raw schemas (Zod, Standard Schema or JSON schema),\n * not ToolStrategy or ProviderStrategy instances.\n */\n if (Array.isArray(responseFormat)) {\n /**\n * if every entry is a ToolStrategy or ProviderStrategy instance, return the array as is\n */\n if (\n responseFormat.every(\n (item) =>\n item instanceof ToolStrategy || item instanceof ProviderStrategy\n )\n ) {\n return responseFormat as unknown as ResponseFormat[];\n }\n\n /**\n * Check if all items are Standard Schema\n */\n if (responseFormat.every((item) => isSerializableSchema(item))) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as SerializableSchema, options)\n );\n }\n\n /**\n * Check if all items are Zod schemas\n */\n if (responseFormat.every((item) => isInteropZodObject(item))) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as InteropZodObject, options)\n );\n }\n\n /**\n * Check if all items are plain objects (JSON schema)\n */\n if (\n responseFormat.every(\n (item) =>\n typeof item === \"object\" &&\n item !== null &&\n !isInteropZodObject(item) &&\n !isSerializableSchema(item)\n )\n ) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as JsonSchemaFormat, options)\n );\n }\n\n throw new Error(\n `Invalid response format: list contains mixed types.\\n` +\n `All items must be either InteropZodObject, Standard Schema, or plain JSON schema objects.`\n );\n }\n\n if (\n responseFormat instanceof ToolStrategy ||\n responseFormat instanceof ProviderStrategy\n ) {\n return [responseFormat];\n }\n\n const useProviderStrategy = hasSupportForJsonSchemaOutput(model);\n\n /**\n * `responseFormat` is a Standard Schema\n */\n if (isSerializableSchema(responseFormat)) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat)]\n : [ToolStrategy.fromSchema(responseFormat, options)];\n }\n\n /**\n * `responseFormat` is a Zod schema\n */\n if (isInteropZodObject(responseFormat)) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat)]\n : [ToolStrategy.fromSchema(responseFormat, options)];\n }\n\n /**\n * Handle plain object (JSON schema)\n */\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"properties\" in responseFormat\n ) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat as JsonSchemaFormat)]\n : [ToolStrategy.fromSchema(responseFormat as JsonSchemaFormat, options)];\n }\n\n throw new Error(`Invalid response format: ${String(responseFormat)}`);\n}\n\n/**\n * Branded type for ToolStrategy arrays that preserves type information\n */\nexport interface TypedToolStrategy<T = unknown> extends Array<\n ToolStrategy<any>\n> {\n _schemaType?: T;\n}\nexport type ToolStrategyError =\n | StructuredOutputParsingError\n | MultipleStructuredOutputsError;\nexport interface ToolStrategyOptions {\n /**\n * Allows you to customize the message that appears in the conversation history when structured\n * output is generated.\n */\n toolMessageContent?: string;\n /**\n * Handle errors from the structured output tool call. Using tools to generate structured output\n * can cause errors, e.g. if:\n * - you provide multiple structured output schemas and the model calls multiple structured output tools\n * - if the structured output generated by the tool call doesn't match provided schema\n *\n * This property allows to handle these errors in different ways:\n * - `true` - retry the tool call\n * - `false` - throw an error\n * - `string` - retry the tool call with the provided message\n * - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error\n *\n * @default true\n */\n handleError?:\n | boolean\n | string\n | ((error: ToolStrategyError) => Promise<string> | string);\n}\n\nexport function toolStrategy<T extends InteropZodType<any>>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function toolStrategy<T extends readonly InteropZodType<any>[]>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<\n { [K in keyof T]: T[K] extends InteropZodType<infer U> ? U : never }[number]\n>;\nexport function toolStrategy(\n responseFormat: SerializableSchema,\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: SerializableSchema[],\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat,\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\n\n/**\n * Creates a tool strategy for structured output using function calling.\n *\n * This function configures structured output by converting schemas into function tools that\n * the model calls. Unlike `providerStrategy`, which uses native JSON schema support,\n * `toolStrategy` works with any model that supports function calling, making it more\n * widely compatible across providers and model versions.\n *\n * The model will call a function with arguments matching your schema, and the agent will\n * extract and validate the structured output from the tool call. This approach is automatically\n * used when your model doesn't support native JSON schema output.\n *\n * @param responseFormat - The schema(s) to enforce. Can be a single Zod schema, a Standard Schema\n * (e.g., Valibot, ArkType, TypeBox), a JSON schema object, or arrays of any of these.\n * @param options - Optional configuration for the tool strategy\n * @param options.handleError - How to handle errors when the model calls multiple structured output tools\n * or when the output doesn't match the schema. Defaults to `true` (auto-retry). Can be `false` (throw),\n * a `string` (retry with message), or a `function` (custom handler).\n * @param options.toolMessageContent - Custom message content to include in conversation history\n * when structured output is generated via tool call\n * @returns A `TypedToolStrategy` instance that can be used as the `responseFormat` in `createAgent`\n *\n * @example\n * ```ts\n * import { toolStrategy, createAgent } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const agent = createAgent({\n * model: \"claude-haiku-4-5\",\n * responseFormat: toolStrategy(\n * z.object({\n * answer: z.string(),\n * confidence: z.number().min(0).max(1),\n * })\n * ),\n * });\n * ```\n *\n * @example\n * ```ts\n * // Multiple schemas - model can choose which one to use\n * const agent = createAgent({\n * model: \"claude-haiku-4-5\",\n * responseFormat: toolStrategy([\n * z.object({ name: z.string(), age: z.number() }),\n * z.object({ email: z.string(), phone: z.string() }),\n * ]),\n * });\n * ```\n */\nexport function toolStrategy(\n responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | SerializableSchema\n | SerializableSchema[]\n | JsonSchemaFormat\n | JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy {\n return transformResponseFormat(responseFormat, options) as TypedToolStrategy;\n}\n\n/**\n * Creates a provider strategy for structured output using native JSON schema support.\n *\n * This function is used to configure structured output for agents when the underlying model\n * supports native JSON schema output (e.g., OpenAI's `gpt-4o`, `gpt-4o-mini`, and newer models).\n * Unlike `toolStrategy`, which uses function calling to extract structured output, `providerStrategy`\n * leverages the provider's native structured output capabilities, resulting in more efficient\n * and reliable schema enforcement.\n *\n * When used with a model that supports JSON schema output, the model will return responses\n * that directly conform to the provided schema without requiring tool calls. This is the\n * recommended approach for structured output when your model supports it.\n *\n * @param responseFormat - The schema to enforce, either a Zod schema, a Standard Schema (e.g., Valibot, ArkType, TypeBox), a JSON schema object, or an options object with `schema` and optional `strict` flag\n * @returns A `ProviderStrategy` instance that can be used as the `responseFormat` in `createAgent`\n *\n * @example\n * ```ts\n * import { providerStrategy, createAgent } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const agent = createAgent({\n * model: \"claude-haiku-4-5\",\n * responseFormat: providerStrategy(\n * z.object({\n * answer: z.string().describe(\"The answer to the question\"),\n * confidence: z.number().min(0).max(1),\n * })\n * ),\n * });\n * ```\n *\n * @example\n * ```ts\n * // Using strict mode for stricter schema enforcement\n * const agent = createAgent({\n * model: \"claude-haiku-4-5\",\n * responseFormat: providerStrategy({\n * schema: z.object({\n * name: z.string(),\n * age: z.number(),\n * }),\n * strict: true\n * }),\n * });\n * ```\n */\nexport function providerStrategy<T extends InteropZodType<unknown>>(\n responseFormat: T | { schema: T; strict?: boolean }\n): ProviderStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function providerStrategy(\n responseFormat:\n | SerializableSchema\n | { schema: SerializableSchema; strict?: boolean }\n): ProviderStrategy<Record<string, unknown>>;\nexport function providerStrategy(\n responseFormat:\n | JsonSchemaFormat\n | { schema: JsonSchemaFormat; strict?: boolean }\n): ProviderStrategy<Record<string, unknown>>;\nexport function providerStrategy(\n responseFormat:\n | InteropZodType<unknown>\n | SerializableSchema\n | JsonSchemaFormat\n | {\n schema: InteropZodType<unknown> | SerializableSchema | JsonSchemaFormat;\n strict?: boolean;\n }\n): ProviderStrategy<unknown> {\n /**\n * Handle options object format\n */\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"schema\" in responseFormat &&\n !isInteropZodSchema(responseFormat) &&\n !isSerializableSchema(responseFormat) &&\n !(\"type\" in responseFormat)\n ) {\n const { schema, strict: strictFlag } = responseFormat as {\n schema: InteropZodType<unknown> | SerializableSchema | JsonSchemaFormat;\n strict?: boolean;\n };\n return ProviderStrategy.fromSchema(\n schema as InteropZodType<unknown>,\n strictFlag\n ) as ProviderStrategy<unknown>;\n }\n\n /**\n * Handle direct schema format\n */\n return ProviderStrategy.fromSchema(\n responseFormat as InteropZodType<unknown>\n ) as ProviderStrategy<unknown>;\n}\n\n/**\n * Type representing a JSON Schema object format.\n * This is a strict type that excludes ToolStrategy and ProviderStrategy instances.\n */\nexport type JsonSchemaFormat = {\n type:\n | \"null\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"number\"\n | \"string\"\n | \"integer\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n} & {\n // Brand to ensure this is not a ToolStrategy or ProviderStrategy\n __brand?: never;\n};\n\n/**\n * Identifies the models that support JSON schema output by reading\n * the model's profile metadata.\n *\n * @param model - A resolved model instance to check. Callers should resolve\n * string model names and ConfigurableModel wrappers before calling this.\n * @returns True if the model supports JSON schema output, false otherwise\n */\nexport function hasSupportForJsonSchemaOutput(\n model?: LanguageModelLike\n): boolean {\n if (\n !model ||\n !isBaseChatModel(model) ||\n !(\"profile\" in model) ||\n typeof model.profile !== \"object\" ||\n !model.profile\n ) {\n return false;\n }\n\n return (\n \"structuredOutput\" in model.profile &&\n model.profile.structuredOutput === true\n );\n}\n","/* oxlint-disable @typescript-eslint/no-explicit-any */\nimport type {\n InteropZodObject,\n InteropZodDefault,\n InteropZodOptional,\n InferInteropZodInput,\n InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\nimport type { InteropZodToStateDefinition } from \"@langchain/langgraph/zod\";\nimport type {\n AnnotationRoot,\n StateSchema,\n InferStateSchemaValue,\n InferStateSchemaUpdate,\n StateDefinitionInit,\n} from \"@langchain/langgraph\";\nimport type {\n AIMessage,\n SystemMessage,\n ToolMessage,\n} from \"@langchain/core/messages\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { Command, StreamTransformer } from \"@langchain/langgraph\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport type { JumpToTarget } from \"../constants.js\";\nimport type { Runtime, AgentBuiltInState } from \"../runtime.js\";\nimport type { ModelRequest } from \"../nodes/types.js\";\n\ntype PromiseOrValue<T> = T | Promise<T>;\n\nexport type AnyAnnotationRoot = AnnotationRoot<any>;\n\n/**\n * Type bag that encapsulates all middleware type parameters.\n *\n * This interface bundles all the generic type parameters used throughout the middleware system\n * into a single configuration object. This pattern simplifies type signatures and makes\n * it easier to add new type parameters without changing multiple function signatures.\n *\n * @typeParam TSchema - The middleware state schema type. Can be a `StateDefinitionInit`\n * (including `InteropZodObject`, `StateSchema`, or `AnnotationRoot`) or `undefined`.\n *\n * @typeParam TContextSchema - The middleware context schema type. Can be an `InteropZodObject`,\n * `InteropZodDefault`, `InteropZodOptional`, or `undefined`.\n *\n * @typeParam TFullContext - The full context type available to middleware hooks.\n *\n * @typeParam TTools - The tools array type registered by the middleware.\n *\n * @typeParam TStreamTransformers - The stream transformer factories registered\n * by the middleware.\n *\n * @example\n * ```typescript\n * // Define a type configuration\n * type MyMiddlewareTypes = MiddlewareTypeConfig<\n * typeof myStateSchema,\n * typeof myContextSchema,\n * MyContextType,\n * typeof myTools\n * >;\n * ```\n */\nexport interface MiddlewareTypeConfig<\n TSchema extends StateDefinitionInit | undefined =\n | StateDefinitionInit\n | undefined,\n TContextSchema extends\n | InteropZodObject\n | InteropZodDefault<InteropZodObject>\n | InteropZodOptional<InteropZodObject>\n | undefined =\n | InteropZodObject\n | InteropZodDefault<InteropZodObject>\n | InteropZodOptional<InteropZodObject>\n | undefined,\n TFullContext = any,\n TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n TStreamTransformers extends ReadonlyArray<() => StreamTransformer<any>> =\n ReadonlyArray<() => StreamTransformer<any>>,\n> {\n /** The middleware state schema type */\n Schema: TSchema;\n /** The middleware context schema type */\n ContextSchema: TContextSchema;\n /** The full context type */\n FullContext: TFullContext;\n /** The tools array type */\n Tools: TTools;\n /** The stream transformer factories registered by the middleware */\n StreamTransformers: TStreamTransformers;\n}\n\n/**\n * Default type configuration for middleware.\n * Used when no explicit type parameters are provided.\n */\nexport type DefaultMiddlewareTypeConfig = MiddlewareTypeConfig;\n\nexport type InferSchemaValueType<TSchema> = [TSchema] extends [never]\n ? AgentBuiltInState\n : TSchema extends StateSchema<infer TFields>\n ? InferStateSchemaValue<TFields> & AgentBuiltInState\n : TSchema extends InteropZodObject\n ? InferInteropZodOutput<TSchema> & AgentBuiltInState\n : TSchema extends StateDefinitionInit\n ? InferSchemaValue<TSchema> & AgentBuiltInState\n : AgentBuiltInState;\n\nexport type InferSchemaUpdateType<TSchema> = [TSchema] extends [never]\n ? AgentBuiltInState\n : TSchema extends StateSchema<infer TFields>\n ? InferStateSchemaUpdate<TFields> & AgentBuiltInState\n : TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema> & AgentBuiltInState\n : TSchema extends StateDefinitionInit\n ? InferSchemaInput<TSchema> & AgentBuiltInState\n : AgentBuiltInState;\n\nexport type NormalizedSchemaInput<\n TSchema extends StateDefinitionInit | undefined | never = any,\n> = InferSchemaValueType<TSchema>;\n\nexport type NormalizedSchemaUpdate<\n TSchema extends StateDefinitionInit | undefined | never = any,\n> = InferSchemaUpdateType<TSchema>;\n\n/**\n * Result type for middleware functions.\n */\nexport type MiddlewareResult<TState> =\n | (TState & {\n jumpTo?: JumpToTarget;\n })\n | void;\n\n/**\n * Represents a tool call request for the wrapToolCall hook.\n * Contains the tool call information along with the agent's current state and runtime.\n */\nexport interface ToolCallRequest<\n TState extends Record<string, unknown> = Record<string, unknown>,\n TContext = unknown,\n> {\n /**\n * The tool call to be executed\n */\n toolCall: ToolCall;\n /**\n * The BaseTool instance being invoked.\n * Provides access to tool metadata like name, description, schema, etc.\n *\n * This will be `undefined` for dynamically registered tools that aren't\n * declared upfront when creating the agent. In such cases, middleware\n * should provide the tool implementation by spreading the request with\n * the tool property.\n *\n * @example Dynamic tool handling\n * ```ts\n * wrapToolCall: async (request, handler) => {\n * if (request.toolCall.name === \"dynamic_tool\" && !request.tool) {\n * // Provide the tool implementation for dynamically registered tools\n * return handler({ ...request, tool: myDynamicTool });\n * }\n * return handler(request);\n * }\n * ```\n */\n tool: ClientTool | ServerTool | undefined;\n /**\n * The current agent state (includes both middleware state and built-in state).\n */\n state: TState & AgentBuiltInState;\n /**\n * The runtime context containing metadata, signal, writer, interrupt, etc.\n */\n runtime: Runtime<TContext>;\n}\n\n/**\n * Handler function type for wrapping tool calls.\n * Takes a tool call request and returns the tool result or a command.\n */\nexport type ToolCallHandler<\n TSchema extends Record<string, unknown> = AgentBuiltInState,\n TContext = unknown,\n> = (\n request: ToolCallRequest<TSchema, TContext>\n) => PromiseOrValue<ToolMessage | Command>;\n\n/**\n * Wrapper function type for the wrapToolCall hook.\n * Allows middleware to intercept and modify tool execution.\n */\nexport type WrapToolCallHook<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> = (\n request: ToolCallRequest<NormalizedSchemaInput<TSchema>, TContext>,\n handler: ToolCallHandler<NormalizedSchemaInput<TSchema>, TContext>\n) => PromiseOrValue<ToolMessage | Command>;\n\n/**\n * Handler function type for wrapping model calls.\n * Takes a model request and returns the AI message response.\n *\n * @param request - The model request containing model, messages, systemPrompt, tools, state, and runtime\n * @returns The AI message response from the model\n */\nexport type WrapModelCallHandler<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> = (\n request: Omit<\n ModelRequest<NormalizedSchemaInput<TSchema>, TContext>,\n /**\n * allow to reset the system prompt or system message\n */\n \"systemPrompt\" | \"systemMessage\"\n > & { systemPrompt?: string; systemMessage?: SystemMessage }\n) => PromiseOrValue<AIMessage>;\n\n/**\n * Wrapper function type for the wrapModelCall hook.\n * Allows middleware to intercept and modify model execution.\n * This enables you to:\n * - Modify the request before calling the model (e.g., change system prompt, add/remove tools)\n * - Handle errors and retry with different parameters\n * - Post-process the response\n * - Implement custom caching, logging, or other cross-cutting concerns\n *\n * @param request - The model request containing all parameters needed for the model call\n * @param handler - The function that invokes the model. Call this with a ModelRequest to get the response\n * @returns The AI message response from the model (or a modified version)\n */\nexport type WrapModelCallHook<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> = (\n request: ModelRequest<NormalizedSchemaInput<TSchema>, TContext>,\n handler: WrapModelCallHandler<TSchema, TContext>\n) => PromiseOrValue<AIMessage | Command>;\n\n/**\n * Handler function type for the beforeAgent hook.\n * Called once at the start of agent invocation before any model calls or tool executions.\n *\n * @param state - The current agent state (includes both middleware state and built-in state)\n * @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.\n * @returns A middleware result containing partial state updates or undefined to pass through\n */\ntype BeforeAgentHandler<TSchema, TContext> = (\n state: InferSchemaValueType<TSchema>,\n runtime: Runtime<TContext>\n) => PromiseOrValue<MiddlewareResult<Partial<InferSchemaUpdateType<TSchema>>>>;\n\n/**\n * Hook type for the beforeAgent lifecycle event.\n * Can be either a handler function or an object with a handler and optional jump targets.\n * This hook is called once at the start of the agent invocation.\n */\nexport type BeforeAgentHook<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> =\n | BeforeAgentHandler<TSchema, TContext>\n | {\n hook: BeforeAgentHandler<TSchema, TContext>;\n canJumpTo?: JumpToTarget[];\n };\n\n/**\n * Handler function type for the beforeModel hook.\n * Called before the model is invoked and before the wrapModelCall hook.\n *\n * @param state - The current agent state (includes both middleware state and built-in state)\n * @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.\n * @returns A middleware result containing partial state updates or undefined to pass through\n */\ntype BeforeModelHandler<TSchema, TContext> = (\n state: InferSchemaValueType<TSchema>,\n runtime: Runtime<TContext>\n) => PromiseOrValue<MiddlewareResult<Partial<InferSchemaUpdateType<TSchema>>>>;\n\n/**\n * Hook type for the beforeModel lifecycle event.\n * Can be either a handler function or an object with a handler and optional jump targets.\n * This hook is called before each model invocation.\n */\nexport type BeforeModelHook<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> =\n | BeforeModelHandler<TSchema, TContext>\n | {\n hook: BeforeModelHandler<TSchema, TContext>;\n canJumpTo?: JumpToTarget[];\n };\n\n/**\n * Handler function type for the afterModel hook.\n * Called after the model is invoked and before any tools are called.\n * Allows modifying the agent state after model invocation, e.g., to update tool call parameters.\n *\n * @param state - The current agent state (includes both middleware state and built-in state)\n * @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.\n * @returns A middleware result containing partial state updates or undefined to pass through\n */\ntype AfterModelHandler<TSchema, TContext> = (\n state: InferSchemaValueType<TSchema>,\n runtime: Runtime<TContext>\n) => PromiseOrValue<MiddlewareResult<Partial<InferSchemaUpdateType<TSchema>>>>;\n\n/**\n * Hook type for the afterModel lifecycle event.\n * Can be either a handler function or an object with a handler and optional jump targets.\n * This hook is called after each model invocation.\n */\nexport type AfterModelHook<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> =\n | AfterModelHandler<TSchema, TContext>\n | {\n hook: AfterModelHandler<TSchema, TContext>;\n canJumpTo?: JumpToTarget[];\n };\n\n/**\n * Handler function type for the afterAgent hook.\n * Called once at the end of agent invocation after all model calls and tool executions are complete.\n *\n * @param state - The current agent state (includes both middleware state and built-in state)\n * @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.\n * @returns A middleware result containing partial state updates or undefined to pass through\n */\ntype AfterAgentHandler<TSchema, TContext> = (\n state: InferSchemaValueType<TSchema>,\n runtime: Runtime<TContext>\n) => PromiseOrValue<MiddlewareResult<Partial<InferSchemaUpdateType<TSchema>>>>;\n\n/**\n * Hook type for the afterAgent lifecycle event.\n * Can be either a handler function or an object with a handler and optional jump targets.\n * This hook is called once at the end of the agent invocation.\n */\nexport type AfterAgentHook<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContext = unknown,\n> =\n | AfterAgentHandler<TSchema, TContext>\n | {\n hook: AfterAgentHandler<TSchema, TContext>;\n canJumpTo?: JumpToTarget[];\n };\n\n/**\n * Unique symbol used to brand middleware instances.\n * This prevents functions from being accidentally assignable to AgentMiddleware\n * since functions have a 'name' property that would otherwise make them structurally compatible.\n */\nexport const MIDDLEWARE_BRAND: symbol = Symbol.for(\"AgentMiddleware\");\n\n/**\n * Widened middleware type for agent configuration arrays. Accepts middleware\n * instances with any registered tools or stream transformers while preserving\n * precise inference when middleware arrays are passed with `const`.\n */\nexport type AnyAgentMiddleware = AgentMiddleware<\n StateDefinitionInit | undefined,\n | InteropZodObject\n | InteropZodDefault<InteropZodObject>\n | InteropZodOptional<InteropZodObject>\n | undefined,\n any,\n readonly (ClientTool | ServerTool)[],\n ReadonlyArray<() => StreamTransformer<any>>\n>;\n\n/**\n * Base middleware interface.\n *\n * @typeParam TSchema - The middleware state schema type\n * @typeParam TContextSchema - The middleware context schema type\n * @typeParam TFullContext - The full context type available to hooks\n * @typeParam TTools - The tools array type registered by the middleware\n * @typeParam TStreamTransformers - The stream transformer factories registered\n * by the middleware\n *\n * @example\n * ```typescript\n * const middleware = createMiddleware({\n * name: \"myMiddleware\",\n * stateSchema: z.object({ count: z.number() }),\n * tools: [myTool],\n * });\n * ```\n */\nexport interface AgentMiddleware<\n TSchema extends StateDefinitionInit | undefined = any,\n TContextSchema extends\n | InteropZodObject\n | InteropZodDefault<InteropZodObject>\n | InteropZodOptional<InteropZodObject>\n | undefined = any,\n TFullContext = any,\n TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n TStreamTransformers extends ReadonlyArray<() => StreamTransformer<any>> =\n ReadonlyArray<() => StreamTransformer<any>>,\n> {\n /**\n * Brand property to distinguish middleware instances from plain objects or functions.\n * This is required and prevents accidental assignment of functions to middleware arrays.\n */\n readonly [MIDDLEWARE_BRAND]: true;\n\n /**\n * Type marker for extracting the MiddlewareTypeConfig from a middleware instance.\n * This is a phantom property used only for type inference.\n * @internal\n */\n readonly \"~middlewareTypes\"?: MiddlewareTypeConfig<\n TSchema,\n TContextSchema,\n TFullContext,\n TTools,\n TStreamTransformers\n >;\n\n /**\n * The name of the middleware.\n */\n name: string;\n\n /**\n * The schema of the middleware state. Middleware state is persisted between multiple invocations. It can be either:\n * - A Zod object (InteropZodObject)\n * - A StateSchema from LangGraph (supports ReducedValue, UntrackedValue)\n * - An AnnotationRoot\n * - Undefined\n */\n stateSchema?: TSchema;\n\n /**\n * The schema of the middleware context. Middleware context is read-only and not persisted between multiple invocations. It can be either:\n * - A Zod object\n * - A Zod optional object\n * - A Zod default object\n * - Undefined\n */\n contextSchema?: TContextSchema;\n\n /**\n * Additional tools registered by the middleware.\n */\n tools?: TTools;\n\n /**\n * Stream transformer factories registered by the middleware.\n * These are merged with `createAgent({ streamTransformers })` when the agent\n * is compiled.\n */\n streamTransformers?: TStreamTransformers;\n\n /**\n * Wraps tool execution with custom logic. This allows you to:\n * - Modify tool call parameters before execution\n * - Handle errors and retry with different parameters\n * - Post-process tool results\n * - Implement caching, logging, authentication, or other cross-cutting concerns\n * - Return Command objects for advanced control flow\n *\n * The handler receives a ToolCallRequest containing the tool call, state, and runtime,\n * along with a handler function to execute the actual tool.\n *\n * @param request - The tool call request containing toolCall, state, and runtime.\n * @param handler - The function that executes the tool. Call this with a ToolCallRequest to get the result.\n * @returns The tool result as a ToolMessage or a Command for advanced control flow.\n *\n * @example\n * ```ts\n * wrapToolCall: async (request, handler) => {\n * console.log(`Calling tool: ${request.tool.name}`);\n * console.log(`Tool description: ${request.tool.description}`);\n *\n * try {\n * // Execute the tool\n * const result = await handler(request);\n * console.log(`Tool ${request.tool.name} succeeded`);\n * return result;\n * } catch (error) {\n * console.error(`Tool ${request.tool.name} failed:`, error);\n * // Could return a custom error message or retry\n * throw error;\n * }\n * }\n * ```\n *\n * @example Authentication\n * ```ts\n * wrapToolCall: async (request, handler) => {\n * // Check if user is authorized for this tool\n * if (!request.runtime.context.isAuthorized(request.tool.name)) {\n * return new ToolMessage({\n * content: \"Unauthorized to call this tool\",\n * tool_call_id: request.toolCall.id,\n * });\n * }\n * return handler(request);\n * }\n * ```\n *\n * @example Caching\n * ```ts\n * const cache = new Map();\n * wrapToolCall: async (request, handler) => {\n * const cacheKey = `${request.tool.name}:${JSON.stringify(request.toolCall.args)}`;\n * if (cache.has(cacheKey)) {\n * return cache.get(cacheKey);\n * }\n * const result = await handler(request);\n * cache.set(cacheKey, result);\n * return result;\n * }\n * ```\n */\n wrapToolCall?: WrapToolCallHook<TSchema, TFullContext>;\n\n /**\n * Wraps the model invocation with custom logic. This allows you to:\n * - Modify the request before calling the model\n * - Handle errors and retry with different parameters\n * - Post-process the response\n * - Implement custom caching, logging, or other cross-cutting concerns\n *\n * @param request - The model request containing model, messages, systemPrompt, tools, state, and runtime.\n * @param handler - The function that invokes the model. Call this with a ModelRequest to get the response.\n * @returns The response from the model (or a modified version).\n *\n * @example\n * ```ts\n * wrapModelCall: async (request, handler) => {\n * // Modify request before calling\n * const modifiedRequest = { ...request, systemPrompt: \"You are helpful\" };\n *\n * try {\n * // Call the model\n * return await handler(modifiedRequest);\n * } catch (error) {\n * // Handle errors and retry with fallback\n * const fallbackRequest = { ...request, model: fallbackModel };\n * return await handler(fallbackRequest);\n * }\n * }\n * ```\n */\n wrapModelCall?: WrapModelCallHook<TSchema, TFullContext>;\n\n /**\n * The function to run before the agent execution starts. This function is called once at the start of the agent invocation.\n * It allows to modify the state of the agent before any model calls or tool executions.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n beforeAgent?: BeforeAgentHook<TSchema, TFullContext>;\n\n /**\n * The function to run before the model call. This function is called before the model is invoked and before the `wrapModelCall` hook.\n * It allows to modify the state of the agent.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n beforeModel?: BeforeModelHook<TSchema, TFullContext>;\n\n /**\n * The function to run after the model call. This function is called after the model is invoked and before any tools are called.\n * It allows to modify the state of the agent after the model is invoked, e.g. to update tool call parameters.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n afterModel?: AfterModelHook<TSchema, TFullContext>;\n\n /**\n * The function to run after the agent execution completes. This function is called once at the end of the agent invocation.\n * It allows to modify the final state of the agent after all model calls and tool executions are complete.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n afterAgent?: AfterAgentHook<TSchema, TFullContext>;\n}\n\n/**\n * Helper type to filter out properties that start with underscore (private properties)\n */\ntype FilterPrivateProps<T> = {\n [K in keyof T as K extends `_${string}` ? never : K]: T[K];\n};\n\n/**\n * Helper type to resolve a MiddlewareTypeConfig from either:\n * - A MiddlewareTypeConfig directly\n * - An AgentMiddleware instance (using `typeof middleware`)\n */\nexport type ResolveMiddlewareTypeConfig<T> = T extends {\n \"~middlewareTypes\"?: infer Types;\n}\n ? Types extends MiddlewareTypeConfig\n ? Types\n : never\n : T extends MiddlewareTypeConfig\n ? T\n : never;\n\n/**\n * Helper type to extract any property from a MiddlewareTypeConfig or AgentMiddleware.\n *\n * @typeParam T - The MiddlewareTypeConfig or AgentMiddleware to extract from\n * @typeParam K - The property key to extract (\"Schema\" | \"ContextSchema\" | \"FullContext\" | \"Tools\" | \"StreamTransformers\")\n */\nexport type InferMiddlewareType<\n T,\n K extends keyof MiddlewareTypeConfig,\n> = ResolveMiddlewareTypeConfig<T>[K];\n\n/**\n * Shorthand helper to extract the Schema type from a MiddlewareTypeConfig or AgentMiddleware.\n */\nexport type InferMiddlewareSchema<T> = InferMiddlewareType<T, \"Schema\">;\n\n/**\n * Shorthand helper to extract the ContextSchema type from a MiddlewareTypeConfig or AgentMiddleware.\n */\nexport type InferMiddlewareContextSchema<T> = InferMiddlewareType<\n T,\n \"ContextSchema\"\n>;\n\n/**\n * Shorthand helper to extract the FullContext type from a MiddlewareTypeConfig or AgentMiddleware.\n */\nexport type InferMiddlewareFullContext<T> = InferMiddlewareType<\n T,\n \"FullContext\"\n>;\n\n/**\n * Shorthand helper to extract the Tools type from a MiddlewareTypeConfig or AgentMiddleware.\n */\nexport type InferMiddlewareToolsFromConfig<T> = InferMiddlewareType<T, \"Tools\">;\n\n/**\n * Shorthand helper to extract the StreamTransformers type from a MiddlewareTypeConfig or AgentMiddleware.\n */\nexport type InferMiddlewareStreamTransformersFromConfig<T> =\n InferMiddlewareType<T, \"StreamTransformers\">;\n\nexport type InferChannelType<T extends AnyAnnotationRoot | InteropZodObject> =\n T extends AnyAnnotationRoot\n ? ToAnnotationRoot<T>[\"State\"]\n : T extends InteropZodObject\n ? InferInteropZodInput<T>\n : {};\n\n/**\n * Helper type to infer the state schema type from a middleware\n * This filters out private properties (those starting with underscore)\n * Supports both Zod schemas (InteropZodObject) and StateSchema from LangGraph\n */\nexport type InferMiddlewareState<T extends AgentMiddleware> =\n T extends AgentMiddleware<infer TSchema, any, any, any, any>\n ? TSchema extends StateSchema<infer TFields>\n ? FilterPrivateProps<InferStateSchemaValue<TFields>>\n : TSchema extends InteropZodObject\n ? FilterPrivateProps<InferInteropZodOutput<TSchema>>\n : TSchema extends StateDefinitionInit\n ? FilterPrivateProps<InferSchemaValue<TSchema>>\n : {}\n : {};\n\n/**\n * Helper type to infer the input state schema type from a middleware (all properties optional)\n * This filters out private properties (those starting with underscore)\n * Supports both Zod schemas (InteropZodObject) and StateSchema from LangGraph\n */\nexport type InferMiddlewareInputState<T extends AgentMiddleware> =\n T extends AgentMiddleware<infer TSchema, any, any, any, any>\n ? TSchema extends StateSchema<infer TFields>\n ? FilterPrivateProps<InferStateSchemaUpdate<TFields>>\n : TSchema extends InteropZodObject\n ? FilterPrivateProps<InferInteropZodInput<TSchema>>\n : TSchema extends StateDefinitionInit\n ? FilterPrivateProps<InferSchemaInput<TSchema>>\n : {}\n : {};\n\n/**\n * Helper type to infer merged state from an array of middleware (just the middleware states)\n */\nexport type InferMiddlewareStates<T extends readonly AnyAgentMiddleware[]> =\n T extends readonly []\n ? {}\n : T extends readonly [infer First, ...infer Rest]\n ? First extends AgentMiddleware\n ? Rest extends readonly AnyAgentMiddleware[]\n ? InferMiddlewareState<First> & InferMiddlewareStates<Rest>\n : InferMiddlewareState<First>\n : {}\n : {};\n\n/**\n * Helper type to infer merged input state from an array of middleware (with optional defaults)\n */\nexport type InferMiddlewareInputStates<\n T extends readonly AnyAgentMiddleware[],\n> = T extends readonly []\n ? {}\n : T extends readonly [infer First, ...infer Rest]\n ? First extends AgentMiddleware\n ? Rest extends readonly AnyAgentMiddleware[]\n ? InferMiddlewareInputState<First> & InferMiddlewareInputStates<Rest>\n : InferMiddlewareInputState<First>\n : {}\n : {};\n\n/**\n * Helper type to infer merged state from an array of middleware (includes built-in state)\n */\nexport type InferMergedState<T extends readonly AnyAgentMiddleware[]> =\n InferMiddlewareStates<T> & AgentBuiltInState;\n\n/**\n * Helper type to infer merged input state from an array of middleware (includes built-in state)\n */\nexport type InferMergedInputState<T extends readonly AnyAgentMiddleware[]> =\n InferMiddlewareInputStates<T> & AgentBuiltInState;\n\n/**\n * Helper type to infer the context schema type from a middleware\n */\nexport type InferMiddlewareContext<T extends AgentMiddleware> =\n T extends AgentMiddleware<any, infer TContextSchema, any, any, any>\n ? TContextSchema extends InteropZodObject\n ? InferInteropZodInput<TContextSchema>\n : {}\n : {};\n\n/**\n * Helper type to infer the input context schema type from a middleware (with optional defaults)\n */\nexport type InferMiddlewareContextInput<T extends AgentMiddleware> =\n T extends AgentMiddleware<any, infer TContextSchema, any, any, any>\n ? TContextSchema extends InteropZodOptional<infer Inner>\n ? InferInteropZodInput<Inner> | undefined\n : TContextSchema extends InteropZodObject\n ? InferInteropZodInput<TContextSchema>\n : {}\n : {};\n\n/**\n * Helper type to infer merged context from an array of middleware\n */\nexport type InferMiddlewareContexts<T extends readonly AnyAgentMiddleware[]> =\n T extends readonly []\n ? {}\n : T extends readonly [infer First, ...infer Rest]\n ? First extends AgentMiddleware\n ? Rest extends readonly AnyAgentMiddleware[]\n ? InferMiddlewareContext<First> & InferMiddlewareContexts<Rest>\n : InferMiddlewareContext<First>\n : {}\n : {};\n\n/**\n * Helper to merge two context types, preserving undefined unions\n */\ntype MergeContextTypes<A, B> = [A] extends [undefined]\n ? [B] extends [undefined]\n ? undefined\n : B | undefined\n : [B] extends [undefined]\n ? A | undefined\n : [A] extends [B]\n ? A\n : [B] extends [A]\n ? B\n : A & B;\n\n/**\n * Helper type to infer merged input context from an array of middleware (with optional defaults)\n */\nexport type InferMiddlewareContextInputs<\n T extends readonly AnyAgentMiddleware[],\n> = T extends readonly []\n ? {}\n : T extends readonly [infer First, ...infer Rest]\n ? First extends AgentMiddleware\n ? Rest extends readonly AnyAgentMiddleware[]\n ? MergeContextTypes<\n InferMiddlewareContextInput<First>,\n InferMiddlewareContextInputs<Rest>\n >\n : InferMiddlewareContextInput<First>\n : {}\n : {};\n\n/**\n * Helper type to extract input type from context schema (with optional defaults)\n */\nexport type InferContextInput<\n ContextSchema extends AnyAnnotationRoot | InteropZodObject,\n> = ContextSchema extends InteropZodObject\n ? InferInteropZodInput<ContextSchema>\n : ContextSchema extends AnyAnnotationRoot\n ? ToAnnotationRoot<ContextSchema>[\"State\"]\n : {};\n\nexport type ToAnnotationRoot<A extends StateDefinitionInit> =\n A extends AnyAnnotationRoot\n ? A\n : A extends InteropZodObject\n ? InteropZodToStateDefinition<A>\n : never;\n\nexport type InferSchemaValue<A extends StateDefinitionInit | undefined> = [\n A,\n] extends [undefined]\n ? {}\n : A extends StateSchema<infer TFields>\n ? InferStateSchemaValue<TFields>\n : A extends InteropZodObject\n ? InferInteropZodOutput<A>\n : A extends AnyAnnotationRoot\n ? A[\"State\"]\n : {};\n\nexport type InferSchemaInput<A extends StateDefinitionInit | undefined> = [\n A,\n] extends [undefined]\n ? {}\n : A extends StateSchema<infer TFields>\n ? InferStateSchemaUpdate<TFields>\n : A extends InteropZodObject\n ? InferInteropZodInput<A>\n : A extends AnyAnnotationRoot\n ? A[\"Update\"]\n : {};\n","import type {\n InteropZodObject,\n InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\nimport type {\n StateDefinitionInit,\n StreamTransformer,\n} from \"@langchain/langgraph\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport {\n MIDDLEWARE_BRAND,\n type AgentMiddleware,\n type WrapToolCallHook,\n type WrapModelCallHook,\n type BeforeAgentHook,\n type BeforeModelHook,\n type AfterModelHook,\n type AfterAgentHook,\n} from \"./middleware/types.js\";\n\n/**\n * Creates a middleware instance with automatic schema inference.\n *\n * @param config - Middleware configuration\n * @param config.name - The name of the middleware\n * @param config.stateSchema - The schema of the middleware state\n * @param config.contextSchema - The schema of the middleware context\n * @param config.wrapModelCall - The function to wrap model invocation\n * @param config.wrapToolCall - The function to wrap tool invocation\n * @param config.beforeModel - The function to run before the model call\n * @param config.afterModel - The function to run after the model call\n * @param config.beforeAgent - The function to run before the agent execution starts\n * @param config.afterAgent - The function to run after the agent execution completes\n * @param config.tools - Additional tools registered by the middleware\n * @param config.streamTransformers - Stream transformer factories registered by the middleware\n * @returns A middleware instance\n *\n * @example Using Zod schema\n * ```ts\n * const authMiddleware = createMiddleware({\n * name: \"AuthMiddleware\",\n * stateSchema: z.object({\n * isAuthenticated: z.boolean().default(false),\n * }),\n * contextSchema: z.object({\n * userId: z.string(),\n * }),\n * beforeModel: async (state, runtime) => {\n * if (!state.isAuthenticated) {\n * throw new Error(\"Not authenticated\");\n * }\n * },\n * });\n * ```\n *\n * @example Using StateSchema\n * ```ts\n * import { StateSchema, ReducedValue } from \"@langchain/langgraph\";\n *\n * const historyMiddleware = createMiddleware({\n * name: \"HistoryMiddleware\",\n * stateSchema: new StateSchema({\n * count: z.number().default(0),\n * history: new ReducedValue(\n * z.array(z.string()).default(() => []),\n * { inputSchema: z.string(), reducer: (current, next) => [...current, next] }\n * ),\n * }),\n * beforeModel: async (state, runtime) => {\n * return { count: state.count + 1 };\n * },\n * });\n * ```\n */\nexport function createMiddleware<\n TSchema extends StateDefinitionInit | undefined = undefined,\n TContextSchema extends InteropZodObject | undefined = undefined,\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n () => StreamTransformer<any>\n > = readonly [],\n>(config: {\n /**\n * The name of the middleware\n */\n name: string;\n /**\n * The schema of the middleware state. Middleware state is persisted between multiple invocations. It can be either:\n * - A Zod object (InteropZodObject)\n * - A StateSchema from LangGraph (supports ReducedValue, UntrackedValue)\n * - An AnnotationRoot\n * - Undefined\n */\n stateSchema?: TSchema;\n /**\n * The schema of the middleware context. Middleware context is read-only and not persisted between multiple invocations. It can be either:\n * - A Zod object\n * - A Zod optional object\n * - A Zod default object\n * - Undefined\n */\n contextSchema?: TContextSchema;\n /**\n * Additional tools registered by the middleware.\n */\n tools?: TTools;\n /**\n * Stream transformer factories registered by the middleware.\n * Merged with `createAgent({ streamTransformers })` when the agent compiles.\n */\n streamTransformers?: TStreamTransformers;\n /**\n * Wraps tool execution with custom logic. This allows you to:\n * - Modify tool call parameters before execution\n * - Handle errors and retry with different parameters\n * - Post-process tool results\n * - Implement caching, logging, authentication, or other cross-cutting concerns\n * - Return Command objects for advanced control flow\n *\n * The handler receives a ToolCallRequest containing the tool call, state, and runtime,\n * along with a handler function to execute the actual tool.\n *\n * @param request - The tool call request containing toolCall, state, and runtime.\n * @param handler - The function that executes the tool. Call this with a ToolCallRequest to get the result.\n * @returns The tool result as a ToolMessage or a Command for advanced control flow.\n *\n * @example\n * ```ts\n * wrapToolCall: async (request, handler) => {\n * console.log(`Calling tool: ${request.tool.name}`);\n * console.log(`Tool description: ${request.tool.description}`);\n *\n * try {\n * // Execute the tool\n * const result = await handler(request);\n * console.log(`Tool ${request.tool.name} succeeded`);\n * return result;\n * } catch (error) {\n * console.error(`Tool ${request.tool.name} failed:`, error);\n * // Could return a custom error message or retry\n * throw error;\n * }\n * }\n * ```\n *\n * @example Authentication\n * ```ts\n * wrapToolCall: async (request, handler) => {\n * // Check if user is authorized for this tool\n * if (!request.runtime.context.isAuthorized(request.tool.name)) {\n * return new ToolMessage({\n * content: \"Unauthorized to call this tool\",\n * tool_call_id: request.toolCall.id,\n * });\n * }\n * return handler(request);\n * }\n * ```\n */\n wrapToolCall?: WrapToolCallHook<\n TSchema,\n NormalizeContextSchema<TContextSchema>\n >;\n\n /**\n * Wraps the model invocation with custom logic. This allows you to:\n * - Modify the request before calling the model\n * - Handle errors and retry with different parameters\n * - Post-process the response\n * - Implement custom caching, logging, or other cross-cutting concerns\n *\n * The request parameter contains: model, messages, systemPrompt, tools, state, and runtime.\n *\n * @param request - The model request containing all the parameters needed.\n * @param handler - The function that invokes the model. Call this with a ModelRequest to get the response.\n * @returns The response from the model (or a modified version).\n *\n * @example\n * ```ts\n * wrapModelCall: async (request, handler) => {\n * // Modify request before calling\n * const modifiedRequest = { ...request, systemPrompt: \"You are helpful\" };\n *\n * try {\n * // Call the model\n * return await handler(modifiedRequest);\n * } catch (error) {\n * // Handle errors and retry with fallback\n * const fallbackRequest = { ...request, model: fallbackModel };\n * return await handler(fallbackRequest);\n * }\n * }\n * ```\n */\n wrapModelCall?: WrapModelCallHook<\n TSchema,\n NormalizeContextSchema<TContextSchema>\n >;\n /**\n * The function to run before the agent execution starts. This function is called once at the start of the agent invocation.\n * It allows to modify the state of the agent before any model calls or tool executions.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n beforeAgent?: BeforeAgentHook<\n TSchema,\n NormalizeContextSchema<TContextSchema>\n >;\n\n /**\n * The function to run before the model call. This function is called before the model is invoked and before the `wrapModelCall` hook.\n * It allows to modify the state of the agent.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n beforeModel?: BeforeModelHook<\n TSchema,\n NormalizeContextSchema<TContextSchema>\n >;\n\n /**\n * The function to run after the model call. This function is called after the model is invoked and before any tools are called.\n * It allows to modify the state of the agent after the model is invoked, e.g. to update tool call parameters.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n afterModel?: AfterModelHook<TSchema, NormalizeContextSchema<TContextSchema>>;\n\n /**\n * The function to run after the agent execution completes. This function is called once at the end of the agent invocation.\n * It allows to modify the final state of the agent after all model calls and tool executions are complete.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n afterAgent?: AfterAgentHook<TSchema, NormalizeContextSchema<TContextSchema>>;\n}): AgentMiddleware<\n TSchema,\n TContextSchema,\n NormalizeContextSchema<TContextSchema>,\n TTools,\n TStreamTransformers\n> {\n const middleware: AgentMiddleware<\n TSchema,\n TContextSchema,\n NormalizeContextSchema<TContextSchema>,\n TTools,\n TStreamTransformers\n > = {\n [MIDDLEWARE_BRAND]: true as const,\n name: config.name,\n stateSchema: config.stateSchema,\n contextSchema: config.contextSchema,\n wrapToolCall: config.wrapToolCall,\n wrapModelCall: config.wrapModelCall,\n beforeAgent: config.beforeAgent,\n beforeModel: config.beforeModel,\n afterModel: config.afterModel,\n afterAgent: config.afterAgent,\n tools: config.tools,\n streamTransformers: config.streamTransformers,\n };\n\n return middleware;\n}\n\ntype NormalizeContextSchema<\n TContextSchema extends InteropZodObject | undefined = undefined,\n> = TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : unknown;\n","export type ConstructorRecord = {\n lc: 2;\n type: \"constructor\";\n id: unknown;\n method?: unknown;\n args?: unknown;\n};\n\nexport const TASKS = \"__pregel_tasks\";\nexport const ERROR = \"__error__\";\nexport const SCHEDULED = \"__scheduled__\";\nexport const INTERRUPT = \"__interrupt__\";\nexport const RESUME = \"__resume__\";\n\n/**\n * Snapshot blob for a `DeltaChannel` with finite snapshot frequency.\n *\n * Stored directly in a checkpoint's `channel_values` in place of the full\n * accumulated value. The ancestor walk in\n * {@link BaseCheckpointSaver.getDeltaChannelHistory} terminates when it\n * encounters a populated `channel_values` entry for a channel; a\n * `DeltaSnapshot` value is the materialized state at that ancestor, so the\n * channel reconstructs directly from `.value` without replaying earlier\n * writes.\n *\n * @remarks Beta. The on-disk representation may change in future releases.\n */\nexport class DeltaSnapshot<Value = unknown> {\n /** Marker used for structural detection across module/realm boundaries. */\n lg_name = \"DeltaSnapshot\" as const;\n\n value: Value;\n\n constructor(value: Value) {\n this.value = value;\n }\n}\n\n/**\n * Structural type guard for {@link DeltaSnapshot}. Uses the `lg_name` marker\n * so it survives serialization round-trips and cross-package duplication.\n */\nexport function isDeltaSnapshot<Value = unknown>(\n value: unknown\n): value is DeltaSnapshot<Value> {\n return (\n value != null &&\n typeof value === \"object\" &&\n (value as { lg_name?: string }).lg_name === \"DeltaSnapshot\"\n );\n}\n\n// Mirrors BaseChannel in \"@langchain/langgraph\"\nexport interface ChannelProtocol<\n ValueType = unknown,\n UpdateType = unknown,\n CheckpointType = unknown,\n> {\n ValueType: ValueType;\n\n UpdateType: UpdateType;\n\n /**\n * The name of the channel.\n */\n lc_graph_name: string;\n\n /**\n * Return a new identical channel, optionally initialized from a checkpoint.\n * Can be thought of as a \"restoration\" from a checkpoint which is a \"snapshot\" of the channel's state.\n *\n * @param {CheckpointType | undefined} checkpoint\n * @returns {this}\n */\n fromCheckpoint(checkpoint?: CheckpointType): this;\n\n /**\n * Update the channel's value with the given sequence of updates.\n * The order of the updates in the sequence is arbitrary.\n *\n * @throws {InvalidUpdateError} if the sequence of updates is invalid.\n * @param {Array<UpdateType>} values\n * @returns {void}\n */\n update(values: UpdateType[]): void;\n\n /**\n * Return the current value of the channel.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet).\n * @returns {ValueType}\n */\n get(): ValueType;\n\n /**\n * Return a string representation of the channel's current state.\n *\n * @throws {EmptyChannelError} if the channel is empty (never updated yet), or doesn't support checkpoints.\n * @returns {CheckpointType | undefined}\n */\n checkpoint(): CheckpointType | undefined;\n}\n\n// Mirrors SendInterface in \"@langchain/langgraph\"\nexport interface SendProtocol {\n node: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n args: any;\n // Optional per-task timeout policy. Structural to avoid a dependency on the\n // langgraph package; mirrors `TimeoutPolicy` in \"@langchain/langgraph\".\n timeout?: {\n runTimeout?: number;\n idleTimeout?: number;\n refreshOn?: \"auto\" | \"heartbeat\";\n };\n}\n","import type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { SerializerProtocol } from \"./serde/base.js\";\nimport { uuid6 } from \"./id.js\";\nimport type {\n PendingWrite,\n CheckpointPendingWrite,\n CheckpointMetadata,\n DeltaChannelHistory,\n} from \"./types.js\";\nimport { ERROR, INTERRUPT, RESUME, SCHEDULED } from \"./serde/types.js\";\nimport { JsonPlusSerializer } from \"./serde/jsonplus.js\";\n\n/** @inline */\ntype ChannelVersion = number | string;\n\nexport type ChannelVersions = Record<string, ChannelVersion>;\n\nexport interface Checkpoint<\n N extends string = string,\n C extends string = string,\n> {\n /**\n * The version of the checkpoint format. Currently 4\n */\n v: number;\n /**\n * Checkpoint ID {uuid6}\n */\n id: string;\n /**\n * Timestamp {new Date().toISOString()}\n */\n ts: string;\n /**\n * @default {}\n */\n channel_values: Record<C, unknown>;\n /**\n * @default {}\n */\n channel_versions: Record<C, ChannelVersion>;\n /**\n * @default {}\n */\n versions_seen: Record<N, Record<C, ChannelVersion>>;\n}\n\nexport interface ReadonlyCheckpoint extends Readonly<Checkpoint> {\n readonly channel_values: Readonly<Record<string, unknown>>;\n readonly channel_versions: Readonly<Record<string, ChannelVersion>>;\n readonly versions_seen: Readonly<\n Record<string, Readonly<Record<string, ChannelVersion>>>\n >;\n}\n\nexport function deepCopy<T>(obj: T): T {\n if (typeof obj !== \"object\" || obj === null) {\n return obj;\n }\n\n const newObj = Array.isArray(obj) ? [] : {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n (newObj as Record<PropertyKey, unknown>)[key] = deepCopy(\n (obj as Record<string, unknown>)[key]\n );\n }\n }\n\n return newObj as T;\n}\n\n/** @hidden */\nexport function emptyCheckpoint(): Checkpoint {\n return {\n v: 4,\n id: uuid6(0),\n ts: new Date().toISOString(),\n channel_values: {},\n channel_versions: {},\n versions_seen: {},\n };\n}\n\n/** @hidden */\nexport function copyCheckpoint(checkpoint: ReadonlyCheckpoint): Checkpoint {\n return {\n v: checkpoint.v,\n id: checkpoint.id,\n ts: checkpoint.ts,\n channel_values: { ...(checkpoint.channel_values ?? {}) },\n channel_versions: { ...(checkpoint.channel_versions ?? {}) },\n versions_seen: deepCopy(checkpoint.versions_seen ?? {}),\n };\n}\n\nexport interface CheckpointTuple {\n config: RunnableConfig;\n checkpoint: Checkpoint;\n metadata?: CheckpointMetadata;\n parentConfig?: RunnableConfig;\n pendingWrites?: CheckpointPendingWrite[];\n}\n\nexport type CheckpointListOptions = {\n limit?: number;\n before?: RunnableConfig;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n filter?: Record<string, any>;\n};\n\nexport abstract class BaseCheckpointSaver<V extends string | number = number> {\n serde: SerializerProtocol = new JsonPlusSerializer();\n\n constructor(serde?: SerializerProtocol) {\n this.serde = serde || this.serde;\n }\n\n /**\n * Prevent `JSON.stringify` from traversing backend clients (e.g. pg Pool\n * timers) when a checkpointer is present in runnable `configurable`.\n */\n toJSON(): string {\n return `[${this.constructor.name}]`;\n }\n\n async get(config: RunnableConfig): Promise<Checkpoint | undefined> {\n const value = await this.getTuple(config);\n return value ? value.checkpoint : undefined;\n }\n\n abstract getTuple(\n config: RunnableConfig\n ): Promise<CheckpointTuple | undefined>;\n\n abstract list(\n config: RunnableConfig,\n options?: CheckpointListOptions\n ): AsyncGenerator<CheckpointTuple>;\n\n abstract put(\n config: RunnableConfig,\n checkpoint: Checkpoint,\n metadata: CheckpointMetadata,\n newVersions: ChannelVersions\n ): Promise<RunnableConfig>;\n\n /**\n * Store intermediate writes linked to a checkpoint.\n */\n abstract putWrites(\n config: RunnableConfig,\n writes: PendingWrite[],\n taskId: string\n ): Promise<void>;\n\n /**\n * Delete all checkpoints and writes associated with a specific thread ID.\n * @param threadId The thread ID whose checkpoints should be deleted.\n */\n abstract deleteThread(threadId: string): Promise<void>;\n\n /**\n * Walk the parent chain returning per-channel writes + seed, used to\n * reconstruct `DeltaChannel` state from `checkpoint_writes`.\n *\n * For each requested channel, walks ancestors of the checkpoint identified\n * by `config` (following `parentConfig`) and accumulates the pending writes\n * for that channel. The walk terminates per-channel at the nearest ancestor\n * whose `channel_values[ch]` is populated; that value is returned as `seed`.\n * If the walk reaches the root without finding a stored value, `seed` is\n * omitted from that channel's entry — the consumer treats the absence as\n * \"start empty\".\n *\n * Walks the parent chain (not `list({ before })`): for forked threads, only\n * on-path ancestors contribute.\n *\n * The default implementation walks `getTuple` + `parentConfig` once for all\n * channels — each ancestor visited once, not once per channel. Savers with\n * direct storage access (e.g. `MemorySaver`) override for performance; the\n * return contract is fixed here.\n *\n * @remarks Beta. The signature, return shape, and interaction with\n * `DeltaSnapshot` blobs may change. Override at your own risk; the default\n * implementation will continue to work against the public\n * `BaseCheckpointSaver` contract.\n *\n * @param options.config Configuration identifying the target checkpoint.\n * @param options.channels Channel names to walk for. Empty → empty mapping.\n * @returns Per-channel {@link DeltaChannelHistory} for every requested name.\n */\n async getDeltaChannelHistory(options: {\n config: RunnableConfig;\n channels: string[];\n }): Promise<Record<string, DeltaChannelHistory>> {\n const { config, channels } = options;\n if (channels.length === 0) return {};\n\n const collectedByCh: Record<string, CheckpointPendingWrite[]> = {};\n const seedByCh: Record<string, unknown> = {};\n const remaining = new Set(channels);\n for (const ch of channels) collectedByCh[ch] = [];\n\n const targetTuple = await this.getTuple(config);\n let cursorConfig: RunnableConfig | undefined = targetTuple?.parentConfig;\n\n while (cursorConfig != null && remaining.size > 0) {\n const tup: CheckpointTuple | undefined =\n await this.getTuple(cursorConfig);\n if (tup === undefined) break;\n if (tup.pendingWrites && tup.pendingWrites.length > 0) {\n // DeltaChannel reconstruction must replay concurrent same-superstep\n // writes in the canonical (task_id, idx) order that live execution uses\n // (see `_applyWrites`), or the reconstructed value can diverge from the\n // live one. Group per channel and stable-sort by task id: a stable sort\n // keeps each task's writes in their stored `idx` order, making the\n // result independent of how a saver returns `pendingWrites`.\n const perChannel: Record<string, CheckpointPendingWrite[]> = {};\n for (const write of tup.pendingWrites) {\n const ch = write[1];\n if (remaining.has(ch)) (perChannel[ch] ??= []).push(write);\n }\n for (const ch of Object.keys(perChannel)) {\n const block = perChannel[ch];\n block.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));\n // Pushed reversed so the final `.reverse()` below yields oldest→newest\n // checkpoints with each checkpoint's writes ascending by (task_id, idx).\n for (let i = block.length - 1; i >= 0; i -= 1) {\n collectedByCh[ch].push(block[i]);\n }\n }\n }\n for (const ch of Array.from(remaining)) {\n if (\n Object.prototype.hasOwnProperty.call(\n tup.checkpoint.channel_values,\n ch\n )\n ) {\n seedByCh[ch] = tup.checkpoint.channel_values[ch];\n remaining.delete(ch);\n }\n }\n cursorConfig = tup.parentConfig;\n }\n\n const result: Record<string, DeltaChannelHistory> = {};\n for (const ch of channels) {\n const entry: DeltaChannelHistory = {\n writes: collectedByCh[ch].slice().reverse(),\n };\n if (Object.prototype.hasOwnProperty.call(seedByCh, ch)) {\n entry.seed = seedByCh[ch];\n }\n result[ch] = entry;\n }\n return result;\n }\n\n /**\n * Generate the next version ID for a channel.\n *\n * Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,\n * as long as they are monotonically increasing.\n */\n getNextVersion(current: V | undefined): V {\n if (typeof current === \"string\") {\n throw new Error(\"Please override this method to use string versions.\");\n }\n return (\n current !== undefined && typeof current === \"number\" ? current + 1 : 1\n ) as V;\n }\n}\n\nexport function compareChannelVersions(\n a: ChannelVersion,\n b: ChannelVersion\n): number {\n if (typeof a === \"number\" && typeof b === \"number\") {\n return Math.sign(a - b);\n }\n\n return String(a).localeCompare(String(b));\n}\n\nexport function maxChannelVersion(\n ...versions: ChannelVersion[]\n): ChannelVersion {\n return versions.reduce((max, version, idx) => {\n if (idx === 0) return version;\n return compareChannelVersions(max, version) >= 0 ? max : version;\n });\n}\n\n/**\n * Mapping from error type to error index.\n * Regular writes just map to their index in the list of writes being saved.\n * Special writes (e.g. errors) map to negative indices, to avoid those writes from\n * conflicting with regular writes.\n * Each Checkpointer implementation should use this mapping in put_writes.\n */\nexport const WRITES_IDX_MAP: Record<string, number> = {\n [ERROR]: -1,\n [SCHEDULED]: -2,\n [INTERRUPT]: -3,\n [RESUME]: -4,\n};\n\n/**\n * Metadata keys that are LangGraph's internal framework bookkeeping and\n * should not be surfaced as user-meaningful metadata.\n *\n * Consumed by stream handlers (e.g. the `tasks` debug stream) to drop\n * framework keys — which are redundant with a task's own fields and\n * namespace — while keeping keys like `lc_agent_name`, `ls_integration`,\n * and user-supplied metadata.\n */\nexport const EXCLUDED_METADATA_KEYS: ReadonlySet<string> = new Set([\n \"thread_id\",\n \"checkpoint_id\",\n \"checkpoint_ns\",\n \"checkpoint_map\",\n \"langgraph_step\",\n \"langgraph_node\",\n \"langgraph_triggers\",\n \"langgraph_path\",\n \"langgraph_checkpoint_ns\",\n]);\n\nexport function getCheckpointId(config: RunnableConfig): string {\n return (\n config.configurable?.checkpoint_id || config.configurable?.thread_ts || \"\"\n );\n}\n","/* oxlint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod/v3\";\nimport { AIMessage, ToolMessage, ToolCall } from \"@langchain/core/messages\";\nimport {\n InferInteropZodInput,\n interopParse,\n} from \"@langchain/core/utils/types\";\nimport { interrupt } from \"@langchain/langgraph\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport type { AgentBuiltInState, Runtime } from \"../runtime.js\";\nimport type { JumpToTarget } from \"../constants.js\";\nimport type { ToolCallRequest } from \"./types.js\";\n\nconst WhenFunctionSchema = z\n .function()\n .args(z.custom<ToolCallRequest<AgentBuiltInState>>()) // request\n .returns(z.union([z.boolean(), z.promise(z.boolean())]));\n\n/**\n * Predicate controlling whether a given tool call triggers an interrupt.\n *\n * Receives a {@link ToolCallRequest} and returns `true` to interrupt or `false`\n * to auto-approve the tool call.\n *\n * The request is constructed with `tool` set to `undefined` and `runtime` set to\n * the node-level {@link Runtime}, so it reflects the batch (`afterModel`) context\n * rather than a per-call tool execution.\n *\n * @param request - The tool call request being evaluated\n * @returns `true` to interrupt for the tool call, `false` to auto-approve it.\n * May also return a promise resolving to a boolean.\n *\n * @example\n * ```typescript\n * import { type WhenPredicate } from \"langchain\";\n *\n * // Only interrupt delete_file calls targeting /etc\n * const when: WhenPredicate = (request) =>\n * String(request.toolCall.args.path ?? \"\").startsWith(\"/etc\");\n * ```\n */\nexport type WhenPredicate = z.infer<typeof WhenFunctionSchema>;\n\nconst DescriptionFunctionSchema = z\n .function()\n .args(\n z.custom<ToolCall>(), // toolCall\n z.custom<AgentBuiltInState>(), // state\n z.custom<Runtime<unknown>>() // runtime\n )\n .returns(z.union([z.string(), z.promise(z.string())]));\n\n/**\n * Function type that dynamically generates a description for a tool call approval request.\n *\n * @param toolCall - The tool call being reviewed\n * @param state - The current agent state\n * @param runtime - The agent runtime context\n * @returns A string description or Promise that resolves to a string description\n *\n * @example\n * ```typescript\n * import { type DescriptionFactory, type ToolCall } from \"langchain\";\n *\n * const descriptionFactory: DescriptionFactory = (toolCall, state, runtime) => {\n * return `Please review: ${toolCall.name}(${JSON.stringify(toolCall.args)})`;\n * };\n * ```\n */\nexport type DescriptionFactory = z.infer<typeof DescriptionFunctionSchema>;\n\n/**\n * The type of decision a human can make.\n */\nconst ALLOWED_DECISIONS = [\"approve\", \"edit\", \"reject\"] as const;\nconst DecisionType = z.enum(ALLOWED_DECISIONS);\nexport type DecisionType = z.infer<typeof DecisionType>;\n\nconst InterruptOnConfigSchema = z.object({\n /**\n * The decisions that are allowed for this action.\n */\n allowedDecisions: z.array(DecisionType),\n /**\n * The description attached to the request for human input.\n * Can be either:\n * - A static string describing the approval request\n * - A callable that dynamically generates the description based on agent state,\n * runtime, and tool call information\n *\n * @example\n * Static string description\n * ```typescript\n * import type { InterruptOnConfig } from \"langchain\";\n *\n * const config: InterruptOnConfig = {\n * allowedDecisions: [\"approve\", \"reject\"],\n * description: \"Please review this tool execution\"\n * };\n * ```\n *\n * @example\n * Dynamic callable description\n * ```typescript\n * import type {\n * AgentBuiltInState,\n * Runtime,\n * DescriptionFactory,\n * ToolCall,\n * InterruptOnConfig\n * } from \"langchain\";\n *\n * const formatToolDescription: DescriptionFactory = (\n * toolCall: ToolCall,\n * state: AgentBuiltInState,\n * runtime: Runtime<unknown>\n * ) => {\n * return `Tool: ${toolCall.name}\\nArguments:\\n${JSON.stringify(toolCall.args, null, 2)}`;\n * };\n *\n * const config: InterruptOnConfig = {\n * allowedDecisions: [\"approve\", \"edit\"],\n * description: formatToolDescription\n * };\n * ```\n */\n description: z.union([z.string(), DescriptionFunctionSchema]).optional(),\n /**\n * JSON schema for the arguments associated with the action, if edits are allowed.\n */\n argsSchema: z.record(z.any()).optional(),\n /**\n * Optional predicate controlling whether to interrupt for a given tool call.\n *\n * Receives a {@link ToolCallRequest} and returns `true` to interrupt or\n * `false` to auto-approve the tool call.\n *\n * The request is constructed with `tool` set to `undefined` and `runtime` set\n * to the node-level {@link Runtime}, so `request.tool` is not available.\n *\n * @example\n * ```typescript\n * import type { InterruptOnConfig } from \"langchain\";\n *\n * // Only interrupt delete_file calls targeting /etc\n * const config: InterruptOnConfig = {\n * allowedDecisions: [\"approve\", \"reject\"],\n * when: (request) =>\n * String(request.toolCall.args.path ?? \"\").startsWith(\"/etc\"),\n * };\n * ```\n */\n when: WhenFunctionSchema.optional(),\n});\nexport type InterruptOnConfig = z.input<typeof InterruptOnConfigSchema>;\n\n/**\n * Represents an action with a name and arguments.\n */\nexport interface Action {\n /**\n * The type or name of action being requested (e.g., \"add_numbers\").\n */\n name: string;\n /**\n * Key-value pairs of arguments needed for the action (e.g., {\"a\": 1, \"b\": 2}).\n */\n args: Record<string, any>;\n}\n\n/**\n * Represents an action request with a name, arguments, and description.\n */\nexport interface ActionRequest {\n /**\n * The name of the action being requested.\n */\n name: string;\n /**\n * Key-value pairs of arguments needed for the action (e.g., {\"a\": 1, \"b\": 2}).\n */\n args: Record<string, any>;\n /**\n * The description of the action to be reviewed.\n */\n description?: string;\n}\n\n/**\n * Policy for reviewing a HITL request.\n */\nexport interface ReviewConfig {\n /**\n * Name of the action associated with this review configuration.\n */\n actionName: string;\n /**\n * The decisions that are allowed for this request.\n */\n allowedDecisions: DecisionType[];\n /**\n * JSON schema for the arguments associated with the action, if edits are allowed.\n */\n argsSchema?: Record<string, any>;\n}\n\n/**\n * Request for human feedback on a sequence of actions requested by a model.\n *\n * @example\n * ```ts\n * const hitlRequest: HITLRequest = {\n * actionRequests: [\n * { name: \"send_email\", args: { to: \"user@example.com\", subject: \"Hello\" } }\n * ],\n * reviewConfigs: [\n * {\n * actionName: \"send_email\",\n * allowedDecisions: [\"approve\", \"edit\", \"reject\"],\n * description: \"Please review the email before sending\"\n * }\n * ]\n * };\n * const response = interrupt(hitlRequest);\n * ```\n */\nexport interface HITLRequest {\n /**\n * A list of agent actions for human review.\n */\n actionRequests: ActionRequest[];\n /**\n * Review configuration for all possible actions.\n */\n reviewConfigs: ReviewConfig[];\n}\n\n/**\n * Response when a human approves the action.\n */\nexport interface ApproveDecision {\n type: \"approve\";\n}\n\n/**\n * Response when a human edits the action.\n */\nexport interface EditDecision {\n type: \"edit\";\n /**\n * Edited action for the agent to perform.\n * Ex: for a tool call, a human reviewer can edit the tool name and args.\n */\n editedAction: Action;\n}\n\n/**\n * Response when a human rejects the action.\n */\nexport interface RejectDecision {\n type: \"reject\";\n /**\n * The message sent to the model explaining why the action was rejected.\n */\n message?: string;\n}\n\n/**\n * Union of all possible decision types.\n */\nexport type Decision = ApproveDecision | EditDecision | RejectDecision;\n\n/**\n * Response payload for a HITLRequest.\n */\nexport interface HITLResponse {\n /**\n * The decisions made by the human.\n */\n decisions: Decision[];\n}\n\nconst contextSchema = z.object({\n /**\n * Mapping of tool name to allowed reviewer responses.\n * If a tool doesn't have an entry, it's auto-approved by default.\n *\n * - `true` -> pause for approval and allow approve/edit/reject decisions\n * - `false` -> auto-approve (no human review)\n * - `InterruptOnConfig` -> explicitly specify which decisions are allowed for this tool\n */\n interruptOn: z\n .record(z.union([z.boolean(), InterruptOnConfigSchema]))\n .optional(),\n /**\n * Prefix used when constructing human-facing approval messages.\n * Provides context about the tool call being reviewed; does not change the underlying action.\n *\n * Note: This prefix is only applied for tools that do not provide a custom\n * `description` via their {@link InterruptOnConfig}. If a tool specifies a custom\n * `description`, that per-tool text is used and this prefix is ignored.\n */\n descriptionPrefix: z.string().default(\"Tool execution requires approval\"),\n});\nexport type HumanInTheLoopMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Creates a Human-in-the-Loop (HITL) middleware for tool approval and oversight.\n *\n * This middleware intercepts tool calls made by an AI agent and provides human oversight\n * capabilities before execution. It enables selective approval workflows where certain tools\n * require human intervention while others can execute automatically.\n *\n * A invocation result that has been interrupted by the middleware will have a `__interrupt__`\n * property that contains the interrupt request.\n *\n * ```ts\n * import { type HITLRequest, type HITLResponse } from \"langchain\";\n * import { type Interrupt } from \"langchain\";\n *\n * const result = await agent.invoke(request);\n * const interruptRequest = result.__interrupt__?.[0] as Interrupt<HITLRequest>;\n *\n * // Examine the action requests and review configs\n * const actionRequests = interruptRequest.value.actionRequests;\n * const reviewConfigs = interruptRequest.value.reviewConfigs;\n *\n * // Create decisions for each action\n * const resume: HITLResponse = {\n * decisions: actionRequests.map((action, i) => {\n * if (action.name === \"calculator\") {\n * return { type: \"approve\" };\n * } else if (action.name === \"write_file\") {\n * return {\n * type: \"edit\",\n * editedAction: { name: \"write_file\", args: { filename: \"safe.txt\", content: \"Safe content\" } }\n * };\n * }\n * return { type: \"reject\", message: \"Action not allowed\" };\n * })\n * };\n *\n * // Resume with decisions\n * await agent.invoke(new Command({ resume }), config);\n * ```\n *\n * ## Features\n *\n * - **Selective Tool Approval**: Configure which tools require human approval\n * - **Multiple Decision Types**: Approve, edit, or reject tool calls\n * - **Asynchronous Workflow**: Uses LangGraph's interrupt mechanism for non-blocking approval\n * - **Custom Approval Messages**: Provide context-specific descriptions for approval requests\n *\n * ## Decision Types\n *\n * When a tool requires approval, the human operator can respond with:\n * - `approve`: Execute the tool with original arguments\n * - `edit`: Modify the tool name and/or arguments before execution\n * - `reject`: Provide a manual response instead of executing the tool\n *\n * @param options - Configuration options for the middleware\n * @param options.interruptOn - Per-tool configuration mapping tool names to their settings\n * @param options.interruptOn[toolName].allowedDecisions - Array of decision types allowed for this tool (e.g., [\"approve\", \"edit\", \"reject\"])\n * @param options.interruptOn[toolName].description - Custom approval message for the tool. Can be either a static string or a callable that dynamically generates the description based on agent state, runtime, and tool call information\n * @param options.interruptOn[toolName].argsSchema - JSON schema for the arguments associated with the action, if edits are allowed\n * @param options.interruptOn[toolName].when - Optional predicate that dynamically controls whether a tool call triggers an interrupt. Returns `true` to interrupt or `false` to auto-approve the tool call.\n * @param options.descriptionPrefix - Default prefix for approval messages (default: \"Tool execution requires approval\"). Only used for tools that do not define a custom `description` in their InterruptOnConfig.\n *\n * @returns A middleware instance that can be passed to `createAgent`\n *\n * @example\n * Basic usage with selective tool approval\n * ```typescript\n * import { humanInTheLoopMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * const hitlMiddleware = humanInTheLoopMiddleware({\n * interruptOn: {\n * // Interrupt write_file tool and allow edits or approvals\n * \"write_file\": {\n * allowedDecisions: [\"approve\", \"edit\"],\n * description: \"⚠️ File write operation requires approval\"\n * },\n * // Auto-approve read_file tool\n * \"read_file\": false\n * }\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4\",\n * tools: [writeFileTool, readFileTool],\n * middleware: [hitlMiddleware]\n * });\n * ```\n *\n * @example\n * Handling approval requests\n * ```typescript\n * import { type HITLRequest, type HITLResponse, type Interrupt } from \"langchain\";\n * import { Command } from \"@langchain/langgraph\";\n *\n * // Initial agent invocation\n * const result = await agent.invoke({\n * messages: [new HumanMessage(\"Write 'Hello' to output.txt\")]\n * }, config);\n *\n * // Check if agent is paused for approval\n * if (result.__interrupt__) {\n * const interruptRequest = result.__interrupt__?.[0] as Interrupt<HITLRequest>;\n *\n * // Show tool call details to user\n * console.log(\"Actions:\", interruptRequest.value.actionRequests);\n * console.log(\"Review configs:\", interruptRequest.value.reviewConfigs);\n *\n * // Resume with approval\n * const resume: HITLResponse = {\n * decisions: [{ type: \"approve\" }]\n * };\n * await agent.invoke(\n * new Command({ resume }),\n * config\n * );\n * }\n * ```\n *\n * @example\n * Different decision types\n * ```typescript\n * import { type HITLResponse } from \"langchain\";\n *\n * // Approve the tool call as-is\n * const resume: HITLResponse = {\n * decisions: [{ type: \"approve\" }]\n * };\n *\n * // Edit the tool arguments\n * const resume: HITLResponse = {\n * decisions: [{\n * type: \"edit\",\n * editedAction: { name: \"write_file\", args: { filename: \"safe.txt\", content: \"Modified\" } }\n * }]\n * };\n *\n * // Reject with feedback\n * const resume: HITLResponse = {\n * decisions: [{\n * type: \"reject\",\n * message: \"File operation not allowed in demo mode\"\n * }]\n * };\n * ```\n *\n * @example\n * Production use case with database operations\n * ```typescript\n * const hitlMiddleware = humanInTheLoopMiddleware({\n * interruptOn: {\n * \"execute_sql\": {\n * allowedDecisions: [\"approve\", \"edit\", \"reject\"],\n * description: \"🚨 SQL query requires DBA approval\\nPlease review for safety and performance\"\n * },\n * \"read_schema\": false, // Reading metadata is safe\n * \"delete_records\": {\n * allowedDecisions: [\"approve\", \"reject\"],\n * description: \"⛔ DESTRUCTIVE OPERATION - Requires manager approval\"\n * }\n * },\n * descriptionPrefix: \"Database operation pending approval\"\n * });\n * ```\n *\n * @example\n * Using dynamic callable descriptions\n * ```typescript\n * import { type DescriptionFactory, type ToolCall } from \"langchain\";\n * import type { AgentBuiltInState, Runtime } from \"langchain/agents\";\n *\n * // Define a dynamic description factory\n * const formatToolDescription: DescriptionFactory = (\n * toolCall: ToolCall,\n * state: AgentBuiltInState,\n * runtime: Runtime<unknown>\n * ) => {\n * return `Tool: ${toolCall.name}\\nArguments:\\n${JSON.stringify(toolCall.args, null, 2)}`;\n * };\n *\n * const hitlMiddleware = humanInTheLoopMiddleware({\n * interruptOn: {\n * \"write_file\": {\n * allowedDecisions: [\"approve\", \"edit\"],\n * // Use dynamic description that can access tool call, state, and runtime\n * description: formatToolDescription\n * },\n * // Or use an inline function\n * \"send_email\": {\n * allowedDecisions: [\"approve\", \"reject\"],\n * description: (toolCall, state, runtime) => {\n * const { to, subject } = toolCall.args;\n * return `Email to ${to}\\nSubject: ${subject}\\n\\nRequires approval before sending`;\n * }\n * }\n * }\n * });\n * ```\n *\n * @remarks\n * - Tool calls are processed in the order they appear in the AI message\n * - Auto-approved tools execute immediately without interruption\n * - Multiple tools requiring approval are bundled into a single interrupt request\n * - The middleware operates in the `afterModel` phase, intercepting before tool execution\n * - Requires a checkpointer to maintain state across interruptions\n *\n * @see {@link createAgent} for agent creation\n * @see {@link Command} for resuming interrupted execution\n * @public\n */\nexport function humanInTheLoopMiddleware(\n options: NonNullable<HumanInTheLoopMiddlewareConfig>\n) {\n const createActionAndConfig = async (\n toolCall: ToolCall,\n config: InterruptOnConfig,\n state: AgentBuiltInState,\n runtime: Runtime<unknown>\n ): Promise<{\n actionRequest: ActionRequest;\n reviewConfig: ReviewConfig;\n }> => {\n const toolName = toolCall.name;\n const toolArgs = toolCall.args;\n\n // Generate description using the description field (str or callable)\n const descriptionValue = config.description;\n let description: string;\n if (typeof descriptionValue === \"function\") {\n description = await descriptionValue(toolCall, state, runtime);\n } else if (descriptionValue !== undefined) {\n description = descriptionValue;\n } else {\n description = `${\n options.descriptionPrefix ?? \"Tool execution requires approval\"\n }\\n\\nTool: ${toolName}\\nArgs: ${JSON.stringify(toolArgs, null, 2)}`;\n }\n\n /**\n * Create ActionRequest with description\n */\n const actionRequest: ActionRequest = {\n name: toolName,\n args: toolArgs,\n description,\n };\n\n /**\n * Create ReviewConfig\n */\n const reviewConfig: ReviewConfig = {\n actionName: toolName,\n allowedDecisions: config.allowedDecisions,\n };\n\n if (config.argsSchema) {\n reviewConfig.argsSchema = config.argsSchema;\n }\n\n return { actionRequest, reviewConfig };\n };\n\n /**\n * Return `false` if the `when` predicate rejects this tool call, `true` otherwise.\n *\n * When no `when` predicate is configured the tool call always interrupts.\n */\n const shouldInterrupt = async (\n toolCall: ToolCall,\n config: InterruptOnConfig,\n state: AgentBuiltInState,\n runtime: Runtime<unknown>\n ): Promise<boolean> => {\n const { when } = config;\n if (when == null) {\n return true;\n }\n const request: ToolCallRequest<AgentBuiltInState> = {\n toolCall,\n tool: undefined,\n state,\n runtime,\n };\n return when(request);\n };\n\n const processDecision = (\n decision: Decision,\n toolCall: ToolCall,\n config: InterruptOnConfig\n ): { revisedToolCall: ToolCall | null; toolMessage: ToolMessage | null } => {\n const allowedDecisions = config.allowedDecisions;\n if (decision.type === \"approve\" && allowedDecisions.includes(\"approve\")) {\n return { revisedToolCall: toolCall, toolMessage: null };\n }\n\n if (decision.type === \"edit\" && allowedDecisions.includes(\"edit\")) {\n const editedAction = decision.editedAction;\n\n /**\n * Validate edited action structure\n */\n if (!editedAction || typeof editedAction.name !== \"string\") {\n throw new Error(\n `Invalid edited action for tool \"${toolCall.name}\": name must be a string`\n );\n }\n if (!editedAction.args || typeof editedAction.args !== \"object\") {\n throw new Error(\n `Invalid edited action for tool \"${toolCall.name}\": args must be an object`\n );\n }\n\n return {\n revisedToolCall: {\n type: \"tool_call\",\n name: editedAction.name,\n args: editedAction.args,\n id: toolCall.id,\n },\n toolMessage: null,\n };\n }\n\n if (decision.type === \"reject\" && allowedDecisions.includes(\"reject\")) {\n /**\n * Validate that message is a string if provided\n */\n if (\n decision.message !== undefined &&\n typeof decision.message !== \"string\"\n ) {\n throw new Error(\n `Tool call response for \"${\n toolCall.name\n }\" must be a string, got ${typeof decision.message}`\n );\n }\n\n // Create a tool message with the human's text response\n const content =\n decision.message ??\n `User rejected the tool call for \\`${toolCall.name}\\` with id ${toolCall.id}`;\n\n const toolMessage = new ToolMessage({\n content,\n name: toolCall.name,\n tool_call_id: toolCall.id!,\n status: \"error\",\n });\n\n return { revisedToolCall: toolCall, toolMessage };\n }\n\n const msg = `Unexpected human decision: ${JSON.stringify(\n decision\n )}. Decision type '${decision.type}' is not allowed for tool '${\n toolCall.name\n }'. Expected one of ${JSON.stringify(\n allowedDecisions\n )} based on the tool's configuration.`;\n throw new Error(msg);\n };\n\n return createMiddleware({\n name: \"HumanInTheLoopMiddleware\",\n contextSchema,\n afterModel: {\n canJumpTo: [\"model\"],\n hook: async (state, runtime) => {\n const config = interopParse(contextSchema, {\n ...options,\n ...(runtime.context || {}),\n });\n if (!config) {\n return;\n }\n\n const { messages } = state;\n if (!messages.length) {\n return;\n }\n\n /**\n * Don't do anything if the last message isn't an AI message with tool calls.\n */\n const lastMessage = [...messages]\n .reverse()\n .find((msg) => AIMessage.isInstance(msg)) as AIMessage;\n if (!lastMessage || !lastMessage.tool_calls?.length) {\n return;\n }\n\n /**\n * If the user omits the interruptOn config, we don't do anything.\n */\n if (!config.interruptOn) {\n return;\n }\n\n /**\n * Resolve per-tool configs (boolean true -> all decisions allowed; false -> auto-approve)\n */\n const resolvedConfigs: Record<string, InterruptOnConfig> = {};\n for (const [toolName, toolConfig] of Object.entries(\n config.interruptOn\n )) {\n if (typeof toolConfig === \"boolean\") {\n if (toolConfig === true) {\n resolvedConfigs[toolName] = {\n allowedDecisions: [...ALLOWED_DECISIONS],\n };\n }\n } else if (toolConfig.allowedDecisions) {\n resolvedConfigs[toolName] = toolConfig as InterruptOnConfig;\n }\n }\n\n const interruptToolCalls: ToolCall[] = [];\n const autoApprovedToolCalls: ToolCall[] = [];\n\n for (const toolCall of lastMessage.tool_calls) {\n const interruptConfig = resolvedConfigs[toolCall.name];\n /**\n * A tool call is interrupted only when it has a resolved config and its\n * optional `when` predicate doesn't opt it out. Otherwise it is\n * auto-approved.\n */\n if (\n interruptConfig &&\n (await shouldInterrupt(toolCall, interruptConfig, state, runtime))\n ) {\n interruptToolCalls.push(toolCall);\n } else {\n autoApprovedToolCalls.push(toolCall);\n }\n }\n\n /**\n * No interrupt tool calls, so we can just return.\n */\n if (!interruptToolCalls.length) {\n return;\n }\n\n /**\n * Create action requests and review configs for all tools that need approval\n */\n const actionRequests: ActionRequest[] = [];\n const reviewConfigs: ReviewConfig[] = [];\n\n for (const toolCall of interruptToolCalls) {\n const interruptConfig = resolvedConfigs[toolCall.name]!;\n\n /**\n * Create ActionRequest and ReviewConfig using helper method\n */\n const { actionRequest, reviewConfig } = await createActionAndConfig(\n toolCall,\n interruptConfig,\n state,\n runtime\n );\n actionRequests.push(actionRequest);\n reviewConfigs.push(reviewConfig);\n }\n\n /**\n * Create single HITLRequest with all actions and configs\n */\n const hitlRequest: HITLRequest = {\n actionRequests,\n reviewConfigs,\n };\n\n /**\n * Send interrupt and get response\n */\n const hitlResponse = (await interrupt(hitlRequest)) as HITLResponse;\n const decisions = hitlResponse.decisions;\n\n /**\n * Validate that decisions is a valid array before checking length\n */\n if (!decisions || !Array.isArray(decisions)) {\n throw new Error(\n \"Invalid HITLResponse: decisions must be a non-empty array\"\n );\n }\n\n /**\n * Validate that the number of decisions matches the number of interrupt tool calls\n */\n if (decisions.length !== interruptToolCalls.length) {\n throw new Error(\n `Number of human decisions (${decisions.length}) does not match number of hanging tool calls (${interruptToolCalls.length}).`\n );\n }\n\n const revisedToolCalls: ToolCall[] = [...autoApprovedToolCalls];\n const artificialToolMessages: ToolMessage[] = [];\n const hasRejectedToolCalls = decisions.some(\n (decision) => decision.type === \"reject\"\n );\n\n /**\n * Process each decision using helper method\n */\n for (let i = 0; i < decisions.length; i++) {\n const decision = decisions[i]!;\n const toolCall = interruptToolCalls[i]!;\n const interruptConfig = resolvedConfigs[toolCall.name]!;\n\n const { revisedToolCall, toolMessage } = processDecision(\n decision,\n toolCall,\n interruptConfig\n );\n\n if (\n revisedToolCall &&\n /**\n * If any decision is a rejected, we are going back to the model\n * with only the tool calls that were rejected as we don't know\n * the results of the approved/updated tool calls at this point.\n */\n (!hasRejectedToolCalls || decision.type === \"reject\")\n ) {\n revisedToolCalls.push(revisedToolCall);\n }\n if (toolMessage) {\n artificialToolMessages.push(toolMessage);\n }\n }\n\n /**\n * Update the AI message to only include approved tool calls\n */\n if (AIMessage.isInstance(lastMessage)) {\n lastMessage.tool_calls = revisedToolCalls;\n }\n\n const jumpTo: JumpToTarget | undefined = hasRejectedToolCalls\n ? \"model\"\n : undefined;\n return {\n messages: [lastMessage, ...artificialToolMessages],\n jumpTo,\n };\n },\n },\n });\n}\n","import { getRetryable } from \"@langchain/core/errors\";\nimport { z } from \"zod/v3\";\n\n/** LangGraph's messages handlers skip runs tagged with this, keeping middleware-internal model calls out of the messages stream. */\nexport const INTERNAL_CALL_TAG = \"nostream\";\n\nexport const RetrySchema = z.object({\n /**\n * Maximum number of retry attempts after the initial call.\n * Default is 2 retries (3 total attempts). Must be >= 0.\n */\n maxRetries: z.number().min(0).default(2),\n\n /**\n * Either an array of error constructors to retry on, or a function\n * that takes an error and returns `true` if it should be retried.\n * Default is to retry unless the error is marked non-retryable.\n */\n retryOn: z\n .union([\n z.function().args(z.instanceof(Error)).returns(z.boolean()),\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => (error: Error) => getRetryable(error) ?? true),\n\n /**\n * Multiplier for exponential backoff. Each retry waits\n * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.\n * Set to 0.0 for constant delay. Default is 2.0.\n */\n backoffFactor: z.number().min(0).default(2.0),\n\n /**\n * Initial delay in milliseconds before first retry. Default is 1000 (1 second).\n */\n initialDelayMs: z.number().min(0).default(1000),\n\n /**\n * Maximum delay in milliseconds between retries. Caps exponential\n * backoff growth. Default is 60000 (60 seconds).\n */\n maxDelayMs: z.number().min(0).default(60000),\n\n /**\n * Whether to add random jitter (±25%) to delay to avoid thundering herd.\n * Default is `true`.\n */\n jitter: z.boolean().default(true),\n});\n","import { z } from \"zod/v3\";\nimport { z as z4 } from \"zod/v4\";\nimport { v4 as uuid } from \"@langchain/core/utils/uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n ToolMessage,\n RemoveMessage,\n trimMessages,\n HumanMessage,\n getBufferString,\n} from \"@langchain/core/messages\";\nimport {\n BaseLanguageModel,\n getModelContextSize,\n} from \"@langchain/core/language_models/base\";\nimport {\n interopSafeParse,\n InferInteropZodInput,\n InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\nimport {\n mergeConfigs,\n pickRunnableConfigKeys,\n type RunnableConfig,\n} from \"@langchain/core/runnables\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\nimport { INTERNAL_CALL_TAG } from \"./constants.js\";\nimport { countTokensApproximately } from \"./utils.js\";\nimport { hasToolCalls } from \"../utils.js\";\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport type { Runtime } from \"../runtime.js\";\n\nexport const DEFAULT_SUMMARY_PROMPT = `<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\nYou're nearing the total number of input tokens you can accept, so you must extract the highest quality/most relevant pieces of information from your conversation history.\nThis context will then overwrite the conversation history presented below. Because of this, ensure the context you extract is only the most important information to your overall goal.\n</objective_information>\n\n<instructions>\nThe conversation history below will be replaced with the context you extract in this step. Because of this, you must do your very best to extract and record all of the most important context from the conversation history.\nYou want to ensure that you don't repeat any actions you've already completed, so the context you extract from the conversation history should be focused on the most important information to your overall goal.\n</instructions>\n\nThe user will message you with the full message history you'll be extracting context from, to then replace. Carefully read over it all, and think deeply about what information is most important to your overall goal that should be saved:\n\nWith all of this in mind, please carefully read over the entire conversation history, and extract the most important and relevant context to replace it so that you can free up space in the conversation history.\nRespond ONLY with the extracted context. Do not include any additional information, or text before or after the extracted context.\n\n<messages>\nMessages to summarize:\n{messages}\n</messages>`;\n\nconst DEFAULT_SUMMARY_PREFIX = \"Here is a summary of the conversation to date:\";\nconst DEFAULT_MESSAGES_TO_KEEP = 20;\nconst DEFAULT_TRIM_TOKEN_LIMIT = 4000;\nconst DEFAULT_FALLBACK_MESSAGE_COUNT = 15;\nconst SEARCH_RANGE_FOR_TOOL_PAIRS = 5;\n\nconst tokenCounterSchema = z\n .function()\n .args(z.array(z.custom<BaseMessage>()))\n .returns(z.union([z.number(), z.promise(z.number())]));\nexport type TokenCounter = (\n messages: BaseMessage[]\n) => number | Promise<number>;\n\nexport const contextSizeSchema = z\n .object({\n /**\n * Fraction of the model's context size to use as the trigger\n */\n fraction: z\n .number()\n .gt(0, \"Fraction must be greater than 0\")\n .max(1, \"Fraction must be less than or equal to 1\")\n .optional(),\n /**\n * Number of tokens to use as the trigger\n */\n tokens: z.number().positive(\"Tokens must be greater than 0\").optional(),\n /**\n * Number of messages to use as the trigger\n */\n messages: z\n .number()\n .int(\"Messages must be an integer\")\n .positive(\"Messages must be greater than 0\")\n .optional(),\n })\n .refine(\n (data) => {\n const count = [data.fraction, data.tokens, data.messages].filter(\n (v) => v !== undefined\n ).length;\n return count >= 1;\n },\n {\n message: \"At least one of fraction, tokens, or messages must be provided\",\n }\n );\nexport type ContextSize = z.infer<typeof contextSizeSchema>;\n\nexport const keepSchema = z\n .object({\n /**\n * Fraction of the model's context size to keep\n */\n fraction: z\n .number()\n .min(0, \"Messages must be non-negative\")\n .max(1, \"Fraction must be less than or equal to 1\")\n .optional(),\n /**\n * Number of tokens to keep\n */\n tokens: z\n .number()\n .min(0, \"Tokens must be greater than or equal to 0\")\n .optional(),\n messages: z\n .number()\n .int(\"Messages must be an integer\")\n .min(0, \"Messages must be non-negative\")\n .optional(),\n })\n .refine(\n (data) => {\n const count = [data.fraction, data.tokens, data.messages].filter(\n (v) => v !== undefined\n ).length;\n return count === 1;\n },\n {\n message: \"Exactly one of fraction, tokens, or messages must be provided\",\n }\n );\nexport type KeepSize = z.infer<typeof keepSchema>;\n\nconst contextSchema = z.object({\n /**\n * Model to use for summarization\n */\n model: z.custom<string | BaseLanguageModel>(),\n /**\n * Trigger conditions for summarization.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 5000 AND messages >= 3\n * trigger: { tokens: 5000, messages: 3 }\n *\n * // Multiple conditions: trigger if (tokens >= 5000 AND messages >= 3) OR (tokens >= 3000 AND messages >= 6)\n * trigger: [\n * { tokens: 5000, messages: 3 },\n * { tokens: 3000, messages: 6 }\n * ]\n * ```\n */\n trigger: z.union([contextSizeSchema, z.array(contextSizeSchema)]).optional(),\n /**\n * Keep conditions for summarization\n */\n keep: keepSchema.optional(),\n /**\n * Token counter function to use for summarization\n */\n tokenCounter: tokenCounterSchema.optional(),\n /**\n * Summary prompt to use for summarization\n * @default {@link DEFAULT_SUMMARY_PROMPT}\n */\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n /**\n * Number of tokens to trim to before summarizing\n */\n trimTokensToSummarize: z.number().optional(),\n /**\n * Prefix to add to the summary\n */\n summaryPrefix: z.string().optional(),\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n maxTokensBeforeSummary: z.number().optional(),\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n messagesToKeep: z.number().optional(),\n});\n\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Get max input tokens from model profile or fallback to model name lookup\n */\nexport function getProfileLimits(input: BaseLanguageModel): number | undefined {\n // Access maxInputTokens on the model profile directly if available\n if (\n \"profile\" in input &&\n typeof input.profile === \"object\" &&\n input.profile &&\n \"maxInputTokens\" in input.profile &&\n (typeof input.profile.maxInputTokens === \"number\" ||\n input.profile.maxInputTokens == null)\n ) {\n return input.profile.maxInputTokens ?? undefined;\n }\n\n // Fallback to using model name if available\n if (\"model\" in input && typeof input.model === \"string\") {\n return getModelContextSize(input.model);\n }\n if (\"modelName\" in input && typeof input.modelName === \"string\") {\n return getModelContextSize(input.modelName);\n }\n\n return undefined;\n}\n\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 4000 AND messages >= 10\n * const agent1 = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * trigger: { tokens: 4000, messages: 10 },\n * keep: { messages: 20 },\n * })\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 5000 AND messages >= 3) OR (tokens >= 3000 AND messages >= 6)\n * const agent2 = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * trigger: [\n * { tokens: 5000, messages: 3 },\n * { tokens: 3000, messages: 6 },\n * ],\n * keep: { messages: 20 },\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: SummarizationMiddlewareConfig\n) {\n /**\n * Parse user options to get their explicit values\n */\n const { data: userOptions, error } = interopSafeParse(contextSchema, options);\n if (error) {\n throw new Error(\n `Invalid summarization middleware options: ${z4.prettifyError(error)}`\n );\n }\n\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema: contextSchema.extend({\n /**\n * `model` should be required when initializing the middleware,\n * but can be omitted within context when invoking the middleware.\n */\n model: z.custom<BaseLanguageModel>().optional(),\n }),\n beforeModel: async (state, runtime) => {\n let trigger: ContextSize | ContextSize[] | undefined =\n userOptions.trigger;\n let keep: ContextSize = userOptions.keep as InferInteropZodOutput<\n typeof keepSchema\n >;\n\n /**\n * Handle deprecated parameters\n */\n if (userOptions.maxTokensBeforeSummary !== undefined) {\n console.warn(\n \"maxTokensBeforeSummary is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: userOptions.maxTokensBeforeSummary };\n }\n }\n\n /**\n * Handle deprecated parameters\n */\n if (userOptions.messagesToKeep !== undefined) {\n console.warn(\n \"messagesToKeep is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (\n !keep ||\n (keep &&\n \"messages\" in keep &&\n keep.messages === DEFAULT_MESSAGES_TO_KEEP)\n ) {\n keep = { messages: userOptions.messagesToKeep };\n }\n }\n\n /**\n * Merge context with user options\n */\n const resolvedTrigger =\n runtime.context?.trigger !== undefined\n ? runtime.context.trigger\n : trigger;\n const resolvedKeep =\n runtime.context?.keep !== undefined\n ? runtime.context.keep\n : (keep ?? { messages: DEFAULT_MESSAGES_TO_KEEP });\n\n const validatedKeep = keepSchema.parse(resolvedKeep);\n\n /**\n * Validate trigger conditions\n */\n let triggerConditions: ContextSize[] = [];\n if (resolvedTrigger === undefined) {\n triggerConditions = [];\n } else if (Array.isArray(resolvedTrigger)) {\n /**\n * It's an array of ContextSize objects\n */\n triggerConditions = (resolvedTrigger as ContextSize[]).map((t) =>\n contextSizeSchema.parse(t)\n );\n } else {\n /**\n * Single ContextSize object - all properties must be satisfied (AND logic)\n */\n triggerConditions = [contextSizeSchema.parse(resolvedTrigger)];\n }\n\n /**\n * Check if profile is required\n */\n const requiresProfile =\n triggerConditions.some((c) => \"fraction\" in c) ||\n \"fraction\" in validatedKeep;\n\n const model =\n typeof userOptions.model === \"string\"\n ? await initChatModel(userOptions.model)\n : userOptions.model;\n\n if (requiresProfile && !getProfileLimits(model)) {\n throw new Error(\n \"Model profile information is required to use fractional token limits. \" +\n \"Use absolute token counts instead.\"\n );\n }\n\n const summaryPrompt =\n runtime.context?.summaryPrompt === DEFAULT_SUMMARY_PROMPT\n ? (userOptions.summaryPrompt ?? DEFAULT_SUMMARY_PROMPT)\n : (runtime.context?.summaryPrompt ??\n userOptions.summaryPrompt ??\n DEFAULT_SUMMARY_PROMPT);\n const summaryPrefix =\n runtime.context.summaryPrefix ??\n userOptions.summaryPrefix ??\n DEFAULT_SUMMARY_PREFIX;\n const trimTokensToSummarize =\n runtime.context?.trimTokensToSummarize !== undefined\n ? runtime.context.trimTokensToSummarize\n : (userOptions.trimTokensToSummarize ?? DEFAULT_TRIM_TOKEN_LIMIT);\n\n /**\n * Ensure all messages have IDs\n */\n ensureMessageIds(state.messages);\n\n const tokenCounter =\n runtime.context?.tokenCounter !== undefined\n ? runtime.context.tokenCounter\n : (userOptions.tokenCounter ?? countTokensApproximately);\n const totalTokens = await tokenCounter(state.messages);\n const doSummarize = await shouldSummarize(\n state.messages,\n totalTokens,\n triggerConditions,\n model\n );\n\n if (!doSummarize) {\n return;\n }\n\n const { systemPrompt, conversationMessages } = splitSystemMessage(\n state.messages\n );\n const cutoffIndex = await determineCutoffIndex(\n conversationMessages,\n validatedKeep,\n tokenCounter,\n model\n );\n\n if (cutoffIndex <= 0) {\n return;\n }\n\n const { messagesToSummarize, preservedMessages } = partitionMessages(\n systemPrompt,\n conversationMessages,\n cutoffIndex\n );\n\n const summary = await createSummary(\n messagesToSummarize,\n model,\n summaryPrompt,\n tokenCounter,\n trimTokensToSummarize,\n runtime\n );\n\n // Reuse a replaced message's id so the summary projects as an update, not a new message.\n const summaryMessage = new HumanMessage({\n content: `${summaryPrefix}\\n\\n${summary}`,\n id: conversationMessages[0].id,\n additional_kwargs: { lc_source: \"summarization\" },\n });\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n summaryMessage,\n ...preservedMessages,\n ],\n };\n },\n });\n}\n\n/**\n * Ensure all messages have unique IDs\n */\nfunction ensureMessageIds(messages: BaseMessage[]): void {\n for (const msg of messages) {\n if (!msg.id) {\n msg.id = uuid();\n }\n }\n}\n\n/**\n * Separate system message from conversation messages\n */\nfunction splitSystemMessage(messages: BaseMessage[]): {\n systemPrompt?: SystemMessage;\n conversationMessages: BaseMessage[];\n} {\n if (messages.length > 0 && SystemMessage.isInstance(messages[0])) {\n return {\n systemPrompt: messages[0] as SystemMessage,\n conversationMessages: messages.slice(1),\n };\n }\n return {\n conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemPrompt: SystemMessage | undefined,\n conversationMessages: BaseMessage[],\n cutoffIndex: number\n): { messagesToSummarize: BaseMessage[]; preservedMessages: BaseMessage[] } {\n const messagesToSummarize = conversationMessages.slice(0, cutoffIndex);\n const preservedMessages = conversationMessages.slice(cutoffIndex);\n\n // Include system message in messages to summarize to capture previous summaries\n if (systemPrompt) {\n messagesToSummarize.unshift(systemPrompt);\n }\n\n return { messagesToSummarize, preservedMessages };\n}\n\n/**\n * Determine whether summarization should run for the current token usage\n *\n * @param messages - Current messages in the conversation\n * @param totalTokens - Total token count for all messages\n * @param triggerConditions - Array of trigger conditions. Returns true if ANY condition is satisfied (OR logic).\n * Within each condition, ALL specified properties must be satisfied (AND logic).\n * @param model - The language model being used\n * @returns true if summarization should be triggered\n */\nasync function shouldSummarize(\n messages: BaseMessage[],\n totalTokens: number,\n triggerConditions: ContextSize[],\n model: BaseLanguageModel\n): Promise<boolean> {\n if (triggerConditions.length === 0) {\n return false;\n }\n\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n conditionMet = false;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger summarization\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine cutoff index respecting retention configuration\n */\nasync function determineCutoffIndex(\n messages: BaseMessage[],\n keep: ContextSize,\n tokenCounter: TokenCounter,\n model: BaseLanguageModel\n): Promise<number> {\n if (\"tokens\" in keep || \"fraction\" in keep) {\n const tokenBasedCutoff = await findTokenBasedCutoff(\n messages,\n keep,\n tokenCounter,\n model\n );\n if (typeof tokenBasedCutoff === \"number\") {\n return tokenBasedCutoff;\n }\n /**\n * Fallback to message count if token-based fails\n */\n return findSafeCutoff(messages, DEFAULT_MESSAGES_TO_KEEP);\n }\n /**\n * find cutoff index based on message count\n */\n return findSafeCutoff(messages, keep.messages ?? DEFAULT_MESSAGES_TO_KEEP);\n}\n\n/**\n * Find cutoff index based on target token retention\n */\nasync function findTokenBasedCutoff(\n messages: BaseMessage[],\n keep: ContextSize,\n tokenCounter: TokenCounter,\n model: BaseLanguageModel\n): Promise<number | undefined> {\n if (messages.length === 0) {\n return 0;\n }\n\n let targetTokenCount: number;\n\n if (\"fraction\" in keep && keep.fraction !== undefined) {\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens !== \"number\") {\n return;\n }\n targetTokenCount = Math.floor(maxInputTokens * keep.fraction);\n } else if (\"tokens\" in keep && keep.tokens !== undefined) {\n targetTokenCount = Math.floor(keep.tokens);\n } else {\n return;\n }\n\n if (targetTokenCount <= 0) {\n targetTokenCount = 1;\n }\n\n const totalTokens = await tokenCounter(messages);\n if (totalTokens <= targetTokenCount) {\n return 0;\n }\n\n /**\n * Use binary search to identify the earliest message index that keeps the\n * suffix within the token budget.\n */\n let left = 0;\n let right = messages.length;\n let cutoffCandidate = messages.length;\n const maxIterations = Math.floor(Math.log2(messages.length)) + 1;\n\n for (let i = 0; i < maxIterations; i++) {\n if (left >= right) {\n break;\n }\n\n const mid = Math.floor((left + right) / 2);\n const suffixTokens = await tokenCounter(messages.slice(mid));\n if (suffixTokens <= targetTokenCount) {\n cutoffCandidate = mid;\n right = mid;\n } else {\n left = mid + 1;\n }\n }\n\n if (cutoffCandidate === messages.length) {\n cutoffCandidate = left;\n }\n\n if (cutoffCandidate >= messages.length) {\n if (messages.length === 1) {\n return 0;\n }\n cutoffCandidate = messages.length - 1;\n }\n\n /**\n * Find safe cutoff point that preserves AI/Tool pairs.\n * If cutoff lands on ToolMessage, move backward to include the AIMessage.\n */\n const safeCutoff = findSafeCutoffPoint(messages, cutoffCandidate);\n\n /**\n * If findSafeCutoffPoint moved forward (fallback case), verify it's safe.\n * If it moved backward, we already have a safe point.\n */\n if (safeCutoff <= cutoffCandidate) {\n return safeCutoff;\n }\n\n /**\n * Fallback: iterate backward to find a safe cutoff\n */\n for (let i = cutoffCandidate; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Find safe cutoff point that preserves AI/Tool message pairs\n */\nfunction findSafeCutoff(\n messages: BaseMessage[],\n messagesToKeep: number\n): number {\n if (messages.length <= messagesToKeep) {\n return 0;\n }\n\n const targetCutoff = messages.length - messagesToKeep;\n\n /**\n * First, try to find a safe cutoff point using findSafeCutoffPoint.\n * This handles the case where cutoff lands on a ToolMessage by moving\n * backward to include the corresponding AIMessage.\n */\n const safeCutoff = findSafeCutoffPoint(messages, targetCutoff);\n\n /**\n * If findSafeCutoffPoint moved backward (found matching AIMessage), use it.\n */\n if (safeCutoff <= targetCutoff) {\n return safeCutoff;\n }\n\n /**\n * Fallback: iterate backward to find a safe cutoff\n */\n for (let i = targetCutoff; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Check if cutting at index would separate AI/Tool message pairs\n */\nfunction isSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): boolean {\n if (cutoffIndex >= messages.length) {\n return true;\n }\n\n /**\n * Prevent preserved messages from starting with AI message containing tool calls\n */\n if (\n cutoffIndex < messages.length &&\n AIMessage.isInstance(messages[cutoffIndex]) &&\n hasToolCalls(messages[cutoffIndex])\n ) {\n return false;\n }\n\n const searchStart = Math.max(0, cutoffIndex - SEARCH_RANGE_FOR_TOOL_PAIRS);\n const searchEnd = Math.min(\n messages.length,\n cutoffIndex + SEARCH_RANGE_FOR_TOOL_PAIRS\n );\n\n for (let i = searchStart; i < searchEnd; i++) {\n if (!hasToolCalls(messages[i])) {\n continue;\n }\n\n const toolCallIds = extractToolCallIds(messages[i] as AIMessage);\n if (cutoffSeparatesToolPair(messages, i, cutoffIndex, toolCallIds)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Extract tool call IDs from an AI message\n */\nfunction extractToolCallIds(aiMessage: AIMessage): Set<string> {\n const toolCallIds = new Set<string>();\n if (aiMessage.tool_calls) {\n for (const toolCall of aiMessage.tool_calls) {\n const id =\n typeof toolCall === \"object\" && \"id\" in toolCall ? toolCall.id : null;\n if (id) {\n toolCallIds.add(id);\n }\n }\n }\n return toolCallIds;\n}\n\n/**\n * Find a safe cutoff point that doesn't split AI/Tool message pairs.\n *\n * If the message at `cutoffIndex` is a `ToolMessage`, search backward for the\n * `AIMessage` containing the corresponding `tool_calls` and adjust the cutoff to\n * include it. This ensures tool call requests and responses stay together.\n *\n * Falls back to advancing forward past `ToolMessage` objects only if no matching\n * `AIMessage` is found (edge case).\n */\nfunction findSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): number {\n if (\n cutoffIndex >= messages.length ||\n !ToolMessage.isInstance(messages[cutoffIndex])\n ) {\n return cutoffIndex;\n }\n\n // Collect tool_call_ids from consecutive ToolMessages at/after cutoff\n const toolCallIds = new Set<string>();\n let idx = cutoffIndex;\n while (idx < messages.length && ToolMessage.isInstance(messages[idx])) {\n const toolMsg = messages[idx] as ToolMessage;\n if (toolMsg.tool_call_id) {\n toolCallIds.add(toolMsg.tool_call_id);\n }\n idx++;\n }\n\n // Search backward for AIMessage with matching tool_calls\n for (let i = cutoffIndex - 1; i >= 0; i--) {\n const msg = messages[i];\n if (AIMessage.isInstance(msg) && hasToolCalls(msg)) {\n const aiToolCallIds = extractToolCallIds(msg as AIMessage);\n // Check if there's any overlap between the tool_call_ids\n for (const id of toolCallIds) {\n if (aiToolCallIds.has(id)) {\n // Found the AIMessage - move cutoff to include it\n return i;\n }\n }\n }\n }\n\n // Fallback: no matching AIMessage found, advance past ToolMessages to avoid\n // orphaned tool responses\n return idx;\n}\n\n/**\n * Check if cutoff separates an AI message from its corresponding tool messages\n */\nfunction cutoffSeparatesToolPair(\n messages: BaseMessage[],\n aiMessageIndex: number,\n cutoffIndex: number,\n toolCallIds: Set<string>\n): boolean {\n for (let j = aiMessageIndex + 1; j < messages.length; j++) {\n const message = messages[j];\n if (\n ToolMessage.isInstance(message) &&\n toolCallIds.has(message.tool_call_id)\n ) {\n const aiBeforeCutoff = aiMessageIndex < cutoffIndex;\n const toolBeforeCutoff = j < cutoffIndex;\n if (aiBeforeCutoff !== toolBeforeCutoff) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Generate summary for the given messages.\n *\n * @param messagesToSummarize - Messages to summarize.\n * @param model - The language model to use for summarization.\n * @param summaryPrompt - The prompt template for summarization.\n * @param tokenCounter - Function to count tokens.\n * @param trimTokensToSummarize - Optional token limit for trimming messages.\n * @param runtime - The runtime environment, used to inherit config so that\n * LangGraph's handlers can properly track and tag the summarization model call.\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter,\n trimTokensToSummarize: number | undefined,\n runtime: Runtime<unknown>\n): Promise<string> {\n if (!messagesToSummarize.length) {\n return \"No previous conversation history.\";\n }\n\n const trimmedMessages = await trimMessagesForSummary(\n messagesToSummarize,\n tokenCounter,\n trimTokensToSummarize\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n /**\n * Format messages using getBufferString to avoid token inflation from metadata\n * when str() / JSON.stringify is called on message objects.\n * This produces compact output like:\n * ```\n * Human: What's the weather?\n * AI: Let me check...[tool_calls]\n * Tool: 72°F and sunny\n * ```\n */\n const formattedMessages = getBufferString(trimmedMessages);\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n formattedMessages\n );\n /**\n * Merge parent runnable config with summarization metadata so LangGraph's\n * stream handlers (and other callback-based consumers) can properly track\n * and tag the summarization model call.\n */\n const baseConfig: RunnableConfig = pickRunnableConfigKeys(runtime) ?? {};\n const config = mergeConfigs(baseConfig, {\n metadata: { lc_source: \"summarization\" },\n tags: [INTERNAL_CALL_TAG],\n });\n const response = await model.invoke(formattedPrompt, config);\n const content = response.content;\n /**\n * Handle both string content and MessageContent array\n */\n if (typeof content === \"string\") {\n return content.trim();\n } else if (Array.isArray(content)) {\n /**\n * Extract text from MessageContent array\n */\n const textContent = content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (typeof item === \"object\" && item !== null && \"text\" in item) {\n return (item as { text: string }).text;\n }\n return \"\";\n })\n .join(\"\");\n return textContent.trim();\n }\n return \"Error generating summary: Invalid response format\";\n } catch (e) {\n return `Error generating summary: ${e}`;\n }\n}\n\n/**\n * Trim messages to fit within summary generation limits\n */\nasync function trimMessagesForSummary(\n messages: BaseMessage[],\n tokenCounter: TokenCounter,\n trimTokensToSummarize: number | undefined\n): Promise<BaseMessage[]> {\n if (trimTokensToSummarize === undefined) {\n return messages;\n }\n\n try {\n return await trimMessages(messages, {\n maxTokens: trimTokensToSummarize,\n tokenCounter: async (msgs) => tokenCounter(msgs),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n /**\n * Fallback to last N messages if trimming fails\n */\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n","import { z } from \"zod/v3\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\nimport { HumanMessage } from \"@langchain/core/messages\";\nimport type { StructuredToolInterface } from \"@langchain/core/tools\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport { INTERNAL_CALL_TAG } from \"./constants.js\";\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport type { Runtime } from \"../runtime.js\";\nimport type { ModelRequest } from \"../nodes/types.js\";\nimport {\n mergeConfigs,\n pickRunnableConfigKeys,\n type RunnableConfig,\n} from \"@langchain/core/runnables\";\n\nconst DEFAULT_SYSTEM_PROMPT =\n \"Your goal is to select the most relevant tools for answering the user's query.\";\n\n/**\n * Prepared inputs for tool selection.\n */\ninterface SelectionRequest {\n availableTools: StructuredToolInterface[];\n systemMessage: string;\n lastUserMessage: HumanMessage;\n model: BaseLanguageModel;\n validToolNames: string[];\n}\n\n/**\n * Create a structured output schema for tool selection.\n *\n * @param tools - Available tools to include in the schema.\n * @returns Zod schema where each tool name is a literal with its description.\n */\nfunction createToolSelectionResponse(tools: StructuredToolInterface[]) {\n if (!tools || tools.length === 0) {\n throw new Error(\"Invalid usage: tools must be non-empty\");\n }\n\n // Create a union of literals for each tool name\n const toolLiterals = tools.map((tool) => z.literal(tool.name));\n const toolEnum = z.union(\n toolLiterals as [\n z.ZodLiteral<string>,\n z.ZodLiteral<string>,\n ...z.ZodLiteral<string>[],\n ]\n );\n\n return z.object({\n tools: z\n .array(toolEnum)\n .describe(\"Tools to use. Place the most relevant tools first.\"),\n });\n}\n\n/**\n * Options for configuring the LLM Tool Selector middleware.\n */\nexport const LLMToolSelectorOptionsSchema = z.object({\n /**\n * The language model to use for tool selection (default: the provided model from the agent options).\n */\n model: z.string().or(z.instanceof(BaseLanguageModel)).optional(),\n /**\n * System prompt for the tool selection model.\n */\n systemPrompt: z.string().optional(),\n /**\n * Maximum number of tools to select. If the model selects more,\n * only the first maxTools will be used. No limit if not specified.\n */\n maxTools: z.number().optional(),\n /**\n * Tool names to always include regardless of selection.\n * These do not count against the maxTools limit.\n */\n alwaysInclude: z.array(z.string()).optional(),\n});\nexport type LLMToolSelectorConfig = InferInteropZodInput<\n typeof LLMToolSelectorOptionsSchema\n>;\n\n/**\n * Middleware for selecting tools using an LLM-based strategy.\n *\n * When an agent has many tools available, this middleware filters them down\n * to only the most relevant ones for the user's query. This reduces token usage\n * and helps the main model focus on the right tools.\n *\n * @param options - Configuration options for the middleware\n * @param options.model - The language model to use for tool selection (default: the provided model from the agent options).\n * @param options.systemPrompt - Instructions for the selection model.\n * @param options.maxTools - Maximum number of tools to select. If the model selects more,\n * only the first maxTools will be used. No limit if not specified.\n * @param options.alwaysInclude - Tool names to always include regardless of selection.\n * These do not count against the maxTools limit.\n *\n * @example\n * Limit to 3 tools:\n * ```ts\n * import { llmToolSelectorMiddleware } from \"langchain/agents/middleware\";\n *\n * const middleware = llmToolSelectorMiddleware({ maxTools: 3 });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [tool1, tool2, tool3, tool4, tool5],\n * middleware: [middleware],\n * });\n * ```\n *\n * @example\n * Use a smaller model for selection:\n * ```ts\n * const middleware = llmToolSelectorMiddleware({\n * model: \"openai:gpt-4o-mini\",\n * maxTools: 2\n * });\n * ```\n */\nexport function llmToolSelectorMiddleware(options: LLMToolSelectorConfig) {\n return createMiddleware({\n name: \"LLMToolSelector\",\n contextSchema: LLMToolSelectorOptionsSchema,\n async wrapModelCall(request, handler) {\n const selectionRequest = await prepareSelectionRequest(\n request,\n options,\n request.runtime\n );\n if (!selectionRequest) {\n return handler(request);\n }\n\n // Create dynamic response model with union of literal tool names\n const toolSelectionSchema = createToolSelectionResponse(\n selectionRequest.availableTools\n );\n const structuredModel =\n await selectionRequest.model.withStructuredOutput?.(\n toolSelectionSchema\n );\n\n const baseConfig: RunnableConfig =\n pickRunnableConfigKeys(request.runtime) ?? {};\n const config = mergeConfigs(baseConfig, {\n metadata: { lc_source: \"llmToolSelector\" },\n tags: [INTERNAL_CALL_TAG],\n callbacks: [],\n });\n\n const response = await structuredModel?.invoke(\n [\n { role: \"system\", content: selectionRequest.systemMessage },\n selectionRequest.lastUserMessage,\n ],\n config\n );\n\n // Response should be an object with a tools array\n if (!response || typeof response !== \"object\" || !(\"tools\" in response)) {\n throw new Error(\n `Expected object response with tools array, got ${typeof response}`\n );\n }\n\n return handler(\n processSelectionResponse(\n response as { tools: string[] },\n selectionRequest.availableTools,\n selectionRequest.validToolNames,\n request,\n options\n )\n );\n },\n });\n}\n\n/**\n * Prepare inputs for tool selection.\n *\n * @param request - The model request to process.\n * @param options - Configuration options.\n * @param runtime - Runtime context.\n * @returns SelectionRequest with prepared inputs, or null if no selection is needed.\n */\nasync function prepareSelectionRequest<\n TState extends Record<string, unknown> = Record<string, unknown>,\n TContext = unknown,\n>(\n request: ModelRequest<TState, TContext>,\n options: LLMToolSelectorConfig,\n runtime: Runtime<LLMToolSelectorConfig>\n): Promise<SelectionRequest | undefined> {\n const model = runtime.context.model ?? options.model;\n const maxTools = runtime.context.maxTools ?? options.maxTools;\n const alwaysInclude =\n runtime.context.alwaysInclude ?? options.alwaysInclude ?? [];\n const systemPrompt =\n runtime.context.systemPrompt ??\n options.systemPrompt ??\n DEFAULT_SYSTEM_PROMPT;\n\n /**\n * If no tools available, return null\n */\n if (!request.tools || request.tools.length === 0) {\n return undefined;\n }\n\n /**\n * Filter to only StructuredToolInterface instances (exclude provider-specific tool dicts)\n */\n const baseTools = request.tools.filter(\n (tool): tool is StructuredToolInterface =>\n typeof tool === \"object\" &&\n \"name\" in tool &&\n \"description\" in tool &&\n typeof tool.name === \"string\"\n );\n\n /**\n * Validate that alwaysInclude tools exist\n */\n if (alwaysInclude.length > 0) {\n const availableToolNames = new Set(baseTools.map((tool) => tool.name));\n const missingTools = alwaysInclude.filter(\n (name) => !availableToolNames.has(name)\n );\n if (missingTools.length > 0) {\n throw new Error(\n `Tools in alwaysInclude not found in request: ${missingTools.join(\n \", \"\n )}. ` +\n `Available tools: ${Array.from(availableToolNames).sort().join(\", \")}`\n );\n }\n }\n\n /**\n * Separate tools that are always included from those available for selection\n */\n const availableTools = baseTools.filter(\n (tool) => !alwaysInclude.includes(tool.name)\n );\n\n /**\n * If no tools available for selection, return null\n */\n if (availableTools.length === 0) {\n return undefined;\n }\n\n let systemMessage = systemPrompt;\n /**\n * If there's a maxTools limit, append instructions to the system prompt\n */\n if (maxTools !== undefined) {\n systemMessage +=\n `\\nIMPORTANT: List the tool names in order of relevance, ` +\n `with the most relevant first. ` +\n `If you exceed the maximum number of tools, ` +\n `only the first ${maxTools} will be used.`;\n }\n\n /**\n * Get the last user message from the conversation history\n */\n let lastUserMessage: HumanMessage | undefined;\n for (const message of request.messages) {\n if (HumanMessage.isInstance(message)) {\n lastUserMessage = message;\n }\n }\n\n if (!lastUserMessage) {\n throw new Error(\"No user message found in request messages\");\n }\n\n const modelInstance = !model\n ? (request.model as BaseLanguageModel)\n : typeof model === \"string\"\n ? await initChatModel(model)\n : model;\n\n const validToolNames = availableTools.map((tool) => tool.name);\n\n return {\n availableTools,\n systemMessage,\n lastUserMessage,\n model: modelInstance,\n validToolNames,\n };\n}\n\n/**\n * Process the selection response and return filtered ModelRequest.\n *\n * @param response - The structured output response from the model.\n * @param availableTools - Tools available for selection.\n * @param validToolNames - Valid tool names that can be selected.\n * @param request - Original model request.\n * @param options - Configuration options.\n * @returns Modified ModelRequest with filtered tools.\n */\nfunction processSelectionResponse<\n TState extends Record<string, unknown> = Record<string, unknown>,\n TContext = unknown,\n>(\n response: { tools: string[] },\n availableTools: StructuredToolInterface[],\n validToolNames: string[],\n request: ModelRequest<TState, TContext>,\n options: LLMToolSelectorConfig\n): ModelRequest<TState, TContext> {\n const maxTools = options.maxTools;\n const alwaysInclude = options.alwaysInclude ?? [];\n\n const selectedToolNames: string[] = [];\n const invalidToolSelections: string[] = [];\n\n for (const toolName of response.tools) {\n if (!validToolNames.includes(toolName)) {\n invalidToolSelections.push(toolName);\n continue;\n }\n\n /**\n * Only add if not already selected and within maxTools limit\n */\n if (\n !selectedToolNames.includes(toolName) &&\n (maxTools === undefined || selectedToolNames.length < maxTools)\n ) {\n selectedToolNames.push(toolName);\n }\n }\n\n if (invalidToolSelections.length > 0) {\n throw new Error(\n `Model selected invalid tools: ${invalidToolSelections.join(\", \")}`\n );\n }\n\n /**\n * Filter tools based on selection\n */\n const selectedTools = availableTools.filter((tool) =>\n selectedToolNames.includes(tool.name)\n );\n\n /**\n * Append always-included tools\n */\n const alwaysIncludedTools = (request.tools ?? []).filter(\n (tool): tool is StructuredToolInterface =>\n typeof tool === \"object\" &&\n \"name\" in tool &&\n typeof tool.name === \"string\" &&\n alwaysInclude.includes(tool.name)\n );\n selectedTools.push(...alwaysIncludedTools);\n\n /**\n * Also preserve any provider-specific tool dicts from the original request\n */\n const providerTools = (request.tools ?? []).filter(\n (tool) =>\n !(\n typeof tool === \"object\" &&\n \"name\" in tool &&\n \"description\" in tool &&\n typeof tool.name === \"string\"\n )\n );\n\n return {\n ...request,\n tools: [...selectedTools, ...providerTools],\n };\n}\n","import { z } from \"zod/v3\";\nimport { sha256 } from \"@langchain/core/utils/hash\";\nimport { AIMessage, HumanMessage, ToolMessage } from \"@langchain/core/messages\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Represents a detected PII match in content\n */\nexport interface PIIMatch {\n /**\n * The matched text\n */\n text: string;\n /**\n * The start index of the match\n */\n start: number;\n /**\n * The end index of the match\n */\n end: number;\n}\n\n/**\n * Error thrown when PII is detected and strategy is 'block'\n */\nexport class PIIDetectionError extends Error {\n constructor(\n public readonly piiType: string,\n public readonly matches: PIIMatch[]\n ) {\n super(`PII detected: ${piiType} found ${matches.length} occurrence(s)`);\n this.name = \"PIIDetectionError\";\n }\n}\n\n/**\n * Strategy for handling detected PII\n */\nexport type PIIStrategy = \"block\" | \"redact\" | \"mask\" | \"hash\";\n\n/**\n * Built-in PII types\n */\nexport type BuiltInPIIType =\n | \"email\"\n | \"credit_card\"\n | \"ip\"\n | \"mac_address\"\n | \"url\";\n\n/**\n * Custom detector function that takes content and returns matches\n */\nexport type PIIDetector = (content: string) => PIIMatch[];\nexport type Detector = PIIDetector | RegExp | string;\n\n/**\n * Configuration for a redaction rule\n */\nexport interface RedactionRuleConfig {\n /**\n * Type of PII to detect (built-in or custom name)\n */\n piiType: BuiltInPIIType | string;\n /**\n * Strategy for handling detected PII\n */\n strategy: PIIStrategy;\n /**\n * Custom detector function or regex pattern string\n */\n detector?: Detector;\n}\n\n/**\n * Resolved redaction rule with a concrete detector function\n */\nexport interface ResolvedRedactionRule {\n piiType: string;\n strategy: PIIStrategy;\n detector: PIIDetector;\n}\n\n/**\n * Email detection regex pattern\n */\nconst EMAIL_PATTERN = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\n\n/**\n * Credit card detection regex pattern (basic, will be validated with Luhn)\n */\nconst CREDIT_CARD_PATTERN = /\\b(?:\\d{4}[-\\s]?){3}\\d{4}\\b/g;\n\n/**\n * IP address detection regex pattern\n */\nconst IP_PATTERN =\n /\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b/g;\n\n/**\n * MAC address detection regex pattern\n */\nconst MAC_ADDRESS_PATTERN = /\\b(?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2})\\b/g;\n\n/**\n * URL detection regex pattern\n */\nconst URL_PATTERN = /(?:https?:\\/\\/|www\\.)[^\\s<>\"{}|\\\\^`[\\]]+/gi;\n\n/**\n * Luhn algorithm for credit card validation\n */\nfunction luhnCheck(cardNumber: string): boolean {\n const digits = cardNumber.replace(/\\D/g, \"\");\n let sum = 0;\n let isEven = false;\n\n for (let i = digits.length - 1; i >= 0; i--) {\n let digit = parseInt(digits[i], 10);\n\n if (isEven) {\n digit *= 2;\n if (digit > 9) {\n digit -= 9;\n }\n }\n\n sum += digit;\n isEven = !isEven;\n }\n\n return sum % 10 === 0;\n}\n\n/**\n * Convert regex match to PIIMatch\n */\nfunction regexMatchToPIIMatch(match: RegExpMatchArray): PIIMatch {\n return {\n text: match[0],\n start: match.index ?? 0,\n end: (match.index ?? 0) + match[0].length,\n };\n}\n\n/**\n * Detect email addresses in content\n */\nexport function detectEmail(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(EMAIL_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n}\n\n/**\n * Detect credit card numbers in content (validated with Luhn algorithm)\n */\nexport function detectCreditCard(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(CREDIT_CARD_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const cardNumber = match[0].replace(/\\D/g, \"\");\n // Credit cards are typically 13-19 digits\n if (\n cardNumber.length >= 13 &&\n cardNumber.length <= 19 &&\n luhnCheck(cardNumber)\n ) {\n matches.push(regexMatchToPIIMatch(match));\n }\n }\n\n return matches;\n}\n\n/**\n * Detect IP addresses in content (validated)\n */\nexport function detectIP(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(IP_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const ip = match[0];\n // Additional validation: each octet should be 0-255\n const parts = ip.split(\".\");\n if (\n parts.length === 4 &&\n parts.every((part) => {\n const num = parseInt(part, 10);\n return num >= 0 && num <= 255;\n })\n ) {\n matches.push(regexMatchToPIIMatch(match));\n }\n }\n\n return matches;\n}\n\n/**\n * Detect MAC addresses in content\n */\nexport function detectMacAddress(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(MAC_ADDRESS_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n}\n\n/**\n * Detect URLs in content\n */\nexport function detectUrl(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(URL_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n}\n\n/**\n * Built-in detector map\n */\nconst BUILT_IN_DETECTORS: Record<BuiltInPIIType, PIIDetector> = {\n email: detectEmail,\n credit_card: detectCreditCard,\n ip: detectIP,\n mac_address: detectMacAddress,\n url: detectUrl,\n};\n\n/**\n * Resolve a redaction rule to a concrete detector function\n */\nexport function resolveRedactionRule(\n config: RedactionRuleConfig\n): ResolvedRedactionRule {\n let detector: PIIDetector;\n\n if (config.detector) {\n if (typeof config.detector === \"string\") {\n // Regex pattern string\n const regex = new RegExp(config.detector, \"g\");\n detector = (content: string) => {\n const matches: PIIMatch[] = [];\n let match: RegExpMatchArray | null;\n const regexCopy = new RegExp(regex);\n\n while ((match = regexCopy.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n };\n // oxlint-disable-next-line no-instanceof/no-instanceof\n } else if (config.detector instanceof RegExp) {\n detector = (content: string) => {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n if (!(config.detector instanceof RegExp)) {\n throw new Error(\"Detector is required\");\n }\n const matches: PIIMatch[] = [];\n let match: RegExpMatchArray | null;\n while ((match = config.detector.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n };\n } else {\n detector = config.detector;\n }\n } else {\n // Use built-in detector\n const builtInType = config.piiType as BuiltInPIIType;\n if (!BUILT_IN_DETECTORS[builtInType]) {\n throw new Error(\n `Unknown PII type: ${config.piiType}. Must be one of: ${Object.keys(\n BUILT_IN_DETECTORS\n ).join(\", \")}, or provide a custom detector.`\n );\n }\n detector = BUILT_IN_DETECTORS[builtInType];\n }\n\n return {\n piiType: config.piiType,\n strategy: config.strategy,\n detector,\n };\n}\n\n/**\n * Apply redact strategy: replace with [REDACTED_TYPE]\n */\nfunction applyRedactStrategy(\n content: string,\n matches: PIIMatch[],\n piiType: string\n): string {\n let result = content;\n // Process matches in reverse order to preserve indices\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const replacement = `[REDACTED_${piiType.toUpperCase()}]`;\n result =\n result.slice(0, match.start) + replacement + result.slice(match.end);\n }\n return result;\n}\n\n/**\n * Apply mask strategy: partially mask PII (show last few characters)\n */\nfunction applyMaskStrategy(\n content: string,\n matches: PIIMatch[],\n piiType: string\n): string {\n let result = content;\n // Process matches in reverse order to preserve indices\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const text = match.text;\n let masked: string;\n\n if (piiType === \"credit_card\") {\n // Show last 4 digits: ****-****-****-1234\n const digits = text.replace(/\\D/g, \"\");\n const last4 = digits.slice(-4);\n masked = `****-****-****-${last4}`;\n } else if (piiType === \"email\") {\n // Show first char and domain: j***@example.com\n const [local, domain] = text.split(\"@\");\n if (local && domain) {\n masked = `${local[0]}***@${domain}`;\n } else {\n masked = \"***\";\n }\n } else {\n // Default: show last 4 characters\n const visibleChars = Math.min(4, text.length);\n masked = `${\"*\".repeat(\n Math.max(0, text.length - visibleChars)\n )}${text.slice(-visibleChars)}`;\n }\n\n result = result.slice(0, match.start) + masked + result.slice(match.end);\n }\n return result;\n}\n\n/**\n * Apply hash strategy: replace with deterministic hash\n */\nfunction applyHashStrategy(\n content: string,\n matches: PIIMatch[],\n piiType: string\n): string {\n let result = content;\n // Process matches in reverse order to preserve indices\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const hash = sha256(match.text).slice(0, 8);\n const replacement = `<${piiType}_hash:${hash}>`;\n result =\n result.slice(0, match.start) + replacement + result.slice(match.end);\n }\n return result;\n}\n\n/**\n * Apply strategy to content based on matches\n */\nexport function applyStrategy(\n content: string,\n matches: PIIMatch[],\n strategy: PIIStrategy,\n piiType: string\n): string {\n if (matches.length === 0) {\n return content;\n }\n\n switch (strategy) {\n case \"block\":\n throw new PIIDetectionError(piiType, matches);\n case \"redact\":\n return applyRedactStrategy(content, matches, piiType);\n case \"mask\":\n return applyMaskStrategy(content, matches, piiType);\n case \"hash\":\n return applyHashStrategy(content, matches, piiType);\n default:\n throw new Error(`Unknown strategy: ${strategy}`);\n }\n}\n\n/**\n * Configuration schema for PII middleware\n */\nconst contextSchema = z.object({\n /**\n * Whether to check user messages before model call\n */\n applyToInput: z.boolean().optional(),\n /**\n * Whether to check AI messages after model call\n */\n applyToOutput: z.boolean().optional(),\n /**\n * Whether to check tool result messages after tool execution\n */\n applyToToolResults: z.boolean().optional(),\n});\n\nexport type PIIMiddlewareConfig = InferInteropZodInput<typeof contextSchema>;\n\n/**\n * Process content for PII detection and apply strategy\n */\nfunction processContent(\n content: string,\n rule: ResolvedRedactionRule\n): { content: string; matches: PIIMatch[] } {\n const matches = rule.detector(content);\n if (matches.length === 0) {\n return { content, matches: [] };\n }\n\n const sanitized = applyStrategy(\n content,\n matches,\n rule.strategy,\n rule.piiType\n );\n return { content: sanitized, matches };\n}\n\n/**\n * Creates a middleware that detects and handles personally identifiable information (PII)\n * in conversations.\n *\n * This middleware detects common PII types and applies configurable strategies to handle them.\n * It can detect emails, credit cards, IP addresses, MAC addresses, and URLs in both user input\n * and agent output.\n *\n * Built-in PII types:\n * - `email`: Email addresses\n * - `credit_card`: Credit card numbers (validated with Luhn algorithm)\n * - `ip`: IP addresses (validated)\n * - `mac_address`: MAC addresses\n * - `url`: URLs (both `http`/`https` and bare URLs)\n *\n * Strategies:\n * - `block`: Raise an exception when PII is detected\n * - `redact`: Replace PII with `[REDACTED_TYPE]` placeholders\n * - `mask`: Partially mask PII (e.g., `****-****-****-1234` for credit card)\n * - `hash`: Replace PII with deterministic hash (e.g., `<email_hash:a1b2c3d4>`)\n *\n * Strategy Selection Guide:\n * | Strategy | Preserves Identity? | Best For |\n * | -------- | ------------------- | --------------------------------------- |\n * | `block` | N/A | Avoid PII completely |\n * | `redact` | No | General compliance, log sanitization |\n * | `mask` | No | Human readability, customer service UIs |\n * | `hash` | Yes (pseudonymous) | Analytics, debugging |\n *\n * @param piiType - Type of PII to detect. Can be a built-in type (`email`, `credit_card`, `ip`, `mac_address`, `url`) or a custom type name.\n * @param options - Configuration options\n * @param options.strategy - How to handle detected PII. Defaults to `\"redact\"`.\n * @param options.detector - Custom detector function or regex pattern string. If not provided, uses built-in detector for the `piiType`.\n * @param options.applyToInput - Whether to check user messages before model call. Defaults to `true`.\n * @param options.applyToOutput - Whether to check AI messages after model call. Defaults to `false`.\n * @param options.applyToToolResults - Whether to check tool result messages after tool execution. Defaults to `false`.\n *\n * @returns Middleware instance for use with `createAgent`\n *\n * @throws {PIIDetectionError} When PII is detected and strategy is `'block'`\n * @throws {Error} If `piiType` is not built-in and no detector is provided\n *\n * @example Basic usage\n * ```typescript\n * import { piiMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * // Redact all emails in user input\n * const agent = createAgent({\n * model: \"openai:gpt-4\",\n * middleware: [\n * piiMiddleware(\"email\", { strategy: \"redact\" }),\n * ],\n * });\n * ```\n *\n * @example Different strategies for different PII types\n * ```typescript\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [\n * piiMiddleware(\"credit_card\", { strategy: \"mask\" }),\n * piiMiddleware(\"url\", { strategy: \"redact\" }),\n * piiMiddleware(\"ip\", { strategy: \"hash\" }),\n * ],\n * });\n * ```\n *\n * @example Custom PII type with regex\n * ```typescript\n * const agent = createAgent({\n * model: \"openai:gpt-4\",\n * middleware: [\n * piiMiddleware(\"api_key\", {\n * detector: \"sk-[a-zA-Z0-9]{32}\",\n * strategy: \"block\",\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function piiMiddleware(\n piiType: BuiltInPIIType | string,\n options: {\n strategy?: PIIStrategy;\n detector?: Detector;\n applyToInput?: boolean;\n applyToOutput?: boolean;\n applyToToolResults?: boolean;\n } = {}\n) {\n const { strategy = \"redact\", detector } = options;\n const resolvedRule = resolveRedactionRule({\n piiType,\n strategy,\n detector,\n });\n\n const middlewareName = `PIIMiddleware[${resolvedRule.piiType}]`;\n\n return createMiddleware({\n name: middlewareName,\n contextSchema,\n beforeModel: async (state, runtime) => {\n const applyToInput =\n runtime.context.applyToInput ?? options.applyToInput ?? true;\n const applyToToolResults =\n runtime.context.applyToToolResults ??\n options.applyToToolResults ??\n false;\n\n if (!applyToInput && !applyToToolResults) {\n return;\n }\n\n const messages = state.messages;\n if (!messages || messages.length === 0) {\n return;\n }\n\n const newMessages = [...messages];\n let anyModified = false;\n\n // Check user input if enabled\n if (applyToInput) {\n // Get last user message\n let lastUserIdx: number | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (HumanMessage.isInstance(messages[i])) {\n lastUserIdx = i;\n break;\n }\n }\n\n if (lastUserIdx !== null) {\n const lastUserMsg = messages[lastUserIdx];\n if (lastUserMsg && lastUserMsg.content) {\n const content = String(lastUserMsg.content);\n const { content: newContent, matches } = processContent(\n content,\n resolvedRule\n );\n\n if (matches.length > 0) {\n newMessages[lastUserIdx] = new HumanMessage({\n content: newContent,\n id: lastUserMsg.id,\n name: lastUserMsg.name,\n });\n anyModified = true;\n }\n }\n }\n }\n\n // Check tool results if enabled\n if (applyToToolResults) {\n // Find the last AIMessage, then process all ToolMessage objects after it\n let lastAiIdx: number | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (AIMessage.isInstance(messages[i])) {\n lastAiIdx = i;\n break;\n }\n }\n\n if (lastAiIdx !== null) {\n // Get all tool messages after the last AI message\n for (let i = lastAiIdx + 1; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n if (!msg.content) {\n continue;\n }\n\n const content = String(msg.content);\n const { content: newContent, matches } = processContent(\n content,\n resolvedRule\n );\n\n if (matches.length > 0) {\n newMessages[i] = new ToolMessage({\n content: newContent,\n id: msg.id,\n name: msg.name,\n tool_call_id: msg.tool_call_id,\n });\n anyModified = true;\n }\n }\n }\n }\n }\n\n if (anyModified) {\n return { messages: newMessages };\n }\n\n return;\n },\n afterModel: async (state, runtime) => {\n const applyToOutput =\n runtime.context.applyToOutput ?? options.applyToOutput ?? false;\n\n if (!applyToOutput) {\n return;\n }\n\n const messages = state.messages;\n if (!messages || messages.length === 0) {\n return;\n }\n\n // Get last AI message\n let lastAiIdx: number | null = null;\n let lastAiMsg: AIMessage | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (AIMessage.isInstance(msg)) {\n lastAiMsg = msg;\n lastAiIdx = i;\n break;\n }\n }\n\n if (lastAiIdx === null || !lastAiMsg || !lastAiMsg.content) {\n return;\n }\n\n // Detect PII in message content\n const content = String(lastAiMsg.content);\n const { content: newContent, matches } = processContent(\n content,\n resolvedRule\n );\n\n if (matches.length === 0) {\n return;\n }\n\n // Create updated message\n const updatedMessage = new AIMessage({\n content: newContent,\n id: lastAiMsg.id,\n name: lastAiMsg.name,\n tool_calls: lastAiMsg.tool_calls,\n });\n\n // Return updated messages\n const newMessages = [...messages];\n newMessages[lastAiIdx] = updatedMessage;\n return { messages: newMessages };\n },\n });\n}\n","import { z } from \"zod/v3\";\nimport {\n BaseMessage,\n AIMessage,\n HumanMessage,\n ToolMessage,\n RemoveMessage,\n SystemMessage,\n} from \"@langchain/core/messages\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Type for the redaction map that stores original values by ID\n */\ntype RedactionMap = Record<string, string>;\n\n/**\n * Configuration schema for the Input Guardrails middleware\n */\nconst contextSchema = z.object({\n /**\n * A record of PII detection rules to apply\n * @default DEFAULT_PII_RULES (with enabled rules only)\n */\n rules: z\n .record(\n z.string(),\n z.instanceof(RegExp).describe(\"Regular expression pattern to match PII\")\n )\n .optional(),\n});\n\n/**\n * @deprecated\n */\nexport type PIIRedactionMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Generate a unique ID for a redaction\n */\nfunction generateRedactionId(): string {\n return Math.random().toString(36).substring(2, 11);\n}\n\n/**\n * Apply PII detection rules to text with ID tracking\n */\nfunction applyPIIRules(\n text: string,\n rules: Record<string, RegExp>,\n redactionMap: RedactionMap\n): string {\n let processedText = text;\n\n for (const [name, pattern] of Object.entries(rules)) {\n const replacement = name.toUpperCase().replace(/[^a-zA-Z0-9_-]/g, \"\");\n processedText = processedText.replace(pattern, (match) => {\n const id = generateRedactionId();\n redactionMap[id] = match;\n // Create a trackable replacement like [REDACTED_SSN_abc123]\n return `[REDACTED_${replacement}_${id}]`;\n });\n }\n\n return processedText;\n}\n\ninterface ProcessHumanMessageConfig {\n rules: Record<string, RegExp>;\n redactionMap: RedactionMap;\n}\n\n/**\n * Process a single human message for PII detection and redaction\n */\nasync function processMessage(\n message: BaseMessage,\n config: ProcessHumanMessageConfig\n): Promise<BaseMessage> {\n /**\n * handle basic message types\n */\n if (\n HumanMessage.isInstance(message) ||\n ToolMessage.isInstance(message) ||\n SystemMessage.isInstance(message)\n ) {\n const content = message.content as string;\n const processedContent = await applyPIIRules(\n content,\n config.rules,\n config.redactionMap\n );\n\n if (processedContent !== content) {\n const MessageConstructor = Object.getPrototypeOf(message).constructor;\n return new MessageConstructor({\n ...message,\n content: processedContent,\n });\n }\n\n return message;\n }\n\n /**\n * Handle AI messages\n */\n if (AIMessage.isInstance(message)) {\n const content =\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content);\n const toolCalls = JSON.stringify(message.tool_calls);\n const processedContent = await applyPIIRules(\n content,\n config.rules,\n config.redactionMap\n );\n const processedToolCalls = await applyPIIRules(\n toolCalls,\n config.rules,\n config.redactionMap\n );\n\n if (processedContent !== content || processedToolCalls !== toolCalls) {\n return new AIMessage({\n ...message,\n content:\n typeof message.content === \"string\"\n ? processedContent\n : JSON.parse(processedContent),\n tool_calls: JSON.parse(processedToolCalls),\n });\n }\n\n return message;\n }\n\n throw new Error(`Unsupported message type: ${message.type}`);\n}\n\n/**\n * Restore original values from redacted text using the redaction map\n */\nfunction restoreRedactedValues(\n text: string,\n redactionMap: RedactionMap\n): string {\n let restoredText = text;\n\n // Pattern to match redacted values like [REDACTED_SSN_abc123]\n const redactionPattern = /\\[REDACTED_[A-Z_]+_(\\w+)\\]/g;\n\n restoredText = restoredText.replace(redactionPattern, (match, id) => {\n if (redactionMap[id]) {\n return redactionMap[id];\n }\n return match; // Keep original if no mapping found\n });\n\n return restoredText;\n}\n\n/**\n * Restore redacted values in a message (creates a new message object)\n */\nfunction restoreMessage(\n message: BaseMessage,\n redactionMap: RedactionMap\n): { message: BaseMessage; changed: boolean } {\n /**\n * handle basic message types\n */\n if (\n HumanMessage.isInstance(message) ||\n ToolMessage.isInstance(message) ||\n SystemMessage.isInstance(message)\n ) {\n const content = message.content as string;\n const restoredContent = restoreRedactedValues(content, redactionMap);\n if (restoredContent !== content) {\n const MessageConstructor = Object.getPrototypeOf(message).constructor;\n const newMessage = new MessageConstructor({\n ...message,\n content: restoredContent,\n });\n return { message: newMessage, changed: true };\n }\n return { message, changed: false };\n }\n\n /**\n * handle AI messages\n */\n if (AIMessage.isInstance(message)) {\n const content =\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content);\n const toolCalls = JSON.stringify(message.tool_calls);\n const processedContent = restoreRedactedValues(content, redactionMap);\n const processedToolCalls = restoreRedactedValues(toolCalls, redactionMap);\n if (processedContent !== content || processedToolCalls !== toolCalls) {\n return {\n message: new AIMessage({\n ...message,\n content:\n typeof message.content === \"string\"\n ? processedContent\n : JSON.parse(processedContent),\n tool_calls: JSON.parse(processedToolCalls),\n }),\n changed: true,\n };\n }\n\n return { message, changed: false };\n }\n\n throw new Error(`Unsupported message type: ${message.type}`);\n}\n\n/**\n * Creates a middleware that detects and redacts personally identifiable information (PII)\n * from messages before they are sent to model providers, and restores original values\n * in model responses for tool execution.\n *\n * ## Mechanism\n *\n * The middleware intercepts agent execution at two points:\n *\n * ### Request Phase (`wrapModelCall`)\n * - Applies regex-based pattern matching to all message content (HumanMessage, ToolMessage, SystemMessage, AIMessage)\n * - Processes both message text and AIMessage tool call arguments\n * - Each matched pattern generates:\n * - Unique identifier: `generateRedactionId()` → `\"abc123\"`\n * - Redaction marker: `[REDACTED_{RULE_NAME}_{ID}]` → `\"[REDACTED_SSN_abc123]\"`\n * - Redaction map entry: `{ \"abc123\": \"123-45-6789\" }`\n * - Returns modified request with redacted message content\n *\n * ### Response Phase (`afterModel`)\n * - Scans AIMessage responses for redaction markers matching pattern: `/\\[REDACTED_[A-Z_]+_(\\w+)\\]/g`\n * - Replaces markers with original values from redaction map\n * - Handles both standard responses and structured output (via tool calls or JSON content)\n * - For structured output, restores values in both the tool call arguments and the `structuredResponse` state field\n * - Returns new message instances via RemoveMessage/AIMessage to update state\n *\n * ## Data Flow\n *\n * ```\n * User Input: \"My SSN is 123-45-6789\"\n * ↓ [beforeModel]\n * Model Request: \"My SSN is [REDACTED_SSN_abc123]\"\n * ↓ [model invocation]\n * Model Response: tool_call({ \"ssn\": \"[REDACTED_SSN_abc123]\" })\n * ↓ [afterModel]\n * Tool Execution: tool({ \"ssn\": \"123-45-6789\" })\n * ```\n *\n * ## Limitations\n *\n * This middleware provides model provider isolation only. PII may still be present in:\n * - LangGraph state checkpoints (memory, databases)\n * - Network traffic between client and application server\n * - Application logs and trace data\n * - Tool execution arguments and responses\n * - Final agent output\n *\n * For comprehensive PII protection, implement additional controls at the application,\n * network, and storage layers.\n *\n * @param options - Configuration options\n * @param options.rules - Record of detection rules mapping rule names to regex patterns.\n * Rule names are normalized to uppercase and used in redaction markers.\n * Patterns must use the global flag (`/pattern/g`) to match all occurrences.\n *\n * @returns Middleware instance for use with `createAgent`\n *\n * @example Basic usage with custom rules\n * ```typescript\n * import { piiRedactionMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod/v3\";\n *\n * const PII_RULES = {\n * ssn: /\\b\\d{3}-?\\d{2}-?\\d{4}\\b/g,\n * email: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g,\n * phone: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n * };\n *\n * const lookupUser = tool(async ({ ssn }) => {\n * // Receives original value: \"123-45-6789\"\n * return { name: \"John Doe\", account: \"active\" };\n * }, {\n * name: \"lookup_user\",\n * description: \"Look up user by SSN\",\n * schema: z.object({ ssn: z.string() })\n * });\n *\n * const agent = createAgent({\n * model: new ChatOpenAI({ model: \"gpt-4\" }),\n * tools: [lookupUser],\n * middleware: [piiRedactionMiddleware({ rules: PII_RULES })]\n * });\n *\n * const result = await agent.invoke({\n * messages: [new HumanMessage(\"Look up SSN 123-45-6789\")]\n * });\n * // Model request: \"Look up SSN [REDACTED_SSN_abc123]\"\n * // Model response: tool_call({ \"ssn\": \"[REDACTED_SSN_abc123]\" })\n * // Tool receives: { \"ssn\": \"123-45-6789\" }\n * ```\n *\n * @example Runtime rule configuration via context\n * ```typescript\n * const agent = createAgent({\n * model: new ChatOpenAI({ model: \"gpt-4\" }),\n * tools: [someTool],\n * middleware: [piiRedactionMiddleware()]\n * });\n *\n * // Configure rules at runtime via middleware context\n * const result = await agent.invoke(\n * { messages: [new HumanMessage(\"...\")] },\n * {\n * configurable: {\n * PIIRedactionMiddleware: {\n * rules: {\n * ssn: /\\b\\d{3}-?\\d{2}-?\\d{4}\\b/g,\n * email: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g,\n * }\n * }\n * }\n * }\n * );\n * ```\n *\n * @example Custom rule patterns\n * ```typescript\n * const customRules = {\n * employee_id: /EMP-\\d{6}/g,\n * api_key: /sk-[a-zA-Z0-9]{32}/g,\n * credit_card: /\\b\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}\\b/g,\n * };\n *\n * const middleware = piiRedactionMiddleware({ rules: customRules });\n * // Generates markers like: [REDACTED_EMPLOYEE_ID_xyz789]\n * ```\n *\n * @deprecated\n */\nexport function piiRedactionMiddleware(\n options: PIIRedactionMiddlewareConfig = {}\n) {\n const redactionMap: RedactionMap = {};\n\n console.warn(\n \"DEPRECATED: piiRedactionMiddleware is deprecated. Please use piiMiddleware instead, go to https://docs.langchain.com/oss/javascript/langchain/middleware/built-in#pii-detection for more information.\"\n );\n\n return createMiddleware({\n name: \"PIIRedactionMiddleware\",\n contextSchema,\n wrapModelCall: async (request, handler) => {\n /**\n * Merge options with context, following bigTool.ts pattern\n */\n const rules = request.runtime.context.rules ?? options.rules ?? {};\n\n /**\n * If no rules are provided, skip processing\n */\n if (Object.keys(rules).length === 0) {\n return handler(request);\n }\n\n const processedMessages = await Promise.all(\n request.state.messages.map((message: BaseMessage) =>\n processMessage(message, {\n rules,\n redactionMap,\n })\n )\n );\n\n return handler({\n ...request,\n messages: processedMessages,\n });\n },\n afterModel: async (state) => {\n /**\n * If no redactions were made, skip processing\n */\n if (Object.keys(redactionMap).length === 0) {\n return;\n }\n\n const lastMessage = state.messages.at(-1);\n if (!AIMessage.isInstance(lastMessage)) {\n return;\n }\n\n /**\n * In cases where we do structured output via tool calls, we also have to look at the second last message\n * as we add a custom last message to the messages array.\n */\n const secondLastMessage = state.messages.at(-2);\n\n const { message: restoredLastMessage, changed } = restoreMessage(\n lastMessage,\n redactionMap\n );\n\n if (!changed) {\n return;\n }\n\n /**\n * Identify if the last message is a structured response and restore the values if so\n */\n let structuredResponse: Record<string, unknown> | undefined;\n if (\n AIMessage.isInstance(lastMessage) &&\n lastMessage?.tool_calls?.length === 0 &&\n typeof lastMessage.content === \"string\" &&\n lastMessage.content.startsWith(\"{\") &&\n lastMessage.content.endsWith(\"}\")\n ) {\n try {\n structuredResponse = JSON.parse(\n restoreRedactedValues(lastMessage.content, redactionMap)\n );\n } catch {\n // ignore\n }\n }\n\n /**\n * Check if the second last message is a structured response tool call\n */\n const isStructuredResponseToolCall =\n AIMessage.isInstance(secondLastMessage) &&\n secondLastMessage?.tool_calls?.length !== 0 &&\n secondLastMessage?.tool_calls?.some((call) =>\n call.name.startsWith(\"extract-\")\n );\n if (isStructuredResponseToolCall) {\n const {\n message: restoredSecondLastMessage,\n changed: changedSecondLastMessage,\n } = restoreMessage(secondLastMessage, redactionMap);\n const structuredResponseRedacted = secondLastMessage.tool_calls?.find(\n (call) => call.name.startsWith(\"extract-\")\n )?.args;\n const structuredResponse = structuredResponseRedacted\n ? JSON.parse(\n restoreRedactedValues(\n JSON.stringify(structuredResponseRedacted),\n redactionMap\n )\n )\n : undefined;\n if (changed || changedSecondLastMessage) {\n return {\n ...state,\n ...(structuredResponse ? { structuredResponse } : {}),\n messages: [\n new RemoveMessage({ id: secondLastMessage.id as string }),\n new RemoveMessage({ id: lastMessage.id as string }),\n restoredSecondLastMessage,\n restoredLastMessage,\n ],\n };\n }\n }\n\n return {\n ...state,\n ...(structuredResponse ? { structuredResponse } : {}),\n messages: [\n new RemoveMessage({ id: lastMessage.id as string }),\n restoredLastMessage,\n ],\n };\n },\n });\n}\n","import { AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { z as z4 } from \"zod/v4\";\nimport { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Build the error message content for ToolMessage when limit is exceeded.\n *\n * This message is sent to the model, so it should not reference thread/run concepts\n * that the model has no notion of.\n *\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A concise message instructing the model not to call the tool again.\n */\nfunction buildToolMessageContent(toolName: string | undefined): string {\n // Always instruct the model not to call again, regardless of which limit was hit\n if (toolName) {\n return `Tool call limit exceeded. Do not call '${toolName}' again.`;\n }\n return \"Tool call limit exceeded. Do not make additional tool calls.\";\n}\n\nconst VALID_EXIT_BEHAVIORS = [\"continue\", \"error\", \"end\"] as const;\nconst DEFAULT_EXIT_BEHAVIOR = \"continue\";\n\n/**\n * Build the final AI message content for 'end' behavior.\n *\n * This message is displayed to the user, so it should include detailed information\n * about which limits were exceeded.\n *\n * @param threadCount - Current thread tool call count.\n * @param runCount - Current run tool call count.\n * @param threadLimit - Thread tool call limit (if set).\n * @param runLimit - Run tool call limit (if set).\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A formatted message describing which limits were exceeded.\n */\nfunction buildFinalAIMessageContent(\n threadCount: number,\n runCount: number,\n threadLimit: number | undefined,\n runLimit: number | undefined,\n toolName: string | undefined\n): string {\n const toolDesc = toolName ? `'${toolName}' tool` : \"Tool\";\n const exceededLimits: string[] = [];\n\n if (threadLimit !== undefined && threadCount > threadLimit) {\n exceededLimits.push(\n `thread limit exceeded (${threadCount}/${threadLimit} calls)`\n );\n }\n if (runLimit !== undefined && runCount > runLimit) {\n exceededLimits.push(`run limit exceeded (${runCount}/${runLimit} calls)`);\n }\n\n const limitsText = exceededLimits.join(\" and \");\n return `${toolDesc} call limit reached: ${limitsText}.`;\n}\n\n/**\n * Schema for the exit behavior.\n */\nconst exitBehaviorSchema = z\n .enum(VALID_EXIT_BEHAVIORS)\n .default(DEFAULT_EXIT_BEHAVIOR);\n\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n\n constructor(\n threadCount: number,\n runCount: number,\n threadLimit: number | undefined,\n runLimit: number | undefined,\n toolName: string | undefined = undefined\n ) {\n const message = buildFinalAIMessageContent(\n threadCount,\n runCount,\n threadLimit,\n runLimit,\n toolName\n );\n super(message);\n\n this.name = \"ToolCallLimitExceededError\";\n this.threadCount = threadCount;\n this.runCount = runCount;\n this.threadLimit = threadLimit;\n this.runLimit = runLimit;\n this.toolName = toolName;\n }\n}\n\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport const ToolCallLimitOptionsSchema = z.object({\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.string().optional(),\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.number().optional(),\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.number().optional(),\n /**\n * What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately, injecting a ToolMessage and an AI message\n * for the single tool call that exceeded the limit. Raises NotImplementedError\n * if there are multiple tool calls.\n *\n * @default \"continue\"\n */\n exitBehavior: exitBehaviorSchema,\n});\n\nexport type ToolCallLimitConfig = InferInteropZodInput<\n typeof ToolCallLimitOptionsSchema\n>;\n\n/**\n * Middleware state schema to track the number of model calls made at the thread and run level.\n */\nconst stateSchema = z.object({\n threadToolCallCount: z.record(z.string(), z.number()).default({}),\n runToolCallCount: z.record(z.string(), z.number()).default({}),\n});\n\nconst DEFAULT_TOOL_COUNT_KEY = \"__all__\";\n\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.\n *\n * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.\n * @throws {NotImplementedError} If exitBehavior is \"end\" and there are multiple tool calls.\n *\n * @example Continue execution with blocked tools (default)\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * // Block exceeded tools but let other tools and model continue\n * const limiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"continue\", // default\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Stop immediately when limit exceeded\n * ```ts\n * // End execution immediately with an AI message\n * const limiter = toolCallLimitMiddleware({\n * runLimit: 5,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Raise exception on limit\n * ```ts\n * // Strict limit with exception handling\n * const limiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * exitBehavior: \"error\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n *\n * try {\n * const result = await agent.invoke({ messages: [new HumanMessage(\"Task\")] });\n * } catch (error) {\n * if (error instanceof ToolCallLimitExceededError) {\n * console.log(`Search limit exceeded: ${error}`);\n * }\n * }\n * ```\n */\nexport function toolCallLimitMiddleware(options: ToolCallLimitConfig) {\n /**\n * Validate that at least one limit is specified\n */\n if (options.threadLimit === undefined && options.runLimit === undefined) {\n throw new Error(\n \"At least one limit must be specified (threadLimit or runLimit)\"\n );\n }\n\n /**\n * Validate exitBehavior (Zod schema already validates, but provide helpful error)\n */\n const exitBehavior = options.exitBehavior ?? DEFAULT_EXIT_BEHAVIOR;\n const parseResult = exitBehaviorSchema.safeParse(exitBehavior);\n if (!parseResult.success) {\n throw new Error(z4.prettifyError(parseResult.error).slice(2));\n }\n\n /**\n * Validate that runLimit does not exceed threadLimit\n */\n if (\n options.threadLimit !== undefined &&\n options.runLimit !== undefined &&\n options.runLimit > options.threadLimit\n ) {\n throw new Error(\n `runLimit (${options.runLimit}) cannot exceed threadLimit (${options.threadLimit}). ` +\n \"The run limit should be less than or equal to the thread limit.\"\n );\n }\n\n /**\n * Generate the middleware name based on the tool name\n */\n const middlewareName = options.toolName\n ? `ToolCallLimitMiddleware[${options.toolName}]`\n : \"ToolCallLimitMiddleware\";\n\n return createMiddleware({\n name: middlewareName,\n stateSchema,\n afterModel: {\n canJumpTo: [\"end\"],\n hook: (state) => {\n /**\n * Get the last AI message to check for tool calls\n */\n const lastAIMessage = [...state.messages]\n .reverse()\n .find(AIMessage.isInstance);\n\n if (!lastAIMessage || !lastAIMessage.tool_calls) {\n return undefined;\n }\n\n /**\n * Helper to check if limit would be exceeded by one more call\n */\n const wouldExceedLimit = (\n threadCount: number,\n runCount: number\n ): boolean => {\n return (\n (options.threadLimit !== undefined &&\n threadCount + 1 > options.threadLimit) ||\n (options.runLimit !== undefined && runCount + 1 > options.runLimit)\n );\n };\n\n /**\n * Helper to check if a tool call matches our filter\n */\n const matchesToolFilter = (toolCall: { name?: string }): boolean => {\n return (\n options.toolName === undefined || toolCall.name === options.toolName\n );\n };\n\n /**\n * Separate tool calls into allowed and blocked based on limits\n */\n const separateToolCalls = (\n toolCalls: ToolCall[],\n threadCount: number,\n runCount: number\n ): {\n allowed: ToolCall[];\n blocked: ToolCall[];\n finalThreadCount: number;\n finalRunCount: number;\n } => {\n const allowed: ToolCall[] = [];\n const blocked: ToolCall[] = [];\n let tempThreadCount = threadCount;\n let tempRunCount = runCount;\n\n for (const toolCall of toolCalls) {\n if (!matchesToolFilter(toolCall)) {\n // Tool call doesn't match our filter, skip it\n continue;\n }\n\n if (wouldExceedLimit(tempThreadCount, tempRunCount)) {\n blocked.push(toolCall);\n } else {\n allowed.push(toolCall);\n tempThreadCount += 1;\n tempRunCount += 1;\n }\n }\n\n return {\n allowed,\n blocked,\n finalThreadCount: tempThreadCount,\n finalRunCount: tempRunCount + blocked.length,\n };\n };\n\n /**\n * Get the count key for this middleware instance\n */\n const countKey = options.toolName ?? DEFAULT_TOOL_COUNT_KEY;\n\n /**\n * Get current counts\n */\n const threadCounts = { ...(state.threadToolCallCount ?? {}) };\n const runCounts = { ...(state.runToolCallCount ?? {}) };\n const currentThreadCount = threadCounts[countKey] ?? 0;\n const currentRunCount = runCounts[countKey] ?? 0;\n\n /**\n * Separate tool calls into allowed and blocked\n */\n const { allowed, blocked, finalThreadCount, finalRunCount } =\n separateToolCalls(\n lastAIMessage.tool_calls,\n currentThreadCount,\n currentRunCount\n );\n\n /**\n * Update counts:\n * - Thread count includes only allowed calls (blocked calls don't count towards thread-level tracking)\n * - Run count includes blocked calls since they were attempted in this run\n */\n threadCounts[countKey] = finalThreadCount;\n runCounts[countKey] = finalRunCount;\n\n /**\n * If no tool calls are blocked, just update counts\n */\n if (blocked.length === 0) {\n if (allowed.length > 0) {\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n };\n }\n return undefined;\n }\n\n /**\n * Handle different exit behaviors\n */\n if (exitBehavior === \"error\") {\n // Use hypothetical thread count to show which limit was exceeded\n const hypotheticalThreadCount = finalThreadCount + blocked.length;\n throw new ToolCallLimitExceededError(\n hypotheticalThreadCount,\n finalRunCount,\n options.threadLimit,\n options.runLimit,\n options.toolName\n );\n }\n\n /**\n * Build tool message content (sent to model - no thread/run details)\n */\n const toolMsgContent = buildToolMessageContent(options.toolName);\n\n /**\n * Inject artificial error ToolMessages for blocked tool calls\n */\n const artificialMessages: Array<ToolMessage | AIMessage> = blocked.map(\n (toolCall) =>\n new ToolMessage({\n content: toolMsgContent,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n })\n );\n\n if (exitBehavior === \"end\") {\n /**\n * Check if there are tool calls to other tools that would continue executing\n * For tool-specific limiters: check for calls to other tools\n * For global limiters: check if there are multiple different tool types\n */\n let otherTools: ToolCall[] = [];\n if (options.toolName !== undefined) {\n /**\n * Tool-specific limiter: check for calls to other tools\n */\n otherTools = lastAIMessage.tool_calls.filter(\n (tc) => tc.name !== options.toolName\n );\n } else {\n /**\n * Global limiter: check if there are multiple different tool types\n * If there are allowed calls, those would execute\n * But even if all are blocked, we can't handle multiple tool types with \"end\"\n */\n const uniqueToolNames = new Set(\n lastAIMessage.tool_calls.map((tc) => tc.name).filter(Boolean)\n );\n if (uniqueToolNames.size > 1) {\n /**\n * Multiple different tool types - use allowed calls to show which ones\n */\n otherTools =\n allowed.length > 0 ? allowed : lastAIMessage.tool_calls;\n }\n }\n\n if (otherTools.length > 0) {\n const toolNames = Array.from(\n new Set(otherTools.map((tc) => tc.name).filter(Boolean))\n ).join(\", \");\n throw new Error(\n `Cannot end execution with other tool calls pending. Found calls to: ${toolNames}. Use 'continue' or 'error' behavior instead.`\n );\n }\n\n /**\n * Build final AI message content (displayed to user - includes thread/run details)\n * Use hypothetical thread count (what it would have been if call wasn't blocked)\n * to show which limit was actually exceeded\n */\n const hypotheticalThreadCount = finalThreadCount + blocked.length;\n const finalMsgContent = buildFinalAIMessageContent(\n hypotheticalThreadCount,\n finalRunCount,\n options.threadLimit,\n options.runLimit,\n options.toolName\n );\n artificialMessages.push(new AIMessage(finalMsgContent));\n\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n jumpTo: \"end\" as const,\n messages: artificialMessages,\n };\n }\n\n /**\n * For exit_behavior=\"continue\", return error messages to block exceeded tools\n */\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n messages: artificialMessages,\n };\n },\n },\n /**\n * reset the run tool call count after the agent execution completes\n */\n afterAgent: () => ({\n runToolCallCount: {},\n }),\n });\n}\n","import { z } from \"zod/v3\";\nimport { Command } from \"@langchain/langgraph\";\nimport { tool } from \"@langchain/core/tools\";\nimport { AIMessage, ToolMessage } from \"@langchain/core/messages\";\n\nimport { createMiddleware } from \"../index.js\";\n\n/**\n * Description for the write_todos tool\n * Ported exactly from Python WRITE_TODOS_DESCRIPTION\n */\nconst WRITE_TODOS_DESCRIPTION = `Use this tool to create and manage a structured task list for your current work session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.\nIt also helps the user understand the progress of the task and overall progress of their requests.\nOnly use this tool if you think it will be helpful in staying organized. If the user's request is trivial and takes less than 3 steps, it is better to NOT use this tool and just do the task directly.\n\n## When to Use This Tool\nUse this tool in these scenarios:\n\n1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions\n2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations\n3. User explicitly requests todo list - When the user directly asks you to use the todo list\n4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)\n5. The plan may need future revisions or updates based on results from the first few steps. Keeping track of this in a list is helpful.\n\n## How to Use This Tool\n1. When you start working on a task - Mark it as in_progress BEFORE beginning work.\n2. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation.\n3. You can also update future tasks, such as deleting them if they are no longer necessary, or adding new tasks that are necessary. Don't change previously completed tasks.\n4. You can make several updates to the todo list at once. For example, when you complete a task, you can mark the next task you need to start as in_progress.\n\n## When NOT to Use This Tool\nIt is important to skip using this tool when:\n1. There is only a single, straightforward task\n2. The task is trivial and tracking it provides no benefit\n3. The task can be completed in less than 3 trivial steps\n4. The task is purely conversational or informational\n\n## Examples of When to Use the Todo List\n\n<example>\nUser: I want to add a dark mode toggle to the application settings. Make sure you run the tests and build when you're done!\nAssistant: I'll help add a dark mode toggle to your application settings. Let me create a todo list to track this implementation.\n*Creates todo list with the following items:*\n1. Create dark mode toggle component in Settings page\n2. Add dark mode state management (context/store)\n3. Implement CSS-in-JS styles for dark theme\n4. Update existing components to support theme switching\n5. Run tests and build process, addressing any failures or errors that occur\n*Begins working on the first task*\n\n<reasoning>\nThe assistant used the todo list because:\n1. Adding dark mode in it of itself is a multi-step feature requiring UI, state management, and styling changes\n2. The assistant inferred that tests and build need to pass by adding \"Ensure tests and build succeed\" as the final task\n3. Both of the user's requests are complex and require multiple steps to complete.\n</reasoning>\n</example>\n\n<example>\nUser: Help me plan a comprehensive marketing campaign for our new product launch, including social media, email marketing, and press releases.\nAssistant: I'll help you plan a comprehensive marketing campaign for your product launch. Let me create a todo list to organize all the components.\n*Creates todo list with the following items:*\n1. Define target audience and key messaging\n2. Create social media content calendar and posting schedule\n3. Design email marketing sequence and automation flows\n4. Draft press release and identify media contacts\n5. Set up tracking and analytics for campaign performance\n6. Create visual assets and brand materials\n7. Coordinate launch timeline and deliverables\n*Begins working on the first task*\n\n<reasoning>\nThe assistant used the todo list because:\n1. Marketing campaign planning involves multiple distinct channels and activities\n2. Each component requires careful coordination and planning\n3. The systematic approach ensures all aspects of the launch are covered\n</reasoning>\n</example>\n\n<example>\nUser: Help me rename the function getCwd to getCurrentWorkingDirectory across my project\nAssistant: Let me first search through your codebase to find all occurrences of 'getCwd'.\n*Uses search tools to locate all instances of getCwd in the codebase*\nAssistant: I've found 15 instances of 'getCwd' across 8 different files. Let me create a todo list to track these changes.\n*Creates todo list with specific items for each file that needs updating*\n\n<reasoning>\nThe assistant used the todo list because:\n1. The assistant searched to understand the scope of the task\n2. Upon finding multiple occurrences across different files, it determined this was a complex task with multiple steps (>3)\n3. The todo list helps ensure every instance is tracked and updated systematically\n4. This approach prevents missing any occurrences and maintains consistency.\n</reasoning>\n</example>\n\n<example>\nUser: I need help organizing my home office: decluttering the desk, setting up a filing system, organizing digital files, and creating a daily workflow.\nAssistant: I'll help you organize your home office systematically. Let me create a todo list to track each area of organization.\n*Creates todo list with items like: 1) Sort and declutter desk items, 2) Set up physical filing system for documents, 3) Organize digital files and folders, 4) Create daily workflow and productivity systems, 5) Establish maintenance routines*\nLet's start with decluttering your desk space to create a clean foundation for the other organizational systems.\n\n<reasoning>\nThe assistant used the todo list because:\n1. The user provided multiple distinct organizational tasks\n2. Each area requires different approaches and careful planning\n3. Home organization benefits from systematic, step-by-step completion\n4. Progress tracking ensures all areas are addressed thoroughly\n</reasoning>\n</example>\n\n## Examples of When NOT to Use the Todo List\n\n<example>\nUser: How do I print 'Hello World' in Python?\nAssistant: In Python, you can print \"Hello World\" with this simple code:\n\n\\`\\`\\`python\nprint(\"Hello World\")\n\\`\\`\\`\n\nThis will output the text \"Hello World\" to the console when executed.</assistant>\n\n<reasoning>\nThe assistant did not use the todo list because this is a single, trivial task that can be completed in one step. There's no need to track multiple tasks or steps for such a straightforward request.\n</reasoning>\n</example>\n\n<example>\nUser: What's the best way to water houseplants?\nAssistant: The best way to water houseplants depends on the specific plant type, but here are some general guidelines:\n\n- Check soil moisture by inserting your finger about 1-2 inches into the soil\n- Water thoroughly when the top inch feels dry, allowing water to drain from the bottom\n- Use room temperature water and water in the morning when possible\n- Avoid overwatering, which is more harmful than underwatering for most plants\n\nDifferent plants have different needs, so it's important to research your specific varieties for optimal care.\n\n<reasoning>\nThe assistant did not use the todo list because this is an informational request with no actual tasks to complete. The user is simply asking for advice and explanation, not for the assistant to perform multiple steps or activities.\n</reasoning>\n</example>\n\n<example>\nUser: Can you add a comment to the calculateTotal function to explain what it does?\nAssistant: Sure, let me add a comment to the calculateTotal function to explain what it does.\n* Uses the Edit tool to add a comment to the calculateTotal function *\n\n<reasoning>\nThe assistant did not use the todo list because this is a single, straightforward task confined to one location. Adding a comment doesn't require tracking multiple steps or systematic organization.\n</reasoning>\n</example>\n\n<example>\nUser: What time is it in Tokyo right now?\nAssistant: I'll check the current time in Tokyo for you.\n\n*Searches for current time in Tokyo*\n\nThe current time in Tokyo, Japan is [current time]. Tokyo is in the Japan Standard Time (JST) zone, which is UTC+9.\n\n<reasoning>\nThe assistant did not use the todo list because this is a single information lookup with immediate results. There are no multiple steps to track or organize, making the todo list unnecessary for this straightforward request.\n</reasoning>\n</example>\n\n<example>\nUser: I need to write a function that checks if a number is prime and then test it out.\nAssistant: I'll help you write a function that checks if a number is prime and then test it out.\n*Writes function that checks if a number is prime*\n*Tests the function*\n\n<reasoning>\nEven though this is a multi-step task, it is very straightforward and can be completed in two trivial steps (which is less than 3 steps!). Using the todo list here is overkill and wastes time and tokens.\n</reasoning>\n</example>\n\n<example>\nUser: I want you to order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway.\nAssistant: I'll help you order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway.\n*Orders a pizza from Dominos*\n*Orders a burger from McDonald's*\n*Orders a salad from Subway*\n\n<reasoning>\nEven though this is a multi-step task, assuming the assistant has the ability to order from these restaurants, it is very straightforward and can be completed in three trivial tool calls. \nUsing the todo list here is overkill and wastes time and tokens. These three tool calls should be made in parallel, in fact.\n</reasoning>\n</example>\n\n\n## Task States and Management\n\n1. **Task States**: Use these states to track progress:\n - pending: Task not yet started\n - in_progress: Currently working on (you can have multiple tasks in_progress at a time if they are not related to each other and can be run in parallel)\n - completed: Task finished successfully\n\n2. **Task Management**:\n - Update task status in real-time as you work\n - Mark tasks complete IMMEDIATELY after finishing (don't batch completions)\n - Complete current tasks before starting new ones\n - Remove tasks that are no longer relevant from the list entirely\n - IMPORTANT: When you write this todo list, you should mark your first task (or tasks) as in_progress immediately!.\n - IMPORTANT: Unless all tasks are completed, you should always have at least one task in_progress to show the user that you are working on something.\n\n3. **Task Completion Requirements**:\n - ONLY mark a task as completed when you have FULLY accomplished it\n - If you encounter errors, blockers, or cannot finish, keep the task as in_progress\n - When blocked, create a new task describing what needs to be resolved\n - Never mark a task as completed if:\n - There are unresolved issues or errors\n - Work is partial or incomplete\n - You encountered blockers that prevent completion\n - You couldn't find necessary resources or dependencies\n - Quality standards haven't been met\n\n4. **Task Breakdown**:\n - Create specific, actionable items\n - Break complex tasks into smaller, manageable steps\n - Use clear, descriptive task names\n\nBeing proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully\nRemember: If you only need to make a few tool calls to complete a task, and it is clear what you need to do, it is better to just do the task directly and NOT call this tool at all.`;\n\nexport const TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT = `## \\`write_todos\\`\n\nYou have access to the \\`write_todos\\` tool to help you manage and plan complex objectives. \nUse this tool for complex objectives to ensure that you are tracking each necessary step and giving the user visibility into your progress.\nThis tool is very helpful for planning complex objectives, and for breaking down these larger complex objectives into smaller steps.\n\nIt is critical that you mark todos as completed as soon as you are done with a step. Do not batch up multiple steps before marking them as completed.\nFor simple objectives that only require a few steps, it is better to just complete the objective directly and NOT use this tool.\nWriting todos takes time and tokens, use it when it is helpful for managing complex many-step problems! But not for simple few-step requests.\n\n## Important To-Do List Usage Notes to Remember\n- The \\`write_todos\\` tool should never be called multiple times in parallel.\n- Don't be afraid to revise the To-Do list as you go. New information may reveal new tasks that need to be done, or old tasks that are irrelevant.`;\n\nconst TodoStatus = z\n .enum([\"pending\", \"in_progress\", \"completed\"])\n .describe(\"Status of the todo\");\nconst TodoSchema = z.object({\n content: z.string().describe(\"Content of the todo item\"),\n status: TodoStatus,\n});\nexport type Todo = z.infer<typeof TodoSchema>;\n\nconst stateSchema = z.object({\n todos: z.array(TodoSchema).default([]),\n});\nexport type TodoMiddlewareState = z.infer<typeof stateSchema>;\n\nexport interface TodoListMiddlewareOptions {\n /**\n * Custom system prompt to guide the agent on using the todo tool.\n * If not provided, uses the default {@link PLANNING_MIDDLEWARE_SYSTEM_PROMPT}.\n */\n systemPrompt?: string;\n /**\n * Custom description for the {@link writeTodos} tool.\n * If not provided, uses the default {@link WRITE_TODOS_DESCRIPTION}.\n */\n toolDescription?: string;\n}\n\n/**\n * Creates a middleware that provides todo list management capabilities to agents.\n *\n * This middleware adds a `write_todos` tool that allows agents to create and manage\n * structured task lists for complex multi-step operations. It's designed to help\n * agents track progress, organize complex tasks, and provide users with visibility\n * into task completion status.\n *\n * The middleware automatically injects system prompts that guide the agent on when\n * and how to use the todo functionality effectively. It also enforces that the\n * `write_todos` tool is called at most once per model turn, since the tool replaces\n * the entire todo list and parallel calls would create ambiguity about precedence.\n *\n * @example\n * ```typescript\n * import { todoListMiddleware, createAgent } from 'langchain';\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [todoListMiddleware()],\n * });\n *\n * // Agent now has access to write_todos tool and todo state tracking\n * const result = await agent.invoke({\n * messages: [new HumanMessage(\"Help me refactor my codebase\")]\n * });\n *\n * console.log(result.todos); // Array of todo items with status tracking\n * ```\n *\n * @returns A configured middleware instance that provides todo management capabilities\n *\n * @see {@link TodoMiddlewareState} for the state schema\n * @see {@link writeTodos} for the tool implementation\n */\nexport function todoListMiddleware(options?: TodoListMiddlewareOptions) {\n /**\n * Write todos tool - manages todo list with Command return\n */\n const writeTodos = tool(\n ({ todos }, config) => {\n return new Command({\n update: {\n todos,\n messages: [\n new ToolMessage({\n content: `Updated todo list to ${JSON.stringify(todos)}`,\n tool_call_id: config.toolCall?.id as string,\n name: \"write_todos\",\n }),\n ],\n },\n });\n },\n {\n name: \"write_todos\",\n description: options?.toolDescription ?? WRITE_TODOS_DESCRIPTION,\n schema: z.object({\n todos: z.array(TodoSchema).describe(\"List of todo items to update\"),\n }),\n }\n );\n\n return createMiddleware({\n name: \"todoListMiddleware\",\n stateSchema,\n tools: [writeTodos],\n wrapModelCall: (request, handler) =>\n handler({\n ...request,\n systemMessage: request.systemMessage.concat(\n `\\n\\n${options?.systemPrompt ?? TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT}`\n ),\n }),\n afterModel: (state) => {\n /**\n * Check for parallel write_todos tool calls and return errors if detected.\n *\n * The todo list is designed to be updated at most once per model turn. Since\n * the `write_todos` tool replaces the entire todo list with each call, making\n * multiple parallel calls would create ambiguity about which update should take\n * precedence. This method prevents such conflicts by rejecting any response that\n * contains multiple write_todos tool calls.\n */\n const messages = state.messages;\n if (!messages || messages.length === 0) {\n return undefined;\n }\n\n /**\n * Find the last AI message\n */\n const lastAiMsg = [...messages]\n .reverse()\n .find((msg) => AIMessage.isInstance(msg));\n if (\n !lastAiMsg ||\n !lastAiMsg.tool_calls ||\n lastAiMsg.tool_calls.length === 0\n ) {\n return undefined;\n }\n\n /**\n * Count write_todos tool calls\n */\n const writeTodosCalls = lastAiMsg.tool_calls.filter(\n (tc) => tc.name === writeTodos.name\n );\n\n if (writeTodosCalls.length > 1) {\n /**\n * Create error tool messages for all write_todos calls\n */\n const errorMessages = writeTodosCalls.map(\n (tc) =>\n new ToolMessage({\n content:\n \"Error: The `write_todos` tool should never be called multiple times \" +\n \"in parallel. Please call it only once per model invocation to update \" +\n \"the todo list.\",\n tool_call_id: tc.id as string,\n name: \"write_todos\",\n status: \"error\",\n })\n );\n\n /**\n * Keep the tool calls in the AI message but return error messages\n * This follows the same pattern as HumanInTheLoopMiddleware\n */\n return { messages: errorMessages };\n }\n\n return undefined;\n },\n });\n}\n","import { z } from \"zod/v3\";\nimport { AIMessage } from \"@langchain/core/messages\";\nimport { InferInteropZodInput } from \"@langchain/core/utils/types\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\nconst DEFAULT_EXIT_BEHAVIOR = \"end\";\n\nconst contextSchema = z.object({\n /**\n * The maximum number of model calls allowed per thread.\n */\n threadLimit: z.number().optional(),\n /**\n * The maximum number of model calls allowed per run.\n */\n runLimit: z.number().optional(),\n /**\n * The behavior to take when the limit is exceeded.\n * - \"error\" will throw an error and stop the agent.\n * - \"end\" will end the agent.\n * @default \"end\"\n */\n exitBehavior: z.enum([\"error\", \"end\"]).optional(),\n});\nexport type ModelCallLimitMiddlewareConfig = Partial<\n InferInteropZodInput<typeof contextSchema>\n>;\n\n/**\n * Middleware state schema to track the number of model calls made at the thread and run level.\n */\nconst stateSchema = z.object({\n threadModelCallCount: z.number().default(0),\n runModelCallCount: z.number().default(0),\n});\n\n/**\n * Error thrown when the model call limit is exceeded.\n *\n * @param threadLimit - The maximum number of model calls allowed per thread.\n * @param runLimit - The maximum number of model calls allowed per run.\n * @param threadCount - The number of model calls made at the thread level.\n * @param runCount - The number of model calls made at the run level.\n */\nclass ModelCallLimitMiddlewareError extends Error {\n constructor({\n threadLimit,\n runLimit,\n threadCount,\n runCount,\n }: {\n threadLimit?: number;\n runLimit?: number;\n threadCount?: number;\n runCount?: number;\n }) {\n const exceededHint: string[] = [];\n if (typeof threadLimit === \"number\" && typeof threadCount === \"number\") {\n exceededHint.push(\n `thread level call limit reached with ${threadCount} model calls`\n );\n }\n if (typeof runLimit === \"number\" && typeof runCount === \"number\") {\n exceededHint.push(\n `run level call limit reached with ${runCount} model calls`\n );\n }\n super(\n `Model call limits exceeded${\n exceededHint.length > 0 ? `: ${exceededHint.join(\", \")}` : \"\"\n }`\n );\n this.name = \"ModelCallLimitMiddlewareError\";\n }\n}\n\n/**\n * Creates a middleware to limit the number of model calls at both thread and run levels.\n *\n * This middleware helps prevent excessive model API calls by enforcing limits on how many\n * times the model can be invoked. It supports two types of limits:\n *\n * - **Thread-level limit**: Restricts the total number of model calls across an entire conversation thread\n * - **Run-level limit**: Restricts the number of model calls within a single agent run/invocation\n *\n * ## How It Works\n *\n * The middleware intercepts model requests before they are sent and checks the current call counts\n * against the configured limits. If either limit is exceeded, it throws a `ModelCallLimitMiddlewareError`\n * to stop execution and prevent further API calls.\n *\n * ## Use Cases\n *\n * - **Cost Control**: Prevent runaway costs from excessive model calls in production\n * - **Testing**: Ensure agents don't make too many calls during development/testing\n * - **Safety**: Limit potential infinite loops or recursive agent behaviors\n * - **Rate Limiting**: Enforce organizational policies on model usage per conversation\n *\n * @param middlewareOptions - Configuration options for the call limits\n * @param middlewareOptions.threadLimit - Maximum number of model calls allowed per thread (optional)\n * @param middlewareOptions.runLimit - Maximum number of model calls allowed per run (optional)\n *\n * @returns A middleware instance that can be passed to `createAgent`\n *\n * @throws {ModelCallLimitMiddlewareError} When either the thread or run limit is exceeded\n *\n * @example\n * ```typescript\n * import { createAgent, modelCallLimitMiddleware } from \"langchain\";\n *\n * // Limit to 10 calls per thread and 3 calls per run\n * const agent = createAgent({\n * model: \"openai:gpt-4o-mini\",\n * tools: [myTool],\n * middleware: [\n * modelCallLimitMiddleware({\n * threadLimit: 10,\n * runLimit: 3\n * })\n * ]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Limits can also be configured at runtime via context\n * const result = await agent.invoke(\n * { messages: [\"Hello\"] },\n * {\n * configurable: {\n * threadLimit: 5 // Override the default limit for this run\n * }\n * }\n * );\n * ```\n */\nexport function modelCallLimitMiddleware(\n middlewareOptions?: ModelCallLimitMiddlewareConfig\n) {\n return createMiddleware({\n name: \"ModelCallLimitMiddleware\",\n contextSchema,\n stateSchema,\n beforeModel: {\n canJumpTo: [\"end\"],\n hook: (state, runtime) => {\n let exitBehavior =\n runtime.context.exitBehavior ??\n middlewareOptions?.exitBehavior ??\n DEFAULT_EXIT_BEHAVIOR;\n\n // @ts-expect-error - throw is deprecated\n if (exitBehavior === \"throw\") {\n console.warn(\n \"The 'throw' exit behavior is deprecated. Please use 'error' instead.\"\n );\n exitBehavior = \"error\";\n }\n\n const threadLimit =\n runtime.context.threadLimit ?? middlewareOptions?.threadLimit;\n const runLimit =\n runtime.context.runLimit ?? middlewareOptions?.runLimit;\n\n const threadCount = state.threadModelCallCount;\n const runCount = state.runModelCallCount;\n if (typeof threadLimit === \"number\" && threadLimit <= threadCount) {\n const error = new ModelCallLimitMiddlewareError({\n threadLimit,\n threadCount,\n });\n if (exitBehavior === \"end\") {\n return {\n jumpTo: \"end\",\n messages: [new AIMessage(error.message)],\n };\n }\n\n throw error;\n }\n if (typeof runLimit === \"number\" && runLimit <= runCount) {\n const error = new ModelCallLimitMiddlewareError({\n runLimit,\n runCount,\n });\n if (exitBehavior === \"end\") {\n return {\n jumpTo: \"end\",\n messages: [new AIMessage(error.message)],\n };\n }\n\n throw error;\n }\n\n return state;\n },\n },\n afterModel: (state) => ({\n runModelCallCount: state.runModelCallCount + 1,\n threadModelCallCount: state.threadModelCallCount + 1,\n }),\n afterAgent: () => ({\n runModelCallCount: 0,\n }),\n });\n}\n","/**\n * Model retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { AIMessage } from \"@langchain/core/messages\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport { sleep, calculateRetryDelay, getRetryAfterMs } from \"./utils.js\";\nimport { RetrySchema } from \"./constants.js\";\nimport { InvalidRetryConfigError } from \"./error.js\";\n\n/**\n * Configuration options for the Model Retry Middleware.\n */\nexport const ModelRetryMiddlewareOptionsSchema = z\n .object({\n /**\n * Behavior when all retries are exhausted. Options:\n * - `\"continue\"` (default): Return an AIMessage with error details, allowing\n * the agent to potentially handle the failure gracefully.\n * - `\"error\"`: Re-raise the exception, stopping agent execution.\n * - Custom function: Function that takes the exception and returns a string\n * for the AIMessage content, allowing custom error formatting.\n */\n onFailure: z\n .union([\n z.literal(\"error\"),\n z.literal(\"continue\"),\n z.function().args(z.instanceof(Error)).returns(z.string()),\n ])\n .default(\"continue\"),\n })\n .merge(RetrySchema);\n\nexport type ModelRetryMiddlewareConfig = z.input<\n typeof ModelRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed model calls with configurable backoff.\n *\n * Supports retrying on specific exceptions and exponential backoff.\n *\n * @example Basic usage with default settings (2 retries, exponential backoff)\n * ```ts\n * import { createAgent, modelRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * middleware: [modelRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { modelRetryMiddleware } from \"langchain\";\n *\n * const retry = modelRetryMiddleware({\n * maxRetries: 4,\n * retryOn: [TimeoutError, NetworkError],\n * backoffFactor: 1.5,\n * });\n * ```\n *\n * @example Custom exception filtering\n * ```ts\n * function shouldRetry(error: Error): boolean {\n * // Only retry on rate limit errors\n * if (error.name === \"RateLimitError\") {\n * return true;\n * }\n * // Or check for specific HTTP status codes\n * if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n * const statusCode = (error as any).statusCode;\n * return statusCode === 429 || statusCode === 503;\n * }\n * return false;\n * }\n *\n * const retry = modelRetryMiddleware({\n * maxRetries: 3,\n * retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Return error message instead of raising\n * ```ts\n * const retry = modelRetryMiddleware({\n * maxRetries: 4,\n * onFailure: \"continue\", // Return AIMessage with error instead of throwing\n * });\n * ```\n *\n * @example Custom error message formatting\n * ```ts\n * const formatError = (error: Error) =>\n * `Model call failed: ${error.message}. Please try again later.`;\n *\n * const retry = modelRetryMiddleware({\n * maxRetries: 4,\n * onFailure: formatError,\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = modelRetryMiddleware({\n * maxRetries: 5,\n * backoffFactor: 0.0, // No exponential growth\n * initialDelayMs: 2000, // Always wait 2 seconds\n * });\n * ```\n *\n * @example Raise exception on failure\n * ```ts\n * const retry = modelRetryMiddleware({\n * maxRetries: 2,\n * onFailure: \"error\", // Re-raise exception instead of returning message\n * });\n * ```\n *\n * @param config - Configuration options for the retry middleware\n * @returns A middleware instance that handles model failures with retries\n */\nexport function modelRetryMiddleware(config: ModelRetryMiddlewareConfig = {}) {\n const { success, error, data } =\n ModelRetryMiddlewareOptionsSchema.safeParse(config);\n if (!success) {\n throw new InvalidRetryConfigError(error);\n }\n const {\n maxRetries,\n retryOn,\n onFailure,\n backoffFactor,\n initialDelayMs,\n maxDelayMs,\n jitter,\n } = data;\n\n /**\n * Check if the exception should trigger a retry.\n */\n const shouldRetryException = (error: Error): boolean => {\n if (typeof retryOn === \"function\") {\n return retryOn(error);\n }\n // retryOn is an array of error constructors\n return retryOn.some(\n (ErrorConstructor) => error.constructor === ErrorConstructor\n );\n };\n\n // Use the exported calculateRetryDelay function with our config\n const delayConfig = { backoffFactor, initialDelayMs, maxDelayMs, jitter };\n\n /**\n * Format the failure message when retries are exhausted.\n */\n const formatFailureMessage = (error: Error, attemptsMade: number): string => {\n const errorType = error.constructor.name;\n const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n return `Model call failed after ${attemptsMade} ${attemptWord} with ${errorType}: ${error.message}`;\n };\n\n /**\n * Handle failure when all retries are exhausted.\n */\n const handleFailure = (error: Error, attemptsMade: number): AIMessage => {\n if (onFailure === \"error\") {\n throw error;\n }\n\n let content: string;\n if (typeof onFailure === \"function\") {\n content = onFailure(error);\n } else {\n content = formatFailureMessage(error, attemptsMade);\n }\n\n return new AIMessage({\n content,\n });\n };\n\n return createMiddleware({\n name: \"modelRetryMiddleware\",\n contextSchema: ModelRetryMiddlewareOptionsSchema,\n wrapModelCall: async (request, handler) => {\n const delegated = {\n ...request,\n modelSettings: { maxRetries: 0, ...request.modelSettings },\n };\n\n // Initial attempt + retries\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await handler(delegated);\n } catch (error) {\n const attemptsMade = attempt + 1; // attempt is 0-indexed\n\n // Ensure error is an Error instance\n const err =\n error && typeof error === \"object\" && \"message\" in error\n ? (error as Error)\n : new Error(String(error));\n\n // Check if we should retry this exception\n if (!shouldRetryException(err)) {\n // Exception is not retryable, handle failure immediately\n return handleFailure(err, attemptsMade);\n }\n\n // Check if we have more retries left\n if (attempt < maxRetries) {\n // Calculate and apply backoff delay\n const delay = calculateRetryDelay(\n delayConfig,\n attempt,\n getRetryAfterMs(err)\n );\n if (delay > 0) {\n await sleep(delay);\n }\n // Continue to next retry\n } else {\n // No more retries, handle failure\n return handleFailure(err, attemptsMade);\n }\n }\n }\n\n // Unreachable: loop always returns via handler success or handleFailure\n throw new Error(\"Unexpected: retry loop completed without returning\");\n },\n });\n}\n","/**\n * Tool retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport { sleep, calculateRetryDelay, getRetryAfterMs } from \"./utils.js\";\nimport { RetrySchema } from \"./constants.js\";\nimport { InvalidRetryConfigError } from \"./error.js\";\n\n/**\n * Configuration options for the Tool Retry Middleware.\n */\nexport const ToolRetryMiddlewareOptionsSchema = z\n .object({\n /**\n * Optional list of tools or tool names to apply retry logic to.\n * Can be a list of `BaseTool` instances or tool name strings.\n * If `undefined`, applies to all tools. Default is `undefined`.\n */\n tools: z\n .array(\n z.union([z.custom<ClientTool>(), z.custom<ServerTool>(), z.string()])\n )\n .optional(),\n\n /**\n * Behavior when all retries are exhausted. Options:\n * - `\"continue\"` (default): Return an AIMessage with error details, allowing\n * the agent to potentially handle the failure gracefully.\n * - `\"error\"`: Re-raise the exception, stopping agent execution.\n * - Custom function: Function that takes the exception and returns a string\n * for the AIMessage content, allowing custom error formatting.\n *\n * Deprecated values:\n * - `\"raise\"`: use `\"error\"` instead.\n * - `\"return_message\"`: use `\"continue\"` instead.\n */\n onFailure: z\n .union([\n z.literal(\"error\"),\n z.literal(\"continue\"),\n /**\n * @deprecated Use `\"error\"` instead.\n */\n z.literal(\"raise\"),\n /**\n * @deprecated Use `\"continue\"` instead.\n */\n z.literal(\"return_message\"),\n z.function().args(z.instanceof(Error)).returns(z.string()),\n ])\n .default(\"continue\"),\n })\n .merge(RetrySchema);\n\nexport type ToolRetryMiddlewareConfig = z.input<\n typeof ToolRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed tool calls with configurable backoff.\n *\n * Supports retrying on specific exceptions and exponential backoff.\n *\n * @example Basic usage with default settings (2 retries, exponential backoff)\n * ```ts\n * import { createAgent, toolRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * middleware: [toolRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { toolRetryMiddleware } from \"langchain\";\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * retryOn: [TimeoutError, NetworkError],\n * backoffFactor: 1.5,\n * });\n * ```\n *\n * @example Custom exception filtering\n * ```ts\n * function shouldRetry(error: Error): boolean {\n * // Only retry on 5xx errors\n * if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n * const statusCode = (error as any).statusCode;\n * return 500 <= statusCode && statusCode < 600;\n * }\n * return false;\n * }\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 3,\n * retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Apply to specific tools with custom error handling\n * ```ts\n * const formatError = (error: Error) =>\n * \"Database temporarily unavailable. Please try again later.\";\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [\"search_database\"],\n * onFailure: formatError,\n * });\n * ```\n *\n * @example Apply to specific tools using BaseTool instances\n * ```ts\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const searchDatabase = tool(\n * async ({ query }) => {\n * // Search implementation\n * return results;\n * },\n * {\n * name: \"search_database\",\n * description: \"Search the database\",\n * schema: z.object({ query: z.string() }),\n * }\n * );\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [searchDatabase], // Pass BaseTool instance\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = toolRetryMiddleware({\n * maxRetries: 5,\n * backoffFactor: 0.0, // No exponential growth\n * initialDelayMs: 2000, // Always wait 2 seconds\n * });\n * ```\n *\n * @example Raise exception on failure\n * ```ts\n * const retry = toolRetryMiddleware({\n * maxRetries: 2,\n * onFailure: \"raise\", // Re-raise exception instead of returning message\n * });\n * ```\n *\n * @param config - Configuration options for the retry middleware\n * @returns A middleware instance that handles tool failures with retries\n */\nexport function toolRetryMiddleware(config: ToolRetryMiddlewareConfig = {}) {\n const { success, error, data } =\n ToolRetryMiddlewareOptionsSchema.safeParse(config);\n if (!success) {\n throw new InvalidRetryConfigError(error);\n }\n const {\n maxRetries,\n tools,\n retryOn,\n onFailure: onFailureConfig,\n backoffFactor,\n initialDelayMs,\n maxDelayMs,\n jitter,\n } = data;\n\n let onFailure = onFailureConfig;\n if (onFailureConfig === \"raise\") {\n console.warn(\n \"⚠️ `onFailure: 'raise'` is deprecated. Use `onFailure: 'error'` instead.\"\n );\n onFailure = \"error\";\n } else if (onFailureConfig === \"return_message\") {\n console.warn(\n \"⚠️ `onFailure: 'return_message'` is deprecated. Use `onFailure: 'continue'` instead.\"\n );\n onFailure = \"continue\";\n }\n\n // Extract tool names from BaseTool instances or strings\n const toolFilter: string[] = [];\n for (const tool of tools ?? []) {\n if (typeof tool === \"string\") {\n toolFilter.push(tool);\n } else if (\"name\" in tool && typeof tool.name === \"string\") {\n toolFilter.push(tool.name);\n } else {\n throw new TypeError(\n \"Expected a tool name string or tool instance to be passed to toolRetryMiddleware\"\n );\n }\n }\n\n /**\n * Check if retry logic should apply to this tool.\n */\n const shouldRetryTool = (toolName: string): boolean => {\n if (toolFilter.length === 0) {\n return true;\n }\n return toolFilter.includes(toolName);\n };\n\n /**\n * Check if the exception should trigger a retry.\n */\n const shouldRetryException = (error: Error): boolean => {\n if (typeof retryOn === \"function\") {\n return retryOn(error);\n }\n // retryOn is an array of error constructors\n return retryOn.some((ErrorConstructor) => {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n return error instanceof ErrorConstructor;\n });\n };\n\n // Use the exported calculateRetryDelay function with our config\n const delayConfig = { backoffFactor, initialDelayMs, maxDelayMs, jitter };\n\n /**\n * Format the failure message when retries are exhausted.\n */\n const formatFailureMessage = (\n toolName: string,\n error: Error,\n attemptsMade: number\n ): string => {\n const errorType = error.constructor.name;\n const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;\n };\n\n /**\n * Handle failure when all retries are exhausted.\n */\n const handleFailure = (\n toolName: string,\n toolCallId: string,\n error: Error,\n attemptsMade: number\n ): ToolMessage => {\n if (onFailure === \"error\") {\n throw error;\n }\n\n let content: string;\n if (typeof onFailure === \"function\") {\n content = onFailure(error);\n } else {\n content = formatFailureMessage(toolName, error, attemptsMade);\n }\n\n return new ToolMessage({\n content,\n tool_call_id: toolCallId,\n name: toolName,\n status: \"error\",\n });\n };\n\n return createMiddleware({\n name: \"toolRetryMiddleware\",\n contextSchema: ToolRetryMiddlewareOptionsSchema,\n wrapToolCall: async (request, handler) => {\n const toolName = (request.tool?.name ?? request.toolCall.name) as string;\n\n // Check if retry should apply to this tool\n if (!shouldRetryTool(toolName)) {\n return handler(request);\n }\n\n const toolCallId = request.toolCall.id ?? \"\";\n\n // Initial attempt + retries\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await handler(request);\n } catch (error) {\n const attemptsMade = attempt + 1; // attempt is 0-indexed\n\n // Ensure error is an Error instance\n const err =\n error && typeof error === \"object\" && \"message\" in error\n ? (error as Error)\n : new Error(String(error));\n\n // Check if we should retry this exception\n if (!shouldRetryException(err)) {\n // Exception is not retryable, handle failure immediately\n return handleFailure(toolName, toolCallId, err, attemptsMade);\n }\n\n // Check if we have more retries left\n if (attempt < maxRetries) {\n // Calculate and apply backoff delay\n const delay = calculateRetryDelay(\n delayConfig,\n attempt,\n getRetryAfterMs(error)\n );\n if (delay > 0) {\n await sleep(delay);\n }\n // Continue to next retry\n } else {\n // No more retries, handle failure\n return handleFailure(toolName, toolCallId, err, attemptsMade);\n }\n }\n }\n\n // Unreachable: loop always returns via handler success or handleFailure\n throw new Error(\"Unexpected: retry loop completed without returning\");\n },\n });\n}\n","import { z } from \"zod/v3\";\nimport { InferInteropZodInput } from \"@langchain/core/utils/types\";\n\nimport { ConfigurableModel } from \"../../../../chat_models/universal.js\";\nimport { createMiddleware } from \"../../../middleware.js\";\n\nconst DEFAULT_ENABLE_CACHING = true;\nconst DEFAULT_TTL = \"5m\";\nconst DEFAULT_MIN_MESSAGES_TO_CACHE = 3;\nconst DEFAULT_UNSUPPORTED_MODEL_BEHAVIOR = \"warn\";\n\nconst contextSchema = z.object({\n /**\n * Whether to enable prompt caching.\n * @default true\n */\n enableCaching: z.boolean().optional(),\n /**\n * The time-to-live for the cached prompt.\n * @default \"5m\"\n */\n ttl: z.enum([\"5m\", \"1h\"]).optional(),\n /**\n * The minimum number of messages required before caching is applied.\n * @default 3\n */\n minMessagesToCache: z.number().optional(),\n /**\n * The behavior to take when an unsupported model is used.\n * - \"ignore\" will ignore the unsupported model and continue without caching.\n * - \"warn\" will warn the user and continue without caching.\n * - \"raise\" will raise an error and stop the agent.\n * @default \"warn\"\n */\n unsupportedModelBehavior: z.enum([\"ignore\", \"warn\", \"raise\"]).optional(),\n});\nexport type PromptCachingMiddlewareConfig = Partial<\n InferInteropZodInput<typeof contextSchema>\n>;\n\nclass PromptCachingMiddlewareError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PromptCachingMiddlewareError\";\n }\n}\n\n/**\n * Creates a prompt caching middleware for Anthropic models to optimize API usage.\n *\n * This middleware automatically adds cache control headers to the last messages when using Anthropic models,\n * enabling their prompt caching feature. This can significantly reduce costs for applications with repetitive\n * prompts, long system messages, or extensive conversation histories.\n *\n * ## How It Works\n *\n * The middleware intercepts model requests and adds cache control metadata that tells Anthropic's\n * API to cache processed prompt prefixes. On subsequent requests with matching prefixes, the\n * cached representations are reused, skipping redundant token processing.\n *\n * ## Benefits\n *\n * - **Cost Reduction**: Avoid reprocessing the same tokens repeatedly (up to 90% savings on cached portions)\n * - **Lower Latency**: Cached prompts are processed faster as embeddings are pre-computed\n * - **Better Scalability**: Reduced computational load enables handling more requests\n * - **Consistent Performance**: Stable response times for repetitive queries\n *\n * @param middlewareOptions - Configuration options for the caching behavior\n * @param middlewareOptions.enableCaching - Whether to enable prompt caching (default: `true`)\n * @param middlewareOptions.ttl - Cache time-to-live: `\"5m\"` for 5 minutes or `\"1h\"` for 1 hour (default: `\"5m\"`)\n * @param middlewareOptions.minMessagesToCache - Minimum number of messages required before caching is applied (default: `3`)\n * @param middlewareOptions.unsupportedModelBehavior - The behavior to take when an unsupported model is used (default: `\"warn\"`)\n *\n * @returns A middleware instance that can be passed to `createAgent`\n *\n * @throws {Error} If used with non-Anthropic models\n *\n * @example\n * Basic usage with default settings\n * ```typescript\n * import { createAgent } from \"langchain\";\n * import { anthropicPromptCachingMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * middleware: [\n * anthropicPromptCachingMiddleware()\n * ]\n * });\n * ```\n *\n * @example\n * Custom configuration for longer conversations\n * ```typescript\n * const cachingMiddleware = anthropicPromptCachingMiddleware({\n * ttl: \"1h\", // Cache for 1 hour instead of default 5 minutes\n * minMessagesToCache: 5 // Only cache after 5 messages\n * });\n *\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * systemPrompt: \"You are a helpful assistant with deep knowledge of...\", // Long system prompt\n * middleware: [cachingMiddleware]\n * });\n * ```\n *\n * @example\n * Conditional caching based on runtime context\n * ```typescript\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * middleware: [\n * anthropicPromptCachingMiddleware({\n * enableCaching: true,\n * ttl: \"5m\"\n * })\n * ]\n * });\n *\n * // Disable caching for specific requests\n * await agent.invoke(\n * { messages: [new HumanMessage(\"Process this without caching\")] },\n * {\n * configurable: {\n * middleware_context: { enableCaching: false }\n * }\n * }\n * );\n * ```\n *\n * @example\n * Optimal setup for customer support chatbot\n * ```typescript\n * const supportAgent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * systemPrompt: `You are a customer support agent for ACME Corp.\n *\n * Company policies:\n * - Always be polite and professional\n * - Refer to knowledge base for product information\n * - Escalate billing issues to human agents\n * ... (extensive policies and guidelines)\n * `,\n * tools: [searchKnowledgeBase, createTicket, checkOrderStatus],\n * middleware: [\n * anthropicPromptCachingMiddleware({\n * ttl: \"1h\", // Long TTL for stable system prompt\n * minMessagesToCache: 1 // Cache immediately due to large system prompt\n * })\n * ]\n * });\n * ```\n *\n * @remarks\n * - **Anthropic Only**: This middleware only works with Anthropic models and will throw an error if used with other providers\n * - **Automatic Application**: Caching is applied automatically when message count exceeds `minMessagesToCache`\n * - **Cache Scope**: Caches are isolated per API key and cannot be shared across different keys\n * - **TTL Options**: Only supports \"5m\" (5 minutes) and \"1h\" (1 hour) as TTL values per Anthropic's API\n * - **Best Use Cases**: Long system prompts, multi-turn conversations, repetitive queries, RAG applications\n * - **Cost Impact**: Cached tokens are billed at 10% of the base input token price, cache writes are billed at 25% of the base\n *\n * @see {@link createAgent} for agent creation\n * @see {@link https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching} Anthropic's prompt caching documentation\n * @public\n */\nexport function anthropicPromptCachingMiddleware(\n middlewareOptions?: PromptCachingMiddlewareConfig\n) {\n return createMiddleware({\n name: \"PromptCachingMiddleware\",\n contextSchema,\n wrapModelCall: (request, handler) => {\n /**\n * Prefer runtime context values over middleware options values over defaults\n */\n const enableCaching =\n request.runtime.context.enableCaching ??\n middlewareOptions?.enableCaching ??\n DEFAULT_ENABLE_CACHING;\n const ttl =\n request.runtime.context.ttl ?? middlewareOptions?.ttl ?? DEFAULT_TTL;\n const minMessagesToCache =\n request.runtime.context.minMessagesToCache ??\n middlewareOptions?.minMessagesToCache ??\n DEFAULT_MIN_MESSAGES_TO_CACHE;\n const unsupportedModelBehavior =\n request.runtime.context.unsupportedModelBehavior ??\n middlewareOptions?.unsupportedModelBehavior ??\n DEFAULT_UNSUPPORTED_MODEL_BEHAVIOR;\n\n // Skip if caching is disabled\n if (!enableCaching || !request.model) {\n return handler(request);\n }\n\n const isAnthropicModel =\n request.model.getName() === \"ChatAnthropic\" ||\n (request.model.getName() === \"ConfigurableModel\" &&\n (request.model as ConfigurableModel)._defaultConfig?.modelProvider ===\n \"anthropic\");\n if (!isAnthropicModel) {\n // Get model name for better error context\n const modelName = request.model.getName();\n const modelInfo =\n request.model.getName() === \"ConfigurableModel\"\n ? `${modelName} (${\n (request.model as ConfigurableModel)._defaultConfig\n ?.modelProvider\n })`\n : modelName;\n\n const baseMessage = `Unsupported model '${modelInfo}'. Prompt caching requires an Anthropic model`;\n\n if (unsupportedModelBehavior === \"raise\") {\n throw new PromptCachingMiddlewareError(\n `${baseMessage} (e.g., 'anthropic:claude-4-0-sonnet').`\n );\n } else if (unsupportedModelBehavior === \"warn\") {\n console.warn(\n `PromptCachingMiddleware: Skipping caching for ${modelName}. Consider switching to an Anthropic model for caching benefits.`\n );\n }\n return handler(request);\n }\n\n const messagesCount =\n request.state.messages.length + (request.systemPrompt ? 1 : 0);\n\n if (messagesCount < minMessagesToCache) {\n return handler(request);\n }\n\n /**\n * The cache_control is applied at the final message formatting layer in ChatAnthropic,\n * which avoids issues with message content block manipulation during earlier\n * processing stages (e.g., streaming response reassembly).\n *\n * @see https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching\n */\n return handler({\n ...request,\n modelSettings: {\n ...request.modelSettings,\n cache_control: {\n type: \"ephemeral\" as const,\n ttl,\n },\n },\n });\n },\n });\n}\n","import { z } from \"zod/v3\";\nimport { InferInteropZodInput } from \"@langchain/core/utils/types\";\n\nimport type { ConfigurableModel } from \"../../../../chat_models/universal.js\";\nimport { createMiddleware } from \"../../../middleware.js\";\n\nconst DEFAULT_ENABLE_CACHING = true;\nconst DEFAULT_TTL = \"5m\";\nconst DEFAULT_MIN_MESSAGES_TO_CACHE = 1;\nconst DEFAULT_UNSUPPORTED_MODEL_BEHAVIOR = \"warn\";\n\nconst contextSchema = z.object({\n /**\n * Whether to enable prompt caching.\n * @default true\n */\n enableCaching: z.boolean().optional(),\n /**\n * The time-to-live for the cached prompt.\n * @default \"5m\"\n */\n ttl: z.enum([\"5m\", \"1h\"]).optional(),\n /**\n * The minimum number of messages required before caching is applied.\n * @default 1\n */\n minMessagesToCache: z.number().optional(),\n /**\n * The behavior to take when an unsupported model is used.\n * - \"ignore\" will ignore the unsupported model and continue without caching.\n * - \"warn\" will warn the user and continue without caching.\n * - \"raise\" will raise an error and stop the agent.\n * @default \"warn\"\n */\n unsupportedModelBehavior: z.enum([\"ignore\", \"warn\", \"raise\"]).optional(),\n});\nexport type BedrockConversePromptCachingMiddlewareConfig = Partial<\n InferInteropZodInput<typeof contextSchema>\n>;\n\nclass BedrockPromptCachingMiddlewareError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BedrockPromptCachingMiddlewareError\";\n }\n}\n\n/**\n * Creates a prompt caching middleware for AWS Bedrock Converse models to optimize API usage.\n *\n * This middleware automatically enables Bedrock's prompt caching when using AWS Bedrock Converse\n * models. This can significantly reduce costs for applications with repetitive prompts, long\n * system messages, or extensive conversation histories.\n *\n * ## How It Works\n *\n * The middleware intercepts model requests and sets a cache control signal that\n * `ChatBedrockConverse` translates into Bedrock `cachePoint` breakpoints. Cache points are\n * inserted after the system prompt, after the tool definitions, and after the final message, so\n * the stable prefix of each request is cached. On subsequent requests with a matching prefix, the\n * cached representations are reused, skipping redundant token processing. Exact placement varies\n * by model (e.g. Amazon Nova models cache fewer breakpoints and ignore the `\"1h\"` TTL).\n *\n * ## Benefits\n *\n * - **Cost Reduction**: Avoid reprocessing the same tokens repeatedly\n * - **Lower Latency**: Cached prompts are processed faster as embeddings are pre-computed\n * - **Better Scalability**: Reduced computational load enables handling more requests\n * - **Consistent Performance**: Stable response times for repetitive queries\n *\n * @param middlewareOptions - Configuration options for the caching behavior\n * @param middlewareOptions.enableCaching - Whether to enable prompt caching (default: `true`)\n * @param middlewareOptions.ttl - Cache time-to-live: `\"5m\"` for 5 minutes or `\"1h\"` for 1 hour (default: `\"5m\"`)\n * @param middlewareOptions.minMessagesToCache - Minimum number of messages required before caching is applied (default: `1`)\n * @param middlewareOptions.unsupportedModelBehavior - The behavior to take when an unsupported model is used (default: `\"warn\"`)\n *\n * @returns A middleware instance that can be passed to `createAgent`\n *\n * @throws {Error} When `unsupportedModelBehavior` is `\"raise\"` and the model is not a\n * cache-capable Bedrock Converse model — either a non-Bedrock provider, or a Bedrock\n * Converse model outside the Anthropic Claude / Amazon Nova families.\n *\n * @example\n * Basic usage with default settings\n * ```typescript\n * import { createAgent } from \"langchain\";\n * import { bedrockPromptCachingMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"bedrock:anthropic.claude-haiku-4-5-20251001-v1:0\",\n * middleware: [\n * bedrockPromptCachingMiddleware()\n * ]\n * });\n * ```\n *\n * @example\n * Custom configuration for longer conversations\n * ```typescript\n * const cachingMiddleware = bedrockPromptCachingMiddleware({\n * ttl: \"1h\", // Cache for 1 hour instead of default 5 minutes\n * minMessagesToCache: 5 // Only cache after 5 messages\n * });\n *\n * const agent = createAgent({\n * model: \"bedrock:anthropic.claude-haiku-4-5-20251001-v1:0\",\n * systemPrompt: \"You are a helpful assistant with deep knowledge of...\", // Long system prompt\n * middleware: [cachingMiddleware]\n * });\n * ```\n *\n * @example\n * Conditional caching based on runtime context\n * ```typescript\n * const agent = createAgent({\n * model: \"bedrock:anthropic.claude-haiku-4-5-20251001-v1:0\",\n * middleware: [\n * bedrockPromptCachingMiddleware({\n * enableCaching: true,\n * ttl: \"5m\"\n * })\n * ]\n * });\n *\n * // Disable caching for specific requests\n * await agent.invoke(\n * { messages: [new HumanMessage(\"Process this without caching\")] },\n * {\n * configurable: {\n * middleware_context: { enableCaching: false }\n * }\n * }\n * );\n * ```\n *\n * @example\n * Optimal setup for customer support chatbot\n * ```typescript\n * const supportAgent = createAgent({\n * model: \"bedrock:anthropic.claude-haiku-4-5-20251001-v1:0\",\n * systemPrompt: `You are a customer support agent for ACME Corp.\n *\n * Company policies:\n * - Always be polite and professional\n * - Refer to knowledge base for product information\n * - Escalate billing issues to human agents\n * ... (extensive policies and guidelines)\n * `,\n * tools: [searchKnowledgeBase, createTicket, checkOrderStatus],\n * middleware: [\n * bedrockPromptCachingMiddleware({\n * ttl: \"1h\", // Long TTL for stable system prompt\n * minMessagesToCache: 1 // Cache immediately due to large system prompt\n * })\n * ]\n * });\n * ```\n *\n * @remarks\n * - **Bedrock Converse Only**: This middleware only applies caching to AWS Bedrock Converse models. Other providers are handled per `unsupportedModelBehavior`\n * - **Supported Families**: Bedrock prompt caching is only available on the **Anthropic Claude** and **Amazon Nova** model families. Other Bedrock Converse models (e.g. Mistral, Cohere, Meta) reject cache points at request time, so they are treated as unsupported and routed through `unsupportedModelBehavior`\n * - **Automatic Application**: Caching is applied automatically when the message count reaches `minMessagesToCache`\n * - **TTL Options**: Only supports \"5m\" (5 minutes) and \"1h\" (1 hour) as TTL values; actual support varies by model\n * - **Best Use Cases**: Long system prompts, multi-turn conversations, repetitive queries, RAG applications\n *\n * @see {@link createAgent} for agent creation\n * @see {@link https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html} AWS Bedrock prompt caching documentation\n * @public\n */\nexport function bedrockPromptCachingMiddleware(\n middlewareOptions?: BedrockConversePromptCachingMiddlewareConfig\n) {\n return createMiddleware({\n name: \"BedrockPromptCachingMiddleware\",\n contextSchema,\n wrapModelCall: (request, handler) => {\n const enableCaching =\n request.runtime.context.enableCaching ??\n middlewareOptions?.enableCaching ??\n DEFAULT_ENABLE_CACHING;\n const ttl =\n request.runtime.context.ttl ?? middlewareOptions?.ttl ?? DEFAULT_TTL;\n const minMessagesToCache =\n request.runtime.context.minMessagesToCache ??\n middlewareOptions?.minMessagesToCache ??\n DEFAULT_MIN_MESSAGES_TO_CACHE;\n const unsupportedModelBehavior =\n request.runtime.context.unsupportedModelBehavior ??\n middlewareOptions?.unsupportedModelBehavior ??\n DEFAULT_UNSUPPORTED_MODEL_BEHAVIOR;\n\n // Skip if caching is disabled\n if (!enableCaching || !request.model) {\n return handler(request);\n }\n\n const modelName = request.model.getName();\n const isBedrockConverseModel =\n modelName === \"ChatBedrockConverse\" ||\n (modelName === \"ConfigurableModel\" &&\n ((request.model as ConfigurableModel)._defaultConfig\n ?.modelProvider === \"bedrock\" ||\n (request.model as ConfigurableModel)._defaultConfig\n ?.modelProvider === \"aws\"));\n\n // Resolve the underlying Bedrock model id for cache-capability detection.\n const modelId =\n modelName === \"ConfigurableModel\"\n ? ((request.model as ConfigurableModel)._defaultConfig?.model as\n | string\n | undefined)\n : (request.model as { model?: string }).model;\n\n // Bedrock prompt caching is only supported on the Anthropic Claude and\n // Amazon Nova model families. Other Converse models (Mistral, Cohere,\n // Meta, etc.) reject `cachePoint` blocks with an AccessDeniedException, so\n // they are treated as unsupported.\n const isCacheCapableModel =\n isBedrockConverseModel &&\n typeof modelId === \"string\" &&\n (modelId.toLowerCase().includes(\"anthropic.claude\") ||\n modelId.toLowerCase().includes(\"amazon.nova\"));\n\n if (!isCacheCapableModel) {\n const modelInfo =\n modelName === \"ConfigurableModel\"\n ? `${modelName} (${\n (request.model as ConfigurableModel)._defaultConfig\n ?.modelProvider\n })`\n : modelName;\n\n const baseMessage = isBedrockConverseModel\n ? `Unsupported model '${modelInfo}'. Bedrock prompt caching is only supported on Anthropic Claude and Amazon Nova models`\n : `Unsupported model '${modelInfo}'. Prompt caching requires an AWS Bedrock Converse model`;\n\n if (unsupportedModelBehavior === \"raise\") {\n throw new BedrockPromptCachingMiddlewareError(\n `${baseMessage} (e.g., 'bedrock:anthropic.claude-haiku-4-5-20251001-v1:0').`\n );\n } else if (unsupportedModelBehavior === \"warn\") {\n console.warn(\n `BedrockPromptCachingMiddleware: Skipping caching for ${modelName}. Consider switching to an Anthropic Claude or Amazon Nova model for caching benefits.`\n );\n }\n return handler(request);\n }\n\n const messagesCount =\n request.state.messages.length + (request.systemPrompt ? 1 : 0);\n\n if (messagesCount < minMessagesToCache) {\n return handler(request);\n }\n\n /**\n * The cache_control is applied at the final message formatting layer in\n * ChatBedrockConverse (translated into Converse `cachePoint` blocks).\n *\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html\n */\n return handler({\n ...request,\n modelSettings: {\n ...request.modelSettings,\n cache_control: {\n type: \"ephemeral\" as const,\n ttl,\n },\n },\n });\n },\n });\n}\n","import { __exportAll } from \"./_virtual/_rolldown/runtime.js\";\nimport { initChatModel } from \"./chat_models/universal.js\";\nimport { tool } from \"./tools/headless.js\";\nimport { MiddlewareError, MultipleStructuredOutputsError, MultipleToolsBoundError, StructuredOutputParsingError, ToolInvocationError } from \"./agents/errors.js\";\nimport { ProviderStrategy, ToolStrategy, providerStrategy, toolStrategy } from \"./agents/responses.js\";\nimport { countTokensApproximately } from \"./agents/middleware/utils.js\";\nimport { createToolCallTransformer } from \"./agents/transformers/tool-call.js\";\nimport { createSubagentTransformer } from \"./agents/transformers/subagent.js\";\nimport { MIDDLEWARE_BRAND } from \"./agents/middleware/types.js\";\nimport { createMiddleware } from \"./agents/middleware.js\";\nimport { FakeToolCallingModel } from \"./agents/tests/utils.js\";\nimport { createAgent } from \"./agents/index.js\";\nimport { humanInTheLoopMiddleware } from \"./agents/middleware/hitl.js\";\nimport { summarizationMiddleware } from \"./agents/middleware/summarization.js\";\nimport { dynamicSystemPromptMiddleware } from \"./agents/middleware/dynamicSystemPrompt.js\";\nimport { llmToolSelectorMiddleware } from \"./agents/middleware/llmToolSelector.js\";\nimport { PIIDetectionError, applyStrategy, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, piiMiddleware, resolveRedactionRule } from \"./agents/middleware/pii.js\";\nimport { piiRedactionMiddleware } from \"./agents/middleware/piiRedaction.js\";\nimport { ClearToolUsesEdit, contextEditingMiddleware } from \"./agents/middleware/contextEditing.js\";\nimport { ToolCallLimitExceededError, toolCallLimitMiddleware } from \"./agents/middleware/toolCallLimit.js\";\nimport { TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, todoListMiddleware } from \"./agents/middleware/todoListMiddleware.js\";\nimport { modelCallLimitMiddleware } from \"./agents/middleware/modelCallLimit.js\";\nimport { modelFallbackMiddleware } from \"./agents/middleware/modelFallback.js\";\nimport { modelRetryMiddleware } from \"./agents/middleware/modelRetry.js\";\nimport { toolRetryMiddleware } from \"./agents/middleware/toolRetry.js\";\nimport { toolErrorMiddleware } from \"./agents/middleware/toolError.js\";\nimport { toolEmulatorMiddleware } from \"./agents/middleware/toolEmulator.js\";\nimport { providerToolSearchMiddleware } from \"./agents/middleware/providerToolSearch.js\";\nimport { openAIModerationMiddleware } from \"./agents/middleware/provider/openai/moderation.js\";\nimport { anthropicPromptCachingMiddleware } from \"./agents/middleware/provider/anthropic/promptCaching.js\";\nimport { bedrockPromptCachingMiddleware } from \"./agents/middleware/provider/aws/promptCaching.js\";\nimport \"./agents/middleware/index.js\";\nimport { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, HumanMessage, HumanMessageChunk, SystemMessage, SystemMessageChunk, ToolMessage, ToolMessageChunk, filterMessages, trimMessages } from \"@langchain/core/messages\";\nimport { DynamicStructuredTool, DynamicTool, StructuredTool, Tool } from \"@langchain/core/tools\";\nimport { context } from \"@langchain/core/utils/context\";\nimport { InMemoryStore } from \"@langchain/core/stores\";\nimport { Document } from \"@langchain/core/documents\";\nimport { fakeModel, langchainMatchers } from \"@langchain/core/testing\";\n//#region src/index.ts\nvar src_exports = /* @__PURE__ */ __exportAll({\n\tAIMessage: () => AIMessage,\n\tAIMessageChunk: () => AIMessageChunk,\n\tBaseMessage: () => BaseMessage,\n\tBaseMessageChunk: () => BaseMessageChunk,\n\tClearToolUsesEdit: () => ClearToolUsesEdit,\n\tDocument: () => Document,\n\tDynamicStructuredTool: () => DynamicStructuredTool,\n\tDynamicTool: () => DynamicTool,\n\tFakeToolCallingModel: () => FakeToolCallingModel,\n\tHumanMessage: () => HumanMessage,\n\tHumanMessageChunk: () => HumanMessageChunk,\n\tInMemoryStore: () => InMemoryStore,\n\tMIDDLEWARE_BRAND: () => MIDDLEWARE_BRAND,\n\tMiddlewareError: () => MiddlewareError,\n\tMultipleStructuredOutputsError: () => MultipleStructuredOutputsError,\n\tMultipleToolsBoundError: () => MultipleToolsBoundError,\n\tPIIDetectionError: () => PIIDetectionError,\n\tProviderStrategy: () => ProviderStrategy,\n\tStructuredOutputParsingError: () => StructuredOutputParsingError,\n\tStructuredTool: () => StructuredTool,\n\tSystemMessage: () => SystemMessage,\n\tSystemMessageChunk: () => SystemMessageChunk,\n\tTODO_LIST_MIDDLEWARE_SYSTEM_PROMPT: () => TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT,\n\tTool: () => Tool,\n\tToolCallLimitExceededError: () => ToolCallLimitExceededError,\n\tToolInvocationError: () => ToolInvocationError,\n\tToolMessage: () => ToolMessage,\n\tToolMessageChunk: () => ToolMessageChunk,\n\tToolStrategy: () => ToolStrategy,\n\tanthropicPromptCachingMiddleware: () => anthropicPromptCachingMiddleware,\n\tapplyStrategy: () => applyStrategy,\n\tbedrockPromptCachingMiddleware: () => bedrockPromptCachingMiddleware,\n\tcontext: () => context,\n\tcontextEditingMiddleware: () => contextEditingMiddleware,\n\tcountTokensApproximately: () => countTokensApproximately,\n\tcreateAgent: () => createAgent,\n\tcreateMiddleware: () => createMiddleware,\n\tcreateSubagentTransformer: () => createSubagentTransformer,\n\tcreateToolCallTransformer: () => createToolCallTransformer,\n\tdetectCreditCard: () => detectCreditCard,\n\tdetectEmail: () => detectEmail,\n\tdetectIP: () => detectIP,\n\tdetectMacAddress: () => detectMacAddress,\n\tdetectUrl: () => detectUrl,\n\tdynamicSystemPromptMiddleware: () => dynamicSystemPromptMiddleware,\n\tfakeModel: () => fakeModel,\n\tfilterMessages: () => filterMessages,\n\thumanInTheLoopMiddleware: () => humanInTheLoopMiddleware,\n\tinitChatModel: () => initChatModel,\n\tlangchainMatchers: () => langchainMatchers,\n\tllmToolSelectorMiddleware: () => llmToolSelectorMiddleware,\n\tmodelCallLimitMiddleware: () => modelCallLimitMiddleware,\n\tmodelFallbackMiddleware: () => modelFallbackMiddleware,\n\tmodelRetryMiddleware: () => modelRetryMiddleware,\n\topenAIModerationMiddleware: () => openAIModerationMiddleware,\n\tpiiMiddleware: () => piiMiddleware,\n\tpiiRedactionMiddleware: () => piiRedactionMiddleware,\n\tproviderStrategy: () => providerStrategy,\n\tproviderToolSearchMiddleware: () => providerToolSearchMiddleware,\n\tresolveRedactionRule: () => resolveRedactionRule,\n\tsummarizationMiddleware: () => summarizationMiddleware,\n\ttodoListMiddleware: () => todoListMiddleware,\n\ttool: () => tool,\n\ttoolCallLimitMiddleware: () => toolCallLimitMiddleware,\n\ttoolEmulatorMiddleware: () => toolEmulatorMiddleware,\n\ttoolErrorMiddleware: () => toolErrorMiddleware,\n\ttoolRetryMiddleware: () => toolRetryMiddleware,\n\ttoolStrategy: () => toolStrategy,\n\ttrimMessages: () => trimMessages\n});\n//#endregion\nexport { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, ClearToolUsesEdit, Document, DynamicStructuredTool, DynamicTool, FakeToolCallingModel, HumanMessage, HumanMessageChunk, InMemoryStore, MIDDLEWARE_BRAND, MiddlewareError, MultipleStructuredOutputsError, MultipleToolsBoundError, PIIDetectionError, ProviderStrategy, StructuredOutputParsingError, StructuredTool, SystemMessage, SystemMessageChunk, TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, Tool, ToolCallLimitExceededError, ToolInvocationError, ToolMessage, ToolMessageChunk, ToolStrategy, anthropicPromptCachingMiddleware, applyStrategy, bedrockPromptCachingMiddleware, context, contextEditingMiddleware, countTokensApproximately, createAgent, createMiddleware, createSubagentTransformer, createToolCallTransformer, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, dynamicSystemPromptMiddleware, fakeModel, filterMessages, humanInTheLoopMiddleware, initChatModel, langchainMatchers, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, piiRedactionMiddleware, providerStrategy, providerToolSearchMiddleware, resolveRedactionRule, src_exports, summarizationMiddleware, todoListMiddleware, tool, toolCallLimitMiddleware, toolEmulatorMiddleware, toolErrorMiddleware, toolRetryMiddleware, toolStrategy, trimMessages };\n\n//# sourceMappingURL=index.js.map","import type { StartMessage } from '../deepagents-bridge-protocol';\n\nexport type PermissionMode = NonNullable<StartMessage['permissionMode']>;\n\n// Native built-in tool -> approval kind (mirrors the host adapter's toolUseKind).\nexport const NATIVE_TOOL_KIND: Readonly<\n Record<string, 'readonly' | 'edit' | 'bash'>\n> = {\n read_file: 'readonly',\n write_file: 'edit',\n edit_file: 'edit',\n execute: 'bash',\n grep: 'readonly',\n glob: 'readonly',\n ls: 'readonly',\n task: 'edit',\n write_todos: 'edit',\n};\n\nconst NATIVE_TO_COMMON: Readonly<Record<string, string>> = {\n read_file: 'read',\n write_file: 'write',\n edit_file: 'edit',\n execute: 'bash',\n};\n\nexport function toCommonName(nativeName: string): string {\n return NATIVE_TO_COMMON[nativeName] ?? nativeName;\n}\n\nexport function isBuiltinToolIncluded(input: {\n nativeName: string;\n toolFiltering: StartMessage['builtinToolFiltering'];\n}): boolean {\n if (input.toolFiltering == null) return true;\n const toolName = toCommonName(input.nativeName);\n return input.toolFiltering.mode === 'allow'\n ? input.toolFiltering.toolNames.includes(toolName)\n : !input.toolFiltering.toolNames.includes(toolName);\n}\n\nexport function builtinToolRequiresApproval(\n kind: 'readonly' | 'edit' | 'bash',\n permissionMode: PermissionMode,\n): boolean {\n if (permissionMode === 'allow-all') return false;\n if (permissionMode === 'allow-edits') return kind === 'bash';\n return kind === 'edit' || kind === 'bash';\n}\n\n// Per-tool HITL config for createDeepAgent; only built-ins are gated (host tools approve at the agent layer).\nexport function buildInterruptOn(\n permissionMode: PermissionMode | undefined,\n builtinToolFiltering: StartMessage['builtinToolFiltering'],\n):\n | Record<string, { allowedDecisions: Array<'approve' | 'reject'> }>\n | undefined {\n const config: Record<\n string,\n { allowedDecisions: Array<'approve' | 'reject'> }\n > = {};\n for (const [nativeName, kind] of Object.entries(NATIVE_TOOL_KIND)) {\n if (\n permissionMode != null &&\n isBuiltinToolIncluded({\n nativeName,\n toolFiltering: builtinToolFiltering,\n }) &&\n builtinToolRequiresApproval(kind, permissionMode)\n ) {\n config[nativeName] = { allowedDecisions: ['approve', 'reject'] };\n }\n }\n return Object.keys(config).length > 0 ? config : undefined;\n}\n\ntype ActionRequest = { name: string; args?: Record<string, unknown> };\ntype HITLInterruptValue = { actionRequests?: ActionRequest[] };\n\n// Flatten LangChain HITL interrupt payloads into the gated tool calls awaiting a decision.\nexport function collectActionRequests(\n interrupts: Array<{ value?: unknown }>,\n): { name: string; args: Record<string, unknown> }[] {\n const out: { name: string; args: Record<string, unknown> }[] = [];\n for (const interrupt of interrupts) {\n const value = interrupt.value as HITLInterruptValue | undefined;\n for (const action of value?.actionRequests ?? []) {\n out.push({ name: action.name, args: action.args ?? {} });\n }\n }\n return out;\n}\n","import { randomUUID } from 'node:crypto';\n\ntype Emit = (event: Record<string, unknown>) => void;\n\nexport type DeepAgentsStreamEvent = {\n event?: string;\n name?: string;\n run_id?: string;\n data?: unknown;\n metadata?: {\n langgraph_checkpoint_ns?: string;\n ls_model_name?: unknown;\n };\n};\n\nexport type DeepAgentsStreamEventState = {\n streamStarted: boolean;\n textBlockId: string | undefined;\n reasoningBlockId: string | undefined;\n inputTokens: number;\n outputTokens: number;\n // Per-call streamed-usage fallback (max over chunks), used only when model-end carries no usage.\n streamedStepInput: number;\n streamedStepOutput: number;\n // Top-level step usage is buffered at model-end and flushed as finish-step only after the step's tools run.\n pendingStep: { input: number; output: number } | undefined;\n // Approval-gated tools are announced before execution; these tie the later run back to the approval id and dedup the call.\n approvedToolQueue: Map<string, string[]>;\n approvedRunIds: Map<string, string>;\n dynamicToolRunIds: Set<string>;\n};\n\nexport function createDeepAgentsStreamEventState(): DeepAgentsStreamEventState {\n return {\n streamStarted: false,\n textBlockId: undefined,\n reasoningBlockId: undefined,\n inputTokens: 0,\n outputTokens: 0,\n streamedStepInput: 0,\n streamedStepOutput: 0,\n pendingStep: undefined,\n approvedToolQueue: new Map(),\n approvedRunIds: new Map(),\n dynamicToolRunIds: new Set(),\n };\n}\n\n// Native Deep Agents tool name -> harness-v1 common name (renames only; grep/glob/ls/task/write_todos forward unchanged).\nconst NATIVE_TO_COMMON: Readonly<Record<string, string>> = {\n read_file: 'read',\n write_file: 'write',\n edit_file: 'edit',\n execute: 'bash',\n};\n\nexport function toCommonName(nativeName: string): string {\n return NATIVE_TO_COMMON[nativeName] ?? nativeName;\n}\n\nexport function createEmitStreamEvent({\n state,\n configuredModel,\n hostToolNames,\n mcpToolNames,\n structuredOutputToolNames = new Set(),\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n configuredModel: string | undefined;\n hostToolNames: ReadonlySet<string>;\n mcpToolNames: ReadonlySet<string>;\n structuredOutputToolNames?: ReadonlySet<string>;\n emit: Emit;\n}): (event: DeepAgentsStreamEvent) => void {\n return event => {\n const kind = event.event;\n const data = (event.data ?? {}) as Record<string, unknown>;\n // Subagent (e.g. `task`) events carry a `|`-delimited checkpoint namespace; keep their internals out of the top-level stream.\n const ns = event.metadata?.langgraph_checkpoint_ns ?? '';\n const nested = ns.includes('|');\n\n if (kind === 'on_chat_model_start') {\n if (!nested) {\n if (!state.streamStarted) {\n state.streamStarted = true;\n const modelId = resolveDeepAgentsModelId({\n configuredModel,\n metadata: event.metadata,\n });\n emit({\n type: 'stream-start',\n ...(modelId ? { modelId } : {}),\n });\n }\n // A new top-level model call means the previous step's tools have run; close it now.\n flushStep({ state, emit });\n }\n } else if (kind === 'on_chat_model_stream') {\n if (nested) return;\n const chunk = data.chunk as\n | {\n content?: unknown;\n usage_metadata?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n }\n | undefined;\n if (!chunk) return;\n const content = chunk.content;\n if (typeof content === 'string' && content) {\n emitText({ state, emit, delta: content });\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (block && typeof block === 'object') {\n const value = block as {\n type?: string;\n text?: string;\n thinking?: string;\n reasoning?: string;\n };\n if (\n (value.type === 'text' || value.type === 'text-delta') &&\n value.text\n ) {\n emitText({ state, emit, delta: value.text });\n } else if (value.type === 'thinking' && value.thinking) {\n emitReasoning({ state, emit, delta: value.thinking });\n } else if (\n (value.type === 'reasoning' ||\n value.type === 'reasoning-delta') &&\n value.reasoning\n ) {\n emitReasoning({ state, emit, delta: value.reasoning });\n }\n }\n }\n }\n const usage = chunk.usage_metadata;\n if (usage) {\n state.streamedStepInput = Math.max(\n state.streamedStepInput,\n usage.input_tokens ?? 0,\n );\n state.streamedStepOutput = Math.max(\n state.streamedStepOutput,\n usage.output_tokens ?? 0,\n );\n }\n } else if (kind === 'on_chat_model_end') {\n // Final usage lands on model-end, not the chunks; each model call is one step.\n const output = data.output as\n | {\n usage_metadata?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n }\n | undefined;\n const usage = output?.usage_metadata;\n // One model call = one step; count its usage exactly once (model-end usage, else the streamed max).\n const stepInput = usage?.input_tokens ?? state.streamedStepInput;\n const stepOutput = usage?.output_tokens ?? state.streamedStepOutput;\n state.inputTokens += stepInput;\n state.outputTokens += stepOutput;\n state.streamedStepInput = 0;\n state.streamedStepOutput = 0;\n // Nested (subagent) calls still count toward total usage, but only top-level calls bound a visible step.\n if (!nested) {\n endTextBlock({ state, emit });\n endReasoningBlock({ state, emit });\n // Buffer the step; flushStep emits finish-step after this step's tools run (next start / turn end).\n state.pendingStep = { input: stepInput, output: stepOutput };\n }\n } else if (kind === 'on_tool_start') {\n const toolName = event.name ?? 'unknown';\n if (structuredOutputToolNames.has(toolName)) return;\n const runId = event.run_id ?? '';\n // Host tools emit their own tool-call; surface only top-level builtin (providerExecuted) tools.\n if (!nested && !hostToolNames.has(toolName)) {\n const isMcpTool = mcpToolNames.has(toolName);\n if (isMcpTool && runId) state.dynamicToolRunIds.add(runId);\n const queued = state.approvedToolQueue.get(toolName);\n if (queued && queued.length > 0) {\n // Already announced at approval time; tie this run to that id and don't re-emit the call.\n const approvalId = queued.shift()!;\n if (runId) state.approvedRunIds.set(runId, approvalId);\n } else {\n endTextBlock({ state, emit });\n endReasoningBlock({ state, emit });\n emit({\n type: 'tool-call',\n toolCallId: runId,\n toolName: toCommonName(toolName),\n input: toToolCallInput(data.input),\n providerExecuted: true,\n nativeName: toolName,\n ...(isMcpTool ? { dynamic: true } : {}),\n });\n }\n }\n } else if (kind === 'on_tool_end') {\n const toolName = event.name ?? 'unknown';\n if (structuredOutputToolNames.has(toolName)) return;\n const runId = event.run_id ?? '';\n if (!nested && !hostToolNames.has(toolName)) {\n const dynamic = state.dynamicToolRunIds.delete(runId);\n let output: unknown = data.output ?? '';\n if (output && typeof output === 'object' && 'content' in output) {\n output = (output as { content: unknown }).content;\n }\n emit({\n type: 'tool-result',\n toolCallId: state.approvedRunIds.get(runId) ?? runId,\n toolName: toCommonName(toolName),\n result: output ?? null,\n ...(dynamic ? { dynamic: true } : {}),\n });\n state.approvedRunIds.delete(runId);\n }\n }\n };\n}\n\nexport function endTextBlock({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): void {\n if (state.textBlockId) {\n emit({ type: 'text-end', id: state.textBlockId });\n state.textBlockId = undefined;\n }\n}\n\nexport function endReasoningBlock({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): void {\n if (state.reasoningBlockId) {\n emit({ type: 'reasoning-end', id: state.reasoningBlockId });\n state.reasoningBlockId = undefined;\n }\n}\n\n// Close the buffered top-level step; called when the next step starts and at turn end so finish-step lands after the step's tools.\nexport function flushStep({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): void {\n if (!state.pendingStep) return;\n emit({\n type: 'finish-step',\n finishReason: { unified: 'stop' },\n usage: {\n inputTokens: { total: state.pendingStep.input },\n outputTokens: { total: state.pendingStep.output },\n },\n });\n state.pendingStep = undefined;\n}\n\nfunction ensureTextBlock({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): string {\n if (!state.textBlockId) {\n state.textBlockId = `text-${randomUUID()}`;\n emit({ type: 'text-start', id: state.textBlockId });\n }\n return state.textBlockId;\n}\n\n// Text and reasoning are mutually exclusive open blocks: starting one closes the other.\nfunction emitText({\n state,\n emit,\n delta,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n delta: string;\n}): void {\n endReasoningBlock({ state, emit });\n emit({ type: 'text-delta', id: ensureTextBlock({ state, emit }), delta });\n}\n\nfunction emitReasoning({\n state,\n emit,\n delta,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n delta: string;\n}): void {\n endTextBlock({ state, emit });\n if (!state.reasoningBlockId) {\n state.reasoningBlockId = `reasoning-${randomUUID()}`;\n emit({ type: 'reasoning-start', id: state.reasoningBlockId });\n }\n emit({ type: 'reasoning-delta', id: state.reasoningBlockId, delta });\n}\n\nfunction resolveDeepAgentsModelId({\n configuredModel,\n metadata,\n}: {\n configuredModel: string | undefined;\n metadata: unknown;\n}): string | undefined {\n if (metadata && typeof metadata === 'object' && !Array.isArray(metadata)) {\n const modelId = (metadata as { ls_model_name?: unknown }).ls_model_name;\n if (typeof modelId === 'string' && modelId.length > 0) return modelId;\n }\n\n return configuredModel;\n}\n\n// LangChain reports some built-in tool args wrapped as `{ input: \"<json>\" }`; unwrap to the inner JSON so AI SDK validates the real shape.\nfunction toToolCallInput(raw: unknown): string {\n if (\n raw &&\n typeof raw === 'object' &&\n !Array.isArray(raw) &&\n Object.keys(raw).length === 1 &&\n typeof (raw as { input?: unknown }).input === 'string'\n ) {\n const inner = (raw as { input: string }).input;\n if (/^\\s*[[{]/.test(inner)) return inner;\n }\n return JSON.stringify(raw ?? {});\n}\n","import { z } from 'zod/v4';\n\nexport type JsonSchemaObject = {\n type?: string | string[];\n description?: string;\n properties?: Record<string, JsonSchemaObject>;\n required?: string[];\n items?: JsonSchemaObject;\n nullable?: boolean;\n};\n\n// Convert a host tool's JSON Schema to a zod object for LangChain's `tool()`.\nexport function jsonSchemaToZodObject(input: unknown) {\n const schema =\n input && typeof input === 'object' ? (input as JsonSchemaObject) : {};\n return z.object(toZodShape(schema));\n}\n\nfunction toZodShape(schema: JsonSchemaObject): Record<string, z.ZodTypeAny> {\n if (!schema.properties) return {};\n const required = new Set(schema.required);\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const [key, propSchema] of Object.entries(schema.properties)) {\n const propType = toZodType(propSchema);\n shape[key] = required.has(key) ? propType : propType.optional();\n }\n return shape;\n}\n\nfunction toZodType(schema: JsonSchemaObject | undefined): z.ZodTypeAny {\n if (!schema) return z.any();\n const types = Array.isArray(schema.type)\n ? schema.type.filter(t => t !== 'null')\n : ([schema.type].filter(Boolean) as string[]);\n let zType: z.ZodTypeAny;\n switch (types[0]) {\n case 'string':\n zType = z.string();\n break;\n case 'number':\n zType = z.number();\n break;\n case 'integer':\n zType = z.number().int();\n break;\n case 'boolean':\n zType = z.boolean();\n break;\n case 'array':\n zType = z.array(toZodType(schema.items));\n break;\n case 'object':\n zType = z.object(toZodShape(schema));\n break;\n case 'null':\n zType = z.null();\n break;\n default:\n zType = z.any();\n }\n if (schema.description) zType = zType.describe(schema.description);\n if (schema.nullable) zType = zType.nullable();\n return zType;\n}\n","import { LocalShellBackend } from 'deepagents';\n\nexport const SANDBOX_PATH_FALLBACK =\n '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';\n\nexport function createLocalShellBackend({\n rootDir,\n env = process.env,\n}: {\n readonly rootDir: string;\n readonly env?: NodeJS.ProcessEnv;\n}): LocalShellBackend {\n return new LocalShellBackend({\n rootDir,\n env: {\n PATH: env.PATH ?? SANDBOX_PATH_FALLBACK,\n },\n });\n}\n","import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { MemorySaver } from '@langchain/langgraph';\n\nconst SNAPSHOT_HEADER = 'deepagents-memory-saver-v1';\n\nfunction encodeString(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64');\n}\n\nfunction decodeString(value: string): string {\n return Buffer.from(value, 'base64').toString('utf8');\n}\n\nfunction encodeBytes(value: Uint8Array): string {\n return Buffer.from(value).toString('base64');\n}\n\nfunction decodeBytes(value: string): Uint8Array {\n return Buffer.from(value, 'base64');\n}\n\nexport async function loadMemorySaver({\n path,\n saver,\n}: {\n path: string;\n saver: MemorySaver;\n}): Promise<void> {\n let snapshot: string;\n try {\n snapshot = await readFile(path, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n\n const [header, ...lines] = snapshot.split('\\n');\n if (header !== SNAPSHOT_HEADER) {\n throw new Error('Unsupported Deep Agents conversation checkpoint format');\n }\n\n const storage: MemorySaver['storage'] = Object.create(null);\n const writes: MemorySaver['writes'] = Object.create(null);\n\n for (const line of lines) {\n if (line === '') continue;\n const fields = line.split('\\t');\n if (fields[0] === 'S' && fields.length === 7) {\n const [, threadIdValue, namespaceValue, checkpointIdValue] = fields;\n const threadId = decodeString(threadIdValue);\n const namespace = decodeString(namespaceValue);\n const checkpointId = decodeString(checkpointIdValue);\n storage[threadId] ??= Object.create(null);\n storage[threadId][namespace] ??= Object.create(null);\n storage[threadId][namespace][checkpointId] = [\n decodeBytes(fields[4]),\n decodeBytes(fields[5]),\n fields[6] === '' ? undefined : decodeString(fields[6]),\n ];\n continue;\n }\n if (fields[0] === 'W' && fields.length === 6) {\n const [, keyValue, indexValue, taskIdValue, channelValue, value] = fields;\n const key = decodeString(keyValue);\n const index = decodeString(indexValue);\n writes[key] ??= Object.create(null);\n writes[key][index] = [\n decodeString(taskIdValue),\n decodeString(channelValue),\n decodeBytes(value),\n ];\n continue;\n }\n throw new Error('Invalid Deep Agents conversation checkpoint');\n }\n\n saver.storage = storage;\n saver.writes = writes;\n}\n\nexport async function saveMemorySaver({\n path,\n saver,\n}: {\n path: string;\n saver: MemorySaver;\n}): Promise<void> {\n const lines = [SNAPSHOT_HEADER];\n\n for (const [threadId, namespaces] of Object.entries(saver.storage)) {\n for (const [namespace, checkpoints] of Object.entries(namespaces)) {\n for (const [\n checkpointId,\n [checkpoint, metadata, parentCheckpointId],\n ] of Object.entries(checkpoints)) {\n lines.push(\n [\n 'S',\n encodeString(threadId),\n encodeString(namespace),\n encodeString(checkpointId),\n encodeBytes(checkpoint),\n encodeBytes(metadata),\n parentCheckpointId == null ? '' : encodeString(parentCheckpointId),\n ].join('\\t'),\n );\n }\n }\n }\n\n for (const [key, indexedWrites] of Object.entries(saver.writes)) {\n for (const [index, [taskId, channel, value]] of Object.entries(\n indexedWrites,\n )) {\n lines.push(\n [\n 'W',\n encodeString(key),\n encodeString(index),\n encodeString(taskId),\n encodeString(channel),\n encodeBytes(value),\n ].join('\\t'),\n );\n }\n }\n\n await mkdir(dirname(path), { recursive: true });\n const temporaryPath = `${path}.${process.pid}.tmp`;\n await writeFile(temporaryPath, `${lines.join('\\n')}\\n`, 'utf8');\n await rename(temporaryPath, path);\n}\n\nexport async function removeMemorySaverSnapshot(path: string): Promise<void> {\n await rm(path, { force: true });\n}\n","import {\n AIMessage,\n ToolMessage,\n type ToolCall,\n} from '@langchain/core/messages';\nimport type { createDeepAgent } from 'deepagents';\nimport type { StartMessage } from '../deepagents-bridge-protocol';\nimport {\n isBuiltinToolIncluded,\n NATIVE_TOOL_KIND,\n toCommonName,\n} from './approvals';\n\ntype DeepAgentsMiddleware = NonNullable<\n NonNullable<Parameters<typeof createDeepAgent>[0]>['middleware']\n>[number];\n\ntype DeepAgentsState = {\n messages: unknown[];\n};\n\ntype DeepAgentsMiddlewareUpdate = {\n messages: unknown[];\n jumpTo?: 'model';\n};\n\nconst MIDDLEWARE_BRAND = Symbol.for('AgentMiddleware');\n\nfunction getBuiltinToolFilteringDenialReason(input: {\n toolName: string;\n}): string {\n return `Tool '${input.toolName}' is inactive due to the HarnessAgent tool filtering policy.`;\n}\n\nfunction stringifyToolInput(input: unknown): string {\n return JSON.stringify(input ?? {});\n}\n\nfunction isNativeBuiltinToolCall(input: { toolCall: ToolCall }): boolean {\n return Object.keys(NATIVE_TOOL_KIND).includes(input.toolCall.name);\n}\n\nfunction isInactiveBuiltinToolCall(input: {\n toolCall: ToolCall;\n builtinToolFiltering: StartMessage['builtinToolFiltering'];\n}): boolean {\n return (\n isNativeBuiltinToolCall({ toolCall: input.toolCall }) &&\n !isBuiltinToolIncluded({\n nativeName: input.toolCall.name,\n toolFiltering: input.builtinToolFiltering,\n })\n );\n}\n\nexport function createBuiltinToolFilteringMiddleware(input: {\n builtinToolFiltering: StartMessage['builtinToolFiltering'];\n emit: (event: Record<string, unknown>) => void;\n}): DeepAgentsMiddleware | undefined {\n if (input.builtinToolFiltering == null) return undefined;\n\n return {\n [MIDDLEWARE_BRAND]: true,\n name: 'HarnessBuiltinToolFilteringMiddleware',\n afterModel: {\n canJumpTo: ['model'],\n hook: (\n state: DeepAgentsState,\n ): DeepAgentsMiddlewareUpdate | undefined => {\n const lastMessage = [...state.messages]\n .reverse()\n .find(message => AIMessage.isInstance(message));\n\n if (!lastMessage?.tool_calls?.length) return undefined;\n\n let hasActiveToolCalls = false;\n const deniedToolMessages: ToolMessage[] = [];\n\n for (const toolCall of lastMessage.tool_calls) {\n if (\n !isInactiveBuiltinToolCall({\n toolCall,\n builtinToolFiltering: input.builtinToolFiltering,\n })\n ) {\n hasActiveToolCalls = true;\n continue;\n }\n\n const nativeName = toolCall.name;\n toolCall.id ??= `${nativeName}-filtered-${deniedToolMessages.length}`;\n const toolName = toCommonName(nativeName);\n const reason = getBuiltinToolFilteringDenialReason({ toolName });\n\n input.emit({\n type: 'tool-call',\n toolCallId: toolCall.id,\n toolName,\n input: stringifyToolInput(toolCall.args),\n providerExecuted: true,\n nativeName,\n });\n input.emit({\n type: 'tool-result',\n toolCallId: toolCall.id,\n toolName,\n result: reason,\n });\n\n deniedToolMessages.push(\n new ToolMessage({\n content: reason,\n name: nativeName,\n tool_call_id: toolCall.id,\n status: 'error',\n }),\n );\n }\n\n if (deniedToolMessages.length === 0) return undefined;\n\n return {\n messages: [lastMessage, ...deniedToolMessages],\n ...(hasActiveToolCalls ? {} : { jumpTo: 'model' }),\n };\n },\n },\n } as DeepAgentsMiddleware;\n}\n"],"mappings":"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","names":["randomUUID","procEnv","bridgeStateDir","pending","tool","Command","MemorySaver","ToolStrategy","tool","asJsonSchema","ProviderStrategy","z","z","z","contextSchema","z","contextSchema","z","contextSchema","z","z","z","z","stateSchema","contextSchema","z","stateSchema","z","z","contextSchema","z","contextSchema","z","AIMessage","AIMessageChunk","BaseMessage","HumanMessage","SystemMessage","ToolMessage","trimMessages","InMemoryStore","interrupt","randomUUID","NATIVE_TO_COMMON","toCommonName","mcpToolNames","z","mkdir","writeFile","AIMessage","ToolMessage","MIDDLEWARE_BRAND","AIMessage","ToolMessage","procEnv","configuredModel","MemorySaver","tool","randomUUID","turn","hostToolNames","toCommonName","Command"]}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["NATIVE_TO_COMMON","toCommonName","toCommonName","procEnv"],"sources":["../../../harness/dist/bridge/index.js","../../src/bridge/approvals.ts","../../src/bridge/create-emit-stream-event.ts","../../src/bridge/json-schema-to-zod.ts","../../src/bridge/local-shell-backend.ts","../../src/bridge/persistent-memory-saver.ts","../../src/bridge/tool-filtering.ts","../../src/bridge/index.ts"],"sourcesContent":["import { appendFile, mkdir, writeFile } from \"node:fs/promises\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\nimport { env, pid, stdout } from \"node:process\";\nimport { WebSocketServer } from \"ws\";\n//#region src/bridge/harness-bridge-capability-unsupported-error.ts\nconst name = \"AI_HarnessBridgeCapabilityUnsupportedError\";\n/**\n* Signals an unsupported capability discovered inside a sandbox bridge.\n* `isInstance` also recognizes the serialized error shape received by the\n* host, where it can be translated to `HarnessCapabilityUnsupportedError`.\n*/\nvar HarnessBridgeCapabilityUnsupportedError = class extends Error {\n\tconstructor({ message, harnessId, cause }) {\n\t\tsuper(message);\n\t\tObject.defineProperty(this, \"name\", { value: name });\n\t\tthis.harnessId = harnessId;\n\t\tthis.cause = cause;\n\t}\n\tstatic isInstance(error) {\n\t\treturn error != null && typeof error === \"object\" && \"name\" in error && error.name === name && \"message\" in error && typeof error.message === \"string\";\n\t}\n};\n//#endregion\n//#region src/bridge/index.ts\nconst DEBUG_LEVEL_WEIGHT = {\n\terror: 0,\n\twarn: 1,\n\tinfo: 2,\n\tdebug: 3,\n\ttrace: 4\n};\n/** Exact-or-dotted-prefix subsystem match (`'bridge'` matches `'bridge.turn'`). */\nfunction subsystemMatches(filters, subsystem) {\n\tif (!filters || filters.length === 0) return true;\n\treturn filters.some((filter) => subsystem === filter || subsystem.startsWith(`${filter}.`));\n}\nfunction formatBridgeError(err) {\n\tif (err instanceof Error) return {\n\t\tname: err.name,\n\t\tmessage: err.message,\n\t\tstack: err.stack\n\t};\n\tif (typeof err === \"string\") return { message: err };\n\tif (err !== null && typeof err === \"object\") try {\n\t\treturn { message: JSON.stringify(err) };\n\t} catch {}\n\treturn { message: String(err) };\n}\nfunction createBridgeUserMessageQueue(options) {\n\tconst messages = [];\n\tconst waiters = [];\n\tconst entries = /* @__PURE__ */ new Map();\n\tlet closed = false;\n\tlet pendingCount = 0;\n\tconst enqueue = (input) => {\n\t\tconst existing = entries.get(input.messageId);\n\t\tif (existing != null) {\n\t\t\tif (existing.response != null) options.respond(existing.response);\n\t\t\treturn;\n\t\t}\n\t\tlet settled = false;\n\t\tconst settle = (response) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tpendingCount--;\n\t\t\tconst entry = entries.get(input.messageId);\n\t\t\tif (entry != null) entry.response = response;\n\t\t\toptions.respond(response);\n\t\t};\n\t\tconst message = {\n\t\t\tmessageId: input.messageId,\n\t\t\ttext: input.text,\n\t\t\taccept: () => {\n\t\t\t\tsettle({\n\t\t\t\t\ttype: \"user-message-response\",\n\t\t\t\t\tmessageId: input.messageId,\n\t\t\t\t\taccepted: true\n\t\t\t\t});\n\t\t\t},\n\t\t\treject: (error) => {\n\t\t\t\tsettle({\n\t\t\t\t\ttype: \"user-message-response\",\n\t\t\t\t\tmessageId: input.messageId,\n\t\t\t\t\taccepted: false,\n\t\t\t\t\terror: { message: formatBridgeError(error).message }\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\tentries.set(input.messageId, { reject: message.reject });\n\t\tpendingCount++;\n\t\tif (closed) {\n\t\t\tmessage.reject(/* @__PURE__ */ new Error(\"The bridge turn is no longer accepting user messages.\"));\n\t\t\treturn;\n\t\t}\n\t\tconst waiter = waiters.shift();\n\t\tif (waiter != null) waiter({\n\t\t\tdone: false,\n\t\t\tvalue: message\n\t\t});\n\t\telse messages.push(message);\n\t};\n\tconst close = (error) => {\n\t\tif (closed) return;\n\t\tclosed = true;\n\t\tconst reason = error ?? /* @__PURE__ */ new Error(\"The bridge turn ended before accepting the user message.\");\n\t\tfor (const entry of entries.values()) if (entry.response == null) entry.reject(reason);\n\t\tmessages.length = 0;\n\t\twhile (waiters.length > 0) waiters.shift()({\n\t\t\tdone: true,\n\t\t\tvalue: void 0\n\t\t});\n\t};\n\treturn {\n\t\tget pendingCount() {\n\t\t\treturn pendingCount;\n\t\t},\n\t\tenqueue,\n\t\tclose,\n\t\t[Symbol.asyncIterator]() {\n\t\t\treturn { next: () => {\n\t\t\t\tconst message = messages.shift();\n\t\t\t\tif (message != null) return Promise.resolve({\n\t\t\t\t\tdone: false,\n\t\t\t\t\tvalue: message\n\t\t\t\t});\n\t\t\t\tif (closed) return Promise.resolve({\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: void 0\n\t\t\t\t});\n\t\t\t\treturn new Promise((resolve) => {\n\t\t\t\t\twaiters.push(resolve);\n\t\t\t\t});\n\t\t\t} };\n\t\t}\n\t};\n}\nfunction parseEnvList(value) {\n\tif (!value) return void 0;\n\tconst items = value.split(\",\").map((item) => item.trim()).filter(Boolean);\n\treturn items.length > 0 ? items : void 0;\n}\nconst ENV_TRUTHY = /* @__PURE__ */ new Set([\n\t\"1\",\n\t\"true\",\n\t\"yes\",\n\t\"on\"\n]);\nconst WS_OPEN = 1;\nasync function runBridge(options) {\n\tconst { bridgeType, bridgeStateDir, onStart, onStop, onDestroy } = options;\n\tconst teardownGraceMs = options.turnTeardownGraceMs ?? 1e4;\n\tconst expectedToken = options.token ?? env.BRIDGE_CHANNEL_TOKEN ?? \"\";\n\tconst bridgeWsPort = options.port ?? parseInt(env.BRIDGE_WS_PORT ?? \"0\", 10);\n\tconst bridgeMetaPath = `${bridgeStateDir}/bridge-meta.json`;\n\tconst startConfigPath = `${bridgeStateDir}/start-config.json`;\n\tconst rerunStartConfigPath = `${bridgeStateDir}/rerun-start-config.json`;\n\tconst eventLogPath = `${bridgeStateDir}/event-log.ndjson`;\n\ttry {\n\t\tawait mkdir(bridgeStateDir, { recursive: true });\n\t} catch {}\n\tlet currentBoundPort = 0;\n\tlet currentTurnState = \"init\";\n\tlet activeSocket;\n\tlet isFirstTurn = true;\n\tlet turnAbort;\n\tlet currentUserMessages;\n\t/**\n\t* Settles when the in-flight turn has fully wound down — `onStart`\n\t* returned or threw AND its completion state was recorded. `undefined`\n\t* between turns. A new `start` fences on this so turns never overlap.\n\t*/\n\tlet activeTurn;\n\tlet debugConfig;\n\tlet consoleCaptureInstalled = false;\n\tconst envDebugEnabled = ENV_TRUTHY.has((env.HARNESS_DEBUG ?? \"\").toLowerCase());\n\tlet seqCounter = 0;\n\tlet eventLog = [];\n\tlet diskBuffer = \"\";\n\tlet flushPromise = null;\n\tconst flushEventsToDisk = async () => {\n\t\twhile (diskBuffer.length > 0) {\n\t\t\tconst buf = diskBuffer;\n\t\t\tdiskBuffer = \"\";\n\t\t\tawait appendFile(eventLogPath, buf).catch(() => {});\n\t\t}\n\t};\n\tconst scheduleEventFlush = () => {\n\t\tif (flushPromise) return;\n\t\tflushPromise = new Promise((resolve) => {\n\t\t\tsetImmediate(() => {\n\t\t\t\tflushEventsToDisk().finally(resolve);\n\t\t\t});\n\t\t}).finally(() => {\n\t\t\tflushPromise = null;\n\t\t\tif (diskBuffer.length > 0) scheduleEventFlush();\n\t\t});\n\t};\n\tconst flushPendingEventsToDisk = async () => {\n\t\tif (diskBuffer.length > 0 && !flushPromise) scheduleEventFlush();\n\t\tlet inFlight = flushPromise;\n\t\twhile (inFlight) {\n\t\t\tawait inFlight;\n\t\t\tinFlight = flushPromise;\n\t\t}\n\t};\n\tif (env.BRIDGE_REPLAY_FROM_DISK === \"1\" && existsSync(eventLogPath)) try {\n\t\teventLog = readFileSync(eventLogPath, \"utf8\").split(\"\\n\").map((line) => line.trim()).filter(Boolean).map((line) => ({\n\t\t\tseq: JSON.parse(line).seq,\n\t\t\tline\n\t\t}));\n\t\tseqCounter = eventLog.at(-1)?.seq ?? 0;\n\t} catch {\n\t\teventLog = [];\n\t\tseqCounter = 0;\n\t}\n\tconst pendingToolResults = /* @__PURE__ */ new Map();\n\tconst bufferedToolResults = [];\n\tconst pendingToolApprovals = /* @__PURE__ */ new Map();\n\tconst writeBridgeMeta = async (state) => {\n\t\ttry {\n\t\t\tawait writeFile(bridgeMetaPath, JSON.stringify({\n\t\t\t\ttype: bridgeType,\n\t\t\t\tport: currentBoundPort,\n\t\t\t\tstate,\n\t\t\t\tpid\n\t\t\t}));\n\t\t} catch {}\n\t};\n\tconst writeStartConfig = async (start) => {\n\t\ttry {\n\t\t\tconst serialized = JSON.stringify(start);\n\t\t\tawait writeFile(startConfigPath, serialized);\n\t\t\tif (!existsSync(rerunStartConfigPath)) await writeFile(rerunStartConfigPath, serialized);\n\t\t} catch {}\n\t};\n\tconst emit = (event) => {\n\t\tconst seq = ++seqCounter;\n\t\tconst line = JSON.stringify({\n\t\t\t...event,\n\t\t\tseq\n\t\t});\n\t\teventLog.push({\n\t\t\tseq,\n\t\t\tline\n\t\t});\n\t\tdiskBuffer += `${line}\\n`;\n\t\tscheduleEventFlush();\n\t\tif (activeSocket?.readyState === WS_OPEN) try {\n\t\t\tactiveSocket.send(line);\n\t\t} catch {}\n\t};\n\tconst replay = (ws, afterSeq) => {\n\t\tfor (const entry of eventLog) if (entry.seq > afterSeq && ws.readyState === WS_OPEN) ws.send(entry.line);\n\t};\n\tconst shouldEmitDebugEvent = (level, subsystem) => {\n\t\tif (!debugConfig?.enabled) return false;\n\t\tconst threshold = debugConfig.level ?? \"debug\";\n\t\tif (DEBUG_LEVEL_WEIGHT[level] > DEBUG_LEVEL_WEIGHT[threshold]) return false;\n\t\treturn subsystemMatches(debugConfig.subsystems, subsystem);\n\t};\n\tconst rawStdoutWrite = process.stdout.write.bind(process.stdout);\n\tconst rawStderrWrite = process.stderr.write.bind(process.stderr);\n\tconst writeErrorToStderr = (input) => {\n\t\ttry {\n\t\t\tconst formatted = formatBridgeError(input.error);\n\t\t\trawStderrWrite(`[harness:${bridgeType}:error] ${input.message}: ${formatted.message}\\n`);\n\t\t\tif (formatted.stack) rawStderrWrite(`${formatted.stack}\\n`);\n\t\t} catch {}\n\t};\n\tconst emitWarning = (input) => {\n\t\ttry {\n\t\t\tfor (const line of input.message.split(\"\\n\")) if (line.trim().length > 0) rawStderrWrite(`[harness:${bridgeType}:warn] ${line}\\n`);\n\t\t} catch {}\n\t};\n\tconst emitError = (input) => {\n\t\twriteErrorToStderr({\n\t\t\tmessage: input.message ?? \"bridge error\",\n\t\t\terror: input.error\n\t\t});\n\t\temit({\n\t\t\ttype: \"error\",\n\t\t\terror: serialiseError(input.error)\n\t\t});\n\t};\n\tconst installConsoleCapture = () => {\n\t\tif (consoleCaptureInstalled) return;\n\t\tconsoleCaptureInstalled = true;\n\t\tconst buffers = {\n\t\t\tstdout: \"\",\n\t\t\tstderr: \"\"\n\t\t};\n\t\tconst patch = (stream, raw) => (chunk, encoding, cb) => {\n\t\t\tif (debugConfig?.enabled) try {\n\t\t\t\tconst enc = typeof encoding === \"string\" ? encoding : \"utf8\";\n\t\t\t\tconst text = typeof chunk === \"string\" ? chunk : Buffer.from(chunk).toString(enc);\n\t\t\t\tconst parts = (buffers[stream] + text.replace(/\\r\\n/g, \"\\n\")).split(\"\\n\");\n\t\t\t\tbuffers[stream] = parts.pop() ?? \"\";\n\t\t\t\tfor (const line of parts) {\n\t\t\t\t\tconst trimmed = line.replace(/\\s+$/, \"\");\n\t\t\t\t\tif (trimmed) emit({\n\t\t\t\t\t\ttype: \"sandbox-log\",\n\t\t\t\t\t\tsource: bridgeType,\n\t\t\t\t\t\tstream,\n\t\t\t\t\t\tline: trimmed\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t\treturn raw(chunk, encoding, cb);\n\t\t};\n\t\tprocess.stdout.write = patch(\"stdout\", rawStdoutWrite);\n\t\tprocess.stderr.write = patch(\"stderr\", rawStderrWrite);\n\t};\n\tconst handleInbound = async (msg, ws) => {\n\t\tswitch (msg.type) {\n\t\t\tcase \"start\": {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst pendingTurn = activeTurn;\n\t\t\t\t\tif (pendingTurn == null) break;\n\t\t\t\t\tturnAbort?.abort();\n\t\t\t\t\tcurrentUserMessages?.close(/* @__PURE__ */ new Error(\"A new bridge turn replaced the active turn.\"));\n\t\t\t\t\tlet graceTimer;\n\t\t\t\t\tconst settled = await Promise.race([pendingTurn.then(() => true), new Promise((resolve) => {\n\t\t\t\t\t\tgraceTimer = setTimeout(() => resolve(false), teardownGraceMs);\n\t\t\t\t\t\tgraceTimer.unref?.();\n\t\t\t\t\t})]);\n\t\t\t\t\tclearTimeout(graceTimer);\n\t\t\t\t\tif (!settled) break;\n\t\t\t\t}\n\t\t\t\tlet turnFinished;\n\t\t\t\tconst thisTurn = new Promise((resolve) => turnFinished = resolve);\n\t\t\t\tactiveTurn = thisTurn;\n\t\t\t\tactiveSocket = ws;\n\t\t\t\tconst firstTurn = isFirstTurn;\n\t\t\t\tisFirstTurn = false;\n\t\t\t\teventLog = [];\n\t\t\t\tdiskBuffer = \"\";\n\t\t\t\twriteFile(eventLogPath, \"\").catch(() => {});\n\t\t\t\tturnAbort = new AbortController();\n\t\t\t\tcurrentTurnState = \"running\";\n\t\t\t\twriteStartConfig(msg);\n\t\t\t\twriteBridgeMeta(\"running\");\n\t\t\t\tconst startDebug = msg.debug;\n\t\t\t\tdebugConfig = {\n\t\t\t\t\tenabled: startDebug?.enabled ?? envDebugEnabled,\n\t\t\t\t\tlevel: startDebug?.level ?? env.HARNESS_DEBUG_LEVEL,\n\t\t\t\t\tsubsystems: startDebug?.subsystems ?? parseEnvList(env.HARNESS_DEBUG_SUBSYSTEMS)\n\t\t\t\t};\n\t\t\t\tif (debugConfig.enabled) installConsoleCapture();\n\t\t\t\tconst userMessages = createBridgeUserMessageQueue({ respond: emit });\n\t\t\t\tconst turn = {\n\t\t\t\t\temit,\n\t\t\t\t\trequestToolResult: (requestInput) => {\n\t\t\t\t\t\tconst request = typeof requestInput === \"string\" ? { toolCallId: requestInput } : requestInput;\n\t\t\t\t\t\tconst bufferedIndex = bufferedToolResults.findIndex((buffered) => buffered.toolCallId === request.toolCallId || request.matches?.(buffered.result) === true);\n\t\t\t\t\t\tif (bufferedIndex >= 0) return Promise.resolve(bufferedToolResults.splice(bufferedIndex, 1)[0].result);\n\t\t\t\t\t\treturn new Promise((resolve) => {\n\t\t\t\t\t\t\tpendingToolResults.set(request.toolCallId, {\n\t\t\t\t\t\t\t\tresolve,\n\t\t\t\t\t\t\t\tmatches: request.matches\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\trequestToolApproval: (approvalId) => new Promise((resolve) => {\n\t\t\t\t\t\tpendingToolApprovals.set(approvalId, resolve);\n\t\t\t\t\t}),\n\t\t\t\t\texperimental_userMessages: userMessages,\n\t\t\t\t\tabortSignal: turnAbort.signal,\n\t\t\t\t\tfirstTurn,\n\t\t\t\t\tbridgeLog: (input) => {\n\t\t\t\t\t\tconst level = input.level ?? \"debug\";\n\t\t\t\t\t\tif (!shouldEmitDebugEvent(level, input.subsystem)) return;\n\t\t\t\t\t\temit({\n\t\t\t\t\t\t\ttype: \"debug-event\",\n\t\t\t\t\t\t\tlevel,\n\t\t\t\t\t\t\tsubsystem: input.subsystem,\n\t\t\t\t\t\t\tmessage: input.message,\n\t\t\t\t\t\t\t...input.attrs ? { attrs: input.attrs } : {},\n\t\t\t\t\t\t\t...input.error !== void 0 ? { error: formatBridgeError(input.error) } : {}\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\temitWarning,\n\t\t\t\t\temitError\n\t\t\t\t};\n\t\t\t\tcurrentUserMessages = userMessages;\n\t\t\t\ttry {\n\t\t\t\t\tawait onStart(msg, turn);\n\t\t\t\t} catch (err) {\n\t\t\t\t\temitError({\n\t\t\t\t\t\terror: err,\n\t\t\t\t\t\tmessage: \"bridge turn failed\"\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tuserMessages.close();\n\t\t\t\t\tif (currentUserMessages === userMessages) currentUserMessages = void 0;\n\t\t\t\t\tif (activeTurn === thisTurn) {\n\t\t\t\t\t\tactiveTurn = void 0;\n\t\t\t\t\t\tcurrentTurnState = \"waiting\";\n\t\t\t\t\t\twriteBridgeMeta(\"waiting\");\n\t\t\t\t\t}\n\t\t\t\t\tturnFinished();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"tool-result\": {\n\t\t\t\tconst result = {\n\t\t\t\t\toutput: msg.output,\n\t\t\t\t\tisError: msg.isError,\n\t\t\t\t\ttoolResult: msg.toolResult\n\t\t\t\t};\n\t\t\t\tconst exactPending = pendingToolResults.get(msg.toolCallId);\n\t\t\t\tconst matchingPending = exactPending == null ? Array.from(pendingToolResults.entries()).find(([, pending]) => pending.matches?.(result) === true) : void 0;\n\t\t\t\tconst pending = exactPending ?? matchingPending?.[1];\n\t\t\t\tconst pendingId = exactPending != null ? msg.toolCallId : matchingPending?.[0];\n\t\t\t\tif (pending != null && pendingId != null) {\n\t\t\t\t\tpendingToolResults.delete(pendingId);\n\t\t\t\t\tpending.resolve(result);\n\t\t\t\t} else bufferedToolResults.push({\n\t\t\t\t\ttoolCallId: msg.toolCallId,\n\t\t\t\t\tresult\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"tool-approval-response\": {\n\t\t\t\tconst resolver = pendingToolApprovals.get(msg.approvalId);\n\t\t\t\tif (resolver) {\n\t\t\t\t\tpendingToolApprovals.delete(msg.approvalId);\n\t\t\t\t\tresolver({\n\t\t\t\t\t\tapproved: msg.approved,\n\t\t\t\t\t\treason: msg.reason\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"user-message\": {\n\t\t\t\tconst messageId = msg.messageId ?? randomUUID();\n\t\t\t\tif (currentUserMessages == null) {\n\t\t\t\t\tsendControl(ws, {\n\t\t\t\t\t\ttype: \"user-message-response\",\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\taccepted: false,\n\t\t\t\t\t\terror: { message: \"The bridge has no active turn to steer.\" }\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (ws !== activeSocket) {\n\t\t\t\t\tsendControl(ws, {\n\t\t\t\t\t\ttype: \"user-message-response\",\n\t\t\t\t\t\tmessageId,\n\t\t\t\t\t\taccepted: false,\n\t\t\t\t\t\terror: { message: \"The connection does not own the active bridge turn.\" }\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcurrentUserMessages.enqueue({\n\t\t\t\t\tmessageId,\n\t\t\t\t\ttext: msg.text\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"abort\":\n\t\t\t\tturnAbort?.abort();\n\t\t\t\treturn;\n\t\t\tcase \"resume\":\n\t\t\t\tactiveSocket = ws;\n\t\t\t\treplay(ws, msg.lastSeenEventId);\n\t\t\t\treturn;\n\t\t\tcase \"destroy\":\n\t\t\t\tcurrentTurnState = \"done\";\n\t\t\t\twriteBridgeMeta(\"done\");\n\t\t\t\tawait onDestroy?.();\n\t\t\t\tdrainThenExit(ws, 1e3, \"destroy\");\n\t\t\t\treturn;\n\t\t\tcase \"stop\":\n\t\t\t\tcurrentTurnState = \"done\";\n\t\t\t\twriteBridgeMeta(\"done\");\n\t\t\t\tsendControl(ws, {\n\t\t\t\t\ttype: \"bridge-stop\",\n\t\t\t\t\tdata: await onStop?.() ?? {}\n\t\t\t\t});\n\t\t\t\tdrainThenExit(ws, 1e3, \"stop\");\n\t\t}\n\t};\n\twriteBridgeMeta(\"init\");\n\tconst wss = new WebSocketServer({\n\t\tport: bridgeWsPort,\n\t\thost: \"0.0.0.0\"\n\t});\n\tconst exit = () => {\n\t\tif (options.onExit) {\n\t\t\toptions.onExit();\n\t\t\treturn;\n\t\t}\n\t\twss.close(() => process.exit(0));\n\t\tsetTimeout(() => process.exit(0), 1e3).unref();\n\t};\n\tconst drainThenExit = (ws, code, reason) => {\n\t\tconst start = Date.now();\n\t\tconst tick = () => {\n\t\t\tif (ws.bufferedAmount === 0 || ws.readyState !== WS_OPEN || Date.now() - start >= 5e3) {\n\t\t\t\tflushPendingEventsToDisk().finally(() => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tws.close(code, reason);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\texit();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetTimeout(tick, 10).unref();\n\t\t};\n\t\ttick();\n\t};\n\twss.on(\"listening\", () => {\n\t\tconst addr = wss.address();\n\t\tcurrentBoundPort = typeof addr === \"object\" && addr ? addr.port : 0;\n\t\tcurrentTurnState = \"waiting\";\n\t\twriteBridgeMeta(\"waiting\");\n\t\tstdout.write(JSON.stringify({\n\t\t\ttype: \"bridge-ready\",\n\t\t\tport: currentBoundPort\n\t\t}) + \"\\n\");\n\t\toptions.onListening?.(currentBoundPort);\n\t});\n\twss.on(\"connection\", (ws, req) => {\n\t\tif (new URL(req.url ?? \"/\", \"http://localhost\").searchParams.get(\"agent_bridge_token\") !== expectedToken) {\n\t\t\tws.close(1008, \"unauthorized\");\n\t\t\treturn;\n\t\t}\n\t\tsendControl(ws, {\n\t\t\ttype: \"bridge-hello\",\n\t\t\tstate: currentTurnState,\n\t\t\tlastSeq: seqCounter,\n\t\t\tcapabilities: { experimental_userMessageResponses: true }\n\t\t});\n\t\tws.on(\"message\", (raw) => {\n\t\t\tlet parsed;\n\t\t\ttry {\n\t\t\t\tconst text = typeof raw === \"string\" ? raw : Buffer.from(raw).toString(\"utf8\");\n\t\t\t\tparsed = JSON.parse(text);\n\t\t\t} catch (err) {\n\t\t\t\tsendControl(ws, {\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\terror: `protocol parse error: ${err.message}`\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleInbound(parsed, ws);\n\t\t});\n\t\tws.on(\"close\", () => {\n\t\t\tif (activeSocket === ws) activeSocket = void 0;\n\t\t});\n\t\tws.on(\"error\", () => {});\n\t});\n\tprocess.on(\"uncaughtException\", (err) => {\n\t\temitError({\n\t\t\terror: err,\n\t\t\tmessage: \"uncaught exception\"\n\t\t});\n\t});\n\tprocess.on(\"unhandledRejection\", (err) => {\n\t\temitError({\n\t\t\terror: err,\n\t\t\tmessage: \"unhandled rejection\"\n\t\t});\n\t});\n\tawait new Promise((resolve, reject) => {\n\t\tif (wss.address() != null) {\n\t\t\tresolve();\n\t\t\treturn;\n\t\t}\n\t\twss.once(\"listening\", resolve);\n\t\twss.once(\"error\", reject);\n\t});\n\treturn {\n\t\tport: currentBoundPort,\n\t\tclose: () => new Promise((resolve) => {\n\t\t\twss.close(() => resolve());\n\t\t})\n\t};\n}\nfunction sendControl(socket, message) {\n\tif (socket?.readyState === WS_OPEN) try {\n\t\tsocket.send(JSON.stringify(message));\n\t} catch {}\n}\nfunction serialiseError(err) {\n\tif (err instanceof Error) return {\n\t\tname: err.name,\n\t\tmessage: err.message,\n\t\tstack: err.stack\n\t};\n\treturn err;\n}\n//#endregion\nexport { HarnessBridgeCapabilityUnsupportedError, runBridge };\n\n//# sourceMappingURL=index.js.map","import type { StartMessage } from '../deepagents-bridge-protocol';\n\nexport type PermissionMode = NonNullable<StartMessage['permissionMode']>;\n\n// Native built-in tool -> approval kind (mirrors the host adapter's toolUseKind).\nexport const NATIVE_TOOL_KIND: Readonly<\n Record<string, 'readonly' | 'edit' | 'bash'>\n> = {\n read_file: 'readonly',\n write_file: 'edit',\n edit_file: 'edit',\n execute: 'bash',\n grep: 'readonly',\n glob: 'readonly',\n ls: 'readonly',\n task: 'edit',\n write_todos: 'edit',\n};\n\nconst NATIVE_TO_COMMON: Readonly<Record<string, string>> = {\n read_file: 'read',\n write_file: 'write',\n edit_file: 'edit',\n execute: 'bash',\n};\n\nexport function toCommonName(nativeName: string): string {\n return NATIVE_TO_COMMON[nativeName] ?? nativeName;\n}\n\nexport function isBuiltinToolIncluded(input: {\n nativeName: string;\n toolFiltering: StartMessage['builtinToolFiltering'];\n}): boolean {\n if (input.toolFiltering == null) return true;\n const toolName = toCommonName(input.nativeName);\n return input.toolFiltering.mode === 'allow'\n ? input.toolFiltering.toolNames.includes(toolName)\n : !input.toolFiltering.toolNames.includes(toolName);\n}\n\nexport function builtinToolRequiresApproval(\n kind: 'readonly' | 'edit' | 'bash',\n permissionMode: PermissionMode,\n): boolean {\n if (permissionMode === 'allow-all') return false;\n if (permissionMode === 'allow-edits') return kind === 'bash';\n return kind === 'edit' || kind === 'bash';\n}\n\n// Per-tool HITL config for createDeepAgent; only built-ins are gated (host tools approve at the agent layer).\nexport function buildInterruptOn(\n permissionMode: PermissionMode | undefined,\n builtinToolFiltering: StartMessage['builtinToolFiltering'],\n):\n | Record<string, { allowedDecisions: Array<'approve' | 'reject'> }>\n | undefined {\n const config: Record<\n string,\n { allowedDecisions: Array<'approve' | 'reject'> }\n > = {};\n for (const [nativeName, kind] of Object.entries(NATIVE_TOOL_KIND)) {\n if (\n permissionMode != null &&\n isBuiltinToolIncluded({\n nativeName,\n toolFiltering: builtinToolFiltering,\n }) &&\n builtinToolRequiresApproval(kind, permissionMode)\n ) {\n config[nativeName] = { allowedDecisions: ['approve', 'reject'] };\n }\n }\n return Object.keys(config).length > 0 ? config : undefined;\n}\n\ntype ActionRequest = { name: string; args?: Record<string, unknown> };\ntype HITLInterruptValue = { actionRequests?: ActionRequest[] };\n\n// Flatten LangChain HITL interrupt payloads into the gated tool calls awaiting a decision.\nexport function collectActionRequests(\n interrupts: Array<{ value?: unknown }>,\n): { name: string; args: Record<string, unknown> }[] {\n const out: { name: string; args: Record<string, unknown> }[] = [];\n for (const interrupt of interrupts) {\n const value = interrupt.value as HITLInterruptValue | undefined;\n for (const action of value?.actionRequests ?? []) {\n out.push({ name: action.name, args: action.args ?? {} });\n }\n }\n return out;\n}\n","import { randomUUID } from 'node:crypto';\n\ntype Emit = (event: Record<string, unknown>) => void;\n\nexport type DeepAgentsStreamEvent = {\n event?: string;\n name?: string;\n run_id?: string;\n data?: unknown;\n metadata?: {\n langgraph_checkpoint_ns?: string;\n ls_model_name?: unknown;\n };\n};\n\nexport type DeepAgentsStreamEventState = {\n streamStarted: boolean;\n textBlockId: string | undefined;\n reasoningBlockId: string | undefined;\n inputTokens: number;\n outputTokens: number;\n // Per-call streamed-usage fallback (max over chunks), used only when model-end carries no usage.\n streamedStepInput: number;\n streamedStepOutput: number;\n // Top-level step usage is buffered at model-end and flushed as finish-step only after the step's tools run.\n pendingStep: { input: number; output: number } | undefined;\n // Approval-gated tools are announced before execution; these tie the later run back to the approval id and dedup the call.\n approvedToolQueue: Map<string, string[]>;\n approvedRunIds: Map<string, string>;\n dynamicToolRunIds: Set<string>;\n};\n\nexport function createDeepAgentsStreamEventState(): DeepAgentsStreamEventState {\n return {\n streamStarted: false,\n textBlockId: undefined,\n reasoningBlockId: undefined,\n inputTokens: 0,\n outputTokens: 0,\n streamedStepInput: 0,\n streamedStepOutput: 0,\n pendingStep: undefined,\n approvedToolQueue: new Map(),\n approvedRunIds: new Map(),\n dynamicToolRunIds: new Set(),\n };\n}\n\n// Native Deep Agents tool name -> harness-v1 common name (renames only; grep/glob/ls/task/write_todos forward unchanged).\nconst NATIVE_TO_COMMON: Readonly<Record<string, string>> = {\n read_file: 'read',\n write_file: 'write',\n edit_file: 'edit',\n execute: 'bash',\n};\n\nexport function toCommonName(nativeName: string): string {\n return NATIVE_TO_COMMON[nativeName] ?? nativeName;\n}\n\nexport function createEmitStreamEvent({\n state,\n configuredModel,\n hostToolNames,\n mcpToolNames,\n structuredOutputToolNames = new Set(),\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n configuredModel: string | undefined;\n hostToolNames: ReadonlySet<string>;\n mcpToolNames: ReadonlySet<string>;\n structuredOutputToolNames?: ReadonlySet<string>;\n emit: Emit;\n}): (event: DeepAgentsStreamEvent) => void {\n return event => {\n const kind = event.event;\n const data = (event.data ?? {}) as Record<string, unknown>;\n // Subagent (e.g. `task`) events carry a `|`-delimited checkpoint namespace; keep their internals out of the top-level stream.\n const ns = event.metadata?.langgraph_checkpoint_ns ?? '';\n const nested = ns.includes('|');\n\n if (kind === 'on_chat_model_start') {\n if (!nested) {\n if (!state.streamStarted) {\n state.streamStarted = true;\n const modelId = resolveDeepAgentsModelId({\n configuredModel,\n metadata: event.metadata,\n });\n emit({\n type: 'stream-start',\n ...(modelId ? { modelId } : {}),\n });\n }\n // A new top-level model call means the previous step's tools have run; close it now.\n flushStep({ state, emit });\n }\n } else if (kind === 'on_chat_model_stream') {\n if (nested) return;\n const chunk = data.chunk as\n | {\n content?: unknown;\n usage_metadata?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n }\n | undefined;\n if (!chunk) return;\n const content = chunk.content;\n if (typeof content === 'string' && content) {\n emitText({ state, emit, delta: content });\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (block && typeof block === 'object') {\n const value = block as {\n type?: string;\n text?: string;\n thinking?: string;\n reasoning?: string;\n };\n if (\n (value.type === 'text' || value.type === 'text-delta') &&\n value.text\n ) {\n emitText({ state, emit, delta: value.text });\n } else if (value.type === 'thinking' && value.thinking) {\n emitReasoning({ state, emit, delta: value.thinking });\n } else if (\n (value.type === 'reasoning' ||\n value.type === 'reasoning-delta') &&\n value.reasoning\n ) {\n emitReasoning({ state, emit, delta: value.reasoning });\n }\n }\n }\n }\n const usage = chunk.usage_metadata;\n if (usage) {\n state.streamedStepInput = Math.max(\n state.streamedStepInput,\n usage.input_tokens ?? 0,\n );\n state.streamedStepOutput = Math.max(\n state.streamedStepOutput,\n usage.output_tokens ?? 0,\n );\n }\n } else if (kind === 'on_chat_model_end') {\n // Final usage lands on model-end, not the chunks; each model call is one step.\n const output = data.output as\n | {\n usage_metadata?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n }\n | undefined;\n const usage = output?.usage_metadata;\n // One model call = one step; count its usage exactly once (model-end usage, else the streamed max).\n const stepInput = usage?.input_tokens ?? state.streamedStepInput;\n const stepOutput = usage?.output_tokens ?? state.streamedStepOutput;\n state.inputTokens += stepInput;\n state.outputTokens += stepOutput;\n state.streamedStepInput = 0;\n state.streamedStepOutput = 0;\n // Nested (subagent) calls still count toward total usage, but only top-level calls bound a visible step.\n if (!nested) {\n endTextBlock({ state, emit });\n endReasoningBlock({ state, emit });\n // Buffer the step; flushStep emits finish-step after this step's tools run (next start / turn end).\n state.pendingStep = { input: stepInput, output: stepOutput };\n }\n } else if (kind === 'on_tool_start') {\n const toolName = event.name ?? 'unknown';\n if (structuredOutputToolNames.has(toolName)) return;\n const runId = event.run_id ?? '';\n // Host tools emit their own tool-call; surface only top-level builtin (providerExecuted) tools.\n if (!nested && !hostToolNames.has(toolName)) {\n const isMcpTool = mcpToolNames.has(toolName);\n if (isMcpTool && runId) state.dynamicToolRunIds.add(runId);\n const queued = state.approvedToolQueue.get(toolName);\n if (queued && queued.length > 0) {\n // Already announced at approval time; tie this run to that id and don't re-emit the call.\n const approvalId = queued.shift()!;\n if (runId) state.approvedRunIds.set(runId, approvalId);\n } else {\n endTextBlock({ state, emit });\n endReasoningBlock({ state, emit });\n emit({\n type: 'tool-call',\n toolCallId: runId,\n toolName: toCommonName(toolName),\n input: toToolCallInput(data.input),\n providerExecuted: true,\n nativeName: toolName,\n ...(isMcpTool ? { dynamic: true } : {}),\n });\n }\n }\n } else if (kind === 'on_tool_end') {\n const toolName = event.name ?? 'unknown';\n if (structuredOutputToolNames.has(toolName)) return;\n const runId = event.run_id ?? '';\n if (!nested && !hostToolNames.has(toolName)) {\n const dynamic = state.dynamicToolRunIds.delete(runId);\n let output: unknown = data.output ?? '';\n if (output && typeof output === 'object' && 'content' in output) {\n output = (output as { content: unknown }).content;\n }\n emit({\n type: 'tool-result',\n toolCallId: state.approvedRunIds.get(runId) ?? runId,\n toolName: toCommonName(toolName),\n result: output ?? null,\n ...(dynamic ? { dynamic: true } : {}),\n });\n state.approvedRunIds.delete(runId);\n }\n }\n };\n}\n\nexport function endTextBlock({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): void {\n if (state.textBlockId) {\n emit({ type: 'text-end', id: state.textBlockId });\n state.textBlockId = undefined;\n }\n}\n\nexport function endReasoningBlock({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): void {\n if (state.reasoningBlockId) {\n emit({ type: 'reasoning-end', id: state.reasoningBlockId });\n state.reasoningBlockId = undefined;\n }\n}\n\n// Close the buffered top-level step; called when the next step starts and at turn end so finish-step lands after the step's tools.\nexport function flushStep({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): void {\n if (!state.pendingStep) return;\n emit({\n type: 'finish-step',\n finishReason: { unified: 'stop' },\n usage: {\n inputTokens: { total: state.pendingStep.input },\n outputTokens: { total: state.pendingStep.output },\n },\n });\n state.pendingStep = undefined;\n}\n\nfunction ensureTextBlock({\n state,\n emit,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n}): string {\n if (!state.textBlockId) {\n state.textBlockId = `text-${randomUUID()}`;\n emit({ type: 'text-start', id: state.textBlockId });\n }\n return state.textBlockId;\n}\n\n// Text and reasoning are mutually exclusive open blocks: starting one closes the other.\nfunction emitText({\n state,\n emit,\n delta,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n delta: string;\n}): void {\n endReasoningBlock({ state, emit });\n emit({ type: 'text-delta', id: ensureTextBlock({ state, emit }), delta });\n}\n\nfunction emitReasoning({\n state,\n emit,\n delta,\n}: {\n state: DeepAgentsStreamEventState;\n emit: Emit;\n delta: string;\n}): void {\n endTextBlock({ state, emit });\n if (!state.reasoningBlockId) {\n state.reasoningBlockId = `reasoning-${randomUUID()}`;\n emit({ type: 'reasoning-start', id: state.reasoningBlockId });\n }\n emit({ type: 'reasoning-delta', id: state.reasoningBlockId, delta });\n}\n\nfunction resolveDeepAgentsModelId({\n configuredModel,\n metadata,\n}: {\n configuredModel: string | undefined;\n metadata: unknown;\n}): string | undefined {\n if (metadata && typeof metadata === 'object' && !Array.isArray(metadata)) {\n const modelId = (metadata as { ls_model_name?: unknown }).ls_model_name;\n if (typeof modelId === 'string' && modelId.length > 0) return modelId;\n }\n\n return configuredModel;\n}\n\n// LangChain reports some built-in tool args wrapped as `{ input: \"<json>\" }`; unwrap to the inner JSON so AI SDK validates the real shape.\nfunction toToolCallInput(raw: unknown): string {\n if (\n raw &&\n typeof raw === 'object' &&\n !Array.isArray(raw) &&\n Object.keys(raw).length === 1 &&\n typeof (raw as { input?: unknown }).input === 'string'\n ) {\n const inner = (raw as { input: string }).input;\n if (/^\\s*[[{]/.test(inner)) return inner;\n }\n return JSON.stringify(raw ?? {});\n}\n","import { z } from 'zod/v4';\n\nexport type JsonSchemaObject = {\n type?: string | string[];\n description?: string;\n properties?: Record<string, JsonSchemaObject>;\n required?: string[];\n items?: JsonSchemaObject;\n nullable?: boolean;\n};\n\n// Convert a host tool's JSON Schema to a zod object for LangChain's `tool()`.\nexport function jsonSchemaToZodObject(input: unknown) {\n const schema =\n input && typeof input === 'object' ? (input as JsonSchemaObject) : {};\n return z.object(toZodShape(schema));\n}\n\nfunction toZodShape(schema: JsonSchemaObject): Record<string, z.ZodTypeAny> {\n if (!schema.properties) return {};\n const required = new Set(schema.required);\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const [key, propSchema] of Object.entries(schema.properties)) {\n const propType = toZodType(propSchema);\n shape[key] = required.has(key) ? propType : propType.optional();\n }\n return shape;\n}\n\nfunction toZodType(schema: JsonSchemaObject | undefined): z.ZodTypeAny {\n if (!schema) return z.any();\n const types = Array.isArray(schema.type)\n ? schema.type.filter(t => t !== 'null')\n : ([schema.type].filter(Boolean) as string[]);\n let zType: z.ZodTypeAny;\n switch (types[0]) {\n case 'string':\n zType = z.string();\n break;\n case 'number':\n zType = z.number();\n break;\n case 'integer':\n zType = z.number().int();\n break;\n case 'boolean':\n zType = z.boolean();\n break;\n case 'array':\n zType = z.array(toZodType(schema.items));\n break;\n case 'object':\n zType = z.object(toZodShape(schema));\n break;\n case 'null':\n zType = z.null();\n break;\n default:\n zType = z.any();\n }\n if (schema.description) zType = zType.describe(schema.description);\n if (schema.nullable) zType = zType.nullable();\n return zType;\n}\n","import { LocalShellBackend } from 'deepagents';\n\nexport const SANDBOX_PATH_FALLBACK =\n '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';\n\nexport function createLocalShellBackend({\n rootDir,\n env = process.env,\n}: {\n readonly rootDir: string;\n readonly env?: NodeJS.ProcessEnv;\n}): LocalShellBackend {\n return new LocalShellBackend({\n rootDir,\n env: {\n PATH: env.PATH ?? SANDBOX_PATH_FALLBACK,\n },\n });\n}\n","import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { MemorySaver } from '@langchain/langgraph';\n\nconst SNAPSHOT_HEADER = 'deepagents-memory-saver-v1';\n\nfunction encodeString(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64');\n}\n\nfunction decodeString(value: string): string {\n return Buffer.from(value, 'base64').toString('utf8');\n}\n\nfunction encodeBytes(value: Uint8Array): string {\n return Buffer.from(value).toString('base64');\n}\n\nfunction decodeBytes(value: string): Uint8Array {\n return Buffer.from(value, 'base64');\n}\n\nexport async function loadMemorySaver({\n path,\n saver,\n}: {\n path: string;\n saver: MemorySaver;\n}): Promise<void> {\n let snapshot: string;\n try {\n snapshot = await readFile(path, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n\n const [header, ...lines] = snapshot.split('\\n');\n if (header !== SNAPSHOT_HEADER) {\n throw new Error('Unsupported Deep Agents conversation checkpoint format');\n }\n\n const storage: MemorySaver['storage'] = Object.create(null);\n const writes: MemorySaver['writes'] = Object.create(null);\n\n for (const line of lines) {\n if (line === '') continue;\n const fields = line.split('\\t');\n if (fields[0] === 'S' && fields.length === 7) {\n const [, threadIdValue, namespaceValue, checkpointIdValue] = fields;\n const threadId = decodeString(threadIdValue);\n const namespace = decodeString(namespaceValue);\n const checkpointId = decodeString(checkpointIdValue);\n storage[threadId] ??= Object.create(null);\n storage[threadId][namespace] ??= Object.create(null);\n storage[threadId][namespace][checkpointId] = [\n decodeBytes(fields[4]),\n decodeBytes(fields[5]),\n fields[6] === '' ? undefined : decodeString(fields[6]),\n ];\n continue;\n }\n if (fields[0] === 'W' && fields.length === 6) {\n const [, keyValue, indexValue, taskIdValue, channelValue, value] = fields;\n const key = decodeString(keyValue);\n const index = decodeString(indexValue);\n writes[key] ??= Object.create(null);\n writes[key][index] = [\n decodeString(taskIdValue),\n decodeString(channelValue),\n decodeBytes(value),\n ];\n continue;\n }\n throw new Error('Invalid Deep Agents conversation checkpoint');\n }\n\n saver.storage = storage;\n saver.writes = writes;\n}\n\nexport async function saveMemorySaver({\n path,\n saver,\n}: {\n path: string;\n saver: MemorySaver;\n}): Promise<void> {\n const lines = [SNAPSHOT_HEADER];\n\n for (const [threadId, namespaces] of Object.entries(saver.storage)) {\n for (const [namespace, checkpoints] of Object.entries(namespaces)) {\n for (const [\n checkpointId,\n [checkpoint, metadata, parentCheckpointId],\n ] of Object.entries(checkpoints)) {\n lines.push(\n [\n 'S',\n encodeString(threadId),\n encodeString(namespace),\n encodeString(checkpointId),\n encodeBytes(checkpoint),\n encodeBytes(metadata),\n parentCheckpointId == null ? '' : encodeString(parentCheckpointId),\n ].join('\\t'),\n );\n }\n }\n }\n\n for (const [key, indexedWrites] of Object.entries(saver.writes)) {\n for (const [index, [taskId, channel, value]] of Object.entries(\n indexedWrites,\n )) {\n lines.push(\n [\n 'W',\n encodeString(key),\n encodeString(index),\n encodeString(taskId),\n encodeString(channel),\n encodeBytes(value),\n ].join('\\t'),\n );\n }\n }\n\n await mkdir(dirname(path), { recursive: true });\n const temporaryPath = `${path}.${process.pid}.tmp`;\n await writeFile(temporaryPath, `${lines.join('\\n')}\\n`, 'utf8');\n await rename(temporaryPath, path);\n}\n\nexport async function removeMemorySaverSnapshot(path: string): Promise<void> {\n await rm(path, { force: true });\n}\n","import {\n AIMessage,\n ToolMessage,\n type ToolCall,\n} from '@langchain/core/messages';\nimport type { createDeepAgent } from 'deepagents';\nimport type { StartMessage } from '../deepagents-bridge-protocol';\nimport {\n isBuiltinToolIncluded,\n NATIVE_TOOL_KIND,\n toCommonName,\n} from './approvals';\n\ntype DeepAgentsMiddleware = NonNullable<\n NonNullable<Parameters<typeof createDeepAgent>[0]>['middleware']\n>[number];\n\ntype DeepAgentsState = {\n messages: unknown[];\n};\n\ntype DeepAgentsMiddlewareUpdate = {\n messages: unknown[];\n jumpTo?: 'model';\n};\n\nconst MIDDLEWARE_BRAND = Symbol.for('AgentMiddleware');\n\nfunction getBuiltinToolFilteringDenialReason(input: {\n toolName: string;\n}): string {\n return `Tool '${input.toolName}' is inactive due to the HarnessAgent tool filtering policy.`;\n}\n\nfunction stringifyToolInput(input: unknown): string {\n return JSON.stringify(input ?? {});\n}\n\nfunction isNativeBuiltinToolCall(input: { toolCall: ToolCall }): boolean {\n return Object.keys(NATIVE_TOOL_KIND).includes(input.toolCall.name);\n}\n\nfunction isInactiveBuiltinToolCall(input: {\n toolCall: ToolCall;\n builtinToolFiltering: StartMessage['builtinToolFiltering'];\n}): boolean {\n return (\n isNativeBuiltinToolCall({ toolCall: input.toolCall }) &&\n !isBuiltinToolIncluded({\n nativeName: input.toolCall.name,\n toolFiltering: input.builtinToolFiltering,\n })\n );\n}\n\nexport function createBuiltinToolFilteringMiddleware(input: {\n builtinToolFiltering: StartMessage['builtinToolFiltering'];\n emit: (event: Record<string, unknown>) => void;\n}): DeepAgentsMiddleware | undefined {\n if (input.builtinToolFiltering == null) return undefined;\n\n return {\n [MIDDLEWARE_BRAND]: true,\n name: 'HarnessBuiltinToolFilteringMiddleware',\n afterModel: {\n canJumpTo: ['model'],\n hook: (\n state: DeepAgentsState,\n ): DeepAgentsMiddlewareUpdate | undefined => {\n const lastMessage = [...state.messages]\n .reverse()\n .find(message => AIMessage.isInstance(message));\n\n if (!lastMessage?.tool_calls?.length) return undefined;\n\n let hasActiveToolCalls = false;\n const deniedToolMessages: ToolMessage[] = [];\n\n for (const toolCall of lastMessage.tool_calls) {\n if (\n !isInactiveBuiltinToolCall({\n toolCall,\n builtinToolFiltering: input.builtinToolFiltering,\n })\n ) {\n hasActiveToolCalls = true;\n continue;\n }\n\n const nativeName = toolCall.name;\n toolCall.id ??= `${nativeName}-filtered-${deniedToolMessages.length}`;\n const toolName = toCommonName(nativeName);\n const reason = getBuiltinToolFilteringDenialReason({ toolName });\n\n input.emit({\n type: 'tool-call',\n toolCallId: toolCall.id,\n toolName,\n input: stringifyToolInput(toolCall.args),\n providerExecuted: true,\n nativeName,\n });\n input.emit({\n type: 'tool-result',\n toolCallId: toolCall.id,\n toolName,\n result: reason,\n });\n\n deniedToolMessages.push(\n new ToolMessage({\n content: reason,\n name: nativeName,\n tool_call_id: toolCall.id,\n status: 'error',\n }),\n );\n }\n\n if (deniedToolMessages.length === 0) return undefined;\n\n return {\n messages: [lastMessage, ...deniedToolMessages],\n ...(hasActiveToolCalls ? {} : { jumpTo: 'model' }),\n };\n },\n },\n } as DeepAgentsMiddleware;\n}\n","// In-sandbox turn driver on `@ai-sdk/harness/bridge`; third-party imports stay external (tsdown) and install in-sandbox from src/bridge/package.json — keep import/externals/deps in sync.\n\nimport { randomUUID } from 'node:crypto';\nimport { argv, env as procEnv } from 'node:process';\nimport {\n runBridge,\n type BridgeEvent,\n type BridgeTurn,\n} from '@ai-sdk/harness/bridge';\nimport { ChatAnthropic } from '@langchain/anthropic';\nimport { tool } from '@langchain/core/tools';\nimport { Command, MemorySaver, Overwrite } from '@langchain/langgraph';\nimport {\n MultiServerMCPClient,\n type ClientConfig,\n} from '@langchain/mcp-adapters';\nimport { createDeepAgent } from 'deepagents';\nimport { createMiddleware, toolStrategy } from 'langchain';\nimport type { StartMessage } from '../deepagents-bridge-protocol';\nimport { buildInterruptOn, collectActionRequests } from './approvals';\nimport {\n createDeepAgentsStreamEventState,\n createEmitStreamEvent,\n endReasoningBlock,\n endTextBlock,\n flushStep,\n toCommonName,\n type DeepAgentsStreamEvent,\n} from './create-emit-stream-event';\nimport { jsonSchemaToZodObject } from './json-schema-to-zod';\nimport { createLocalShellBackend } from './local-shell-backend';\nimport {\n loadMemorySaver,\n removeMemorySaverSnapshot,\n saveMemorySaver,\n} from './persistent-memory-saver';\nimport { createBuiltinToolFilteringMiddleware } from './tool-filtering';\n\nconst HARNESS_CLIENT_APP = procEnv.AI_SDK_HARNESS_CLIENT_APP;\n\nfunction parseArgs(rawArgs: string[]): Record<string, string> {\n const out: Record<string, string> = {};\n for (let i = 0; i < rawArgs.length; i++) {\n const arg = rawArgs[i];\n if (arg.startsWith('--')) {\n const key = arg\n .slice(2)\n .replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n out[key] = rawArgs[i + 1];\n i++;\n }\n }\n return out;\n}\n\n// Always drive the Anthropic client. Through the gateway, models keep their\n// `creator/model` slug (gateway translates); direct Anthropic wants the bare id.\nfunction buildModel({\n rawModel,\n thinking,\n effort,\n headers,\n}: {\n rawModel: string | undefined;\n thinking: StartMessage['thinking'];\n effort: StartMessage['effort'];\n headers: StartMessage['headers'];\n}) {\n if (!rawModel) return undefined;\n const baseUrl = procEnv.ANTHROPIC_BASE_URL;\n const model = baseUrl ? rawModel : rawModel.replace(/^anthropic[/:]/, '');\n return new ChatAnthropic({\n model,\n ...(thinking ? { thinking } : {}),\n ...(effort ? { outputConfig: { effort } } : {}),\n ...(procEnv.ANTHROPIC_API_KEY ? { apiKey: procEnv.ANTHROPIC_API_KEY } : {}),\n ...(baseUrl ? { anthropicApiUrl: baseUrl } : {}),\n ...(headers != null || procEnv.AI_GATEWAY_API_KEY\n ? {\n clientOptions: {\n defaultHeaders: {\n ...headers,\n ...(procEnv.AI_GATEWAY_API_KEY && HARNESS_CLIENT_APP\n ? {\n 'User-Agent': HARNESS_CLIENT_APP,\n 'x-client-app': HARNESS_CLIENT_APP,\n }\n : {}),\n },\n },\n }\n : {}),\n });\n}\n\nfunction createModelMiddleware() {\n return createMiddleware({\n name: 'harnessModel',\n wrapModelCall: async (request, handler) => {\n if (!activeModel && !activeThinking && !activeEffort && !activeHeaders) {\n return handler(request);\n }\n\n if (activeModel) {\n const configuredModel = buildModel({\n rawModel: activeModel,\n thinking: activeThinking,\n effort: activeEffort,\n headers: activeHeaders,\n });\n if (!configuredModel) throw new Error('Deep Agents model is missing');\n return handler({ ...request, model: configuredModel });\n }\n\n let model = request.model;\n if (\n '_getModelInstance' in model &&\n typeof model._getModelInstance === 'function'\n ) {\n model = await model._getModelInstance();\n }\n\n if (!(model instanceof ChatAnthropic)) {\n throw new Error('Deep Agents reasoning requires ChatAnthropic');\n }\n\n const configuredModel = buildModel({\n rawModel: model.model,\n thinking: activeThinking,\n effort: activeEffort,\n headers: activeHeaders,\n });\n if (!configuredModel) throw new Error('Deep Agents model is missing');\n\n return handler({ ...request, model: configuredModel });\n },\n });\n}\n\nconst args = parseArgs(argv.slice(2));\nconst workdir = args.workdir;\nconst bridgeStateDir = args.bridgeStateDir;\nif (!workdir || !bridgeStateDir) {\n // eslint-disable-next-line no-console\n console.error('deepagents bridge: missing --workdir / --bridge-state-dir');\n process.exit(1);\n}\nconst conversationCheckpointPath = `${bridgeStateDir}/conversation.checkpoint`;\n\n// One agent per bridge process, reused across turns; host tools read the live turn via `currentTurn`.\nlet agent: ReturnType<typeof createDeepAgent> | undefined;\nlet currentTurn: BridgeTurn | undefined;\nlet mcpClient: MultiServerMCPClient | undefined;\nlet mcpToolNames = new Set<string>();\nlet currentResponseFormat: ReturnType<typeof toolStrategy> | undefined;\nconst checkpointer = new MemorySaver();\nif (args.resume === 'true') {\n await loadMemorySaver({\n path: conversationCheckpointPath,\n saver: checkpointer,\n });\n} else {\n await removeMemorySaverSnapshot(conversationCheckpointPath);\n}\nlet agentConfigurationSignature: string | undefined;\nlet activeModel: string | undefined;\nlet activeThinking: StartMessage['thinking'];\nlet activeEffort: StartMessage['effort'];\nlet activeHeaders: StartMessage['headers'];\nconst modelMiddleware = createModelMiddleware();\n\ntype DeepAgentsJsonSchema = Record<string, unknown> & {\n type:\n | 'null'\n | 'boolean'\n | 'object'\n | 'array'\n | 'number'\n | 'string'\n | 'integer';\n};\n\nconst responseFormatMiddleware = createMiddleware({\n name: 'HarnessResponseFormat',\n wrapModelCall(request, handler) {\n return handler({\n ...request,\n ...(currentResponseFormat == null\n ? {}\n : { responseFormat: currentResponseFormat }),\n });\n },\n});\n\n// Host tools become LangChain tools that emit a `tool-call` and block on the host's `tool-result`.\nfunction buildHostTools(toolSchemas: StartMessage['tools']) {\n return (toolSchemas ?? []).map(schema =>\n tool(\n async (input: Record<string, unknown>) => {\n const turn = currentTurn;\n if (!turn) throw new Error('no active turn');\n const toolCallId = `${schema.name}-${randomUUID()}`;\n turn.emit({\n type: 'tool-call',\n toolCallId,\n toolName: schema.name,\n input: JSON.stringify(input),\n providerExecuted: false,\n } as BridgeEvent);\n const { output, isError } = await turn.requestToolResult(toolCallId);\n turn.emit({\n type: 'tool-result',\n toolCallId,\n toolName: schema.name,\n result: output ?? null,\n ...(isError !== undefined ? { isError } : {}),\n });\n return typeof output === 'string' ? output : JSON.stringify(output);\n },\n {\n name: schema.name,\n description: schema.description ?? '',\n schema: jsonSchemaToZodObject(schema.inputSchema),\n },\n ),\n );\n}\n\nasync function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {\n currentTurn = turn;\n if (start.model) activeModel = start.model;\n activeThinking = start.thinking;\n activeEffort = start.effort;\n activeHeaders = start.headers;\n currentResponseFormat =\n start.responseFormat?.type === 'json' && start.responseFormat.schema != null\n ? toolStrategy(start.responseFormat.schema as DeepAgentsJsonSchema)\n : undefined;\n const emit = (event: Record<string, unknown>) =>\n turn.emit(event as BridgeEvent);\n\n const interruptOn = buildInterruptOn(\n start.permissionMode,\n start.builtinToolFiltering,\n );\n const config = {\n version: 'v2' as const,\n configurable: { thread_id: 'bridge-session' },\n ...(start.recursionLimit != null\n ? { recursionLimit: start.recursionLimit }\n : {}),\n signal: turn.abortSignal,\n };\n const nextAgentConfigurationSignature = JSON.stringify({\n instructions: start.instructions,\n tools: start.tools,\n skillsPaths: start.skillsPaths,\n });\n const rebuildAgent =\n agent == null ||\n agentConfigurationSignature !== nextAgentConfigurationSignature ||\n start.skillsChanged === true;\n if (rebuildAgent) {\n if (agent != null && start.skillsChanged === true) {\n await agent.updateState(config, {\n skillsMetadata: new Overwrite([]),\n } as never);\n }\n await closeMcpClient();\n const builtinToolFilteringMiddleware = createBuiltinToolFilteringMiddleware(\n {\n builtinToolFiltering: start.builtinToolFiltering,\n emit: event => {\n const turn = currentTurn;\n if (!turn) throw new Error('no active turn');\n turn.emit(event as BridgeEvent);\n },\n },\n );\n const middleware = [\n responseFormatMiddleware,\n modelMiddleware,\n ...(builtinToolFilteringMiddleware\n ? [builtinToolFilteringMiddleware]\n : []),\n ];\n const hostTools = buildHostTools(start.tools);\n const hostToolNames = new Set(hostTools.map(hostTool => hostTool.name));\n const externalTools = await loadMcpTools({\n mcpServers: start.mcpServers,\n });\n const mcpTools = externalTools.filter(\n externalTool => !hostToolNames.has(externalTool.name),\n );\n mcpToolNames = new Set(mcpTools.map(mcpTool => mcpTool.name));\n agent = createDeepAgent({\n tools: [...mcpTools, ...hostTools],\n backend: createLocalShellBackend({ rootDir: workdir }),\n systemPrompt: start.instructions\n ? { suffix: start.instructions }\n : undefined,\n // Native skills loaded from the source dirs ($HOME-materialized + <workDir> for repo-provided skills).\n ...(start.skillsPaths?.length ? { skills: start.skillsPaths } : {}),\n ...(middleware.length > 0 ? { middleware } : {}),\n // Gate built-in tools behind HITL approval when the permission mode requires it.\n ...(interruptOn ? { interruptOn } : {}),\n // Real instance (LangGraph rejects `true` for root graphs); gives multi-turn memory.\n checkpointer,\n });\n agentConfigurationSignature = nextAgentConfigurationSignature;\n }\n const activeAgent = agent;\n if (activeAgent == null) {\n throw new Error('Deep Agents runtime was not initialized');\n }\n\n const hostToolNames = new Set((start.tools ?? []).map(t => t.name));\n const streamEventState = createDeepAgentsStreamEventState();\n const emitStreamEvent = createEmitStreamEvent({\n state: streamEventState,\n configuredModel: activeModel,\n hostToolNames,\n mcpToolNames,\n structuredOutputToolNames: new Set(\n currentResponseFormat?.map(format => format.name),\n ),\n emit,\n });\n\n // After a stream segment ends, return the tool calls paused by HITL interrupts (empty when the turn is truly done).\n const readPendingApprovals = async () => {\n try {\n const state = (await activeAgent.getState({\n configurable: { thread_id: 'bridge-session' },\n })) as { tasks?: Array<{ interrupts?: Array<{ value?: unknown }> }> };\n return collectActionRequests(\n (state.tasks ?? []).flatMap(t => t.interrupts ?? []),\n );\n } catch {\n return [];\n }\n };\n\n let resumeInput: unknown = {\n messages: [{ role: 'user', content: start.prompt }],\n };\n let emittedStructuredOutput = false;\n\n while (true) {\n const stream = await activeAgent.streamEvents(resumeInput as never, config);\n\n for await (const event of stream) {\n emitStreamEvent(event as DeepAgentsStreamEvent);\n const streamEvent = event as DeepAgentsStreamEvent;\n const namespace = streamEvent.metadata?.langgraph_checkpoint_ns ?? '';\n const output = (streamEvent.data as { output?: unknown } | undefined)\n ?.output as { structuredResponse?: unknown } | undefined;\n if (\n !emittedStructuredOutput &&\n streamEvent.event === 'on_chain_end' &&\n !namespace.includes('|') &&\n output?.structuredResponse !== undefined\n ) {\n const id = `structured-output-${randomUUID()}`;\n emit({ type: 'text-start', id });\n emit({\n type: 'text-delta',\n id,\n delta: JSON.stringify(output.structuredResponse),\n });\n emit({ type: 'text-end', id });\n emittedStructuredOutput = true;\n }\n }\n\n const actionRequests = await readPendingApprovals();\n if (actionRequests.length === 0) break;\n\n // HITL paused the run: announce each gated call, collect host decisions, then resume.\n const decisions: Array<\n { type: 'approve' } | { type: 'reject'; message?: string }\n > = [];\n for (const action of actionRequests) {\n const approvalId = `approval-${randomUUID()}`;\n endTextBlock({ state: streamEventState, emit });\n endReasoningBlock({ state: streamEventState, emit });\n emit({\n type: 'tool-call',\n toolCallId: approvalId,\n toolName: toCommonName(action.name),\n input: JSON.stringify(action.args ?? {}),\n providerExecuted: true,\n nativeName: action.name,\n });\n emit({\n type: 'tool-approval-request',\n approvalId,\n toolCallId: approvalId,\n });\n flushStep({ state: streamEventState, emit });\n const decision = await turn.requestToolApproval(approvalId);\n if (decision.approved) {\n const queue = streamEventState.approvedToolQueue.get(action.name) ?? [];\n queue.push(approvalId);\n streamEventState.approvedToolQueue.set(action.name, queue);\n decisions.push({ type: 'approve' });\n } else {\n // Rejected tools never execute, so surface the outcome as the result now.\n emit({\n type: 'tool-result',\n toolCallId: approvalId,\n toolName: toCommonName(action.name),\n result: decision.reason ?? 'Rejected by user.',\n });\n decisions.push({\n type: 'reject',\n ...(decision.reason ? { message: decision.reason } : {}),\n });\n }\n }\n\n resumeInput = new Command({ resume: { decisions } });\n }\n\n endTextBlock({ state: streamEventState, emit });\n endReasoningBlock({ state: streamEventState, emit });\n flushStep({ state: streamEventState, emit });\n emit({\n type: 'finish',\n finishReason: { unified: 'stop' },\n totalUsage: {\n inputTokens: { total: streamEventState.inputTokens },\n outputTokens: { total: streamEventState.outputTokens },\n },\n });\n}\n\nawait runBridge<StartMessage>({\n bridgeType: 'deepagents',\n bridgeStateDir: bridgeStateDir!,\n onStart: runTurn,\n onStop: async () => {\n await closeMcpClient();\n await saveMemorySaver({\n path: conversationCheckpointPath,\n saver: checkpointer,\n });\n return {};\n },\n onDestroy: async () => {\n await closeMcpClient();\n await removeMemorySaverSnapshot(conversationCheckpointPath);\n },\n});\n\nasync function loadMcpTools({\n mcpServers,\n}: {\n mcpServers: Record<string, unknown> | undefined;\n}) {\n if (mcpServers == null || Object.keys(mcpServers).length === 0) return [];\n for (const [name, value] of Object.entries(mcpServers)) {\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(\n `DeepAgents MCP server ${JSON.stringify(name)} must be configured with an object value.`,\n );\n }\n }\n mcpClient = new MultiServerMCPClient({\n mcpServers: mcpServers as ClientConfig['mcpServers'],\n prefixToolNameWithServerName: true,\n additionalToolNamePrefix: 'mcp',\n });\n return mcpClient.getTools();\n}\n\nasync function closeMcpClient(): Promise<void> {\n const client = mcpClient;\n mcpClient = undefined;\n mcpToolNames = new Set();\n await client?.close();\n}\n"],"mappings":"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"}
|