langchain 1.0.2 → 1.0.4
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 +18 -0
- package/dist/agents/ReactAgent.cjs +21 -41
- package/dist/agents/ReactAgent.cjs.map +1 -1
- package/dist/agents/ReactAgent.js +21 -41
- package/dist/agents/ReactAgent.js.map +1 -1
- package/dist/agents/annotation.cjs +7 -4
- package/dist/agents/annotation.cjs.map +1 -1
- package/dist/agents/annotation.js +8 -5
- package/dist/agents/annotation.js.map +1 -1
- package/dist/agents/middleware/contextEditing.d.cts.map +1 -1
- package/dist/agents/middleware/contextEditing.d.ts.map +1 -1
- package/dist/agents/middleware/dynamicSystemPrompt.d.cts.map +1 -1
- package/dist/agents/middleware/dynamicSystemPrompt.d.ts.map +1 -1
- package/dist/agents/middleware/hitl.cjs +7 -2
- package/dist/agents/middleware/hitl.cjs.map +1 -1
- package/dist/agents/middleware/hitl.d.cts.map +1 -1
- package/dist/agents/middleware/hitl.d.ts.map +1 -1
- package/dist/agents/middleware/hitl.js +7 -2
- package/dist/agents/middleware/hitl.js.map +1 -1
- package/dist/agents/middleware/index.cjs +2 -1
- package/dist/agents/middleware/index.js +2 -1
- package/dist/agents/middleware/llmToolSelector.d.cts +4 -4
- package/dist/agents/middleware/llmToolSelector.d.cts.map +1 -1
- package/dist/agents/middleware/{callLimit.cjs → modelCallLimit.cjs} +22 -7
- package/dist/agents/middleware/modelCallLimit.cjs.map +1 -0
- package/dist/agents/middleware/{callLimit.d.cts → modelCallLimit.d.cts} +12 -3
- package/dist/agents/middleware/modelCallLimit.d.cts.map +1 -0
- package/dist/agents/middleware/{callLimit.d.ts → modelCallLimit.d.ts} +12 -3
- package/dist/agents/middleware/modelCallLimit.d.ts.map +1 -0
- package/dist/agents/middleware/{callLimit.js → modelCallLimit.js} +22 -7
- package/dist/agents/middleware/modelCallLimit.js.map +1 -0
- package/dist/agents/middleware/promptCaching.d.cts.map +1 -1
- package/dist/agents/middleware/promptCaching.d.ts.map +1 -1
- package/dist/agents/middleware/summarization.cjs +274 -52
- package/dist/agents/middleware/summarization.cjs.map +1 -1
- package/dist/agents/middleware/summarization.d.cts +326 -30
- package/dist/agents/middleware/summarization.d.cts.map +1 -1
- package/dist/agents/middleware/summarization.d.ts +325 -29
- package/dist/agents/middleware/summarization.d.ts.map +1 -1
- package/dist/agents/middleware/summarization.js +276 -54
- package/dist/agents/middleware/summarization.js.map +1 -1
- package/dist/agents/middleware/todoListMiddleware.d.cts.map +1 -1
- package/dist/agents/middleware/todoListMiddleware.d.ts.map +1 -1
- package/dist/agents/middleware/toolCallLimit.cjs +215 -93
- package/dist/agents/middleware/toolCallLimit.cjs.map +1 -1
- package/dist/agents/middleware/toolCallLimit.d.cts +48 -37
- package/dist/agents/middleware/toolCallLimit.d.cts.map +1 -1
- package/dist/agents/middleware/toolCallLimit.d.ts +48 -37
- package/dist/agents/middleware/toolCallLimit.d.ts.map +1 -1
- package/dist/agents/middleware/toolCallLimit.js +216 -94
- package/dist/agents/middleware/toolCallLimit.js.map +1 -1
- package/dist/agents/middleware/toolRetry.cjs +224 -0
- package/dist/agents/middleware/toolRetry.cjs.map +1 -0
- package/dist/agents/middleware/toolRetry.d.cts +179 -0
- package/dist/agents/middleware/toolRetry.d.cts.map +1 -0
- package/dist/agents/middleware/toolRetry.d.ts +179 -0
- package/dist/agents/middleware/toolRetry.d.ts.map +1 -0
- package/dist/agents/middleware/toolRetry.js +223 -0
- package/dist/agents/middleware/toolRetry.js.map +1 -0
- package/dist/agents/middleware/types.d.cts +21 -19
- package/dist/agents/middleware/types.d.cts.map +1 -1
- package/dist/agents/middleware/types.d.ts +21 -19
- package/dist/agents/middleware/types.d.ts.map +1 -1
- package/dist/agents/middleware/utils.cjs +7 -0
- package/dist/agents/middleware/utils.cjs.map +1 -1
- package/dist/agents/middleware/utils.d.cts.map +1 -1
- package/dist/agents/middleware/utils.d.ts.map +1 -1
- package/dist/agents/middleware/utils.js +7 -1
- package/dist/agents/middleware/utils.js.map +1 -1
- package/dist/agents/middleware.cjs.map +1 -1
- package/dist/agents/middleware.d.cts +4 -4
- package/dist/agents/middleware.d.cts.map +1 -1
- package/dist/agents/middleware.d.ts +4 -4
- package/dist/agents/middleware.d.ts.map +1 -1
- package/dist/agents/middleware.js.map +1 -1
- package/dist/agents/nodes/AgentNode.cjs +21 -51
- package/dist/agents/nodes/AgentNode.cjs.map +1 -1
- package/dist/agents/nodes/AgentNode.js +23 -53
- package/dist/agents/nodes/AgentNode.js.map +1 -1
- package/dist/agents/nodes/ToolNode.cjs +12 -18
- package/dist/agents/nodes/ToolNode.cjs.map +1 -1
- package/dist/agents/nodes/ToolNode.js +12 -18
- package/dist/agents/nodes/ToolNode.js.map +1 -1
- package/dist/agents/nodes/middleware.cjs +9 -7
- package/dist/agents/nodes/middleware.cjs.map +1 -1
- package/dist/agents/nodes/middleware.js +10 -8
- package/dist/agents/nodes/middleware.js.map +1 -1
- package/dist/agents/nodes/types.d.cts +1 -1
- package/dist/agents/nodes/types.d.cts.map +1 -1
- package/dist/agents/nodes/types.d.ts +1 -1
- package/dist/agents/nodes/types.d.ts.map +1 -1
- package/dist/agents/nodes/utils.cjs +5 -1
- package/dist/agents/nodes/utils.cjs.map +1 -1
- package/dist/agents/nodes/utils.js +5 -1
- package/dist/agents/nodes/utils.js.map +1 -1
- package/dist/agents/responses.cjs +0 -1
- package/dist/agents/responses.js +1 -1
- package/dist/agents/runtime.d.cts +11 -27
- package/dist/agents/runtime.d.cts.map +1 -1
- package/dist/agents/runtime.d.ts +11 -27
- package/dist/agents/runtime.d.ts.map +1 -1
- package/dist/agents/state.cjs +45 -0
- package/dist/agents/state.cjs.map +1 -0
- package/dist/agents/state.js +44 -0
- package/dist/agents/state.js.map +1 -0
- package/dist/agents/types.d.cts +1 -1
- package/dist/agents/types.d.cts.map +1 -1
- package/dist/agents/types.d.ts +1 -1
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/utils.cjs +10 -2
- package/dist/agents/utils.cjs.map +1 -1
- package/dist/agents/utils.js +10 -2
- package/dist/agents/utils.js.map +1 -1
- package/dist/chat_models/universal.cjs +2 -2
- package/dist/chat_models/universal.cjs.map +1 -1
- package/dist/chat_models/universal.js +2 -2
- package/dist/chat_models/universal.js.map +1 -1
- package/dist/index.cjs +6 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/dist/agents/middleware/callLimit.cjs.map +0 -1
- package/dist/agents/middleware/callLimit.d.cts.map +0 -1
- package/dist/agents/middleware/callLimit.d.ts.map +0 -1
- package/dist/agents/middleware/callLimit.js.map +0 -1
- package/dist/agents/tools.d.cts +0 -9
- package/dist/agents/tools.d.cts.map +0 -1
- package/dist/agents/tools.d.ts +0 -9
- package/dist/agents/tools.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolNode.cjs","names":["input: unknown","BaseMessage","error: unknown","toolCall: ToolCall","ToolInvocationError","ToolMessage","RunnableCallable","tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[]","options?: ToolNodeOptions","call: ToolCall","isMiddlewareError: boolean","config: RunnableConfig","state?: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","request: ToolCallRequest","request","tool","mergeAbortSignals","e: unknown","ToolInputParsingException","#handleError","state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","AIMessage","isCommand","combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[]","parentCommand: Command | null","Command","x: unknown","Send"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { ToolInvocationError } from \"../errors.js\";\nimport type { PrivateState } from \"../runtime.js\";\nimport type {\n AnyAnnotationRoot,\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n /**\n * Optional function to get the private state (threadLevelCallCount, runModelCallCount).\n * Used to provide runtime metadata to wrapToolCall middleware.\n */\n getPrivateState?: () => PrivateState;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (input: unknown): input is { lg_tool_call: ToolCall } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (error instanceof ToolInvocationError) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = any,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = any\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall?: WrapToolCallHook;\n\n getPrivateState?: () => PrivateState;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, wrapToolCall, getPrivateState } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateSchema>[\"State\"] &\n PreHookAnnotation[\"State\"],\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.wrapToolCall = wrapToolCall;\n this.getPrivateState = getPrivateState;\n this.signal = options?.signal;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (isMiddlewareError && this.handleToolErrors !== true) {\n throw error;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw error;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(error, call);\n if (result && ToolMessage.isInstance(result)) {\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw error;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw error;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state?: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]\n ): Promise<ToolMessage | Command> {\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall } = request;\n const tool = this.tools.find((tool) => tool.name === toolCall.name);\n if (tool === undefined) {\n throw new Error(`Tool \"${toolCall.name}\" not found.`);\n }\n\n try {\n const output = await tool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: tool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n\n /**\n * Get private state if available\n */\n const privateState = this.getPrivateState?.() || {\n threadLevelCallCount: 0,\n runModelCallCount: 0,\n };\n\n const runtime = {\n context: lgConfig?.context,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n threadLevelCallCount: privateState.threadLevelCallCount,\n runModelCallCount: privateState.runModelCallCount,\n };\n\n /**\n * Find the tool instance to include in the request\n */\n const tool = this.tools.find((t) => t.name === call.name);\n if (!tool) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n\n const request = {\n toolCall: call,\n tool,\n state: state || ({} as any),\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall && state) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n outputs = [await this.runTool(state.lg_tool_call, config, state)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":";;;;;;;;;AA+EA,MAAM,qBAAqB,CAACA,UAC1B,MAAM,QAAQ,MAAM,IAAI,MAAM,MAAMC,sCAAY,WAAW;AAE7D,MAAM,kBAAkB,CACtBD,UAEA,OAAO,UAAU,YACjB,SAAS,QACT,cAAc,SACd,mBAAmB,MAAM,SAAS;AAEpC,MAAM,cAAc,CAACA,UACnB,OAAO,UAAU,YAAY,SAAS,QAAQ,kBAAkB;;;;;;;;;;;AAYlE,SAAS,wBACPE,OACAC,UACyB;AACzB,KAAI,iBAAiBC,mCACnB,QAAO,IAAIC,sCAAY;EACrB,SAAS,MAAM;EACf,cAAc,SAAS;EACvB,MAAM,SAAS;CAChB;;;;AAKH,QAAO,IAAIA,sCAAY;EACrB,SAAS,GAAG,MAAM,4BAA4B,CAAC;EAC/C,cAAc,SAAS;EACvB,MAAM,SAAS;CAChB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CD,IAAa,WAAb,cAGUC,0CAA6C;CACrD;CAEA,QAAQ;CAER;CAEA,mBAGE;CAEF;CAEA;CAEA,YACEC,OACOC,SACP;EACA,MAAM,EAAE,MAAM,MAAM,kBAAkB,cAAc,iBAAiB,GACnE,WAAW,CAAE;EACf,MAAM;GACJ;GACA;GACA,MAAM,CAAC,OAAO,WACZ,KAAK,IACH,OAEA,OACD;EACJ,EAAC;EAbK;EAcP,KAAK,QAAQ;EACb,KAAK,mBAAmB,oBAAoB,KAAK;EACjD,KAAK,eAAe;EACpB,KAAK,kBAAkB;EACvB,KAAK,SAAS,SAAS;CACxB;;;;;;;;CASD,aACEN,OACAO,MACAC,mBACa;;;;;;AAMb,kDAAqB,MAAM,CACzB,OAAM;;;;AAMR,MAAI,KAAK,QAAQ,QACf,OAAM;;;;;AAOR,MAAI,qBAAqB,KAAK,qBAAqB,KACjD,OAAM;;;;AAMR,MAAI,CAAC,KAAK,iBACR,OAAM;;;;AAMR,MAAI,OAAO,KAAK,qBAAqB,YAAY;GAC/C,MAAM,SAAS,KAAK,iBAAiB,OAAO,KAAK;AACjD,OAAI,UAAUL,sCAAY,WAAW,OAAO,CAC1C,QAAO;;;;AAMT,SAAM;EACP,WAAU,KAAK,iBACd,QAAO,IAAIA,sCAAY;GACrB,MAAM,KAAK;GACX,SAAS,GAAG,MAAM,4BAA4B,CAAC;GAC/C,cAAc,KAAK;EACpB;;;;AAMH,QAAM;CACP;CAED,MAAgB,QACdI,MACAE,QACAC,OACgC;;;;;;;EAOhC,MAAM,cAAc,OAClBC,cACmC;GACnC,MAAM,EAAE,UAAU,GAAGC;GACrB,MAAMC,SAAO,KAAK,MAAM,KAAK,CAACA,WAASA,OAAK,SAAS,SAAS,KAAK;AACnE,OAAIA,WAAS,OACX,OAAM,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,KAAK,YAAY,CAAC;AAGtD,OAAI;IACF,MAAM,SAAS,MAAMA,OAAK,OACxB;KAAE,GAAG;KAAU,MAAM;IAAa,GAClC;KACE,GAAG;KACH,QAAQC,gCAAkB,KAAK,QAAQ,OAAO,OAAO;IACtD,EACF;AAED,QAAIX,sCAAY,WAAW,OAAO,yCAAc,OAAO,CACrD,QAAO;AAGT,WAAO,IAAIA,sCAAY;KACrB,MAAMU,OAAK;KACX,SAAS,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,OAAO;KACrE,cAAc,SAAS;IACxB;GACF,SAAQE,GAAY;;;;;AAKnB,QAAI,aAAaC,iDACf,OAAM,IAAId,mCAAoB,GAAG;;;;AAKnC,UAAM;GACP;EACF;;;;EAKD,MAAM,WAAW;;;;EAKjB,MAAM,eAAe,KAAK,mBAAmB,IAAI;GAC/C,sBAAsB;GACtB,mBAAmB;EACpB;EAED,MAAM,UAAU;GACd,SAAS,UAAU;GACnB,QAAQ,UAAU;GAClB,WAAW,UAAU;GACrB,QAAQ,UAAU;GAClB,sBAAsB,aAAa;GACnC,mBAAmB,aAAa;EACjC;;;;EAKD,MAAM,OAAO,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,KAAK;AACzD,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,KAAK,YAAY,CAAC;EAGlD,MAAM,UAAU;GACd,UAAU;GACV;GACA,OAAO,SAAU,CAAE;GACnB;EACD;;;;AAKD,MAAI,KAAK,gBAAgB,MACvB,KAAI;AACF,UAAO,MAAM,KAAK,aAAa,SAAS,YAAY;EACrD,SAAQa,GAAY;;;;AAInB,UAAO,KAAKE,aAAa,GAAG,MAAM,KAAK;EACxC;;;;AAMH,MAAI;AACF,UAAO,MAAM,YAAY,QAAQ;EAClC,SAAQF,GAAY;;;;AAInB,UAAO,KAAKE,aAAa,GAAG,MAAM,MAAM;EACzC;CACF;CAED,MAAgB,IACdC,OACAT,QACwB;EACxB,IAAIU;AAEJ,MAAI,YAAY,MAAM,EACpB,UAAU,CAAC,MAAM,KAAK,QAAQ,MAAM,cAAc,QAAQ,MAAM,AAAC;OAC5D;GACL,IAAIC;AACJ,OAAI,mBAAmB,MAAM,EAC3B,WAAW;YACF,gBAAgB,MAAM,EAC/B,WAAW,MAAM;OAEjB,OAAM,IAAI,MACR;GAIJ,MAAMC,iBAA8B,IAAI,IACtC,SACG,OAAO,CAAC,QAAQ,IAAI,SAAS,KAAK,OAAO,CACzC,IAAI,CAAC,QAAS,IAAoB,aAAa;GAGpD,IAAIC;AACJ,QAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;IAChD,MAAM,UAAU,SAAS;AACzB,QAAIC,oCAAU,WAAW,QAAQ,EAAE;KACjC,YAAY;AACZ;IACD;GACF;AAED,OAAI,CAACA,oCAAU,WAAW,UAAU,CAClC,OAAM,IAAI,MAAM;GAGlB,UAAU,MAAM,QAAQ,IACtB,UAAU,YACN,OAAO,CAAC,SAAS,KAAK,MAAM,QAAQ,CAAC,eAAe,IAAI,KAAK,GAAG,CAAC,CAClE,IAAI,CAAC,SAAS,KAAK,QAAQ,MAAM,QAAQ,MAAM,CAAC,IAAI,CAAE,EAC1D;EACF;AAGD,MAAI,CAAC,QAAQ,KAAKC,gCAAU,CAC1B,QAAQ,MAAM,QAAQ,MAAM,GACxB,UACA,EAAE,UAAU,QAAS;EAI3B,MAAMC,kBAIA,CAAE;EACR,IAAIC,gBAAgC;AAEpC,OAAK,MAAM,UAAU,QACnB,0CAAc,OAAO,CACnB,KACE,OAAO,UAAUC,8BAAQ,UACzB,MAAM,QAAQ,OAAO,KAAK,IAC1B,OAAO,KAAK,MAAM,CAAC,SAAS,OAAO,KAAK,CAAC,CAEzC,KAAI,eACD,cAAc,KAAgB,KAAK,GAAI,OAAO,KAAgB;OAE/D,gBAAgB,IAAIA,8BAAQ;GAC1B,OAAOA,8BAAQ;GACf,MAAM,OAAO;EACd;OAGH,gBAAgB,KAAK,OAAO;OAG9B,gBAAgB,KACd,MAAM,QAAQ,MAAM,GAAG,CAAC,MAAO,IAAG,EAAE,UAAU,CAAC,MAAO,EAAE,EACzD;AAIL,MAAI,eACF,gBAAgB,KAAK,cAAc;AAGrC,SAAO;CACR;AACF;AAED,SAAgB,OAAOC,GAAuB;AAC5C,QAAO,aAAaC;AACrB"}
|
|
1
|
+
{"version":3,"file":"ToolNode.cjs","names":["input: unknown","BaseMessage","error: unknown","toolCall: ToolCall","ToolInvocationError","ToolMessage","RunnableCallable","tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[]","options?: ToolNodeOptions","call: ToolCall","isMiddlewareError: boolean","config: RunnableConfig","state: AgentBuiltInState","request: ToolCallRequest","request","tool","mergeAbortSignals","e: unknown","ToolInputParsingException","#handleError","state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","AIMessage","isCommand","combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[]","parentCommand: Command | null","Command","x: unknown","Send"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { ToolInvocationError } from \"../errors.js\";\nimport type {\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\nimport type { AgentBuiltInState } from \"../runtime.js\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (input: unknown): input is { lg_tool_call: ToolCall } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (error instanceof ToolInvocationError) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends InteropZodObject = any,\n ContextSchema extends InteropZodObject = any\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall: WrapToolCallHook | undefined;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, signal, wrapToolCall } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateSchema>[\"State\"] &\n PreHookAnnotation[\"State\"],\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = signal;\n this.wrapToolCall = wrapToolCall;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (isMiddlewareError && this.handleToolErrors !== true) {\n throw error;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw error;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(error, call);\n if (result && ToolMessage.isInstance(result)) {\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw error;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw error;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state: AgentBuiltInState\n ): Promise<ToolMessage | Command> {\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall } = request;\n const tool = this.tools.find((tool) => tool.name === toolCall.name);\n if (tool === undefined) {\n throw new Error(`Tool \"${toolCall.name}\" not found.`);\n }\n\n try {\n const output = await tool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n /**\n * extend to match ToolRuntime\n */\n config,\n toolCallId: toolCall.id!,\n state: config.configurable?.__pregel_scratchpad?.currentTaskInput,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: tool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n const runtime = {\n context: lgConfig?.context,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n };\n\n /**\n * Find the tool instance to include in the request\n */\n const tool = this.tools.find((t) => t.name === call.name);\n if (!tool) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n\n const request = {\n toolCall: call,\n tool,\n state,\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n const { lg_tool_call, jumpTo, ...newState } = state;\n outputs = [await this.runTool(state.lg_tool_call, config, newState)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":"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"}
|
|
@@ -84,9 +84,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
84
84
|
signal;
|
|
85
85
|
handleToolErrors = defaultHandleToolErrors;
|
|
86
86
|
wrapToolCall;
|
|
87
|
-
getPrivateState;
|
|
88
87
|
constructor(tools, options) {
|
|
89
|
-
const { name, tags, handleToolErrors,
|
|
88
|
+
const { name, tags, handleToolErrors, signal, wrapToolCall } = options ?? {};
|
|
90
89
|
super({
|
|
91
90
|
name,
|
|
92
91
|
tags,
|
|
@@ -95,9 +94,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
95
94
|
this.options = options;
|
|
96
95
|
this.tools = tools;
|
|
97
96
|
this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;
|
|
97
|
+
this.signal = signal;
|
|
98
98
|
this.wrapToolCall = wrapToolCall;
|
|
99
|
-
this.getPrivateState = getPrivateState;
|
|
100
|
-
this.signal = options?.signal;
|
|
101
99
|
}
|
|
102
100
|
/**
|
|
103
101
|
* Handle errors from tool execution or middleware.
|
|
@@ -163,6 +161,9 @@ var ToolNode = class extends RunnableCallable {
|
|
|
163
161
|
type: "tool_call"
|
|
164
162
|
}, {
|
|
165
163
|
...config,
|
|
164
|
+
config,
|
|
165
|
+
toolCallId: toolCall.id,
|
|
166
|
+
state: config.configurable?.__pregel_scratchpad?.currentTaskInput,
|
|
166
167
|
signal: mergeAbortSignals(this.signal, config.signal)
|
|
167
168
|
});
|
|
168
169
|
if (ToolMessage.isInstance(output) || isCommand(output)) return output;
|
|
@@ -187,20 +188,11 @@ var ToolNode = class extends RunnableCallable {
|
|
|
187
188
|
* Build runtime from LangGraph config
|
|
188
189
|
*/
|
|
189
190
|
const lgConfig = config;
|
|
190
|
-
/**
|
|
191
|
-
* Get private state if available
|
|
192
|
-
*/
|
|
193
|
-
const privateState = this.getPrivateState?.() || {
|
|
194
|
-
threadLevelCallCount: 0,
|
|
195
|
-
runModelCallCount: 0
|
|
196
|
-
};
|
|
197
191
|
const runtime = {
|
|
198
192
|
context: lgConfig?.context,
|
|
199
193
|
writer: lgConfig?.writer,
|
|
200
194
|
interrupt: lgConfig?.interrupt,
|
|
201
|
-
signal: lgConfig?.signal
|
|
202
|
-
threadLevelCallCount: privateState.threadLevelCallCount,
|
|
203
|
-
runModelCallCount: privateState.runModelCallCount
|
|
195
|
+
signal: lgConfig?.signal
|
|
204
196
|
};
|
|
205
197
|
/**
|
|
206
198
|
* Find the tool instance to include in the request
|
|
@@ -210,13 +202,13 @@ var ToolNode = class extends RunnableCallable {
|
|
|
210
202
|
const request = {
|
|
211
203
|
toolCall: call,
|
|
212
204
|
tool: tool$1,
|
|
213
|
-
state
|
|
205
|
+
state,
|
|
214
206
|
runtime
|
|
215
207
|
};
|
|
216
208
|
/**
|
|
217
209
|
* If wrapToolCall is provided, use it to wrap the tool execution
|
|
218
210
|
*/
|
|
219
|
-
if (this.wrapToolCall
|
|
211
|
+
if (this.wrapToolCall) try {
|
|
220
212
|
return await this.wrapToolCall(request, baseHandler);
|
|
221
213
|
} catch (e) {
|
|
222
214
|
/**
|
|
@@ -238,8 +230,10 @@ var ToolNode = class extends RunnableCallable {
|
|
|
238
230
|
}
|
|
239
231
|
async run(state, config) {
|
|
240
232
|
let outputs;
|
|
241
|
-
if (isSendInput(state))
|
|
242
|
-
|
|
233
|
+
if (isSendInput(state)) {
|
|
234
|
+
const { lg_tool_call, jumpTo,...newState } = state;
|
|
235
|
+
outputs = [await this.runTool(state.lg_tool_call, config, newState)];
|
|
236
|
+
} else {
|
|
243
237
|
let messages;
|
|
244
238
|
if (isBaseMessageArray(state)) messages = state;
|
|
245
239
|
else if (isMessagesState(state)) messages = state.messages;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolNode.js","names":["input: unknown","error: unknown","toolCall: ToolCall","tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[]","options?: ToolNodeOptions","call: ToolCall","isMiddlewareError: boolean","config: RunnableConfig","state?: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","request: ToolCallRequest","request","tool","e: unknown","#handleError","state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[]","parentCommand: Command | null","x: unknown"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { ToolInvocationError } from \"../errors.js\";\nimport type { PrivateState } from \"../runtime.js\";\nimport type {\n AnyAnnotationRoot,\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n /**\n * Optional function to get the private state (threadLevelCallCount, runModelCallCount).\n * Used to provide runtime metadata to wrapToolCall middleware.\n */\n getPrivateState?: () => PrivateState;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (input: unknown): input is { lg_tool_call: ToolCall } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (error instanceof ToolInvocationError) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = any,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = any\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall?: WrapToolCallHook;\n\n getPrivateState?: () => PrivateState;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, wrapToolCall, getPrivateState } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateSchema>[\"State\"] &\n PreHookAnnotation[\"State\"],\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.wrapToolCall = wrapToolCall;\n this.getPrivateState = getPrivateState;\n this.signal = options?.signal;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (isMiddlewareError && this.handleToolErrors !== true) {\n throw error;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw error;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(error, call);\n if (result && ToolMessage.isInstance(result)) {\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw error;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw error;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state?: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]\n ): Promise<ToolMessage | Command> {\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall } = request;\n const tool = this.tools.find((tool) => tool.name === toolCall.name);\n if (tool === undefined) {\n throw new Error(`Tool \"${toolCall.name}\" not found.`);\n }\n\n try {\n const output = await tool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: tool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n\n /**\n * Get private state if available\n */\n const privateState = this.getPrivateState?.() || {\n threadLevelCallCount: 0,\n runModelCallCount: 0,\n };\n\n const runtime = {\n context: lgConfig?.context,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n threadLevelCallCount: privateState.threadLevelCallCount,\n runModelCallCount: privateState.runModelCallCount,\n };\n\n /**\n * Find the tool instance to include in the request\n */\n const tool = this.tools.find((t) => t.name === call.name);\n if (!tool) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n\n const request = {\n toolCall: call,\n tool,\n state: state || ({} as any),\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall && state) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n outputs = [await this.runTool(state.lg_tool_call, config, state)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolNode.js","names":["input: unknown","error: unknown","toolCall: ToolCall","tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[]","options?: ToolNodeOptions","call: ToolCall","isMiddlewareError: boolean","config: RunnableConfig","state: AgentBuiltInState","request: ToolCallRequest","request","tool","e: unknown","#handleError","state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[]","parentCommand: Command | null","x: unknown"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { ToolInvocationError } from \"../errors.js\";\nimport type {\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\nimport type { AgentBuiltInState } from \"../runtime.js\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (input: unknown): input is { lg_tool_call: ToolCall } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (error instanceof ToolInvocationError) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends InteropZodObject = any,\n ContextSchema extends InteropZodObject = any\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall: WrapToolCallHook | undefined;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, signal, wrapToolCall } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateSchema>[\"State\"] &\n PreHookAnnotation[\"State\"],\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = signal;\n this.wrapToolCall = wrapToolCall;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (isMiddlewareError && this.handleToolErrors !== true) {\n throw error;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw error;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(error, call);\n if (result && ToolMessage.isInstance(result)) {\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw error;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw error;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state: AgentBuiltInState\n ): Promise<ToolMessage | Command> {\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall } = request;\n const tool = this.tools.find((tool) => tool.name === toolCall.name);\n if (tool === undefined) {\n throw new Error(`Tool \"${toolCall.name}\" not found.`);\n }\n\n try {\n const output = await tool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n /**\n * extend to match ToolRuntime\n */\n config,\n toolCallId: toolCall.id!,\n state: config.configurable?.__pregel_scratchpad?.currentTaskInput,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: tool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n const runtime = {\n context: lgConfig?.context,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n };\n\n /**\n * Find the tool instance to include in the request\n */\n const tool = this.tools.find((t) => t.name === call.name);\n if (!tool) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n\n const request = {\n toolCall: call,\n tool,\n state,\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n const { lg_tool_call, jumpTo, ...newState } = state;\n outputs = [await this.runTool(state.lg_tool_call, config, newState)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":";;;;;;;;AAyEA,MAAM,qBAAqB,CAACA,UAC1B,MAAM,QAAQ,MAAM,IAAI,MAAM,MAAM,YAAY,WAAW;AAE7D,MAAM,kBAAkB,CACtBA,UAEA,OAAO,UAAU,YACjB,SAAS,QACT,cAAc,SACd,mBAAmB,MAAM,SAAS;AAEpC,MAAM,cAAc,CAACA,UACnB,OAAO,UAAU,YAAY,SAAS,QAAQ,kBAAkB;;;;;;;;;;;AAYlE,SAAS,wBACPC,OACAC,UACyB;AACzB,KAAI,iBAAiB,oBACnB,QAAO,IAAI,YAAY;EACrB,SAAS,MAAM;EACf,cAAc,SAAS;EACvB,MAAM,SAAS;CAChB;;;;AAKH,QAAO,IAAI,YAAY;EACrB,SAAS,GAAG,MAAM,4BAA4B,CAAC;EAC/C,cAAc,SAAS;EACvB,MAAM,SAAS;CAChB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CD,IAAa,WAAb,cAGU,iBAA6C;CACrD;CAEA,QAAQ;CAER;CAEA,mBAGE;CAEF;CAEA,YACEC,OACOC,SACP;EACA,MAAM,EAAE,MAAM,MAAM,kBAAkB,QAAQ,cAAc,GAC1D,WAAW,CAAE;EACf,MAAM;GACJ;GACA;GACA,MAAM,CAAC,OAAO,WACZ,KAAK,IACH,OAEA,OACD;EACJ,EAAC;EAbK;EAcP,KAAK,QAAQ;EACb,KAAK,mBAAmB,oBAAoB,KAAK;EACjD,KAAK,SAAS;EACd,KAAK,eAAe;CACrB;;;;;;;;CASD,aACEH,OACAI,MACAC,mBACa;;;;;;AAMb,MAAI,iBAAiB,MAAM,CACzB,OAAM;;;;AAMR,MAAI,KAAK,QAAQ,QACf,OAAM;;;;;AAOR,MAAI,qBAAqB,KAAK,qBAAqB,KACjD,OAAM;;;;AAMR,MAAI,CAAC,KAAK,iBACR,OAAM;;;;AAMR,MAAI,OAAO,KAAK,qBAAqB,YAAY;GAC/C,MAAM,SAAS,KAAK,iBAAiB,OAAO,KAAK;AACjD,OAAI,UAAU,YAAY,WAAW,OAAO,CAC1C,QAAO;;;;AAMT,SAAM;EACP,WAAU,KAAK,iBACd,QAAO,IAAI,YAAY;GACrB,MAAM,KAAK;GACX,SAAS,GAAG,MAAM,4BAA4B,CAAC;GAC/C,cAAc,KAAK;EACpB;;;;AAMH,QAAM;CACP;CAED,MAAgB,QACdD,MACAE,QACAC,OACgC;;;;;;;EAOhC,MAAM,cAAc,OAClBC,cACmC;GACnC,MAAM,EAAE,UAAU,GAAGC;GACrB,MAAMC,SAAO,KAAK,MAAM,KAAK,CAACA,WAASA,OAAK,SAAS,SAAS,KAAK;AACnE,OAAIA,WAAS,OACX,OAAM,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,KAAK,YAAY,CAAC;AAGtD,OAAI;IACF,MAAM,SAAS,MAAMA,OAAK,OACxB;KAAE,GAAG;KAAU,MAAM;IAAa,GAClC;KACE,GAAG;KAIH;KACA,YAAY,SAAS;KACrB,OAAO,OAAO,cAAc,qBAAqB;KACjD,QAAQ,kBAAkB,KAAK,QAAQ,OAAO,OAAO;IACtD,EACF;AAED,QAAI,YAAY,WAAW,OAAO,IAAI,UAAU,OAAO,CACrD,QAAO;AAGT,WAAO,IAAI,YAAY;KACrB,MAAMA,OAAK;KACX,SAAS,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,OAAO;KACrE,cAAc,SAAS;IACxB;GACF,SAAQC,GAAY;;;;;AAKnB,QAAI,aAAa,0BACf,OAAM,IAAI,oBAAoB,GAAG;;;;AAKnC,UAAM;GACP;EACF;;;;EAKD,MAAM,WAAW;EACjB,MAAM,UAAU;GACd,SAAS,UAAU;GACnB,QAAQ,UAAU;GAClB,WAAW,UAAU;GACrB,QAAQ,UAAU;EACnB;;;;EAKD,MAAMD,SAAO,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,KAAK;AACzD,MAAI,CAACA,OACH,OAAM,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,KAAK,YAAY,CAAC;EAGlD,MAAM,UAAU;GACd,UAAU;GACV;GACA;GACA;EACD;;;;AAKD,MAAI,KAAK,aACP,KAAI;AACF,UAAO,MAAM,KAAK,aAAa,SAAS,YAAY;EACrD,SAAQC,GAAY;;;;AAInB,UAAO,KAAKC,aAAa,GAAG,MAAM,KAAK;EACxC;;;;AAMH,MAAI;AACF,UAAO,MAAM,YAAY,QAAQ;EAClC,SAAQD,GAAY;;;;AAInB,UAAO,KAAKC,aAAa,GAAG,MAAM,MAAM;EACzC;CACF;CAED,MAAgB,IACdC,OACAP,QACwB;EACxB,IAAIQ;AAEJ,MAAI,YAAY,MAAM,EAAE;GACtB,MAAM,EAAE,cAAc,OAAQ,GAAG,UAAU,GAAG;GAC9C,UAAU,CAAC,MAAM,KAAK,QAAQ,MAAM,cAAc,QAAQ,SAAS,AAAC;EACrE,OAAM;GACL,IAAIC;AACJ,OAAI,mBAAmB,MAAM,EAC3B,WAAW;YACF,gBAAgB,MAAM,EAC/B,WAAW,MAAM;OAEjB,OAAM,IAAI,MACR;GAIJ,MAAMC,iBAA8B,IAAI,IACtC,SACG,OAAO,CAAC,QAAQ,IAAI,SAAS,KAAK,OAAO,CACzC,IAAI,CAAC,QAAS,IAAoB,aAAa;GAGpD,IAAIC;AACJ,QAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;IAChD,MAAM,UAAU,SAAS;AACzB,QAAI,UAAU,WAAW,QAAQ,EAAE;KACjC,YAAY;AACZ;IACD;GACF;AAED,OAAI,CAAC,UAAU,WAAW,UAAU,CAClC,OAAM,IAAI,MAAM;GAGlB,UAAU,MAAM,QAAQ,IACtB,UAAU,YACN,OAAO,CAAC,SAAS,KAAK,MAAM,QAAQ,CAAC,eAAe,IAAI,KAAK,GAAG,CAAC,CAClE,IAAI,CAAC,SAAS,KAAK,QAAQ,MAAM,QAAQ,MAAM,CAAC,IAAI,CAAE,EAC1D;EACF;AAGD,MAAI,CAAC,QAAQ,KAAK,UAAU,CAC1B,QAAQ,MAAM,QAAQ,MAAM,GACxB,UACA,EAAE,UAAU,QAAS;EAI3B,MAAMC,kBAIA,CAAE;EACR,IAAIC,gBAAgC;AAEpC,OAAK,MAAM,UAAU,QACnB,KAAI,UAAU,OAAO,CACnB,KACE,OAAO,UAAU,QAAQ,UACzB,MAAM,QAAQ,OAAO,KAAK,IAC1B,OAAO,KAAK,MAAM,CAAC,SAAS,OAAO,KAAK,CAAC,CAEzC,KAAI,eACD,cAAc,KAAgB,KAAK,GAAI,OAAO,KAAgB;OAE/D,gBAAgB,IAAI,QAAQ;GAC1B,OAAO,QAAQ;GACf,MAAM,OAAO;EACd;OAGH,gBAAgB,KAAK,OAAO;OAG9B,gBAAgB,KACd,MAAM,QAAQ,MAAM,GAAG,CAAC,MAAO,IAAG,EAAE,UAAU,CAAC,MAAO,EAAE,EACzD;AAIL,MAAI,eACF,gBAAgB,KAAK,cAAc;AAGrC,SAAO;CACR;AACF;AAED,SAAgB,OAAOC,GAAuB;AAC5C,QAAO,aAAa;AACrB"}
|
|
@@ -16,7 +16,7 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
16
16
|
super(fields);
|
|
17
17
|
this.#options = options;
|
|
18
18
|
}
|
|
19
|
-
async invokeMiddleware(
|
|
19
|
+
async invokeMiddleware(invokeState, config) {
|
|
20
20
|
/**
|
|
21
21
|
* Filter context based on middleware's contextSchema
|
|
22
22
|
*/
|
|
@@ -40,6 +40,11 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
40
40
|
filteredContext = (0, __langchain_core_utils_types.interopParse)(this.middleware.contextSchema, relevantContext);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
const state = {
|
|
44
|
+
...this.#options.getState(),
|
|
45
|
+
...invokeState,
|
|
46
|
+
messages: invokeState.messages
|
|
47
|
+
};
|
|
43
48
|
/**
|
|
44
49
|
* ToDo: implement later
|
|
45
50
|
*/
|
|
@@ -47,8 +52,7 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
47
52
|
context: filteredContext,
|
|
48
53
|
writer: config?.writer,
|
|
49
54
|
interrupt: config?.interrupt,
|
|
50
|
-
signal: config?.signal
|
|
51
|
-
...this.#options.getPrivateState()
|
|
55
|
+
signal: config?.signal
|
|
52
56
|
};
|
|
53
57
|
const result = await this.runHook(
|
|
54
58
|
state,
|
|
@@ -61,7 +65,6 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
61
65
|
context: Object.freeze(Object.assign(new AgentContext(), filteredContext))
|
|
62
66
|
}))
|
|
63
67
|
);
|
|
64
|
-
delete result?._privateState;
|
|
65
68
|
/**
|
|
66
69
|
* If result is undefined, return current state
|
|
67
70
|
*/
|
|
@@ -91,7 +94,6 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
91
94
|
const suggestion = jumpToConstraint && jumpToConstraint.length > 0 ? `must be one of: ${jumpToConstraint?.join(", ")}.` : constraint ? `no ${constraint} defined in middleware ${this.middleware.name}` : "";
|
|
92
95
|
throw new Error(`Invalid jump target: ${result.jumpTo}, ${suggestion}.`);
|
|
93
96
|
}
|
|
94
|
-
const jumpTo = require_utils.parseJumpToTarget(result.jumpTo);
|
|
95
97
|
/**
|
|
96
98
|
* If result is a control action, handle it
|
|
97
99
|
*/
|
|
@@ -101,7 +103,7 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
101
103
|
return {
|
|
102
104
|
...state,
|
|
103
105
|
...result.result || {},
|
|
104
|
-
jumpTo
|
|
106
|
+
jumpTo: result.jumpTo
|
|
105
107
|
};
|
|
106
108
|
}
|
|
107
109
|
throw new Error(`Invalid control action: ${JSON.stringify(result)}`);
|
|
@@ -112,7 +114,7 @@ var MiddlewareNode = class extends require_RunnableCallable.RunnableCallable {
|
|
|
112
114
|
return {
|
|
113
115
|
...state,
|
|
114
116
|
...result,
|
|
115
|
-
jumpTo
|
|
117
|
+
jumpTo: result.jumpTo
|
|
116
118
|
};
|
|
117
119
|
}
|
|
118
120
|
get nodeOptions() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.cjs","names":["RunnableCallable","fields: RunnableCallableArgs<TStateSchema, NodeOutput<TStateSchema>>","options: MiddlewareNodeOptions","#options","
|
|
1
|
+
{"version":3,"file":"middleware.cjs","names":["RunnableCallable","fields: RunnableCallableArgs<TStateSchema, NodeOutput<TStateSchema>>","options: MiddlewareNodeOptions","#options","invokeState: TStateSchema","config?: LangGraphRunnableConfig","relevantContext: Record<string, unknown>","state: TStateSchema","runtime: Runtime<TContextSchema>","jumpToConstraint: JumpToTarget[] | undefined","constraint: string | undefined","getHookConstraint","derivePrivateState"],"sources":["../../../src/agents/nodes/middleware.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod/v3\";\nimport { LangGraphRunnableConfig, Command } from \"@langchain/langgraph\";\nimport { interopParse } from \"@langchain/core/utils/types\";\n\nimport { RunnableCallable, RunnableCallableArgs } from \"../RunnableCallable.js\";\nimport type { JumpToTarget } from \"../constants.js\";\nimport type { Runtime } from \"../runtime.js\";\nimport type { AgentMiddleware, MiddlewareResult } from \"../middleware/types.js\";\nimport { derivePrivateState } from \"./utils.js\";\nimport { getHookConstraint } from \"../middleware/utils.js\";\n\n/**\n * Named class for context objects to provide better error messages\n */\nclass AgentContext {}\nclass AgentRuntime {}\n\ntype NodeOutput<TStateSchema extends Record<string, any>> =\n | TStateSchema\n | Command<any, TStateSchema, string>;\n\nexport interface MiddlewareNodeOptions {\n getState: () => Record<string, unknown>;\n}\n\nexport abstract class MiddlewareNode<\n TStateSchema extends Record<string, any>,\n TContextSchema extends Record<string, any>\n> extends RunnableCallable<TStateSchema, NodeOutput<TStateSchema>> {\n #options: MiddlewareNodeOptions;\n\n abstract middleware: AgentMiddleware<\n z.ZodObject<z.ZodRawShape>,\n z.ZodObject<z.ZodRawShape>\n >;\n\n constructor(\n fields: RunnableCallableArgs<TStateSchema, NodeOutput<TStateSchema>>,\n options: MiddlewareNodeOptions\n ) {\n super(fields);\n this.#options = options;\n }\n\n abstract runHook(\n state: TStateSchema,\n config?: Runtime<TContextSchema>\n ): Promise<MiddlewareResult<TStateSchema>> | MiddlewareResult<TStateSchema>;\n\n async invokeMiddleware(\n invokeState: TStateSchema,\n config?: LangGraphRunnableConfig\n ): Promise<NodeOutput<TStateSchema>> {\n /**\n * Filter context based on middleware's contextSchema\n */\n let filteredContext = {} as TContextSchema;\n /**\n * Parse context using middleware's contextSchema to apply defaults and validation\n */\n if (this.middleware.contextSchema) {\n /**\n * Extract only the fields relevant to this middleware's schema\n */\n const schemaShape = this.middleware.contextSchema?.shape;\n if (schemaShape) {\n const relevantContext: Record<string, unknown> = {};\n const invokeContext = config?.context || {};\n for (const key of Object.keys(schemaShape)) {\n if (key in invokeContext) {\n relevantContext[key] = invokeContext[key];\n }\n }\n /**\n * Parse to apply defaults and validation, even if relevantContext is empty\n * This will throw if required fields are missing and no defaults exist\n */\n filteredContext = interopParse(\n this.middleware.contextSchema,\n relevantContext\n ) as TContextSchema;\n }\n }\n\n const state: TStateSchema = {\n ...this.#options.getState(),\n ...invokeState,\n /**\n * don't overwrite possible outdated messages from other middleware nodes\n */\n messages: invokeState.messages,\n };\n\n /**\n * ToDo: implement later\n */\n const runtime: Runtime<TContextSchema> = {\n context: filteredContext,\n writer: config?.writer,\n interrupt: config?.interrupt,\n signal: config?.signal,\n };\n\n const result = await this.runHook(\n state,\n /**\n * assign runtime and context values into empty named class\n * instances to create a better error message.\n */\n Object.freeze(\n Object.assign(new AgentRuntime(), {\n ...runtime,\n context: Object.freeze(\n Object.assign(new AgentContext(), filteredContext)\n ),\n })\n )\n );\n\n /**\n * If result is undefined, return current state\n */\n if (!result) {\n return { ...state, jumpTo: undefined };\n }\n\n /**\n * Verify that the jump target is allowed for the middleware\n */\n let jumpToConstraint: JumpToTarget[] | undefined;\n let constraint: string | undefined;\n\n if (this.name?.startsWith(\"BeforeAgentNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.beforeAgent);\n constraint = \"beforeAgent.canJumpTo\";\n } else if (this.name?.startsWith(\"BeforeModelNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.beforeModel);\n constraint = \"beforeModel.canJumpTo\";\n } else if (this.name?.startsWith(\"AfterAgentNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.afterAgent);\n constraint = \"afterAgent.canJumpTo\";\n } else if (this.name?.startsWith(\"AfterModelNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.afterModel);\n constraint = \"afterModel.canJumpTo\";\n }\n\n if (\n typeof result.jumpTo === \"string\" &&\n !jumpToConstraint?.includes(result.jumpTo as JumpToTarget)\n ) {\n const suggestion =\n jumpToConstraint && jumpToConstraint.length > 0\n ? `must be one of: ${jumpToConstraint?.join(\", \")}.`\n : constraint\n ? `no ${constraint} defined in middleware ${this.middleware.name}`\n : \"\";\n throw new Error(`Invalid jump target: ${result.jumpTo}, ${suggestion}.`);\n }\n\n /**\n * If result is a control action, handle it\n */\n if (typeof result === \"object\" && \"type\" in result) {\n // Handle control actions\n if (result.type === \"terminate\") {\n if (result.error) {\n throw result.error;\n }\n return {\n ...state,\n ...(result.result || {}),\n jumpTo: result.jumpTo,\n };\n }\n\n throw new Error(`Invalid control action: ${JSON.stringify(result)}`);\n }\n\n /**\n * If result is a state update, merge it with current state\n */\n return { ...state, ...result, jumpTo: result.jumpTo };\n }\n\n get nodeOptions(): {\n input: z.ZodObject<TStateSchema>;\n } {\n return {\n input: derivePrivateState(\n this.middleware.stateSchema\n ) as z.ZodObject<TStateSchema>,\n };\n }\n}\n"],"mappings":";;;;;;;;;;AAeA,IAAM,eAAN,MAAmB,CAAE;AACrB,IAAM,eAAN,MAAmB,CAAE;AAUrB,IAAsB,iBAAtB,cAGUA,0CAAyD;CACjE;CAOA,YACEC,QACAC,SACA;EACA,MAAM,OAAO;EACb,KAAKC,WAAW;CACjB;CAOD,MAAM,iBACJC,aACAC,QACmC;;;;EAInC,IAAI,kBAAkB,CAAE;;;;AAIxB,MAAI,KAAK,WAAW,eAAe;;;;GAIjC,MAAM,cAAc,KAAK,WAAW,eAAe;AACnD,OAAI,aAAa;IACf,MAAMC,kBAA2C,CAAE;IACnD,MAAM,gBAAgB,QAAQ,WAAW,CAAE;AAC3C,SAAK,MAAM,OAAO,OAAO,KAAK,YAAY,CACxC,KAAI,OAAO,eACT,gBAAgB,OAAO,cAAc;;;;;IAOzC,iEACE,KAAK,WAAW,eAChB,gBACD;GACF;EACF;EAED,MAAMC,QAAsB;GAC1B,GAAG,KAAKJ,SAAS,UAAU;GAC3B,GAAG;GAIH,UAAU,YAAY;EACvB;;;;EAKD,MAAMK,UAAmC;GACvC,SAAS;GACT,QAAQ,QAAQ;GAChB,WAAW,QAAQ;GACnB,QAAQ,QAAQ;EACjB;EAED,MAAM,SAAS,MAAM,KAAK;GACxB;;;;;GAKA,OAAO,OACL,OAAO,OAAO,IAAI,gBAAgB;IAChC,GAAG;IACH,SAAS,OAAO,OACd,OAAO,OAAO,IAAI,gBAAgB,gBAAgB,CACnD;GACF,EAAC,CACH;GACF;;;;AAKD,MAAI,CAAC,OACH,QAAO;GAAE,GAAG;GAAO,QAAQ;EAAW;;;;EAMxC,IAAIC;EACJ,IAAIC;AAEJ,MAAI,KAAK,MAAM,WAAW,mBAAmB,EAAE;GAC7C,mBAAmBC,kCAAkB,KAAK,WAAW,YAAY;GACjE,aAAa;EACd,WAAU,KAAK,MAAM,WAAW,mBAAmB,EAAE;GACpD,mBAAmBA,kCAAkB,KAAK,WAAW,YAAY;GACjE,aAAa;EACd,WAAU,KAAK,MAAM,WAAW,kBAAkB,EAAE;GACnD,mBAAmBA,kCAAkB,KAAK,WAAW,WAAW;GAChE,aAAa;EACd,WAAU,KAAK,MAAM,WAAW,kBAAkB,EAAE;GACnD,mBAAmBA,kCAAkB,KAAK,WAAW,WAAW;GAChE,aAAa;EACd;AAED,MACE,OAAO,OAAO,WAAW,YACzB,CAAC,kBAAkB,SAAS,OAAO,OAAuB,EAC1D;GACA,MAAM,aACJ,oBAAoB,iBAAiB,SAAS,IAC1C,CAAC,gBAAgB,EAAE,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,GAClD,aACA,CAAC,GAAG,EAAE,WAAW,uBAAuB,EAAE,KAAK,WAAW,MAAM,GAChE;AACN,SAAM,IAAI,MAAM,CAAC,qBAAqB,EAAE,OAAO,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;EACxE;;;;AAKD,MAAI,OAAO,WAAW,YAAY,UAAU,QAAQ;AAElD,OAAI,OAAO,SAAS,aAAa;AAC/B,QAAI,OAAO,MACT,OAAM,OAAO;AAEf,WAAO;KACL,GAAG;KACH,GAAI,OAAO,UAAU,CAAE;KACvB,QAAQ,OAAO;IAChB;GACF;AAED,SAAM,IAAI,MAAM,CAAC,wBAAwB,EAAE,KAAK,UAAU,OAAO,EAAE;EACpE;;;;AAKD,SAAO;GAAE,GAAG;GAAO,GAAG;GAAQ,QAAQ,OAAO;EAAQ;CACtD;CAED,IAAI,cAEF;AACA,SAAO,EACL,OAAOC,iCACL,KAAK,WAAW,YACjB,CACF;CACF;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RunnableCallable } from "../RunnableCallable.js";
|
|
2
|
-
import { derivePrivateState
|
|
2
|
+
import { derivePrivateState } from "./utils.js";
|
|
3
3
|
import { getHookConstraint } from "../middleware/utils.js";
|
|
4
4
|
import { interopParse } from "@langchain/core/utils/types";
|
|
5
5
|
|
|
@@ -15,7 +15,7 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
15
15
|
super(fields);
|
|
16
16
|
this.#options = options;
|
|
17
17
|
}
|
|
18
|
-
async invokeMiddleware(
|
|
18
|
+
async invokeMiddleware(invokeState, config) {
|
|
19
19
|
/**
|
|
20
20
|
* Filter context based on middleware's contextSchema
|
|
21
21
|
*/
|
|
@@ -39,6 +39,11 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
39
39
|
filteredContext = interopParse(this.middleware.contextSchema, relevantContext);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
const state = {
|
|
43
|
+
...this.#options.getState(),
|
|
44
|
+
...invokeState,
|
|
45
|
+
messages: invokeState.messages
|
|
46
|
+
};
|
|
42
47
|
/**
|
|
43
48
|
* ToDo: implement later
|
|
44
49
|
*/
|
|
@@ -46,8 +51,7 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
46
51
|
context: filteredContext,
|
|
47
52
|
writer: config?.writer,
|
|
48
53
|
interrupt: config?.interrupt,
|
|
49
|
-
signal: config?.signal
|
|
50
|
-
...this.#options.getPrivateState()
|
|
54
|
+
signal: config?.signal
|
|
51
55
|
};
|
|
52
56
|
const result = await this.runHook(
|
|
53
57
|
state,
|
|
@@ -60,7 +64,6 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
60
64
|
context: Object.freeze(Object.assign(new AgentContext(), filteredContext))
|
|
61
65
|
}))
|
|
62
66
|
);
|
|
63
|
-
delete result?._privateState;
|
|
64
67
|
/**
|
|
65
68
|
* If result is undefined, return current state
|
|
66
69
|
*/
|
|
@@ -90,7 +93,6 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
90
93
|
const suggestion = jumpToConstraint && jumpToConstraint.length > 0 ? `must be one of: ${jumpToConstraint?.join(", ")}.` : constraint ? `no ${constraint} defined in middleware ${this.middleware.name}` : "";
|
|
91
94
|
throw new Error(`Invalid jump target: ${result.jumpTo}, ${suggestion}.`);
|
|
92
95
|
}
|
|
93
|
-
const jumpTo = parseJumpToTarget(result.jumpTo);
|
|
94
96
|
/**
|
|
95
97
|
* If result is a control action, handle it
|
|
96
98
|
*/
|
|
@@ -100,7 +102,7 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
100
102
|
return {
|
|
101
103
|
...state,
|
|
102
104
|
...result.result || {},
|
|
103
|
-
jumpTo
|
|
105
|
+
jumpTo: result.jumpTo
|
|
104
106
|
};
|
|
105
107
|
}
|
|
106
108
|
throw new Error(`Invalid control action: ${JSON.stringify(result)}`);
|
|
@@ -111,7 +113,7 @@ var MiddlewareNode = class extends RunnableCallable {
|
|
|
111
113
|
return {
|
|
112
114
|
...state,
|
|
113
115
|
...result,
|
|
114
|
-
jumpTo
|
|
116
|
+
jumpTo: result.jumpTo
|
|
115
117
|
};
|
|
116
118
|
}
|
|
117
119
|
get nodeOptions() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","names":["fields: RunnableCallableArgs<TStateSchema, NodeOutput<TStateSchema>>","options: MiddlewareNodeOptions","#options","
|
|
1
|
+
{"version":3,"file":"middleware.js","names":["fields: RunnableCallableArgs<TStateSchema, NodeOutput<TStateSchema>>","options: MiddlewareNodeOptions","#options","invokeState: TStateSchema","config?: LangGraphRunnableConfig","relevantContext: Record<string, unknown>","state: TStateSchema","runtime: Runtime<TContextSchema>","jumpToConstraint: JumpToTarget[] | undefined","constraint: string | undefined"],"sources":["../../../src/agents/nodes/middleware.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod/v3\";\nimport { LangGraphRunnableConfig, Command } from \"@langchain/langgraph\";\nimport { interopParse } from \"@langchain/core/utils/types\";\n\nimport { RunnableCallable, RunnableCallableArgs } from \"../RunnableCallable.js\";\nimport type { JumpToTarget } from \"../constants.js\";\nimport type { Runtime } from \"../runtime.js\";\nimport type { AgentMiddleware, MiddlewareResult } from \"../middleware/types.js\";\nimport { derivePrivateState } from \"./utils.js\";\nimport { getHookConstraint } from \"../middleware/utils.js\";\n\n/**\n * Named class for context objects to provide better error messages\n */\nclass AgentContext {}\nclass AgentRuntime {}\n\ntype NodeOutput<TStateSchema extends Record<string, any>> =\n | TStateSchema\n | Command<any, TStateSchema, string>;\n\nexport interface MiddlewareNodeOptions {\n getState: () => Record<string, unknown>;\n}\n\nexport abstract class MiddlewareNode<\n TStateSchema extends Record<string, any>,\n TContextSchema extends Record<string, any>\n> extends RunnableCallable<TStateSchema, NodeOutput<TStateSchema>> {\n #options: MiddlewareNodeOptions;\n\n abstract middleware: AgentMiddleware<\n z.ZodObject<z.ZodRawShape>,\n z.ZodObject<z.ZodRawShape>\n >;\n\n constructor(\n fields: RunnableCallableArgs<TStateSchema, NodeOutput<TStateSchema>>,\n options: MiddlewareNodeOptions\n ) {\n super(fields);\n this.#options = options;\n }\n\n abstract runHook(\n state: TStateSchema,\n config?: Runtime<TContextSchema>\n ): Promise<MiddlewareResult<TStateSchema>> | MiddlewareResult<TStateSchema>;\n\n async invokeMiddleware(\n invokeState: TStateSchema,\n config?: LangGraphRunnableConfig\n ): Promise<NodeOutput<TStateSchema>> {\n /**\n * Filter context based on middleware's contextSchema\n */\n let filteredContext = {} as TContextSchema;\n /**\n * Parse context using middleware's contextSchema to apply defaults and validation\n */\n if (this.middleware.contextSchema) {\n /**\n * Extract only the fields relevant to this middleware's schema\n */\n const schemaShape = this.middleware.contextSchema?.shape;\n if (schemaShape) {\n const relevantContext: Record<string, unknown> = {};\n const invokeContext = config?.context || {};\n for (const key of Object.keys(schemaShape)) {\n if (key in invokeContext) {\n relevantContext[key] = invokeContext[key];\n }\n }\n /**\n * Parse to apply defaults and validation, even if relevantContext is empty\n * This will throw if required fields are missing and no defaults exist\n */\n filteredContext = interopParse(\n this.middleware.contextSchema,\n relevantContext\n ) as TContextSchema;\n }\n }\n\n const state: TStateSchema = {\n ...this.#options.getState(),\n ...invokeState,\n /**\n * don't overwrite possible outdated messages from other middleware nodes\n */\n messages: invokeState.messages,\n };\n\n /**\n * ToDo: implement later\n */\n const runtime: Runtime<TContextSchema> = {\n context: filteredContext,\n writer: config?.writer,\n interrupt: config?.interrupt,\n signal: config?.signal,\n };\n\n const result = await this.runHook(\n state,\n /**\n * assign runtime and context values into empty named class\n * instances to create a better error message.\n */\n Object.freeze(\n Object.assign(new AgentRuntime(), {\n ...runtime,\n context: Object.freeze(\n Object.assign(new AgentContext(), filteredContext)\n ),\n })\n )\n );\n\n /**\n * If result is undefined, return current state\n */\n if (!result) {\n return { ...state, jumpTo: undefined };\n }\n\n /**\n * Verify that the jump target is allowed for the middleware\n */\n let jumpToConstraint: JumpToTarget[] | undefined;\n let constraint: string | undefined;\n\n if (this.name?.startsWith(\"BeforeAgentNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.beforeAgent);\n constraint = \"beforeAgent.canJumpTo\";\n } else if (this.name?.startsWith(\"BeforeModelNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.beforeModel);\n constraint = \"beforeModel.canJumpTo\";\n } else if (this.name?.startsWith(\"AfterAgentNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.afterAgent);\n constraint = \"afterAgent.canJumpTo\";\n } else if (this.name?.startsWith(\"AfterModelNode_\")) {\n jumpToConstraint = getHookConstraint(this.middleware.afterModel);\n constraint = \"afterModel.canJumpTo\";\n }\n\n if (\n typeof result.jumpTo === \"string\" &&\n !jumpToConstraint?.includes(result.jumpTo as JumpToTarget)\n ) {\n const suggestion =\n jumpToConstraint && jumpToConstraint.length > 0\n ? `must be one of: ${jumpToConstraint?.join(\", \")}.`\n : constraint\n ? `no ${constraint} defined in middleware ${this.middleware.name}`\n : \"\";\n throw new Error(`Invalid jump target: ${result.jumpTo}, ${suggestion}.`);\n }\n\n /**\n * If result is a control action, handle it\n */\n if (typeof result === \"object\" && \"type\" in result) {\n // Handle control actions\n if (result.type === \"terminate\") {\n if (result.error) {\n throw result.error;\n }\n return {\n ...state,\n ...(result.result || {}),\n jumpTo: result.jumpTo,\n };\n }\n\n throw new Error(`Invalid control action: ${JSON.stringify(result)}`);\n }\n\n /**\n * If result is a state update, merge it with current state\n */\n return { ...state, ...result, jumpTo: result.jumpTo };\n }\n\n get nodeOptions(): {\n input: z.ZodObject<TStateSchema>;\n } {\n return {\n input: derivePrivateState(\n this.middleware.stateSchema\n ) as z.ZodObject<TStateSchema>,\n };\n }\n}\n"],"mappings":";;;;;;;;;AAeA,IAAM,eAAN,MAAmB,CAAE;AACrB,IAAM,eAAN,MAAmB,CAAE;AAUrB,IAAsB,iBAAtB,cAGU,iBAAyD;CACjE;CAOA,YACEA,QACAC,SACA;EACA,MAAM,OAAO;EACb,KAAKC,WAAW;CACjB;CAOD,MAAM,iBACJC,aACAC,QACmC;;;;EAInC,IAAI,kBAAkB,CAAE;;;;AAIxB,MAAI,KAAK,WAAW,eAAe;;;;GAIjC,MAAM,cAAc,KAAK,WAAW,eAAe;AACnD,OAAI,aAAa;IACf,MAAMC,kBAA2C,CAAE;IACnD,MAAM,gBAAgB,QAAQ,WAAW,CAAE;AAC3C,SAAK,MAAM,OAAO,OAAO,KAAK,YAAY,CACxC,KAAI,OAAO,eACT,gBAAgB,OAAO,cAAc;;;;;IAOzC,kBAAkB,aAChB,KAAK,WAAW,eAChB,gBACD;GACF;EACF;EAED,MAAMC,QAAsB;GAC1B,GAAG,KAAKJ,SAAS,UAAU;GAC3B,GAAG;GAIH,UAAU,YAAY;EACvB;;;;EAKD,MAAMK,UAAmC;GACvC,SAAS;GACT,QAAQ,QAAQ;GAChB,WAAW,QAAQ;GACnB,QAAQ,QAAQ;EACjB;EAED,MAAM,SAAS,MAAM,KAAK;GACxB;;;;;GAKA,OAAO,OACL,OAAO,OAAO,IAAI,gBAAgB;IAChC,GAAG;IACH,SAAS,OAAO,OACd,OAAO,OAAO,IAAI,gBAAgB,gBAAgB,CACnD;GACF,EAAC,CACH;GACF;;;;AAKD,MAAI,CAAC,OACH,QAAO;GAAE,GAAG;GAAO,QAAQ;EAAW;;;;EAMxC,IAAIC;EACJ,IAAIC;AAEJ,MAAI,KAAK,MAAM,WAAW,mBAAmB,EAAE;GAC7C,mBAAmB,kBAAkB,KAAK,WAAW,YAAY;GACjE,aAAa;EACd,WAAU,KAAK,MAAM,WAAW,mBAAmB,EAAE;GACpD,mBAAmB,kBAAkB,KAAK,WAAW,YAAY;GACjE,aAAa;EACd,WAAU,KAAK,MAAM,WAAW,kBAAkB,EAAE;GACnD,mBAAmB,kBAAkB,KAAK,WAAW,WAAW;GAChE,aAAa;EACd,WAAU,KAAK,MAAM,WAAW,kBAAkB,EAAE;GACnD,mBAAmB,kBAAkB,KAAK,WAAW,WAAW;GAChE,aAAa;EACd;AAED,MACE,OAAO,OAAO,WAAW,YACzB,CAAC,kBAAkB,SAAS,OAAO,OAAuB,EAC1D;GACA,MAAM,aACJ,oBAAoB,iBAAiB,SAAS,IAC1C,CAAC,gBAAgB,EAAE,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,GAClD,aACA,CAAC,GAAG,EAAE,WAAW,uBAAuB,EAAE,KAAK,WAAW,MAAM,GAChE;AACN,SAAM,IAAI,MAAM,CAAC,qBAAqB,EAAE,OAAO,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;EACxE;;;;AAKD,MAAI,OAAO,WAAW,YAAY,UAAU,QAAQ;AAElD,OAAI,OAAO,SAAS,aAAa;AAC/B,QAAI,OAAO,MACT,OAAM,OAAO;AAEf,WAAO;KACL,GAAG;KACH,GAAI,OAAO,UAAU,CAAE;KACvB,QAAQ,OAAO;IAChB;GACF;AAED,SAAM,IAAI,MAAM,CAAC,wBAAwB,EAAE,KAAK,UAAU,OAAO,EAAE;EACpE;;;;AAKD,SAAO;GAAE,GAAG;GAAO,GAAG;GAAQ,QAAQ,OAAO;EAAQ;CACtD;CAED,IAAI,cAEF;AACA,SAAO,EACL,OAAO,mBACL,KAAK,WAAW,YACjB,CACF;CACF;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ClientTool, ServerTool } from "../tools.cjs";
|
|
2
1
|
import { AgentBuiltInState, Runtime } from "../runtime.cjs";
|
|
3
2
|
import { LanguageModelLike } from "@langchain/core/language_models/base";
|
|
4
3
|
import { BaseMessage } from "@langchain/core/messages";
|
|
4
|
+
import { ClientTool, ServerTool } from "@langchain/core/tools";
|
|
5
5
|
|
|
6
6
|
//#region src/agents/nodes/types.d.ts
|
|
7
7
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":["LanguageModelLike","BaseMessage","ServerTool","ClientTool","Runtime","AgentBuiltInState","ModelRequest","Record","TState","TContext"],"sources":["../../../src/agents/nodes/types.d.ts"],"sourcesContent":["import type { LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { ServerTool, ClientTool } from \"
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":["LanguageModelLike","BaseMessage","ServerTool","ClientTool","Runtime","AgentBuiltInState","ModelRequest","Record","TState","TContext"],"sources":["../../../src/agents/nodes/types.d.ts"],"sourcesContent":["import type { LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { ServerTool, ClientTool } from \"@langchain/core/tools\";\nimport type { Runtime, AgentBuiltInState } from \"../runtime.js\";\n/**\n * Configuration for modifying a model call at runtime.\n * All fields are optional and only provided fields will override defaults.\n *\n * @template TState - The agent's state type, must extend Record<string, unknown>. Defaults to Record<string, unknown>.\n * @template TContext - The runtime context type for accessing metadata and control flow. Defaults to unknown.\n */\nexport interface ModelRequest<TState extends Record<string, unknown> = Record<string, unknown>, TContext = unknown> {\n /**\n * The model to use for this step.\n */\n model: LanguageModelLike;\n /**\n * The messages to send to the model.\n */\n messages: BaseMessage[];\n /**\n * The system message for this step.\n */\n systemPrompt?: string;\n /**\n * Tool choice configuration (model-specific format).\n * Can be one of:\n * - `\"auto\"`: means the model can pick between generating a message or calling one or more tools.\n * - `\"none\"`: means the model will not call any tool and instead generates a message.\n * - `\"required\"`: means the model must call one or more tools.\n * - `{ type: \"function\", function: { name: string } }`: The model will use the specified function.\n */\n toolChoice?: \"auto\" | \"none\" | \"required\" | {\n type: \"function\";\n function: {\n name: string;\n };\n };\n /**\n * The tools to make available for this step.\n */\n tools: (ServerTool | ClientTool)[];\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 * Additional settings to bind to the model when preparing it for invocation.\n * These settings are applied via `bindTools()` and can include parameters like\n * `headers`, `container`, etc. The model is re-bound on each request,\n * so these settings can vary per invocation.\n *\n * @example\n * ```ts\n * modelSettings: {\n * headers: { \"anthropic-beta\": \"code-execution-2025-08-25\" },\n * container: \"container_abc123\"\n * }\n * ```\n */\n modelSettings?: Record<string, unknown>;\n}\n"],"mappings":";;;;;;;;;AAWA;;;;;AAQcC,UARGK,YAQHL,CAAAA,eAR+BM,MAQ/BN,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,GARyDM,MAQzDN,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,EAAAA,WAAAA,OAAAA,CAAAA,CAAAA;EAAW;;;EA0BR,KAAGI,EA9BTL,iBA8BSK;EAAiB;;;EAmBX,QAAA,EA7CZJ,WA6CY,EAAA;;;;;;;;;;;;;;;;;;;;;;UAvBdC,aAAaC;;;;SAIdK,SAASH;;;;WAIPD,QAAQK;;;;;;;;;;;;;;;kBAeDF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ClientTool, ServerTool } from "../tools.js";
|
|
2
1
|
import { AgentBuiltInState, Runtime } from "../runtime.js";
|
|
3
2
|
import { BaseMessage } from "@langchain/core/messages";
|
|
3
|
+
import { ClientTool, ServerTool } from "@langchain/core/tools";
|
|
4
4
|
import { LanguageModelLike } from "@langchain/core/language_models/base";
|
|
5
5
|
|
|
6
6
|
//#region src/agents/nodes/types.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":["LanguageModelLike","BaseMessage","ServerTool","ClientTool","Runtime","AgentBuiltInState","ModelRequest","Record","TState","TContext"],"sources":["../../../src/agents/nodes/types.d.ts"],"sourcesContent":["import type { LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { ServerTool, ClientTool } from \"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":["LanguageModelLike","BaseMessage","ServerTool","ClientTool","Runtime","AgentBuiltInState","ModelRequest","Record","TState","TContext"],"sources":["../../../src/agents/nodes/types.d.ts"],"sourcesContent":["import type { LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { ServerTool, ClientTool } from \"@langchain/core/tools\";\nimport type { Runtime, AgentBuiltInState } from \"../runtime.js\";\n/**\n * Configuration for modifying a model call at runtime.\n * All fields are optional and only provided fields will override defaults.\n *\n * @template TState - The agent's state type, must extend Record<string, unknown>. Defaults to Record<string, unknown>.\n * @template TContext - The runtime context type for accessing metadata and control flow. Defaults to unknown.\n */\nexport interface ModelRequest<TState extends Record<string, unknown> = Record<string, unknown>, TContext = unknown> {\n /**\n * The model to use for this step.\n */\n model: LanguageModelLike;\n /**\n * The messages to send to the model.\n */\n messages: BaseMessage[];\n /**\n * The system message for this step.\n */\n systemPrompt?: string;\n /**\n * Tool choice configuration (model-specific format).\n * Can be one of:\n * - `\"auto\"`: means the model can pick between generating a message or calling one or more tools.\n * - `\"none\"`: means the model will not call any tool and instead generates a message.\n * - `\"required\"`: means the model must call one or more tools.\n * - `{ type: \"function\", function: { name: string } }`: The model will use the specified function.\n */\n toolChoice?: \"auto\" | \"none\" | \"required\" | {\n type: \"function\";\n function: {\n name: string;\n };\n };\n /**\n * The tools to make available for this step.\n */\n tools: (ServerTool | ClientTool)[];\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 * Additional settings to bind to the model when preparing it for invocation.\n * These settings are applied via `bindTools()` and can include parameters like\n * `headers`, `container`, etc. The model is re-bound on each request,\n * so these settings can vary per invocation.\n *\n * @example\n * ```ts\n * modelSettings: {\n * headers: { \"anthropic-beta\": \"code-execution-2025-08-25\" },\n * container: \"container_abc123\"\n * }\n * ```\n */\n modelSettings?: Record<string, unknown>;\n}\n"],"mappings":";;;;;;;;;AAWA;;;;;AAQcC,UARGK,YAQHL,CAAAA,eAR+BM,MAQ/BN,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,GARyDM,MAQzDN,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,EAAAA,WAAAA,OAAAA,CAAAA,CAAAA;EAAW;;;EA0BR,KAAGI,EA9BTL,iBA8BSK;EAAiB;;;EAmBX,QAAA,EA7CZJ,WA6CY,EAAA;;;;;;;;;;;;;;;;;;;;;;UAvBdC,aAAaC;;;;SAIdK,SAASH;;;;WAIPD,QAAQK;;;;;;;;;;;;;;;kBAeDF"}
|
|
@@ -13,7 +13,11 @@ const __langchain_core_utils_types = require_rolldown_runtime.__toESM(require("@
|
|
|
13
13
|
*/
|
|
14
14
|
async function initializeMiddlewareStates(middlewareList, state) {
|
|
15
15
|
const middlewareStates = {};
|
|
16
|
-
for (const middleware of middlewareList)
|
|
16
|
+
for (const middleware of middlewareList) {
|
|
17
|
+
/**
|
|
18
|
+
* skip middleware if it doesn't have a state schema
|
|
19
|
+
*/
|
|
20
|
+
if (!middleware.stateSchema) continue;
|
|
17
21
|
const modifiedSchema = (0, __langchain_core_utils_types.interopZodObjectMakeFieldsOptional)(middleware.stateSchema, (key) => key.startsWith("_"));
|
|
18
22
|
const parseResult = await (0, __langchain_core_utils_types.interopSafeParseAsync)(modifiedSchema, state);
|
|
19
23
|
if (parseResult.success) {
|