langchain 1.0.5 → 1.1.0
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 +26 -0
- package/README.md +1 -1
- package/chat_models/universal.cjs +1 -0
- package/chat_models/universal.d.cts +1 -0
- package/chat_models/universal.d.ts +1 -0
- package/chat_models/universal.js +1 -0
- package/dist/agents/ReactAgent.cjs +43 -39
- package/dist/agents/ReactAgent.cjs.map +1 -1
- package/dist/agents/ReactAgent.js +46 -42
- package/dist/agents/ReactAgent.js.map +1 -1
- package/dist/agents/index.d.cts +0 -2
- package/dist/agents/index.d.ts +0 -2
- package/dist/agents/middleware/constants.cjs +16 -0
- package/dist/agents/middleware/constants.cjs.map +1 -0
- package/dist/agents/middleware/constants.js +15 -0
- package/dist/agents/middleware/constants.js.map +1 -0
- package/dist/agents/middleware/contextEditing.cjs.map +1 -1
- package/dist/agents/middleware/contextEditing.d.cts +23 -7
- package/dist/agents/middleware/contextEditing.d.ts +23 -7
- package/dist/agents/middleware/contextEditing.js.map +1 -1
- package/dist/agents/middleware/dynamicSystemPrompt.cjs +5 -2
- package/dist/agents/middleware/dynamicSystemPrompt.cjs.map +1 -1
- package/dist/agents/middleware/dynamicSystemPrompt.d.cts +2 -1
- package/dist/agents/middleware/dynamicSystemPrompt.d.ts +2 -1
- package/dist/agents/middleware/dynamicSystemPrompt.js +4 -2
- package/dist/agents/middleware/dynamicSystemPrompt.js.map +1 -1
- package/dist/agents/middleware/error.cjs +20 -0
- package/dist/agents/middleware/error.cjs.map +1 -0
- package/dist/agents/middleware/error.js +19 -0
- package/dist/agents/middleware/error.js.map +1 -0
- package/dist/agents/middleware/index.cjs +4 -2
- package/dist/agents/middleware/index.d.ts +18 -0
- package/dist/agents/middleware/index.js +4 -2
- package/dist/agents/middleware/modelRetry.cjs +162 -0
- package/dist/agents/middleware/modelRetry.cjs.map +1 -0
- package/dist/agents/middleware/modelRetry.d.cts +134 -0
- package/dist/agents/middleware/modelRetry.d.ts +134 -0
- package/dist/agents/middleware/modelRetry.js +161 -0
- package/dist/agents/middleware/modelRetry.js.map +1 -0
- package/dist/agents/middleware/{promptCaching.cjs → provider/anthropic/promptCaching.cjs} +3 -3
- package/dist/agents/middleware/provider/anthropic/promptCaching.cjs.map +1 -0
- package/dist/agents/middleware/{promptCaching.d.cts → provider/anthropic/promptCaching.d.cts} +2 -2
- package/dist/agents/middleware/{promptCaching.d.ts → provider/anthropic/promptCaching.d.ts} +2 -2
- package/dist/agents/middleware/{promptCaching.js → provider/anthropic/promptCaching.js} +2 -2
- package/dist/agents/middleware/provider/anthropic/promptCaching.js.map +1 -0
- package/dist/agents/middleware/provider/openai/moderation.cjs +299 -0
- package/dist/agents/middleware/provider/openai/moderation.cjs.map +1 -0
- package/dist/agents/middleware/provider/openai/moderation.d.cts +133 -0
- package/dist/agents/middleware/provider/openai/moderation.d.ts +133 -0
- package/dist/agents/middleware/provider/openai/moderation.js +298 -0
- package/dist/agents/middleware/provider/openai/moderation.js.map +1 -0
- package/dist/agents/middleware/summarization.d.cts +0 -4
- package/dist/agents/middleware/summarization.d.ts +0 -4
- package/dist/agents/middleware/todoListMiddleware.cjs +1 -1
- package/dist/agents/middleware/todoListMiddleware.cjs.map +1 -1
- package/dist/agents/middleware/todoListMiddleware.js +1 -1
- package/dist/agents/middleware/todoListMiddleware.js.map +1 -1
- package/dist/agents/middleware/toolRetry.cjs +32 -44
- package/dist/agents/middleware/toolRetry.cjs.map +1 -1
- package/dist/agents/middleware/toolRetry.d.cts +16 -36
- package/dist/agents/middleware/toolRetry.d.ts +16 -36
- package/dist/agents/middleware/toolRetry.js +32 -44
- package/dist/agents/middleware/toolRetry.js.map +1 -1
- package/dist/agents/middleware/types.d.cts +9 -10
- package/dist/agents/middleware/types.d.ts +9 -10
- package/dist/agents/middleware/utils.cjs +23 -0
- package/dist/agents/middleware/utils.cjs.map +1 -1
- package/dist/agents/middleware/utils.d.ts +2 -0
- package/dist/agents/middleware/utils.js +23 -1
- package/dist/agents/middleware/utils.js.map +1 -1
- package/dist/agents/nodes/AgentNode.cjs +72 -28
- package/dist/agents/nodes/AgentNode.cjs.map +1 -1
- package/dist/agents/nodes/AgentNode.js +74 -31
- package/dist/agents/nodes/AgentNode.js.map +1 -1
- package/dist/agents/nodes/ToolNode.cjs +5 -0
- package/dist/agents/nodes/ToolNode.cjs.map +1 -1
- package/dist/agents/nodes/ToolNode.js +5 -1
- package/dist/agents/nodes/ToolNode.js.map +1 -1
- package/dist/agents/nodes/types.d.cts +39 -3
- package/dist/agents/nodes/types.d.ts +39 -3
- package/dist/agents/responses.cjs.map +1 -1
- package/dist/agents/responses.d.cts +2 -19
- package/dist/agents/responses.d.ts +2 -19
- package/dist/agents/responses.js.map +1 -1
- package/dist/agents/runtime.d.ts +1 -0
- package/dist/agents/tests/utils.cjs +10 -1
- package/dist/agents/tests/utils.cjs.map +1 -1
- package/dist/agents/tests/utils.js +10 -1
- package/dist/agents/tests/utils.js.map +1 -1
- package/dist/agents/types.d.cts +68 -2
- package/dist/agents/types.d.ts +68 -2
- package/dist/agents/utils.cjs +15 -12
- package/dist/agents/utils.cjs.map +1 -1
- package/dist/agents/utils.js +16 -13
- package/dist/agents/utils.js.map +1 -1
- package/dist/chat_models/universal.cjs +50 -16
- package/dist/chat_models/universal.cjs.map +1 -1
- package/dist/chat_models/universal.d.cts +19 -1
- package/dist/chat_models/universal.d.ts +19 -1
- package/dist/chat_models/universal.js +50 -16
- package/dist/chat_models/universal.js.map +1 -1
- package/dist/index.cjs +8 -2
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +7 -3
- package/dist/load/import_constants.cjs +2 -1
- package/dist/load/import_constants.cjs.map +1 -1
- package/dist/load/import_constants.js +2 -1
- package/dist/load/import_constants.js.map +1 -1
- package/dist/load/import_map.cjs +2 -19
- package/dist/load/import_map.cjs.map +1 -1
- package/dist/load/import_map.js +2 -19
- package/dist/load/import_map.js.map +1 -1
- package/hub/node.cjs +1 -0
- package/hub/node.d.cts +1 -0
- package/hub/node.d.ts +1 -0
- package/hub/node.js +1 -0
- package/hub.cjs +1 -0
- package/hub.d.cts +1 -0
- package/hub.d.ts +1 -0
- package/hub.js +1 -0
- package/load/serializable.cjs +1 -0
- package/load/serializable.d.cts +1 -0
- package/load/serializable.d.ts +1 -0
- package/load/serializable.js +1 -0
- package/load.cjs +1 -0
- package/load.d.cts +1 -0
- package/load.d.ts +1 -0
- package/load.js +1 -0
- package/package.json +65 -52
- package/storage/encoder_backed.cjs +1 -0
- package/storage/encoder_backed.d.cts +1 -0
- package/storage/encoder_backed.d.ts +1 -0
- package/storage/encoder_backed.js +1 -0
- package/storage/file_system.cjs +1 -0
- package/storage/file_system.d.cts +1 -0
- package/storage/file_system.d.ts +1 -0
- package/storage/file_system.js +1 -0
- package/storage/in_memory.cjs +1 -0
- package/storage/in_memory.d.cts +1 -0
- package/storage/in_memory.d.ts +1 -0
- package/storage/in_memory.js +1 -0
- package/dist/agents/ReactAgent.d.cts.map +0 -1
- package/dist/agents/ReactAgent.d.ts.map +0 -1
- package/dist/agents/constants.cjs +0 -7
- package/dist/agents/constants.cjs.map +0 -1
- package/dist/agents/constants.d.cts.map +0 -1
- package/dist/agents/constants.d.ts.map +0 -1
- package/dist/agents/constants.js +0 -6
- package/dist/agents/constants.js.map +0 -1
- package/dist/agents/errors.d.cts.map +0 -1
- package/dist/agents/errors.d.ts.map +0 -1
- package/dist/agents/index.d.cts.map +0 -1
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/middleware/contextEditing.d.cts.map +0 -1
- package/dist/agents/middleware/contextEditing.d.ts.map +0 -1
- package/dist/agents/middleware/dynamicSystemPrompt.d.cts.map +0 -1
- package/dist/agents/middleware/dynamicSystemPrompt.d.ts.map +0 -1
- package/dist/agents/middleware/hitl.d.cts.map +0 -1
- package/dist/agents/middleware/hitl.d.ts.map +0 -1
- package/dist/agents/middleware/llmToolSelector.d.cts.map +0 -1
- package/dist/agents/middleware/llmToolSelector.d.ts.map +0 -1
- package/dist/agents/middleware/modelCallLimit.d.cts.map +0 -1
- package/dist/agents/middleware/modelCallLimit.d.ts.map +0 -1
- package/dist/agents/middleware/modelFallback.d.cts.map +0 -1
- package/dist/agents/middleware/modelFallback.d.ts.map +0 -1
- package/dist/agents/middleware/pii.d.cts.map +0 -1
- package/dist/agents/middleware/pii.d.ts.map +0 -1
- package/dist/agents/middleware/piiRedaction.d.cts.map +0 -1
- package/dist/agents/middleware/piiRedaction.d.ts.map +0 -1
- package/dist/agents/middleware/promptCaching.cjs.map +0 -1
- package/dist/agents/middleware/promptCaching.d.cts.map +0 -1
- package/dist/agents/middleware/promptCaching.d.ts.map +0 -1
- package/dist/agents/middleware/promptCaching.js.map +0 -1
- package/dist/agents/middleware/summarization.d.cts.map +0 -1
- package/dist/agents/middleware/summarization.d.ts.map +0 -1
- package/dist/agents/middleware/todoListMiddleware.d.cts.map +0 -1
- package/dist/agents/middleware/todoListMiddleware.d.ts.map +0 -1
- package/dist/agents/middleware/toolCallLimit.d.cts.map +0 -1
- package/dist/agents/middleware/toolCallLimit.d.ts.map +0 -1
- package/dist/agents/middleware/toolEmulator.d.cts.map +0 -1
- package/dist/agents/middleware/toolEmulator.d.ts.map +0 -1
- package/dist/agents/middleware/toolRetry.d.cts.map +0 -1
- package/dist/agents/middleware/toolRetry.d.ts.map +0 -1
- package/dist/agents/middleware/types.d.cts.map +0 -1
- package/dist/agents/middleware/types.d.ts.map +0 -1
- package/dist/agents/middleware/utils.d.cts.map +0 -1
- package/dist/agents/middleware/utils.d.ts.map +0 -1
- package/dist/agents/middleware.d.cts.map +0 -1
- package/dist/agents/middleware.d.ts.map +0 -1
- package/dist/agents/nodes/types.d.cts.map +0 -1
- package/dist/agents/nodes/types.d.ts.map +0 -1
- package/dist/agents/responses.d.cts.map +0 -1
- package/dist/agents/responses.d.ts.map +0 -1
- package/dist/agents/runtime.d.cts.map +0 -1
- package/dist/agents/runtime.d.ts.map +0 -1
- package/dist/agents/tests/utils.d.cts.map +0 -1
- package/dist/agents/tests/utils.d.ts.map +0 -1
- package/dist/agents/types.d.cts.map +0 -1
- package/dist/agents/types.d.ts.map +0 -1
- package/dist/chat_models/universal.d.cts.map +0 -1
- package/dist/chat_models/universal.d.ts.map +0 -1
- package/dist/hub/base.d.cts.map +0 -1
- package/dist/hub/base.d.ts.map +0 -1
- package/dist/hub/index.d.cts.map +0 -1
- package/dist/hub/index.d.ts.map +0 -1
- package/dist/hub/node.d.cts.map +0 -1
- package/dist/hub/node.d.ts.map +0 -1
- package/dist/load/import_type.d.cts.map +0 -1
- package/dist/load/import_type.d.ts.map +0 -1
- package/dist/load/index.d.cts.map +0 -1
- package/dist/load/index.d.ts.map +0 -1
- package/dist/storage/encoder_backed.d.cts.map +0 -1
- package/dist/storage/encoder_backed.d.ts.map +0 -1
- package/dist/storage/file_system.d.cts.map +0 -1
- package/dist/storage/file_system.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: 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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"}
|
|
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\n/**\n * The name of the tool node in the state graph.\n */\nexport const TOOLS_NODE_NAME = \"tools\";\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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"}
|
|
@@ -6,6 +6,10 @@ import { ToolInputParsingException } from "@langchain/core/tools";
|
|
|
6
6
|
import { Command, Send, isCommand, isGraphInterrupt } from "@langchain/langgraph";
|
|
7
7
|
|
|
8
8
|
//#region src/agents/nodes/ToolNode.ts
|
|
9
|
+
/**
|
|
10
|
+
* The name of the tool node in the state graph.
|
|
11
|
+
*/
|
|
12
|
+
const TOOLS_NODE_NAME = "tools";
|
|
9
13
|
const isBaseMessageArray = (input) => Array.isArray(input) && input.every(BaseMessage.isInstance);
|
|
10
14
|
const isMessagesState = (input) => typeof input === "object" && input != null && "messages" in input && isBaseMessageArray(input.messages);
|
|
11
15
|
const isSendInput = (input) => typeof input === "object" && input != null && "lg_tool_call" in input;
|
|
@@ -269,5 +273,5 @@ function isSend(x) {
|
|
|
269
273
|
}
|
|
270
274
|
|
|
271
275
|
//#endregion
|
|
272
|
-
export { ToolNode };
|
|
276
|
+
export { TOOLS_NODE_NAME, ToolNode };
|
|
273
277
|
//# sourceMappingURL=ToolNode.js.map
|
|
@@ -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: 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":"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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\n/**\n * The name of the tool node in the state graph.\n */\nexport const TOOLS_NODE_NAME = \"tools\";\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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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AgentBuiltInState, Runtime } from "../runtime.cjs";
|
|
2
2
|
import { LanguageModelLike } from "@langchain/core/language_models/base";
|
|
3
|
-
import { BaseMessage } from "@langchain/core/messages";
|
|
3
|
+
import { BaseMessage, SystemMessage } from "@langchain/core/messages";
|
|
4
4
|
import { ClientTool, ServerTool } from "@langchain/core/tools";
|
|
5
5
|
|
|
6
6
|
//#region src/agents/nodes/types.d.ts
|
|
@@ -22,9 +22,45 @@ interface ModelRequest<TState extends Record<string, unknown> = Record<string, u
|
|
|
22
22
|
*/
|
|
23
23
|
messages: BaseMessage[];
|
|
24
24
|
/**
|
|
25
|
-
* The system message for this step.
|
|
25
|
+
* The system message string for this step.
|
|
26
|
+
*
|
|
27
|
+
* @default ""
|
|
28
|
+
* @deprecated Use {@link ModelRequest.systemMessage} instead.
|
|
29
|
+
*/
|
|
30
|
+
systemPrompt: string;
|
|
31
|
+
/**
|
|
32
|
+
* The system message for this step. If no `systemPrompt` was provided, when `createAgent`
|
|
33
|
+
* was initialized, an empty system message will be used.
|
|
34
|
+
*
|
|
35
|
+
* @default new SystemMessage("")
|
|
36
|
+
* @example extend system message with a string
|
|
37
|
+
* ```ts
|
|
38
|
+
* wrapModelCall: async (request, handler) => {
|
|
39
|
+
* return handler({
|
|
40
|
+
* ...request,
|
|
41
|
+
* systemMessage: request.systemMessage.concat("something")
|
|
42
|
+
* });
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
* @example extend system message with a SystemMessage and cache control
|
|
46
|
+
* ```ts
|
|
47
|
+
* wrapModelCall: async (request, handler) => {
|
|
48
|
+
* return handler({
|
|
49
|
+
* ...request,
|
|
50
|
+
* systemMessage: request.systemMessage.concat(
|
|
51
|
+
* new SystemMessage({
|
|
52
|
+
* content: [{
|
|
53
|
+
* type: "text",
|
|
54
|
+
* text: "something",
|
|
55
|
+
* cache_control: { type: "ephemeral", ttl: "1m" }
|
|
56
|
+
* }],
|
|
57
|
+
* })
|
|
58
|
+
* ),
|
|
59
|
+
* });
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
26
62
|
*/
|
|
27
|
-
|
|
63
|
+
systemMessage: SystemMessage;
|
|
28
64
|
/**
|
|
29
65
|
* Tool choice configuration (model-specific format).
|
|
30
66
|
* Can be one of:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentBuiltInState, Runtime } from "../runtime.js";
|
|
2
|
-
import { BaseMessage } from "@langchain/core/messages";
|
|
2
|
+
import { BaseMessage, SystemMessage } from "@langchain/core/messages";
|
|
3
3
|
import { ClientTool, ServerTool } from "@langchain/core/tools";
|
|
4
4
|
import { LanguageModelLike } from "@langchain/core/language_models/base";
|
|
5
5
|
|
|
@@ -22,9 +22,45 @@ interface ModelRequest<TState extends Record<string, unknown> = Record<string, u
|
|
|
22
22
|
*/
|
|
23
23
|
messages: BaseMessage[];
|
|
24
24
|
/**
|
|
25
|
-
* The system message for this step.
|
|
25
|
+
* The system message string for this step.
|
|
26
|
+
*
|
|
27
|
+
* @default ""
|
|
28
|
+
* @deprecated Use {@link ModelRequest.systemMessage} instead.
|
|
29
|
+
*/
|
|
30
|
+
systemPrompt: string;
|
|
31
|
+
/**
|
|
32
|
+
* The system message for this step. If no `systemPrompt` was provided, when `createAgent`
|
|
33
|
+
* was initialized, an empty system message will be used.
|
|
34
|
+
*
|
|
35
|
+
* @default new SystemMessage("")
|
|
36
|
+
* @example extend system message with a string
|
|
37
|
+
* ```ts
|
|
38
|
+
* wrapModelCall: async (request, handler) => {
|
|
39
|
+
* return handler({
|
|
40
|
+
* ...request,
|
|
41
|
+
* systemMessage: request.systemMessage.concat("something")
|
|
42
|
+
* });
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
* @example extend system message with a SystemMessage and cache control
|
|
46
|
+
* ```ts
|
|
47
|
+
* wrapModelCall: async (request, handler) => {
|
|
48
|
+
* return handler({
|
|
49
|
+
* ...request,
|
|
50
|
+
* systemMessage: request.systemMessage.concat(
|
|
51
|
+
* new SystemMessage({
|
|
52
|
+
* content: [{
|
|
53
|
+
* type: "text",
|
|
54
|
+
* text: "something",
|
|
55
|
+
* cache_control: { type: "ephemeral", ttl: "1m" }
|
|
56
|
+
* }],
|
|
57
|
+
* })
|
|
58
|
+
* ),
|
|
59
|
+
* });
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
26
62
|
*/
|
|
27
|
-
|
|
63
|
+
systemMessage: SystemMessage;
|
|
28
64
|
/**
|
|
29
65
|
* Tool choice configuration (model-specific format).
|
|
30
66
|
* Can be one of:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.cjs","names":["schema: Record<string, unknown>","tool: {\n type: \"function\";\n function: FunctionDefinition;\n }","options?: ToolStrategyOptions","schema: InteropZodObject | Record<string, unknown>","outputOptions?: ToolStrategyOptions","name?: string","asJsonSchema","tool","functionDefinition: FunctionDefinition","toolArgs: Record<string, unknown>","Validator","StructuredOutputParsingError","schema: InteropZodType<T> | Record<string, unknown>","response: AIMessage","responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined","model?: LanguageModelLike | string","responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]","responseFormat: InteropZodType<any> | JsonSchemaFormat","isConfigurableModel","isBaseChatModel"],"sources":["../../src/agents/responses.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport {\n InteropZodObject,\n isInteropZodSchema,\n InteropZodType,\n isInteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport { type AIMessage } from \"@langchain/core/messages\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { toJsonSchema, Validator } from \"@langchain/core/utils/json_schema\";\nimport { type FunctionDefinition } from \"@langchain/core/language_models/base\";\n\nimport {\n StructuredOutputParsingError,\n MultipleStructuredOutputsError,\n} from \"./errors.js\";\nimport { isConfigurableModel, isBaseChatModel } from \"./model.js\";\n\n/**\n * Special type to indicate that no response format is provided.\n * When this type is used, the structuredResponse property should not be present in the result.\n */\nexport type ResponseFormatUndefined = {\n __responseFormatUndefined: true;\n};\n\n/**\n * This is a global counter for generating unique names for tools.\n */\nlet bindingIdentifier = 0;\n\n/**\n * Information for tracking structured output tool metadata.\n * This contains all necessary information to handle structured responses generated\n * via tool calls, including the original schema, its type classification, and the\n * corresponding tool implementation used by the tools strategy.\n */\nexport class ToolStrategy<_T = unknown> {\n private constructor(\n /**\n * The original JSON Schema provided for structured output\n */\n public readonly schema: Record<string, unknown>,\n\n /**\n * The tool that will be used to parse the tool call arguments.\n */\n public readonly tool: {\n type: \"function\";\n function: FunctionDefinition;\n },\n\n /**\n * The options to use for the tool output.\n */\n public readonly options?: ToolStrategyOptions\n ) {}\n\n get name() {\n return this.tool.function.name;\n }\n\n static fromSchema<S extends InteropZodObject>(\n schema: S,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<S extends InteropZodType<infer U> ? U : unknown>;\n\n static fromSchema(\n schema: Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: InteropZodObject | Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<any> {\n /**\n * It is required for tools to have a name so we can map the tool call to the correct tool\n * when parsing the response.\n */\n function getFunctionName(name?: string) {\n return name ?? `extract-${++bindingIdentifier}`;\n }\n\n if (isInteropZodSchema(schema)) {\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: {\n name: getFunctionName(),\n strict: false,\n description:\n asJsonSchema.description ??\n \"Tool for extracting structured output from the model's response.\",\n parameters: asJsonSchema,\n },\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n let functionDefinition: FunctionDefinition;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n functionDefinition = schema as unknown as FunctionDefinition;\n } else {\n functionDefinition = {\n name: getFunctionName(schema.title as string),\n description: (schema.description as string) ?? \"\",\n parameters: schema.schema || (schema as Record<string, unknown>),\n };\n }\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: functionDefinition,\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n /**\n * Parse tool arguments according to the schema.\n *\n * @throws {StructuredOutputParsingError} if the response is not valid\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(toolArgs: Record<string, unknown>): Record<string, unknown> {\n const validator = new Validator(this.schema);\n const result = validator.validate(toolArgs);\n if (!result.valid) {\n throw new StructuredOutputParsingError(\n this.name,\n result.errors.map((e) => e.error)\n );\n }\n return toolArgs;\n }\n}\n\nexport class ProviderStrategy<T = unknown> {\n // @ts-expect-error - _schemaType is used only for type inference\n private _schemaType?: T;\n\n private constructor(public readonly schema: Record<string, unknown>) {}\n\n static fromSchema<T>(schema: InteropZodType<T>): ProviderStrategy<T>;\n\n static fromSchema(\n schema: Record<string, unknown>\n ): ProviderStrategy<Record<string, unknown>>;\n\n static fromSchema<T = unknown>(\n schema: InteropZodType<T> | Record<string, unknown>\n ): ProviderStrategy<T> | ProviderStrategy<Record<string, unknown>> {\n const asJsonSchema = toJsonSchema(schema);\n return new ProviderStrategy(asJsonSchema) as\n | ProviderStrategy<T>\n | ProviderStrategy<Record<string, unknown>>;\n }\n\n /**\n * Parse tool arguments according to the schema. If the response is not valid, return undefined.\n *\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(response: AIMessage) {\n /**\n * return if the response doesn't contain valid content\n */\n if (typeof response.content !== \"string\" || response.content === \"\") {\n return;\n }\n\n try {\n const content = JSON.parse(response.content);\n const validator = new Validator(this.schema);\n const result = validator.validate(content);\n if (!result.valid) {\n return;\n }\n\n return content;\n } catch {\n // no-op\n }\n }\n}\n\nexport type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;\n\n/**\n * Handle user input for `responseFormat` parameter of `CreateAgentParams`.\n * This function defines the default behavior for the `responseFormat` parameter, which is:\n *\n * - if value is a Zod schema, default to structured output via tool calling\n * - if value is a JSON schema, default to structured output via tool calling\n * - if value is a custom response format, return it as is\n * - if value is an array, ensure all array elements are instance of `ToolStrategy`\n * @param responseFormat - The response format to transform, provided by the user\n * @param options - The response format options for tool strategy\n * @param model - The model to check if it supports JSON schema output\n * @returns\n */\nexport function transformResponseFormat(\n responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined,\n options?: ToolStrategyOptions,\n model?: LanguageModelLike | string\n): ResponseFormat[] {\n if (!responseFormat) {\n return [];\n }\n\n // Handle ResponseFormatUndefined case\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"__responseFormatUndefined\" in responseFormat\n ) {\n return [];\n }\n\n /**\n * If users provide an array, it should only contain raw schemas (Zod or JSON schema),\n * not ToolStrategy or ProviderStrategy instances.\n */\n if (Array.isArray(responseFormat)) {\n /**\n * if every entry is a ToolStrategy or ProviderStrategy instance, return the array as is\n */\n if (\n responseFormat.every(\n (item) =>\n item instanceof ToolStrategy || item instanceof ProviderStrategy\n )\n ) {\n return responseFormat as unknown as ResponseFormat[];\n }\n\n /**\n * Check if all items are Zod schemas\n */\n if (responseFormat.every((item) => isInteropZodObject(item))) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as InteropZodObject, options)\n );\n }\n\n /**\n * Check if all items are plain objects (JSON schema)\n */\n if (\n responseFormat.every(\n (item) =>\n typeof item === \"object\" && item !== null && !isInteropZodObject(item)\n )\n ) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as JsonSchemaFormat, options)\n );\n }\n\n throw new Error(\n `Invalid response format: list contains mixed types.\\n` +\n `All items must be either InteropZodObject or plain JSON schema objects.`\n );\n }\n\n if (\n responseFormat instanceof ToolStrategy ||\n responseFormat instanceof ProviderStrategy\n ) {\n return [responseFormat];\n }\n\n const useProviderStrategy = hasSupportForJsonSchemaOutput(model);\n\n /**\n * `responseFormat` is a Zod schema\n */\n if (isInteropZodObject(responseFormat)) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat)]\n : [ToolStrategy.fromSchema(responseFormat, options)];\n }\n\n /**\n * Handle plain object (JSON schema)\n */\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"properties\" in responseFormat\n ) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat as JsonSchemaFormat)]\n : [ToolStrategy.fromSchema(responseFormat as JsonSchemaFormat, options)];\n }\n\n throw new Error(`Invalid response format: ${String(responseFormat)}`);\n}\n\n/**\n * Branded type for ToolStrategy arrays that preserves type information\n */\nexport interface TypedToolStrategy<T = unknown>\n extends Array<ToolStrategy<any>> {\n _schemaType?: T;\n}\nexport type ToolStrategyError =\n | StructuredOutputParsingError\n | MultipleStructuredOutputsError;\nexport interface ToolStrategyOptions {\n /**\n * Allows you to customize the message that appears in the conversation history when structured\n * output is generated.\n */\n toolMessageContent?: string;\n /**\n * Handle errors from the structured output tool call. Using tools to generate structured output\n * can cause errors, e.g. if:\n * - you provide multiple structured output schemas and the model calls multiple structured output tools\n * - if the structured output generated by the tool call doesn't match provided schema\n *\n * This property allows to handle these errors in different ways:\n * - `true` - retry the tool call\n * - `false` - throw an error\n * - `string` - retry the tool call with the provided message\n * - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error\n */\n handleError?:\n | boolean\n | string\n | ((error: ToolStrategyError) => Promise<string> | string);\n}\n\nexport function toolStrategy<T extends InteropZodType<any>>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function toolStrategy<T extends readonly InteropZodType<any>[]>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<\n { [K in keyof T]: T[K] extends InteropZodType<infer U> ? U : never }[number]\n>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat,\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\n\n/**\n * Define how to transform the response format from a tool call.\n *\n * @param responseFormat - The response format to transform\n * @param options - The options to use for the transformation\n * @param options.handleError - Whether to handle errors from the tool call\n * @returns The transformed response format\n */\nexport function toolStrategy(\n responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy {\n return transformResponseFormat(responseFormat, options) as TypedToolStrategy;\n}\n\nexport function providerStrategy<T extends InteropZodType<any>>(\n responseFormat: T\n): ProviderStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function providerStrategy(\n responseFormat: JsonSchemaFormat\n): ProviderStrategy<Record<string, unknown>>;\nexport function providerStrategy(\n responseFormat: InteropZodType<any> | JsonSchemaFormat\n): ProviderStrategy<any> {\n return ProviderStrategy.fromSchema(\n responseFormat as any\n ) as ProviderStrategy<any>;\n}\n\n/**\n * Type representing a JSON Schema object format.\n * This is a strict type that excludes ToolStrategy and ProviderStrategy instances.\n */\nexport type JsonSchemaFormat = {\n type:\n | \"null\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"number\"\n | \"string\"\n | \"integer\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n} & {\n // Brand to ensure this is not a ToolStrategy or ProviderStrategy\n __brand?: never;\n};\n\nconst CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\"ChatOpenAI\", \"ChatXAI\"];\nconst MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\n \"grok\",\n \"gpt-5\",\n \"gpt-4.1\",\n \"gpt-4o\",\n \"gpt-oss\",\n \"o3-pro\",\n \"o3-mini\",\n];\n\n/**\n * Identifies the models that support JSON schema output\n * @param model - The model to check\n * @returns True if the model supports JSON schema output, false otherwise\n */\nexport function hasSupportForJsonSchemaOutput(\n model?: LanguageModelLike | string\n): boolean {\n if (!model) {\n return false;\n }\n\n if (typeof model === \"string\") {\n const modelName = model.split(\":\").pop() as string;\n return MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) => modelName.includes(modelNameSnippet)\n );\n }\n\n if (isConfigurableModel(model)) {\n const configurableModel = model as unknown as {\n _defaultConfig: { model: string };\n };\n return hasSupportForJsonSchemaOutput(\n configurableModel._defaultConfig.model\n );\n }\n\n if (!isBaseChatModel(model)) {\n return false;\n }\n\n const chatModelClass = model.getName();\n\n /**\n * for testing purposes only\n */\n if (chatModelClass === \"FakeToolCallingChatModel\") {\n return true;\n }\n\n if (\n CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.includes(chatModelClass) &&\n /**\n * OpenAI models\n */ ((\"model\" in model &&\n MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) =>\n typeof model.model === \"string\" &&\n model.model.includes(modelNameSnippet)\n )) ||\n /**\n * for testing purposes only\n */\n (chatModelClass === \"FakeToolCallingModel\" &&\n \"structuredResponse\" in model))\n ) {\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"responses.cjs","names":["schema: Record<string, unknown>","tool: {\n type: \"function\";\n function: FunctionDefinition;\n }","options?: ToolStrategyOptions","schema: InteropZodObject | Record<string, unknown>","outputOptions?: ToolStrategyOptions","name?: string","asJsonSchema","tool","functionDefinition: FunctionDefinition","toolArgs: Record<string, unknown>","Validator","StructuredOutputParsingError","schema: InteropZodType<T> | Record<string, unknown>","response: AIMessage","responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined","model?: LanguageModelLike | string","responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]","responseFormat: InteropZodType<any> | JsonSchemaFormat","isConfigurableModel","isBaseChatModel"],"sources":["../../src/agents/responses.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport {\n InteropZodObject,\n isInteropZodSchema,\n InteropZodType,\n isInteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport { type AIMessage } from \"@langchain/core/messages\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { toJsonSchema, Validator } from \"@langchain/core/utils/json_schema\";\nimport { type FunctionDefinition } from \"@langchain/core/language_models/base\";\n\nimport {\n StructuredOutputParsingError,\n MultipleStructuredOutputsError,\n} from \"./errors.js\";\nimport { isConfigurableModel, isBaseChatModel } from \"./model.js\";\n\n/**\n * Special type to indicate that no response format is provided.\n * When this type is used, the structuredResponse property should not be present in the result.\n */\nexport type ResponseFormatUndefined = {\n __responseFormatUndefined: true;\n};\n\n/**\n * This is a global counter for generating unique names for tools.\n */\nlet bindingIdentifier = 0;\n\n/**\n * Information for tracking structured output tool metadata.\n * This contains all necessary information to handle structured responses generated\n * via tool calls, including the original schema, its type classification, and the\n * corresponding tool implementation used by the tools strategy.\n */\nexport class ToolStrategy<_T = unknown> {\n private constructor(\n /**\n * The original JSON Schema provided for structured output\n */\n public readonly schema: Record<string, unknown>,\n\n /**\n * The tool that will be used to parse the tool call arguments.\n */\n public readonly tool: {\n type: \"function\";\n function: FunctionDefinition;\n },\n\n /**\n * The options to use for the tool output.\n */\n public readonly options?: ToolStrategyOptions\n ) {}\n\n get name() {\n return this.tool.function.name;\n }\n\n static fromSchema<S extends InteropZodObject>(\n schema: S,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<S extends InteropZodType<infer U> ? U : unknown>;\n\n static fromSchema(\n schema: Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: InteropZodObject | Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<any> {\n /**\n * It is required for tools to have a name so we can map the tool call to the correct tool\n * when parsing the response.\n */\n function getFunctionName(name?: string) {\n return name ?? `extract-${++bindingIdentifier}`;\n }\n\n if (isInteropZodSchema(schema)) {\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: {\n name: getFunctionName(),\n strict: false,\n description:\n asJsonSchema.description ??\n \"Tool for extracting structured output from the model's response.\",\n parameters: asJsonSchema,\n },\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n let functionDefinition: FunctionDefinition;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n functionDefinition = schema as unknown as FunctionDefinition;\n } else {\n functionDefinition = {\n name: getFunctionName(schema.title as string),\n description: (schema.description as string) ?? \"\",\n parameters: schema.schema || (schema as Record<string, unknown>),\n };\n }\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: functionDefinition,\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n /**\n * Parse tool arguments according to the schema.\n *\n * @throws {StructuredOutputParsingError} if the response is not valid\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(toolArgs: Record<string, unknown>): Record<string, unknown> {\n const validator = new Validator(this.schema);\n const result = validator.validate(toolArgs);\n if (!result.valid) {\n throw new StructuredOutputParsingError(\n this.name,\n result.errors.map((e) => e.error)\n );\n }\n return toolArgs;\n }\n}\n\nexport class ProviderStrategy<T = unknown> {\n // @ts-expect-error - _schemaType is used only for type inference\n private _schemaType?: T;\n\n private constructor(public readonly schema: Record<string, unknown>) {}\n\n static fromSchema<T>(schema: InteropZodType<T>): ProviderStrategy<T>;\n\n static fromSchema(\n schema: Record<string, unknown>\n ): ProviderStrategy<Record<string, unknown>>;\n\n static fromSchema<T = unknown>(\n schema: InteropZodType<T> | Record<string, unknown>\n ): ProviderStrategy<T> | ProviderStrategy<Record<string, unknown>> {\n const asJsonSchema = toJsonSchema(schema);\n return new ProviderStrategy(asJsonSchema) as\n | ProviderStrategy<T>\n | ProviderStrategy<Record<string, unknown>>;\n }\n\n /**\n * Parse tool arguments according to the schema. If the response is not valid, return undefined.\n *\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(response: AIMessage) {\n /**\n * return if the response doesn't contain valid content\n */\n if (typeof response.content !== \"string\" || response.content === \"\") {\n return;\n }\n\n try {\n const content = JSON.parse(response.content);\n const validator = new Validator(this.schema);\n const result = validator.validate(content);\n if (!result.valid) {\n return;\n }\n\n return content;\n } catch {\n // no-op\n }\n }\n}\n\nexport type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;\n\n/**\n * Handle user input for `responseFormat` parameter of `CreateAgentParams`.\n * This function defines the default behavior for the `responseFormat` parameter, which is:\n *\n * - if value is a Zod schema, default to structured output via tool calling\n * - if value is a JSON schema, default to structured output via tool calling\n * - if value is a custom response format, return it as is\n * - if value is an array, ensure all array elements are instance of `ToolStrategy`\n * @param responseFormat - The response format to transform, provided by the user\n * @param options - The response format options for tool strategy\n * @param model - The model to check if it supports JSON schema output\n * @returns\n */\nexport function transformResponseFormat(\n responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined,\n options?: ToolStrategyOptions,\n model?: LanguageModelLike | string\n): ResponseFormat[] {\n if (!responseFormat) {\n return [];\n }\n\n // Handle ResponseFormatUndefined case\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"__responseFormatUndefined\" in responseFormat\n ) {\n return [];\n }\n\n /**\n * If users provide an array, it should only contain raw schemas (Zod or JSON schema),\n * not ToolStrategy or ProviderStrategy instances.\n */\n if (Array.isArray(responseFormat)) {\n /**\n * if every entry is a ToolStrategy or ProviderStrategy instance, return the array as is\n */\n if (\n responseFormat.every(\n (item) =>\n item instanceof ToolStrategy || item instanceof ProviderStrategy\n )\n ) {\n return responseFormat as unknown as ResponseFormat[];\n }\n\n /**\n * Check if all items are Zod schemas\n */\n if (responseFormat.every((item) => isInteropZodObject(item))) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as InteropZodObject, options)\n );\n }\n\n /**\n * Check if all items are plain objects (JSON schema)\n */\n if (\n responseFormat.every(\n (item) =>\n typeof item === \"object\" && item !== null && !isInteropZodObject(item)\n )\n ) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as JsonSchemaFormat, options)\n );\n }\n\n throw new Error(\n `Invalid response format: list contains mixed types.\\n` +\n `All items must be either InteropZodObject or plain JSON schema objects.`\n );\n }\n\n if (\n responseFormat instanceof ToolStrategy ||\n responseFormat instanceof ProviderStrategy\n ) {\n return [responseFormat];\n }\n\n const useProviderStrategy = hasSupportForJsonSchemaOutput(model);\n\n /**\n * `responseFormat` is a Zod schema\n */\n if (isInteropZodObject(responseFormat)) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat)]\n : [ToolStrategy.fromSchema(responseFormat, options)];\n }\n\n /**\n * Handle plain object (JSON schema)\n */\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"properties\" in responseFormat\n ) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat as JsonSchemaFormat)]\n : [ToolStrategy.fromSchema(responseFormat as JsonSchemaFormat, options)];\n }\n\n throw new Error(`Invalid response format: ${String(responseFormat)}`);\n}\n\n/**\n * Branded type for ToolStrategy arrays that preserves type information\n */\nexport interface TypedToolStrategy<T = unknown>\n extends Array<ToolStrategy<any>> {\n _schemaType?: T;\n}\nexport type ToolStrategyError =\n | StructuredOutputParsingError\n | MultipleStructuredOutputsError;\nexport interface ToolStrategyOptions {\n /**\n * Allows you to customize the message that appears in the conversation history when structured\n * output is generated.\n */\n toolMessageContent?: string;\n /**\n * Handle errors from the structured output tool call. Using tools to generate structured output\n * can cause errors, e.g. if:\n * - you provide multiple structured output schemas and the model calls multiple structured output tools\n * - if the structured output generated by the tool call doesn't match provided schema\n *\n * This property allows to handle these errors in different ways:\n * - `true` - retry the tool call\n * - `false` - throw an error\n * - `string` - retry the tool call with the provided message\n * - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error\n *\n * @default true\n */\n handleError?:\n | boolean\n | string\n | ((error: ToolStrategyError) => Promise<string> | string);\n}\n\nexport function toolStrategy<T extends InteropZodType<any>>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function toolStrategy<T extends readonly InteropZodType<any>[]>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<\n { [K in keyof T]: T[K] extends InteropZodType<infer U> ? U : never }[number]\n>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat,\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\n\n/**\n * Define how to transform the response format from a tool call.\n *\n * @param responseFormat - The response format to transform\n * @param options - The options to use for the transformation\n * @param options.handleError - Whether to handle errors from the tool call\n * @returns The transformed response format\n */\nexport function toolStrategy(\n responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy {\n return transformResponseFormat(responseFormat, options) as TypedToolStrategy;\n}\n\nexport function providerStrategy<T extends InteropZodType<any>>(\n responseFormat: T\n): ProviderStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function providerStrategy(\n responseFormat: JsonSchemaFormat\n): ProviderStrategy<Record<string, unknown>>;\nexport function providerStrategy(\n responseFormat: InteropZodType<any> | JsonSchemaFormat\n): ProviderStrategy<any> {\n return ProviderStrategy.fromSchema(\n responseFormat as any\n ) as ProviderStrategy<any>;\n}\n\n/**\n * Type representing a JSON Schema object format.\n * This is a strict type that excludes ToolStrategy and ProviderStrategy instances.\n */\nexport type JsonSchemaFormat = {\n type:\n | \"null\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"number\"\n | \"string\"\n | \"integer\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n} & {\n // Brand to ensure this is not a ToolStrategy or ProviderStrategy\n __brand?: never;\n};\n\nconst CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\"ChatOpenAI\", \"ChatXAI\"];\nconst MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\n \"grok\",\n \"gpt-5\",\n \"gpt-4.1\",\n \"gpt-4o\",\n \"gpt-oss\",\n \"o3-pro\",\n \"o3-mini\",\n];\n\n/**\n * Identifies the models that support JSON schema output\n * @param model - The model to check\n * @returns True if the model supports JSON schema output, false otherwise\n */\nexport function hasSupportForJsonSchemaOutput(\n model?: LanguageModelLike | string\n): boolean {\n if (!model) {\n return false;\n }\n\n if (typeof model === \"string\") {\n const modelName = model.split(\":\").pop() as string;\n return MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) => modelName.includes(modelNameSnippet)\n );\n }\n\n if (isConfigurableModel(model)) {\n const configurableModel = model as unknown as {\n _defaultConfig: { model: string };\n };\n return hasSupportForJsonSchemaOutput(\n configurableModel._defaultConfig.model\n );\n }\n\n if (!isBaseChatModel(model)) {\n return false;\n }\n\n const chatModelClass = model.getName();\n\n /**\n * for testing purposes only\n */\n if (chatModelClass === \"FakeToolCallingChatModel\") {\n return true;\n }\n\n if (\n CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.includes(chatModelClass) &&\n /**\n * OpenAI models\n */ ((\"model\" in model &&\n MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) =>\n typeof model.model === \"string\" &&\n model.model.includes(modelNameSnippet)\n )) ||\n /**\n * for testing purposes only\n */\n (chatModelClass === \"FakeToolCallingModel\" &&\n \"structuredResponse\" in model))\n ) {\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
|
|
@@ -54,20 +54,6 @@ declare class ProviderStrategy<T = unknown> {
|
|
|
54
54
|
parse(response: AIMessage): any;
|
|
55
55
|
}
|
|
56
56
|
type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;
|
|
57
|
-
/**
|
|
58
|
-
* Handle user input for `responseFormat` parameter of `CreateAgentParams`.
|
|
59
|
-
* This function defines the default behavior for the `responseFormat` parameter, which is:
|
|
60
|
-
*
|
|
61
|
-
* - if value is a Zod schema, default to structured output via tool calling
|
|
62
|
-
* - if value is a JSON schema, default to structured output via tool calling
|
|
63
|
-
* - if value is a custom response format, return it as is
|
|
64
|
-
* - if value is an array, ensure all array elements are instance of `ToolStrategy`
|
|
65
|
-
* @param responseFormat - The response format to transform, provided by the user
|
|
66
|
-
* @param options - The response format options for tool strategy
|
|
67
|
-
* @param model - The model to check if it supports JSON schema output
|
|
68
|
-
* @returns
|
|
69
|
-
*/
|
|
70
|
-
|
|
71
57
|
/**
|
|
72
58
|
* Branded type for ToolStrategy arrays that preserves type information
|
|
73
59
|
*/
|
|
@@ -92,6 +78,8 @@ interface ToolStrategyOptions {
|
|
|
92
78
|
* - `false` - throw an error
|
|
93
79
|
* - `string` - retry the tool call with the provided message
|
|
94
80
|
* - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error
|
|
81
|
+
*
|
|
82
|
+
* @default true
|
|
95
83
|
*/
|
|
96
84
|
handleError?: boolean | string | ((error: ToolStrategyError) => Promise<string> | string);
|
|
97
85
|
}
|
|
@@ -115,11 +103,6 @@ type JsonSchemaFormat = {
|
|
|
115
103
|
// Brand to ensure this is not a ToolStrategy or ProviderStrategy
|
|
116
104
|
__brand?: never;
|
|
117
105
|
};
|
|
118
|
-
/**
|
|
119
|
-
* Identifies the models that support JSON schema output
|
|
120
|
-
* @param model - The model to check
|
|
121
|
-
* @returns True if the model supports JSON schema output, false otherwise
|
|
122
|
-
*/
|
|
123
106
|
//#endregion
|
|
124
107
|
export { JsonSchemaFormat, ProviderStrategy, ResponseFormat, ResponseFormatUndefined, ToolStrategy, TypedToolStrategy, providerStrategy, toolStrategy };
|
|
125
108
|
//# sourceMappingURL=responses.d.cts.map
|
|
@@ -54,20 +54,6 @@ declare class ProviderStrategy<T = unknown> {
|
|
|
54
54
|
parse(response: AIMessage): any;
|
|
55
55
|
}
|
|
56
56
|
type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;
|
|
57
|
-
/**
|
|
58
|
-
* Handle user input for `responseFormat` parameter of `CreateAgentParams`.
|
|
59
|
-
* This function defines the default behavior for the `responseFormat` parameter, which is:
|
|
60
|
-
*
|
|
61
|
-
* - if value is a Zod schema, default to structured output via tool calling
|
|
62
|
-
* - if value is a JSON schema, default to structured output via tool calling
|
|
63
|
-
* - if value is a custom response format, return it as is
|
|
64
|
-
* - if value is an array, ensure all array elements are instance of `ToolStrategy`
|
|
65
|
-
* @param responseFormat - The response format to transform, provided by the user
|
|
66
|
-
* @param options - The response format options for tool strategy
|
|
67
|
-
* @param model - The model to check if it supports JSON schema output
|
|
68
|
-
* @returns
|
|
69
|
-
*/
|
|
70
|
-
|
|
71
57
|
/**
|
|
72
58
|
* Branded type for ToolStrategy arrays that preserves type information
|
|
73
59
|
*/
|
|
@@ -92,6 +78,8 @@ interface ToolStrategyOptions {
|
|
|
92
78
|
* - `false` - throw an error
|
|
93
79
|
* - `string` - retry the tool call with the provided message
|
|
94
80
|
* - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error
|
|
81
|
+
*
|
|
82
|
+
* @default true
|
|
95
83
|
*/
|
|
96
84
|
handleError?: boolean | string | ((error: ToolStrategyError) => Promise<string> | string);
|
|
97
85
|
}
|
|
@@ -115,11 +103,6 @@ type JsonSchemaFormat = {
|
|
|
115
103
|
// Brand to ensure this is not a ToolStrategy or ProviderStrategy
|
|
116
104
|
__brand?: never;
|
|
117
105
|
};
|
|
118
|
-
/**
|
|
119
|
-
* Identifies the models that support JSON schema output
|
|
120
|
-
* @param model - The model to check
|
|
121
|
-
* @returns True if the model supports JSON schema output, false otherwise
|
|
122
|
-
*/
|
|
123
106
|
//#endregion
|
|
124
107
|
export { JsonSchemaFormat, ProviderStrategy, ResponseFormat, ResponseFormatUndefined, ToolStrategy, TypedToolStrategy, providerStrategy, toolStrategy };
|
|
125
108
|
//# sourceMappingURL=responses.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.js","names":["schema: Record<string, unknown>","tool: {\n type: \"function\";\n function: FunctionDefinition;\n }","options?: ToolStrategyOptions","schema: InteropZodObject | Record<string, unknown>","outputOptions?: ToolStrategyOptions","name?: string","asJsonSchema","tool","functionDefinition: FunctionDefinition","toolArgs: Record<string, unknown>","schema: InteropZodType<T> | Record<string, unknown>","response: AIMessage","responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined","model?: LanguageModelLike | string","responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]","responseFormat: InteropZodType<any> | JsonSchemaFormat"],"sources":["../../src/agents/responses.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport {\n InteropZodObject,\n isInteropZodSchema,\n InteropZodType,\n isInteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport { type AIMessage } from \"@langchain/core/messages\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { toJsonSchema, Validator } from \"@langchain/core/utils/json_schema\";\nimport { type FunctionDefinition } from \"@langchain/core/language_models/base\";\n\nimport {\n StructuredOutputParsingError,\n MultipleStructuredOutputsError,\n} from \"./errors.js\";\nimport { isConfigurableModel, isBaseChatModel } from \"./model.js\";\n\n/**\n * Special type to indicate that no response format is provided.\n * When this type is used, the structuredResponse property should not be present in the result.\n */\nexport type ResponseFormatUndefined = {\n __responseFormatUndefined: true;\n};\n\n/**\n * This is a global counter for generating unique names for tools.\n */\nlet bindingIdentifier = 0;\n\n/**\n * Information for tracking structured output tool metadata.\n * This contains all necessary information to handle structured responses generated\n * via tool calls, including the original schema, its type classification, and the\n * corresponding tool implementation used by the tools strategy.\n */\nexport class ToolStrategy<_T = unknown> {\n private constructor(\n /**\n * The original JSON Schema provided for structured output\n */\n public readonly schema: Record<string, unknown>,\n\n /**\n * The tool that will be used to parse the tool call arguments.\n */\n public readonly tool: {\n type: \"function\";\n function: FunctionDefinition;\n },\n\n /**\n * The options to use for the tool output.\n */\n public readonly options?: ToolStrategyOptions\n ) {}\n\n get name() {\n return this.tool.function.name;\n }\n\n static fromSchema<S extends InteropZodObject>(\n schema: S,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<S extends InteropZodType<infer U> ? U : unknown>;\n\n static fromSchema(\n schema: Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: InteropZodObject | Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<any> {\n /**\n * It is required for tools to have a name so we can map the tool call to the correct tool\n * when parsing the response.\n */\n function getFunctionName(name?: string) {\n return name ?? `extract-${++bindingIdentifier}`;\n }\n\n if (isInteropZodSchema(schema)) {\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: {\n name: getFunctionName(),\n strict: false,\n description:\n asJsonSchema.description ??\n \"Tool for extracting structured output from the model's response.\",\n parameters: asJsonSchema,\n },\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n let functionDefinition: FunctionDefinition;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n functionDefinition = schema as unknown as FunctionDefinition;\n } else {\n functionDefinition = {\n name: getFunctionName(schema.title as string),\n description: (schema.description as string) ?? \"\",\n parameters: schema.schema || (schema as Record<string, unknown>),\n };\n }\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: functionDefinition,\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n /**\n * Parse tool arguments according to the schema.\n *\n * @throws {StructuredOutputParsingError} if the response is not valid\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(toolArgs: Record<string, unknown>): Record<string, unknown> {\n const validator = new Validator(this.schema);\n const result = validator.validate(toolArgs);\n if (!result.valid) {\n throw new StructuredOutputParsingError(\n this.name,\n result.errors.map((e) => e.error)\n );\n }\n return toolArgs;\n }\n}\n\nexport class ProviderStrategy<T = unknown> {\n // @ts-expect-error - _schemaType is used only for type inference\n private _schemaType?: T;\n\n private constructor(public readonly schema: Record<string, unknown>) {}\n\n static fromSchema<T>(schema: InteropZodType<T>): ProviderStrategy<T>;\n\n static fromSchema(\n schema: Record<string, unknown>\n ): ProviderStrategy<Record<string, unknown>>;\n\n static fromSchema<T = unknown>(\n schema: InteropZodType<T> | Record<string, unknown>\n ): ProviderStrategy<T> | ProviderStrategy<Record<string, unknown>> {\n const asJsonSchema = toJsonSchema(schema);\n return new ProviderStrategy(asJsonSchema) as\n | ProviderStrategy<T>\n | ProviderStrategy<Record<string, unknown>>;\n }\n\n /**\n * Parse tool arguments according to the schema. If the response is not valid, return undefined.\n *\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(response: AIMessage) {\n /**\n * return if the response doesn't contain valid content\n */\n if (typeof response.content !== \"string\" || response.content === \"\") {\n return;\n }\n\n try {\n const content = JSON.parse(response.content);\n const validator = new Validator(this.schema);\n const result = validator.validate(content);\n if (!result.valid) {\n return;\n }\n\n return content;\n } catch {\n // no-op\n }\n }\n}\n\nexport type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;\n\n/**\n * Handle user input for `responseFormat` parameter of `CreateAgentParams`.\n * This function defines the default behavior for the `responseFormat` parameter, which is:\n *\n * - if value is a Zod schema, default to structured output via tool calling\n * - if value is a JSON schema, default to structured output via tool calling\n * - if value is a custom response format, return it as is\n * - if value is an array, ensure all array elements are instance of `ToolStrategy`\n * @param responseFormat - The response format to transform, provided by the user\n * @param options - The response format options for tool strategy\n * @param model - The model to check if it supports JSON schema output\n * @returns\n */\nexport function transformResponseFormat(\n responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined,\n options?: ToolStrategyOptions,\n model?: LanguageModelLike | string\n): ResponseFormat[] {\n if (!responseFormat) {\n return [];\n }\n\n // Handle ResponseFormatUndefined case\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"__responseFormatUndefined\" in responseFormat\n ) {\n return [];\n }\n\n /**\n * If users provide an array, it should only contain raw schemas (Zod or JSON schema),\n * not ToolStrategy or ProviderStrategy instances.\n */\n if (Array.isArray(responseFormat)) {\n /**\n * if every entry is a ToolStrategy or ProviderStrategy instance, return the array as is\n */\n if (\n responseFormat.every(\n (item) =>\n item instanceof ToolStrategy || item instanceof ProviderStrategy\n )\n ) {\n return responseFormat as unknown as ResponseFormat[];\n }\n\n /**\n * Check if all items are Zod schemas\n */\n if (responseFormat.every((item) => isInteropZodObject(item))) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as InteropZodObject, options)\n );\n }\n\n /**\n * Check if all items are plain objects (JSON schema)\n */\n if (\n responseFormat.every(\n (item) =>\n typeof item === \"object\" && item !== null && !isInteropZodObject(item)\n )\n ) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as JsonSchemaFormat, options)\n );\n }\n\n throw new Error(\n `Invalid response format: list contains mixed types.\\n` +\n `All items must be either InteropZodObject or plain JSON schema objects.`\n );\n }\n\n if (\n responseFormat instanceof ToolStrategy ||\n responseFormat instanceof ProviderStrategy\n ) {\n return [responseFormat];\n }\n\n const useProviderStrategy = hasSupportForJsonSchemaOutput(model);\n\n /**\n * `responseFormat` is a Zod schema\n */\n if (isInteropZodObject(responseFormat)) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat)]\n : [ToolStrategy.fromSchema(responseFormat, options)];\n }\n\n /**\n * Handle plain object (JSON schema)\n */\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"properties\" in responseFormat\n ) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat as JsonSchemaFormat)]\n : [ToolStrategy.fromSchema(responseFormat as JsonSchemaFormat, options)];\n }\n\n throw new Error(`Invalid response format: ${String(responseFormat)}`);\n}\n\n/**\n * Branded type for ToolStrategy arrays that preserves type information\n */\nexport interface TypedToolStrategy<T = unknown>\n extends Array<ToolStrategy<any>> {\n _schemaType?: T;\n}\nexport type ToolStrategyError =\n | StructuredOutputParsingError\n | MultipleStructuredOutputsError;\nexport interface ToolStrategyOptions {\n /**\n * Allows you to customize the message that appears in the conversation history when structured\n * output is generated.\n */\n toolMessageContent?: string;\n /**\n * Handle errors from the structured output tool call. Using tools to generate structured output\n * can cause errors, e.g. if:\n * - you provide multiple structured output schemas and the model calls multiple structured output tools\n * - if the structured output generated by the tool call doesn't match provided schema\n *\n * This property allows to handle these errors in different ways:\n * - `true` - retry the tool call\n * - `false` - throw an error\n * - `string` - retry the tool call with the provided message\n * - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error\n */\n handleError?:\n | boolean\n | string\n | ((error: ToolStrategyError) => Promise<string> | string);\n}\n\nexport function toolStrategy<T extends InteropZodType<any>>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function toolStrategy<T extends readonly InteropZodType<any>[]>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<\n { [K in keyof T]: T[K] extends InteropZodType<infer U> ? U : never }[number]\n>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat,\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\n\n/**\n * Define how to transform the response format from a tool call.\n *\n * @param responseFormat - The response format to transform\n * @param options - The options to use for the transformation\n * @param options.handleError - Whether to handle errors from the tool call\n * @returns The transformed response format\n */\nexport function toolStrategy(\n responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy {\n return transformResponseFormat(responseFormat, options) as TypedToolStrategy;\n}\n\nexport function providerStrategy<T extends InteropZodType<any>>(\n responseFormat: T\n): ProviderStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function providerStrategy(\n responseFormat: JsonSchemaFormat\n): ProviderStrategy<Record<string, unknown>>;\nexport function providerStrategy(\n responseFormat: InteropZodType<any> | JsonSchemaFormat\n): ProviderStrategy<any> {\n return ProviderStrategy.fromSchema(\n responseFormat as any\n ) as ProviderStrategy<any>;\n}\n\n/**\n * Type representing a JSON Schema object format.\n * This is a strict type that excludes ToolStrategy and ProviderStrategy instances.\n */\nexport type JsonSchemaFormat = {\n type:\n | \"null\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"number\"\n | \"string\"\n | \"integer\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n} & {\n // Brand to ensure this is not a ToolStrategy or ProviderStrategy\n __brand?: never;\n};\n\nconst CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\"ChatOpenAI\", \"ChatXAI\"];\nconst MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\n \"grok\",\n \"gpt-5\",\n \"gpt-4.1\",\n \"gpt-4o\",\n \"gpt-oss\",\n \"o3-pro\",\n \"o3-mini\",\n];\n\n/**\n * Identifies the models that support JSON schema output\n * @param model - The model to check\n * @returns True if the model supports JSON schema output, false otherwise\n */\nexport function hasSupportForJsonSchemaOutput(\n model?: LanguageModelLike | string\n): boolean {\n if (!model) {\n return false;\n }\n\n if (typeof model === \"string\") {\n const modelName = model.split(\":\").pop() as string;\n return MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) => modelName.includes(modelNameSnippet)\n );\n }\n\n if (isConfigurableModel(model)) {\n const configurableModel = model as unknown as {\n _defaultConfig: { model: string };\n };\n return hasSupportForJsonSchemaOutput(\n configurableModel._defaultConfig.model\n );\n }\n\n if (!isBaseChatModel(model)) {\n return false;\n }\n\n const chatModelClass = model.getName();\n\n /**\n * for testing purposes only\n */\n if (chatModelClass === \"FakeToolCallingChatModel\") {\n return true;\n }\n\n if (\n CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.includes(chatModelClass) &&\n /**\n * OpenAI models\n */ ((\"model\" in model &&\n MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) =>\n typeof model.model === \"string\" &&\n model.model.includes(modelNameSnippet)\n )) ||\n /**\n * for testing purposes only\n */\n (chatModelClass === \"FakeToolCallingModel\" &&\n \"structuredResponse\" in model))\n ) {\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"responses.js","names":["schema: Record<string, unknown>","tool: {\n type: \"function\";\n function: FunctionDefinition;\n }","options?: ToolStrategyOptions","schema: InteropZodObject | Record<string, unknown>","outputOptions?: ToolStrategyOptions","name?: string","asJsonSchema","tool","functionDefinition: FunctionDefinition","toolArgs: Record<string, unknown>","schema: InteropZodType<T> | Record<string, unknown>","response: AIMessage","responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined","model?: LanguageModelLike | string","responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]","responseFormat: InteropZodType<any> | JsonSchemaFormat"],"sources":["../../src/agents/responses.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-instanceof/no-instanceof */\nimport {\n InteropZodObject,\n isInteropZodSchema,\n InteropZodType,\n isInteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport { type AIMessage } from \"@langchain/core/messages\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { toJsonSchema, Validator } from \"@langchain/core/utils/json_schema\";\nimport { type FunctionDefinition } from \"@langchain/core/language_models/base\";\n\nimport {\n StructuredOutputParsingError,\n MultipleStructuredOutputsError,\n} from \"./errors.js\";\nimport { isConfigurableModel, isBaseChatModel } from \"./model.js\";\n\n/**\n * Special type to indicate that no response format is provided.\n * When this type is used, the structuredResponse property should not be present in the result.\n */\nexport type ResponseFormatUndefined = {\n __responseFormatUndefined: true;\n};\n\n/**\n * This is a global counter for generating unique names for tools.\n */\nlet bindingIdentifier = 0;\n\n/**\n * Information for tracking structured output tool metadata.\n * This contains all necessary information to handle structured responses generated\n * via tool calls, including the original schema, its type classification, and the\n * corresponding tool implementation used by the tools strategy.\n */\nexport class ToolStrategy<_T = unknown> {\n private constructor(\n /**\n * The original JSON Schema provided for structured output\n */\n public readonly schema: Record<string, unknown>,\n\n /**\n * The tool that will be used to parse the tool call arguments.\n */\n public readonly tool: {\n type: \"function\";\n function: FunctionDefinition;\n },\n\n /**\n * The options to use for the tool output.\n */\n public readonly options?: ToolStrategyOptions\n ) {}\n\n get name() {\n return this.tool.function.name;\n }\n\n static fromSchema<S extends InteropZodObject>(\n schema: S,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<S extends InteropZodType<infer U> ? U : unknown>;\n\n static fromSchema(\n schema: Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<Record<string, unknown>>;\n\n static fromSchema(\n schema: InteropZodObject | Record<string, unknown>,\n outputOptions?: ToolStrategyOptions\n ): ToolStrategy<any> {\n /**\n * It is required for tools to have a name so we can map the tool call to the correct tool\n * when parsing the response.\n */\n function getFunctionName(name?: string) {\n return name ?? `extract-${++bindingIdentifier}`;\n }\n\n if (isInteropZodSchema(schema)) {\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: {\n name: getFunctionName(),\n strict: false,\n description:\n asJsonSchema.description ??\n \"Tool for extracting structured output from the model's response.\",\n parameters: asJsonSchema,\n },\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n let functionDefinition: FunctionDefinition;\n if (\n typeof schema.name === \"string\" &&\n typeof schema.parameters === \"object\" &&\n schema.parameters != null\n ) {\n functionDefinition = schema as unknown as FunctionDefinition;\n } else {\n functionDefinition = {\n name: getFunctionName(schema.title as string),\n description: (schema.description as string) ?? \"\",\n parameters: schema.schema || (schema as Record<string, unknown>),\n };\n }\n const asJsonSchema = toJsonSchema(schema);\n const tool = {\n type: \"function\" as const,\n function: functionDefinition,\n };\n return new ToolStrategy(asJsonSchema, tool, outputOptions);\n }\n\n /**\n * Parse tool arguments according to the schema.\n *\n * @throws {StructuredOutputParsingError} if the response is not valid\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(toolArgs: Record<string, unknown>): Record<string, unknown> {\n const validator = new Validator(this.schema);\n const result = validator.validate(toolArgs);\n if (!result.valid) {\n throw new StructuredOutputParsingError(\n this.name,\n result.errors.map((e) => e.error)\n );\n }\n return toolArgs;\n }\n}\n\nexport class ProviderStrategy<T = unknown> {\n // @ts-expect-error - _schemaType is used only for type inference\n private _schemaType?: T;\n\n private constructor(public readonly schema: Record<string, unknown>) {}\n\n static fromSchema<T>(schema: InteropZodType<T>): ProviderStrategy<T>;\n\n static fromSchema(\n schema: Record<string, unknown>\n ): ProviderStrategy<Record<string, unknown>>;\n\n static fromSchema<T = unknown>(\n schema: InteropZodType<T> | Record<string, unknown>\n ): ProviderStrategy<T> | ProviderStrategy<Record<string, unknown>> {\n const asJsonSchema = toJsonSchema(schema);\n return new ProviderStrategy(asJsonSchema) as\n | ProviderStrategy<T>\n | ProviderStrategy<Record<string, unknown>>;\n }\n\n /**\n * Parse tool arguments according to the schema. If the response is not valid, return undefined.\n *\n * @param toolArgs - The arguments from the tool call\n * @returns The parsed response according to the schema type\n */\n parse(response: AIMessage) {\n /**\n * return if the response doesn't contain valid content\n */\n if (typeof response.content !== \"string\" || response.content === \"\") {\n return;\n }\n\n try {\n const content = JSON.parse(response.content);\n const validator = new Validator(this.schema);\n const result = validator.validate(content);\n if (!result.valid) {\n return;\n }\n\n return content;\n } catch {\n // no-op\n }\n }\n}\n\nexport type ResponseFormat = ToolStrategy<any> | ProviderStrategy<any>;\n\n/**\n * Handle user input for `responseFormat` parameter of `CreateAgentParams`.\n * This function defines the default behavior for the `responseFormat` parameter, which is:\n *\n * - if value is a Zod schema, default to structured output via tool calling\n * - if value is a JSON schema, default to structured output via tool calling\n * - if value is a custom response format, return it as is\n * - if value is an array, ensure all array elements are instance of `ToolStrategy`\n * @param responseFormat - The response format to transform, provided by the user\n * @param options - The response format options for tool strategy\n * @param model - The model to check if it supports JSON schema output\n * @returns\n */\nexport function transformResponseFormat(\n responseFormat?:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[]\n | ResponseFormat\n | ToolStrategy<any>[]\n | ResponseFormatUndefined,\n options?: ToolStrategyOptions,\n model?: LanguageModelLike | string\n): ResponseFormat[] {\n if (!responseFormat) {\n return [];\n }\n\n // Handle ResponseFormatUndefined case\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"__responseFormatUndefined\" in responseFormat\n ) {\n return [];\n }\n\n /**\n * If users provide an array, it should only contain raw schemas (Zod or JSON schema),\n * not ToolStrategy or ProviderStrategy instances.\n */\n if (Array.isArray(responseFormat)) {\n /**\n * if every entry is a ToolStrategy or ProviderStrategy instance, return the array as is\n */\n if (\n responseFormat.every(\n (item) =>\n item instanceof ToolStrategy || item instanceof ProviderStrategy\n )\n ) {\n return responseFormat as unknown as ResponseFormat[];\n }\n\n /**\n * Check if all items are Zod schemas\n */\n if (responseFormat.every((item) => isInteropZodObject(item))) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as InteropZodObject, options)\n );\n }\n\n /**\n * Check if all items are plain objects (JSON schema)\n */\n if (\n responseFormat.every(\n (item) =>\n typeof item === \"object\" && item !== null && !isInteropZodObject(item)\n )\n ) {\n return responseFormat.map((item) =>\n ToolStrategy.fromSchema(item as JsonSchemaFormat, options)\n );\n }\n\n throw new Error(\n `Invalid response format: list contains mixed types.\\n` +\n `All items must be either InteropZodObject or plain JSON schema objects.`\n );\n }\n\n if (\n responseFormat instanceof ToolStrategy ||\n responseFormat instanceof ProviderStrategy\n ) {\n return [responseFormat];\n }\n\n const useProviderStrategy = hasSupportForJsonSchemaOutput(model);\n\n /**\n * `responseFormat` is a Zod schema\n */\n if (isInteropZodObject(responseFormat)) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat)]\n : [ToolStrategy.fromSchema(responseFormat, options)];\n }\n\n /**\n * Handle plain object (JSON schema)\n */\n if (\n typeof responseFormat === \"object\" &&\n responseFormat !== null &&\n \"properties\" in responseFormat\n ) {\n return useProviderStrategy\n ? [ProviderStrategy.fromSchema(responseFormat as JsonSchemaFormat)]\n : [ToolStrategy.fromSchema(responseFormat as JsonSchemaFormat, options)];\n }\n\n throw new Error(`Invalid response format: ${String(responseFormat)}`);\n}\n\n/**\n * Branded type for ToolStrategy arrays that preserves type information\n */\nexport interface TypedToolStrategy<T = unknown>\n extends Array<ToolStrategy<any>> {\n _schemaType?: T;\n}\nexport type ToolStrategyError =\n | StructuredOutputParsingError\n | MultipleStructuredOutputsError;\nexport interface ToolStrategyOptions {\n /**\n * Allows you to customize the message that appears in the conversation history when structured\n * output is generated.\n */\n toolMessageContent?: string;\n /**\n * Handle errors from the structured output tool call. Using tools to generate structured output\n * can cause errors, e.g. if:\n * - you provide multiple structured output schemas and the model calls multiple structured output tools\n * - if the structured output generated by the tool call doesn't match provided schema\n *\n * This property allows to handle these errors in different ways:\n * - `true` - retry the tool call\n * - `false` - throw an error\n * - `string` - retry the tool call with the provided message\n * - `(error: ToolStrategyError) => Promise<string> | string` - retry with the provided message or throw the error\n *\n * @default true\n */\n handleError?:\n | boolean\n | string\n | ((error: ToolStrategyError) => Promise<string> | string);\n}\n\nexport function toolStrategy<T extends InteropZodType<any>>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function toolStrategy<T extends readonly InteropZodType<any>[]>(\n responseFormat: T,\n options?: ToolStrategyOptions\n): TypedToolStrategy<\n { [K in keyof T]: T[K] extends InteropZodType<infer U> ? U : never }[number]\n>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat,\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\nexport function toolStrategy(\n responseFormat: JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy<Record<string, unknown>>;\n\n/**\n * Define how to transform the response format from a tool call.\n *\n * @param responseFormat - The response format to transform\n * @param options - The options to use for the transformation\n * @param options.handleError - Whether to handle errors from the tool call\n * @returns The transformed response format\n */\nexport function toolStrategy(\n responseFormat:\n | InteropZodType<any>\n | InteropZodType<any>[]\n | JsonSchemaFormat\n | JsonSchemaFormat[],\n options?: ToolStrategyOptions\n): TypedToolStrategy {\n return transformResponseFormat(responseFormat, options) as TypedToolStrategy;\n}\n\nexport function providerStrategy<T extends InteropZodType<any>>(\n responseFormat: T\n): ProviderStrategy<T extends InteropZodType<infer U> ? U : never>;\nexport function providerStrategy(\n responseFormat: JsonSchemaFormat\n): ProviderStrategy<Record<string, unknown>>;\nexport function providerStrategy(\n responseFormat: InteropZodType<any> | JsonSchemaFormat\n): ProviderStrategy<any> {\n return ProviderStrategy.fromSchema(\n responseFormat as any\n ) as ProviderStrategy<any>;\n}\n\n/**\n * Type representing a JSON Schema object format.\n * This is a strict type that excludes ToolStrategy and ProviderStrategy instances.\n */\nexport type JsonSchemaFormat = {\n type:\n | \"null\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"number\"\n | \"string\"\n | \"integer\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n} & {\n // Brand to ensure this is not a ToolStrategy or ProviderStrategy\n __brand?: never;\n};\n\nconst CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\"ChatOpenAI\", \"ChatXAI\"];\nconst MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT = [\n \"grok\",\n \"gpt-5\",\n \"gpt-4.1\",\n \"gpt-4o\",\n \"gpt-oss\",\n \"o3-pro\",\n \"o3-mini\",\n];\n\n/**\n * Identifies the models that support JSON schema output\n * @param model - The model to check\n * @returns True if the model supports JSON schema output, false otherwise\n */\nexport function hasSupportForJsonSchemaOutput(\n model?: LanguageModelLike | string\n): boolean {\n if (!model) {\n return false;\n }\n\n if (typeof model === \"string\") {\n const modelName = model.split(\":\").pop() as string;\n return MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) => modelName.includes(modelNameSnippet)\n );\n }\n\n if (isConfigurableModel(model)) {\n const configurableModel = model as unknown as {\n _defaultConfig: { model: string };\n };\n return hasSupportForJsonSchemaOutput(\n configurableModel._defaultConfig.model\n );\n }\n\n if (!isBaseChatModel(model)) {\n return false;\n }\n\n const chatModelClass = model.getName();\n\n /**\n * for testing purposes only\n */\n if (chatModelClass === \"FakeToolCallingChatModel\") {\n return true;\n }\n\n if (\n CHAT_MODELS_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.includes(chatModelClass) &&\n /**\n * OpenAI models\n */ ((\"model\" in model &&\n MODEL_NAMES_THAT_SUPPORT_JSON_SCHEMA_OUTPUT.some(\n (modelNameSnippet) =>\n typeof model.model === \"string\" &&\n model.model.includes(modelNameSnippet)\n )) ||\n /**\n * for testing purposes only\n */\n (chatModelClass === \"FakeToolCallingModel\" &&\n \"structuredResponse\" in model))\n ) {\n return true;\n }\n\n return false;\n}\n"],"mappings":";;;;;;;;;AA8BA,IAAI,oBAAoB;;;;;;;AAQxB,IAAa,eAAb,MAAa,aAA2B;CACtC,AAAQ,YAIUA,QAKAC,MAQAC,SAChB;EAdgB;EAKA;EAQA;CACd;CAEJ,IAAI,OAAO;AACT,SAAO,KAAK,KAAK,SAAS;CAC3B;CAYD,OAAO,WACLC,QACAC,eACmB;;;;;EAKnB,SAAS,gBAAgBC,MAAe;AACtC,UAAO,QAAQ,CAAC,QAAQ,EAAE,EAAE,mBAAmB;EAChD;AAED,MAAI,mBAAmB,OAAO,EAAE;GAC9B,MAAMC,iBAAe,aAAa,OAAO;GACzC,MAAMC,SAAO;IACX,MAAM;IACN,UAAU;KACR,MAAM,iBAAiB;KACvB,QAAQ;KACR,aACED,eAAa,eACb;KACF,YAAYA;IACb;GACF;AACD,UAAO,IAAI,aAAaA,gBAAcC,QAAM;EAC7C;EAED,IAAIC;AACJ,MACE,OAAO,OAAO,SAAS,YACvB,OAAO,OAAO,eAAe,YAC7B,OAAO,cAAc,MAErB,qBAAqB;OAErB,qBAAqB;GACnB,MAAM,gBAAgB,OAAO,MAAgB;GAC7C,aAAc,OAAO,eAA0B;GAC/C,YAAY,OAAO,UAAW;EAC/B;EAEH,MAAM,eAAe,aAAa,OAAO;EACzC,MAAM,OAAO;GACX,MAAM;GACN,UAAU;EACX;AACD,SAAO,IAAI,aAAa,cAAc,MAAM;CAC7C;;;;;;;;CASD,MAAMC,UAA4D;EAChE,MAAM,YAAY,IAAI,UAAU,KAAK;EACrC,MAAM,SAAS,UAAU,SAAS,SAAS;AAC3C,MAAI,CAAC,OAAO,MACV,OAAM,IAAI,6BACR,KAAK,MACL,OAAO,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM;AAGrC,SAAO;CACR;AACF;AAED,IAAa,mBAAb,MAAa,iBAA8B;CAEzC,AAAQ;CAER,AAAQ,YAA4BT,QAAiC;EAAjC;CAAmC;CAQvE,OAAO,WACLU,QACiE;EACjE,MAAM,eAAe,aAAa,OAAO;AACzC,SAAO,IAAI,iBAAiB;CAG7B;;;;;;;CAQD,MAAMC,UAAqB;;;;AAIzB,MAAI,OAAO,SAAS,YAAY,YAAY,SAAS,YAAY,GAC/D;AAGF,MAAI;GACF,MAAM,UAAU,KAAK,MAAM,SAAS,QAAQ;GAC5C,MAAM,YAAY,IAAI,UAAU,KAAK;GACrC,MAAM,SAAS,UAAU,SAAS,QAAQ;AAC1C,OAAI,CAAC,OAAO,MACV;AAGF,UAAO;EACR,QAAO,CAEP;CACF;AACF;;;;;;;;;;;;;;AAiBD,SAAgB,wBACdC,gBAQAV,SACAW,OACkB;AAClB,KAAI,CAAC,eACH,QAAO,CAAE;AAIX,KACE,OAAO,mBAAmB,YAC1B,mBAAmB,QACnB,+BAA+B,eAE/B,QAAO,CAAE;;;;;AAOX,KAAI,MAAM,QAAQ,eAAe,EAAE;;;;AAIjC,MACE,eAAe,MACb,CAAC,SACC,gBAAgB,gBAAgB,gBAAgB,iBACnD,CAED,QAAO;;;;AAMT,MAAI,eAAe,MAAM,CAAC,SAAS,mBAAmB,KAAK,CAAC,CAC1D,QAAO,eAAe,IAAI,CAAC,SACzB,aAAa,WAAW,MAA0B,QAAQ,CAC3D;;;;AAMH,MACE,eAAe,MACb,CAAC,SACC,OAAO,SAAS,YAAY,SAAS,QAAQ,CAAC,mBAAmB,KAAK,CACzE,CAED,QAAO,eAAe,IAAI,CAAC,SACzB,aAAa,WAAW,MAA0B,QAAQ,CAC3D;AAGH,QAAM,IAAI,MACR;CAGH;AAED,KACE,0BAA0B,gBAC1B,0BAA0B,iBAE1B,QAAO,CAAC,cAAe;CAGzB,MAAM,sBAAsB,8BAA8B,MAAM;;;;AAKhE,KAAI,mBAAmB,eAAe,CACpC,QAAO,sBACH,CAAC,iBAAiB,WAAW,eAAe,AAAC,IAC7C,CAAC,aAAa,WAAW,gBAAgB,QAAQ,AAAC;;;;AAMxD,KACE,OAAO,mBAAmB,YAC1B,mBAAmB,QACnB,gBAAgB,eAEhB,QAAO,sBACH,CAAC,iBAAiB,WAAW,eAAmC,AAAC,IACjE,CAAC,aAAa,WAAW,gBAAoC,QAAQ,AAAC;AAG5E,OAAM,IAAI,MAAM,CAAC,yBAAyB,EAAE,OAAO,eAAe,EAAE;AACrE;;;;;;;;;AAiED,SAAgB,aACdC,gBAKAZ,SACmB;AACnB,QAAO,wBAAwB,gBAAgB,QAAQ;AACxD;AAQD,SAAgB,iBACda,gBACuB;AACvB,QAAO,iBAAiB,WACtB,eACD;AACF;AAwBD,MAAM,8CAA8C,CAAC,cAAc,SAAU;AAC7E,MAAM,8CAA8C;CAClD;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;;;;;AAOD,SAAgB,8BACdF,OACS;AACT,KAAI,CAAC,MACH,QAAO;AAGT,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,YAAY,MAAM,MAAM,IAAI,CAAC,KAAK;AACxC,SAAO,4CAA4C,KACjD,CAAC,qBAAqB,UAAU,SAAS,iBAAiB,CAC3D;CACF;AAED,KAAI,oBAAoB,MAAM,EAAE;EAC9B,MAAM,oBAAoB;AAG1B,SAAO,8BACL,kBAAkB,eAAe,MAClC;CACF;AAED,KAAI,CAAC,gBAAgB,MAAM,CACzB,QAAO;CAGT,MAAM,iBAAiB,MAAM,SAAS;;;;AAKtC,KAAI,mBAAmB,2BACrB,QAAO;AAGT,KACE,4CAA4C,SAAS,eAAe,KAG9D,WAAW,SACf,4CAA4C,KAC1C,CAAC,qBACC,OAAO,MAAM,UAAU,YACvB,MAAM,MAAM,SAAS,iBAAiB,CACzC,IAIA,mBAAmB,0BAClB,wBAAwB,OAE5B,QAAO;AAGT,QAAO;AACR"}
|
package/dist/agents/runtime.d.ts
CHANGED