langchain 1.5.18 → 1.5.20

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ReactAgent.js","names":["builtInState","agentConfig"],"sources":["../../src/agents/ReactAgent.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\nimport { InteropZodObject } from \"@langchain/core/utils/types\";\n\nimport {\n StateGraph,\n END,\n START,\n Send,\n Command,\n CompiledStateGraph,\n isCommand,\n type GetStateOptions,\n type LangGraphRunnableConfig,\n type StreamMode,\n type StreamOutputMap,\n type PregelOptions,\n type StreamTransformer,\n} from \"@langchain/langgraph\";\nimport type {\n BaseCheckpointSaver,\n BaseStore,\n CheckpointListOptions,\n} from \"@langchain/langgraph-checkpoint\";\nimport {\n ToolMessage,\n AIMessage,\n MessageStructure,\n} from \"@langchain/core/messages\";\nimport { IterableReadableStream } from \"@langchain/core/utils/stream\";\nimport {\n mergeConfigs,\n type Runnable,\n type RunnableConfig,\n} from \"@langchain/core/runnables\";\nimport type { StreamEvent } from \"@langchain/core/tracers/log_stream\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\nimport { createAgentState } from \"./annotation.js\";\nimport {\n isClientTool,\n validateLLMHasNoBoundTools,\n wrapToolCall,\n normalizeSystemPrompt,\n} from \"./utils.js\";\n\nimport { AgentNode, AGENT_NODE_NAME } from \"./nodes/AgentNode.js\";\nimport { ToolNode, TOOLS_NODE_NAME } from \"./nodes/ToolNode.js\";\nimport { BeforeAgentNode } from \"./nodes/BeforeAgentNode.js\";\nimport { BeforeModelNode } from \"./nodes/BeforeModelNode.js\";\nimport { AfterModelNode } from \"./nodes/AfterModelNode.js\";\nimport { AfterAgentNode } from \"./nodes/AfterAgentNode.js\";\nimport {\n initializeMiddlewareStates,\n parseJumpToTarget,\n} from \"./nodes/utils.js\";\nimport {\n createToolCallTransformer,\n createSubagentTransformer,\n type AgentRunStream,\n type InferStreamExtensions,\n} from \"./transformers/index.js\";\n\nimport type {\n WithStateGraphNodes,\n AgentTypeConfig,\n CreateAgentParams,\n ToolsToMessageToolSet,\n} from \"./types.js\";\n\nimport type { BuiltInState, JumpTo, UserInput } from \"./types.js\";\nimport type { InvokeConfiguration, StreamConfiguration } from \"./runtime.js\";\nimport type {\n AgentMiddleware,\n AnyAgentMiddleware,\n InferMiddlewareContextInputs,\n InferMiddlewareStates,\n InferMiddlewareInputStates,\n InferContextInput,\n AnyAnnotationRoot,\n InferSchemaValue,\n ToAnnotationRoot,\n} from \"./middleware/types.js\";\nimport { type ResponseFormatUndefined } from \"./responses.js\";\nimport { getHookConstraint } from \"./middleware/utils.js\";\nimport { toGraphDefaultConfig } from \"./utils.js\";\n\n/**\n * In the ReAct pattern we have three main nodes:\n * - model_request: The node that makes the model call.\n * - tools: The node that calls the tools.\n * - END: The end of the graph.\n *\n * These are the only nodes that can be jumped to from other nodes.\n */\ntype BaseGraphDestination =\n | typeof TOOLS_NODE_NAME\n | typeof AGENT_NODE_NAME\n | typeof END;\n\n// Helper type to get the state definition with middleware states\ntype MergedAgentState<Types extends AgentTypeConfig> = InferSchemaValue<\n Types[\"State\"]\n> &\n (Types[\"Response\"] extends ResponseFormatUndefined\n ? Omit<\n BuiltInState<MessageStructure<ToolsToMessageToolSet<Types[\"Tools\"]>>>,\n \"jumpTo\"\n >\n : Omit<\n BuiltInState<MessageStructure<ToolsToMessageToolSet<Types[\"Tools\"]>>>,\n \"jumpTo\"\n > & {\n structuredResponse: Types[\"Response\"];\n }) &\n InferMiddlewareStates<Types[\"Middleware\"]>;\n\ntype InvokeStateParameter<Types extends AgentTypeConfig> =\n | (UserInput<Types[\"State\"]> &\n InferMiddlewareInputStates<Types[\"Middleware\"]>)\n | Command<any, any, any>\n | null;\n\ntype AgentGraph<Types extends AgentTypeConfig> = CompiledStateGraph<\n any,\n any,\n any,\n any,\n MergedAgentState<Types>,\n ToAnnotationRoot<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n >[\"spec\"],\n unknown\n>;\n\n/**\n * ReactAgent is a production-ready ReAct (Reasoning + Acting) agent that combines\n * language models with tools and middleware.\n *\n * The agent is parameterized by a single type bag `Types` that encapsulates all\n * type information:\n *\n * @typeParam Types - An {@link AgentTypeConfig} that bundles:\n * - `Response`: The structured response type\n * - `State`: The custom state schema type\n * - `Context`: The context schema type\n * - `Middleware`: The middleware array type\n * - `Tools`: The combined tools type from agent and middleware\n *\n * @example\n * ```typescript\n * // Using the type bag pattern\n * type MyTypes = AgentTypeConfig<\n * { name: string }, // Response\n * typeof myState, // State\n * typeof myContext, // Context\n * typeof middleware, // Middleware\n * typeof tools // Tools\n * >;\n *\n * const agent: ReactAgent<MyTypes> = createAgent({ ... });\n * ```\n */\nexport class ReactAgent<\n Types extends AgentTypeConfig = AgentTypeConfig<\n Record<string, any>,\n undefined,\n AnyAnnotationRoot,\n readonly AnyAgentMiddleware[],\n readonly (ClientTool | ServerTool)[],\n ReadonlyArray<() => StreamTransformer<any>>\n >,\n> {\n /**\n * Type marker for extracting the AgentTypeConfig from a ReactAgent instance.\n * This is a phantom property used only for type inference.\n * @internal\n */\n declare readonly \"~agentTypes\": Types;\n\n #graph: CompiledStateGraph<any, any, any, any, any, any, unknown>;\n\n #toolBehaviorVersion: \"v1\" | \"v2\" = \"v2\";\n\n #agentNode: AgentNode<any, AnyAnnotationRoot>;\n\n #defaultConfig: RunnableConfig;\n\n constructor(\n public options: CreateAgentParams<\n Types[\"Response\"],\n Types[\"State\"],\n Types[\"Context\"]\n >,\n defaultConfig?: RunnableConfig\n ) {\n this.#defaultConfig = mergeConfigs(defaultConfig ?? {}, {\n metadata: { ls_integration: \"langchain_create_agent\" },\n configurable: { ls_agent_type: \"root\" },\n });\n if (options.name) {\n this.#defaultConfig = mergeConfigs(this.#defaultConfig, {\n metadata: { lc_agent_name: options.name },\n });\n }\n this.#toolBehaviorVersion = options.version ?? this.#toolBehaviorVersion;\n\n /**\n * validate that model option is provided\n */\n if (!options.model) {\n throw new Error(\"`model` option is required to create an agent.\");\n }\n\n /**\n * Check if the LLM already has bound tools and throw if it does.\n */\n if (typeof options.model !== \"string\") {\n validateLLMHasNoBoundTools(options.model);\n }\n\n /**\n * define complete list of tools based on options and middleware\n */\n const middlewareTools = (this.options.middleware\n ?.filter((m) => m.tools)\n .flatMap((m) => m.tools) ?? []) as (ClientTool | ServerTool)[];\n const toolClasses = [...(options.tools ?? []), ...middlewareTools];\n\n /**\n * If any of the tools are configured to return_directly after running,\n * our graph needs to check if these were called\n */\n const shouldReturnDirect = new Set(\n toolClasses\n .filter(isClientTool)\n .filter((tool) => \"returnDirect\" in tool && tool.returnDirect)\n .map((tool) => tool.name)\n );\n\n /**\n * Create a schema that merges agent base schema with middleware state schemas\n * Using Zod with withLangGraph ensures LangGraph Studio gets proper metadata\n */\n const hasDynamicStructuredResponse = Boolean(\n this.options.middleware?.some((middleware) => middleware.wrapModelCall)\n );\n const { state, input, output } = createAgentState<\n Types[\"State\"],\n Types[\"Middleware\"]\n >(\n this.options.responseFormat !== undefined || hasDynamicStructuredResponse,\n this.options.stateSchema as Types[\"State\"],\n this.options.middleware as Types[\"Middleware\"]\n );\n\n const workflow = new StateGraph(state, {\n input,\n output,\n context: this.options.contextSchema,\n });\n\n const allNodeWorkflows = workflow as WithStateGraphNodes<\n typeof TOOLS_NODE_NAME | typeof AGENT_NODE_NAME | string,\n typeof workflow\n >;\n\n // Generate node names for middleware nodes that have hooks\n const beforeAgentNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const beforeModelNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const afterModelNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const afterAgentNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const wrapModelCallHookMiddleware: AgentMiddleware[] = [];\n\n this.#agentNode = new AgentNode({\n model: this.options.model,\n systemMessage: normalizeSystemPrompt(this.options.systemPrompt),\n includeAgentName: this.options.includeAgentName,\n name: this.options.name,\n responseFormat: this.options.responseFormat,\n middleware: this.options.middleware,\n toolClasses,\n shouldReturnDirect,\n signal: this.options.signal,\n wrapModelCallHookMiddleware,\n });\n\n const middlewareNames = new Set<string>();\n const middleware = this.options.middleware ?? [];\n for (let i = 0; i < middleware.length; i++) {\n let beforeAgentNode: BeforeAgentNode | undefined;\n let beforeModelNode: BeforeModelNode | undefined;\n let afterModelNode: AfterModelNode | undefined;\n let afterAgentNode: AfterAgentNode | undefined;\n const m = middleware[i];\n if (middlewareNames.has(m.name)) {\n throw new Error(`Middleware ${m.name} is defined multiple times`);\n }\n\n middlewareNames.add(m.name);\n if (m.beforeAgent) {\n beforeAgentNode = new BeforeAgentNode(m);\n const name = `${m.name}.before_agent`;\n beforeAgentNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.beforeAgent),\n });\n allNodeWorkflows.addNode(\n name,\n beforeAgentNode,\n beforeAgentNode.nodeOptions\n );\n }\n if (m.beforeModel) {\n beforeModelNode = new BeforeModelNode(m);\n const name = `${m.name}.before_model`;\n beforeModelNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.beforeModel),\n });\n allNodeWorkflows.addNode(\n name,\n beforeModelNode,\n beforeModelNode.nodeOptions\n );\n }\n if (m.afterModel) {\n afterModelNode = new AfterModelNode(m);\n const name = `${m.name}.after_model`;\n afterModelNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.afterModel),\n });\n allNodeWorkflows.addNode(\n name,\n afterModelNode,\n afterModelNode.nodeOptions\n );\n }\n if (m.afterAgent) {\n afterAgentNode = new AfterAgentNode(m);\n const name = `${m.name}.after_agent`;\n afterAgentNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.afterAgent),\n });\n allNodeWorkflows.addNode(\n name,\n afterAgentNode,\n afterAgentNode.nodeOptions\n );\n }\n\n if (m.wrapModelCall) {\n wrapModelCallHookMiddleware.push(m);\n }\n }\n\n /**\n * Add Nodes\n */\n allNodeWorkflows.addNode(AGENT_NODE_NAME, this.#agentNode);\n\n /**\n * Check if any middleware has wrapToolCall defined.\n * If so, we need to create a ToolNode even without pre-registered tools\n * to allow middleware to handle dynamically registered tools.\n */\n const hasWrapToolCallMiddleware = middleware.some((m) => m.wrapToolCall);\n if (\n this.#toolBehaviorVersion === \"v1\" &&\n middleware.some(\n (m) => m.name === \"HumanInTheLoopMiddleware\" && m.wrapToolCall\n )\n ) {\n throw new Error(\n 'humanInTheLoopMiddleware({ interruptMode: \"per_call\" }) requires createAgent version \"v2\" (the default). Version \"v1\" runs every tool call in one task, so per-call interrupts would share an ID.'\n );\n }\n const clientTools = toolClasses.filter(isClientTool);\n\n /**\n * Create ToolNode if we have client-side tools OR if middleware defines wrapToolCall\n * (which may handle dynamically registered tools)\n */\n if (clientTools.length > 0 || hasWrapToolCallMiddleware) {\n const toolNode = new ToolNode(clientTools, {\n signal: this.options.signal,\n wrapToolCall: wrapToolCall(middleware),\n });\n allNodeWorkflows.addNode(TOOLS_NODE_NAME, toolNode);\n }\n\n /**\n * Add Edges\n */\n // Determine the entry node (runs once at start): before_agent -> before_model -> model_request\n let entryNode: string;\n if (beforeAgentNodes.length > 0) {\n entryNode = beforeAgentNodes[0].name;\n } else if (beforeModelNodes.length > 0) {\n entryNode = beforeModelNodes[0].name;\n } else {\n entryNode = AGENT_NODE_NAME;\n }\n\n // Determine the loop entry node (beginning of agent loop, excludes before_agent)\n // This is where tools will loop back to for the next iteration\n const loopEntryNode =\n beforeModelNodes.length > 0 ? beforeModelNodes[0].name : AGENT_NODE_NAME;\n\n // Determine the exit node (runs once at end): after_agent or END\n const exitNode =\n afterAgentNodes.length > 0\n ? afterAgentNodes[afterAgentNodes.length - 1].name\n : END;\n\n allNodeWorkflows.addEdge(START, entryNode);\n\n /**\n * Determine if we have tools available for routing.\n * This includes both registered client tools AND dynamic tools via middleware.\n */\n const hasToolsAvailable =\n clientTools.length > 0 || hasWrapToolCallMiddleware;\n\n // Connect beforeAgent nodes (run once at start)\n for (let i = 0; i < beforeAgentNodes.length; i++) {\n const node = beforeAgentNodes[i];\n const current = node.name;\n const isLast = i === beforeAgentNodes.length - 1;\n const nextDefault = isLast ? loopEntryNode : beforeAgentNodes[i + 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n // Replace END with exitNode (which could be an afterAgent node)\n const destinations = Array.from(\n new Set([\n nextDefault,\n ...allowedMapped.map((dest) => (dest === END ? exitNode : dest)),\n ])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createBeforeAgentRouter(\n clientTools,\n nextDefault,\n exitNode,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect beforeModel nodes; add conditional routing ONLY if allowed jumps are specified\n for (let i = 0; i < beforeModelNodes.length; i++) {\n const node = beforeModelNodes[i];\n const current = node.name;\n const isLast = i === beforeModelNodes.length - 1;\n const nextDefault = isLast\n ? AGENT_NODE_NAME\n : beforeModelNodes[i + 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n const destinations = Array.from(\n new Set([nextDefault, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createBeforeModelRouter(\n clientTools,\n nextDefault,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect agent to last afterModel node (for reverse order execution)\n const lastAfterModelNode = afterModelNodes.at(-1);\n if (afterModelNodes.length > 0 && lastAfterModelNode) {\n allNodeWorkflows.addEdge(AGENT_NODE_NAME, lastAfterModelNode.name);\n } else {\n // If no afterModel nodes, connect model_request directly to model paths\n const modelPaths = this.#getModelPaths(\n clientTools,\n false,\n hasToolsAvailable\n );\n // Replace END with exitNode in destinations, since exitNode might be an afterAgent node\n const destinations = modelPaths.map((p) =>\n p === END ? exitNode : p\n ) as BaseGraphDestination[];\n if (destinations.length === 1) {\n allNodeWorkflows.addEdge(AGENT_NODE_NAME, destinations[0]);\n } else {\n allNodeWorkflows.addConditionalEdges(\n AGENT_NODE_NAME,\n this.#createModelRouter(exitNode),\n destinations\n );\n }\n }\n\n // Connect afterModel nodes in reverse sequence; add conditional routing ONLY if allowed jumps are specified per node\n for (let i = afterModelNodes.length - 1; i > 0; i--) {\n const node = afterModelNodes[i];\n const current = node.name;\n const nextDefault = afterModelNodes[i - 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n const destinations = Array.from(\n new Set([nextDefault, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createAfterModelSequenceRouter(\n clientTools,\n node.allowed,\n nextDefault,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect first afterModel node (last to execute) to model paths with jumpTo support\n if (afterModelNodes.length > 0) {\n const firstAfterModel = afterModelNodes[0];\n const firstAfterModelNode = firstAfterModel.name;\n\n // Include exitNode in the paths since afterModel should be able to route to after_agent or END\n const modelPaths = this.#getModelPaths(\n clientTools,\n true,\n hasToolsAvailable\n ).filter((p) => p !== TOOLS_NODE_NAME || hasToolsAvailable);\n\n const allowJump = Boolean(\n firstAfterModel.allowed && firstAfterModel.allowed.length > 0\n );\n\n // Replace END with exitNode in destinations, since exitNode might be an afterAgent node\n const destinations = modelPaths.map((p) =>\n p === END ? exitNode : p\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n firstAfterModelNode,\n this.#createAfterModelRouter(\n clientTools,\n allowJump,\n exitNode,\n hasToolsAvailable\n ),\n destinations\n );\n }\n\n // Connect afterAgent nodes (run once at end, in reverse order like afterModel)\n for (let i = afterAgentNodes.length - 1; i > 0; i--) {\n const node = afterAgentNodes[i];\n const current = node.name;\n const nextDefault = afterAgentNodes[i - 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n const destinations = Array.from(\n new Set([nextDefault, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createAfterModelSequenceRouter(\n clientTools,\n node.allowed,\n nextDefault,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect the first afterAgent node (last to execute) to END\n if (afterAgentNodes.length > 0) {\n const firstAfterAgent = afterAgentNodes[0];\n const firstAfterAgentNode = firstAfterAgent.name;\n\n if (firstAfterAgent.allowed && firstAfterAgent.allowed.length > 0) {\n const allowedMapped = firstAfterAgent.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n\n /**\n * For after_agent, only use explicitly allowed destinations (don't add loopEntryNode)\n * The default destination (when no jump occurs) should be END\n */\n const destinations = Array.from(\n new Set([END, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n firstAfterAgentNode,\n this.#createAfterModelSequenceRouter(\n clientTools,\n firstAfterAgent.allowed,\n END as string,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(firstAfterAgentNode, END);\n }\n }\n\n /**\n * add edges for tools node (includes both registered tools and dynamic tools via middleware)\n */\n if (hasToolsAvailable) {\n // Tools should return to loop entry node (not including before_agent)\n const toolReturnTarget = loopEntryNode;\n\n if (shouldReturnDirect.size > 0) {\n allNodeWorkflows.addConditionalEdges(\n TOOLS_NODE_NAME,\n this.#createToolsRouter(\n shouldReturnDirect,\n exitNode,\n toolReturnTarget\n ),\n [toolReturnTarget, exitNode as string]\n );\n } else {\n allNodeWorkflows.addEdge(TOOLS_NODE_NAME, toolReturnTarget);\n }\n }\n\n /**\n * compile the graph with native + user-defined stream transformers\n */\n const middlewareStreamTransformers = (\n this.options.middleware ?? []\n ).flatMap((m) => m.streamTransformers ?? []);\n const compileTransformers = [\n /* built-in stream transformers */\n createToolCallTransformer([]),\n createSubagentTransformer([]),\n /* middleware stream transformers */\n ...middlewareStreamTransformers,\n /* user-defined stream transformers */\n ...(this.options.streamTransformers ?? []),\n ];\n\n this.#graph = allNodeWorkflows.compile({\n checkpointer: this.options.checkpointer,\n store: this.options.store,\n name: this.options.name,\n description: this.options.description,\n transformers: compileTransformers,\n }) as unknown as AgentGraph<Types>;\n\n /**\n * LangGraph API resolves exported agents by unwrapping ReactAgent to the\n * inner compiled graph (see langgraph-api load.utils `afterResolve`) and\n * calls streamEvents on that pregel directly. That path only sees config\n * baked into the graph via `.withConfig()`, not ReactAgent's #defaultConfig\n * merged at invoke/stream time — so propagate static defaults here.\n */\n const graphDefaultConfig = toGraphDefaultConfig(this.#defaultConfig);\n if (Object.keys(graphDefaultConfig).length > 0) {\n this.#graph = this.#graph.withConfig(graphDefaultConfig);\n }\n }\n\n /**\n * Get the compiled {@link https://docs.langchain.com/oss/javascript/langgraph/use-graph-api | StateGraph}.\n */\n get graph(): AgentGraph<Types> {\n return this.#graph;\n }\n\n get checkpointer(): BaseCheckpointSaver | boolean | undefined {\n return this.#graph.checkpointer;\n }\n\n set checkpointer(value: BaseCheckpointSaver | boolean | undefined) {\n this.#graph.checkpointer = value;\n }\n\n get store(): BaseStore | undefined {\n return this.#graph.store;\n }\n\n set store(value: BaseStore | undefined) {\n this.#graph.store = value;\n }\n\n /**\n * Creates a new ReactAgent with the given config merged into the existing config.\n * Follows the same pattern as LangGraph's Pregel.withConfig().\n *\n * The merged config is applied as a default that gets merged with any config\n * passed at invocation time (invoke/stream). Invocation-time config takes precedence.\n *\n * @param config - Configuration to merge with existing config\n * @returns A new ReactAgent instance with the merged configuration\n *\n * @example\n * ```typescript\n * const agent = createAgent({ model: \"gpt-4o\", tools: [...] });\n *\n * // Set a default recursion limit\n * const configuredAgent = agent.withConfig({ recursionLimit: 1000 });\n *\n * // Chain multiple configs\n * const debugAgent = agent\n * .withConfig({ recursionLimit: 1000 })\n * .withConfig({ tags: [\"debug\"] });\n * ```\n */\n withConfig(\n config: Omit<RunnableConfig, \"store\" | \"writer\" | \"interrupt\">\n ): ReactAgent<Types> {\n return new ReactAgent(\n this.options,\n mergeConfigs(this.#defaultConfig, config)\n );\n }\n\n #getGraphConfig(config?: RunnableConfig) {\n return mergeConfigs(\n { ...this.#defaultConfig, callbacks: undefined },\n config\n );\n }\n\n /**\n * Get possible edge destinations from model node.\n * @param toolClasses names of tools to call\n * @param includeModelRequest whether to include \"model_request\" as a valid path (for jumpTo routing)\n * @param hasToolsAvailable whether tools are available (includes dynamic tools via middleware)\n * @returns list of possible edge destinations\n */\n #getModelPaths(\n toolClasses: (ClientTool | ServerTool)[],\n includeModelRequest: boolean = false,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ): BaseGraphDestination[] {\n const paths: BaseGraphDestination[] = [];\n if (hasToolsAvailable) {\n paths.push(TOOLS_NODE_NAME);\n }\n\n if (includeModelRequest) {\n paths.push(AGENT_NODE_NAME);\n }\n\n paths.push(END);\n\n return paths;\n }\n\n /**\n * Create routing function for tools node conditional edges.\n */\n #createToolsRouter(\n shouldReturnDirect: Set<string>,\n exitNode: string | typeof END,\n toolReturnTarget: string\n ) {\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n const messages = builtInState.messages;\n const lastMessage = messages[messages.length - 1];\n\n // Check if we just executed a returnDirect tool successfully. A failed\n // call goes back to the model so it can correct itself and retry.\n if (\n ToolMessage.isInstance(lastMessage) &&\n lastMessage.name &&\n lastMessage.status !== \"error\" &&\n shouldReturnDirect.has(lastMessage.name)\n ) {\n // If we have a response format, route to agent to generate structured response\n // Otherwise, return directly to exit node (could be after_agent or END)\n return this.options.responseFormat ? toolReturnTarget : exitNode;\n }\n\n // For non-returnDirect tools, route back to loop entry node (could be middleware or agent)\n return toolReturnTarget;\n };\n }\n\n /**\n * Create routing function for model node conditional edges.\n * @param exitNode - The exit node to route to (could be after_agent or END)\n */\n #createModelRouter(exitNode: string | typeof END = END) {\n /**\n * determine if the agent should continue or not\n */\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n const messages = builtInState.messages;\n const lastMessage = messages.at(-1);\n\n if (\n !AIMessage.isInstance(lastMessage) ||\n !lastMessage.tool_calls ||\n lastMessage.tool_calls.length === 0\n ) {\n return exitNode;\n }\n\n // Check if all tool calls are for structured response extraction\n const hasOnlyStructuredResponseCalls = lastMessage.tool_calls.every(\n (toolCall) => toolCall.name.startsWith(\"extract-\")\n );\n\n if (hasOnlyStructuredResponseCalls) {\n // If all tool calls are for structured response extraction, go to exit node\n // The AgentNode will handle these internally and return the structured response\n return exitNode;\n }\n\n /**\n * The tool node processes a single message.\n */\n if (this.#toolBehaviorVersion === \"v1\") {\n return TOOLS_NODE_NAME;\n }\n\n /**\n * Route to tools node (filter out any structured response tool calls)\n */\n const regularToolCalls = lastMessage.tool_calls.filter(\n (toolCall) => !toolCall.name.startsWith(\"extract-\")\n );\n\n if (regularToolCalls.length === 0) {\n return exitNode;\n }\n\n return regularToolCalls.map(\n (toolCall) =>\n new Send(TOOLS_NODE_NAME, { ...state, lg_tool_call: toolCall })\n );\n };\n }\n\n /**\n * Create routing function for jumpTo functionality after afterModel hooks.\n *\n * This router checks if the `jumpTo` property is set in the state after afterModel middleware\n * execution. If set, it routes to the specified target (\"model_request\" or \"tools\").\n * If not set, it falls back to the normal model routing logic for afterModel context.\n *\n * The jumpTo property is automatically cleared after use to prevent infinite loops.\n *\n * @param toolClasses - Available tool classes for validation\n * @param allowJump - Whether jumping is allowed\n * @param exitNode - The exit node to route to (could be after_agent or END)\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n * @returns Router function that handles jumpTo logic and normal routing\n */\n #createAfterModelRouter(\n toolClasses: (ClientTool | ServerTool)[],\n allowJump: boolean,\n exitNode: string | typeof END,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n const hasStructuredResponse = Boolean(this.options.responseFormat);\n\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as Omit<BuiltInState, \"jumpTo\"> & {\n jumpTo?: JumpTo;\n };\n // First, check if we just processed a structured response\n // If so, ignore any existing jumpTo and go to exitNode\n const messages = builtInState.messages;\n const lastMessage = messages.at(-1);\n if (\n AIMessage.isInstance(lastMessage) &&\n (!lastMessage.tool_calls || lastMessage.tool_calls.length === 0)\n ) {\n return exitNode;\n }\n\n // Check if jumpTo is set in the state and allowed\n if (allowJump && builtInState.jumpTo) {\n const destination = parseJumpToTarget(builtInState.jumpTo);\n if (destination === END) {\n return exitNode;\n }\n if (destination === TOOLS_NODE_NAME) {\n // If trying to jump to tools but no tools are available, go to exitNode\n if (!hasToolsAvailable) {\n return exitNode;\n }\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n // destination === \"model_request\"\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n }\n\n // check if there are pending tool calls\n const toolMessages = messages.filter(ToolMessage.isInstance);\n const lastAiMessage = messages.filter(AIMessage.isInstance).at(-1);\n const pendingToolCalls = lastAiMessage?.tool_calls?.filter(\n (call) => !toolMessages.some((m) => m.tool_call_id === call.id)\n );\n if (pendingToolCalls && pendingToolCalls.length > 0) {\n /**\n * v1: route the full message to the ToolNode; it filters already-processed\n * calls internally and runs the remaining ones via Promise.all.\n * v2: dispatch each pending call as a separate Send task.\n */\n if (this.#toolBehaviorVersion === \"v1\") {\n return TOOLS_NODE_NAME;\n }\n return pendingToolCalls.map(\n (toolCall) =>\n new Send(TOOLS_NODE_NAME, { ...state, lg_tool_call: toolCall })\n );\n }\n\n // if we exhausted all tool calls, but still have no structured response tool calls,\n // go back to model_request\n const hasStructuredResponseCalls = lastAiMessage?.tool_calls?.some(\n (toolCall) => toolCall.name.startsWith(\"extract-\")\n );\n\n if (\n pendingToolCalls &&\n pendingToolCalls.length === 0 &&\n !hasStructuredResponseCalls &&\n hasStructuredResponse\n ) {\n return AGENT_NODE_NAME;\n }\n\n if (\n !AIMessage.isInstance(lastMessage) ||\n !lastMessage.tool_calls ||\n lastMessage.tool_calls.length === 0\n ) {\n return exitNode;\n }\n\n // Check if all tool calls are for structured response extraction\n const hasOnlyStructuredResponseCalls = lastMessage.tool_calls.every(\n (toolCall) => toolCall.name.startsWith(\"extract-\")\n );\n\n // Check if there are any regular tool calls (non-structured response)\n const hasRegularToolCalls = lastMessage.tool_calls.some(\n (toolCall) => !toolCall.name.startsWith(\"extract-\")\n );\n\n if (hasOnlyStructuredResponseCalls || !hasRegularToolCalls) {\n return exitNode;\n }\n\n /**\n * v1: route the full AIMessage to a single ToolNode invocation so all\n * tool calls run concurrently via Promise.all.\n *\n * v2: dispatch each regular tool call as a separate Send task, matching\n * the behaviour of #createModelRouter when no afterModel middleware is\n * present.\n */\n if (this.#toolBehaviorVersion === \"v1\") {\n return TOOLS_NODE_NAME;\n }\n\n const regularToolCalls = (lastMessage as AIMessage).tool_calls!.filter(\n (toolCall) => !toolCall.name.startsWith(\"extract-\")\n );\n\n if (regularToolCalls.length === 0) {\n return exitNode;\n }\n\n return regularToolCalls.map(\n (toolCall) =>\n new Send(TOOLS_NODE_NAME, { ...state, lg_tool_call: toolCall })\n );\n };\n }\n\n /**\n * Router for afterModel sequence nodes (connecting later middlewares to earlier ones),\n * honoring allowed jump targets and defaulting to the next node.\n * @param toolClasses - Available tool classes for validation\n * @param allowed - List of allowed jump targets\n * @param nextDefault - Default node to route to\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n */\n #createAfterModelSequenceRouter(\n toolClasses: (ClientTool | ServerTool)[],\n allowed: string[],\n nextDefault: string,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n const allowedSet = new Set(allowed.map((t) => parseJumpToTarget(t)));\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n if (builtInState.jumpTo) {\n const dest = parseJumpToTarget(builtInState.jumpTo);\n if (dest === END && allowedSet.has(END)) {\n return END;\n }\n if (dest === TOOLS_NODE_NAME && allowedSet.has(TOOLS_NODE_NAME)) {\n if (!hasToolsAvailable) return END;\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n if (dest === AGENT_NODE_NAME && allowedSet.has(AGENT_NODE_NAME)) {\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n }\n }\n return nextDefault;\n };\n }\n\n /**\n * Create routing function for jumpTo functionality after beforeAgent hooks.\n * Falls back to the default next node if no jumpTo is present.\n * When jumping to END, routes to exitNode (which could be an afterAgent node).\n * @param toolClasses - Available tool classes for validation\n * @param nextDefault - Default node to route to\n * @param exitNode - Exit node to route to (could be after_agent or END)\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n */\n #createBeforeAgentRouter(\n toolClasses: (ClientTool | ServerTool)[],\n nextDefault: string,\n exitNode: string | typeof END,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n if (!builtInState.jumpTo) {\n return nextDefault;\n }\n const destination = parseJumpToTarget(builtInState.jumpTo);\n if (destination === END) {\n /**\n * When beforeAgent jumps to END, route to exitNode (first afterAgent node)\n */\n return exitNode;\n }\n if (destination === TOOLS_NODE_NAME) {\n if (!hasToolsAvailable) {\n return exitNode;\n }\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n };\n }\n\n /**\n * Create routing function for jumpTo functionality after beforeModel hooks.\n * Falls back to the default next node if no jumpTo is present.\n * @param toolClasses - Available tool classes for validation\n * @param nextDefault - Default node to route to\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n */\n #createBeforeModelRouter(\n toolClasses: (ClientTool | ServerTool)[],\n nextDefault: string,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n if (!builtInState.jumpTo) {\n return nextDefault;\n }\n const destination = parseJumpToTarget(builtInState.jumpTo);\n if (destination === END) {\n return END;\n }\n if (destination === TOOLS_NODE_NAME) {\n if (!hasToolsAvailable) {\n return END;\n }\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n };\n }\n\n /**\n * Initialize middleware states if not already present in the input state.\n */\n async #initializeMiddlewareStates(\n state: InvokeStateParameter<Types>,\n config: RunnableConfig\n ): Promise<InvokeStateParameter<Types>> {\n if (\n !this.options.middleware ||\n this.options.middleware.length === 0 ||\n isCommand(state) ||\n !state\n ) {\n return state;\n }\n\n const defaultStates = await initializeMiddlewareStates(\n this.options.middleware,\n state\n );\n const threadState = await this.#graph\n .getState(config)\n .catch(() => ({ values: {} }));\n const updatedState = {\n ...threadState.values,\n ...state,\n } as InvokeStateParameter<Types>;\n if (!updatedState) {\n return updatedState;\n }\n\n // Only add defaults for keys that don't exist in current state\n for (const [key, value] of Object.entries(defaultStates)) {\n if (!(key in updatedState)) {\n updatedState[key as keyof typeof updatedState] = value;\n }\n }\n\n return updatedState;\n }\n\n /**\n * Executes the agent with the given state and returns the final state after all processing.\n *\n * This method runs the agent's entire workflow synchronously, including:\n * - Processing the input messages through any configured middleware\n * - Calling the language model to generate responses\n * - Executing any tool calls made by the model\n * - Running all middleware hooks (beforeModel, afterModel, etc.)\n *\n * @param state - The initial state for the agent execution. Can be:\n * - An object containing `messages` array and any middleware-specific state properties\n * - A Command object for more advanced control flow\n *\n * @param config - Optional runtime configuration including:\n * @param config.context - The context for the agent execution.\n * @param config.configurable - LangGraph configuration options like `thread_id`, `run_id`, etc.\n * @param config.store - The store for the agent execution for persisting state, see more in {@link https://docs.langchain.com/oss/javascript/langgraph/memory#memory-storage | Memory storage}.\n * @param config.signal - An optional {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | `AbortSignal`} for the agent execution.\n * @param config.recursionLimit - The recursion limit for the agent execution.\n *\n * @returns A Promise that resolves to the final agent state after execution completes.\n * The returned state includes:\n * - a `messages` property containing an array with all messages (input, AI responses, tool calls/results)\n * - a `structuredResponse` property containing the structured response (if configured)\n * - all state values defined in the middleware\n *\n * @example\n * ```typescript\n * const agent = new ReactAgent({\n * llm: myModel,\n * tools: [calculator, webSearch],\n * responseFormat: z.object({\n * weather: z.string(),\n * }),\n * });\n *\n * const result = await agent.invoke({\n * messages: [{ role: \"human\", content: \"What's the weather in Paris?\" }]\n * });\n *\n * console.log(result.structuredResponse.weather); // outputs: \"It's sunny and 75°F.\"\n * ```\n */\n async invoke(\n state: InvokeStateParameter<Types>,\n config?: InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n >\n ) {\n type FullState = MergedAgentState<Types>;\n const mergedConfig = this.#getGraphConfig(config);\n const initializedState = await this.#initializeMiddlewareStates(\n state,\n mergedConfig as RunnableConfig\n );\n\n return this.#graph.invoke(\n initializedState,\n mergedConfig\n ) as Promise<FullState>;\n }\n\n /**\n * Executes the agent with streaming, returning an async iterable of state updates as they occur.\n *\n * This method runs the agent's workflow similar to `invoke`, but instead of waiting for\n * completion, it streams high-level state updates in real-time. This allows you to:\n * - Display intermediate results to users as they're generated\n * - Monitor the agent's progress through each step\n * - React to state changes as nodes complete\n *\n * For more granular event-level streaming (like individual LLM tokens), use `streamEvents` instead.\n *\n * @param state - The initial state for the agent execution. Can be:\n * - An object containing `messages` array and any middleware-specific state properties\n * - A Command object for more advanced control flow\n *\n * @param config - Optional runtime configuration including:\n * @param config.context - The context for the agent execution.\n * @param config.configurable - LangGraph configuration options like `thread_id`, `run_id`, etc.\n * @param config.store - The store for the agent execution for persisting state, see more in {@link https://docs.langchain.com/oss/javascript/langgraph/memory#memory-storage | Memory storage}.\n * @param config.signal - An optional {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | `AbortSignal`} for the agent execution.\n * @param config.streamMode - The streaming mode for the agent execution, see more in {@link https://docs.langchain.com/oss/javascript/langgraph/streaming#supported-stream-modes | Supported stream modes}.\n * @param config.recursionLimit - The recursion limit for the agent execution.\n *\n * @returns A Promise that resolves to an IterableReadableStream of state updates.\n * Each update contains the current state after a node completes.\n *\n * @example\n * ```typescript\n * const agent = new ReactAgent({\n * llm: myModel,\n * tools: [calculator, webSearch]\n * });\n *\n * const stream = await agent.stream({\n * messages: [{ role: \"human\", content: \"What's 2+2 and the weather in NYC?\" }]\n * });\n *\n * for await (const chunk of stream) {\n * console.log(chunk); // State update from each node\n * }\n * ```\n */\n async stream<\n TStreamMode extends StreamMode | StreamMode[] | undefined,\n TSubgraphs extends boolean,\n TEncoding extends \"text/event-stream\" | undefined,\n >(\n state: InvokeStateParameter<Types>,\n config?: StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n TStreamMode,\n TSubgraphs,\n TEncoding\n >\n ) {\n const mergedConfig = this.#getGraphConfig(config);\n const initializedState = await this.#initializeMiddlewareStates(\n state,\n mergedConfig as RunnableConfig\n );\n return this.#graph.stream(initializedState, mergedConfig) as Promise<\n IterableReadableStream<\n StreamOutputMap<\n TStreamMode,\n TSubgraphs,\n MergedAgentState<Types>,\n MergedAgentState<Types>,\n string,\n unknown,\n unknown,\n TEncoding\n >\n >\n >;\n }\n\n /**\n * Executes the agent with the v3 streaming interface, returning an\n * {@link AgentRunStream} that provides ergonomic, typed projections for\n * messages, tool calls, and middleware events — without requiring knowledge\n * of Pregel channels, stream modes, or namespace routing.\n *\n * Pass `version: \"v3\"` to opt into this projection-oriented stream. Omitting\n * `version` preserves the legacy internal LangGraph event-stream behavior\n * for compatibility with LangGraph Platform integrations.\n *\n * This v3 stream is experimental and its API may change in future releases.\n * It will become the default in a future major release.\n *\n * @param state - The initial state for the agent execution. Can be:\n * - An object containing `messages` array and any middleware-specific state properties\n * - A Command object for more advanced control flow\n *\n * @param config - Runtime configuration including:\n * @param config.version - Must be `\"v3\"` to use the {@link AgentRunStream}\n * interface. The default legacy event stream is maintained for internal\n * integrations and should not be used for new user-facing agent streaming.\n * @param config.context - The context for the agent execution.\n * @param config.configurable - LangGraph configuration options like `thread_id`, `run_id`, etc.\n * @param config.store - The store for the agent execution for persisting state.\n * @param config.signal - An optional AbortSignal for the agent execution.\n * @param config.recursionLimit - The recursion limit for the agent execution.\n * @param config.transformers - Additional call-site stream transformers. These\n * run after the built-in agent transformers and any transformers registered\n * at creation time via `createAgent({ streamTransformers })`.\n *\n * @returns A Promise that resolves to an {@link AgentRunStream} providing:\n * - `run.messages` — all AI message lifecycles with streaming `.text` and `.reasoning`\n * - `run.toolCalls` — individual tool call streams with `.input`, `.output`, `.status`\n * - `run.middleware` — middleware lifecycle events (before/after agent/model)\n * - `run.values` — state snapshots (async iterable + promise-like)\n * - `run.output` — final agent state when the run completes\n * - `run.subgraphs` — child subgraph run streams\n * - `run.extensions` — merged projections from user-supplied transformers\n *\n * @example\n * ```typescript\n * const run = await agent.streamEvents(\n * {\n * messages: [{ role: \"user\", content: \"What's the weather in Paris?\" }],\n * },\n * { version: \"v3\" }\n * );\n *\n * // Stream all messages\n * for await (const msg of run.messages) {\n * for await (const token of msg.text) {\n * process.stdout.write(token);\n * }\n * }\n *\n * // Observe tool calls\n * for await (const call of run.toolCalls) {\n * console.log(`Tool: ${call.name}`, call.input);\n * console.log(`Result:`, await call.output);\n * }\n *\n * // Get final state\n * const state = await run.output;\n * ```\n */\n streamEvents(\n state: InvokeStateParameter<Types>,\n config: InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n > & {\n version: \"v3\";\n transformers?: ReadonlyArray<() => StreamTransformer<any>>;\n }\n ): Promise<\n AgentRunStream<\n MergedAgentState<Types>,\n Types[\"Tools\"],\n InferStreamExtensions<Types[\"StreamTransformers\"]>\n >\n >;\n\n streamEvents(\n state: InvokeStateParameter<Types>,\n config?: StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\" | undefined\n > & { version?: \"v1\" | \"v2\" },\n streamOptions?: Parameters<Runnable[\"streamEvents\"]>[2]\n ): IterableReadableStream<StreamEvent>;\n\n streamEvents(\n state: InvokeStateParameter<Types>,\n config:\n | (StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\" | undefined\n > & { version?: \"v1\" | \"v2\" })\n | undefined,\n streamOptions: Parameters<Runnable[\"streamEvents\"]>[2]\n ): IterableReadableStream<StreamEvent>;\n\n streamEvents(\n state: InvokeStateParameter<Types>,\n config?:\n | (InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n > & {\n version: \"v3\";\n transformers?: ReadonlyArray<() => StreamTransformer<any>>;\n })\n | (StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\" | undefined\n > & { version?: \"v1\" | \"v2\" }),\n streamOptions?: Parameters<Runnable[\"streamEvents\"]>[2]\n ):\n | Promise<\n AgentRunStream<\n MergedAgentState<Types>,\n Types[\"Tools\"],\n InferStreamExtensions<Types[\"StreamTransformers\"]>\n >\n >\n | IterableReadableStream<StreamEvent> {\n if (config?.version !== \"v3\" || streamOptions != null) {\n const mergedConfig = this.#getGraphConfig(config);\n const version =\n config?.version === \"v1\" || config?.version === \"v2\"\n ? config.version\n : \"v2\";\n return this.#graph.streamEvents(\n state,\n {\n ...(mergedConfig as Partial<\n PregelOptions<\n any,\n any,\n any,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\"\n >\n >),\n version,\n },\n streamOptions\n );\n }\n\n return (async () => {\n type FullState = MergedAgentState<Types>;\n const agentConfig = config as InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n > & {\n version: \"v3\";\n transformers?: ReadonlyArray<() => StreamTransformer<any>>;\n };\n\n const {\n transformers: callSiteTransformers,\n version: _version,\n ...restConfig\n } = agentConfig ?? {};\n const mergedConfig = this.#getGraphConfig(restConfig);\n const initializedState = await this.#initializeMiddlewareStates(\n state,\n mergedConfig as RunnableConfig\n );\n\n return (await this.#graph.streamEvents(initializedState, {\n ...(mergedConfig as Record<string, any>),\n version: \"v3\",\n transformers: callSiteTransformers,\n })) as unknown as AgentRunStream<\n FullState,\n Types[\"Tools\"],\n InferStreamExtensions<Types[\"StreamTransformers\"]>\n >;\n })();\n }\n\n /**\n * Visualize the graph as a PNG image.\n * @param params - Parameters for the drawMermaidPng method.\n * @param params.withStyles - Whether to include styles in the graph.\n * @param params.curveStyle - The style of the graph's curves.\n * @param params.nodeColors - The colors of the graph's nodes.\n * @param params.wrapLabelNWords - The maximum number of words to wrap in a node's label.\n * @param params.backgroundColor - The background color of the graph.\n * @returns PNG image as a buffer\n */\n async drawMermaidPng(params?: {\n withStyles?: boolean;\n curveStyle?: string;\n nodeColors?: Record<string, string>;\n wrapLabelNWords?: number;\n backgroundColor?: string;\n }) {\n const representation = await this.#graph.getGraphAsync();\n const image = await representation.drawMermaidPng(params);\n const arrayBuffer = await image.arrayBuffer();\n const buffer = new Uint8Array(arrayBuffer);\n return buffer;\n }\n\n /**\n * Draw the graph as a Mermaid string.\n * @param params - Parameters for the drawMermaid method.\n * @param params.withStyles - Whether to include styles in the graph.\n * @param params.curveStyle - The style of the graph's curves.\n * @param params.nodeColors - The colors of the graph's nodes.\n * @param params.wrapLabelNWords - The maximum number of words to wrap in a node's label.\n * @param params.backgroundColor - The background color of the graph.\n * @returns Mermaid string\n */\n async drawMermaid(params?: {\n withStyles?: boolean;\n curveStyle?: string;\n nodeColors?: Record<string, string>;\n wrapLabelNWords?: number;\n backgroundColor?: string;\n }) {\n const representation = await this.#graph.getGraphAsync();\n return representation.drawMermaid(params);\n }\n\n /**\n * The following are internal methods to enable support for LangGraph Platform.\n * They are not part of the createAgent public API.\n *\n * Note: we intentionally return as `never` to avoid type errors due to type inference.\n */\n /**\n * @internal\n */\n getGraphAsync(config?: RunnableConfig) {\n return this.#graph.getGraphAsync(config) as never;\n }\n /**\n * @internal\n */\n getState(config: RunnableConfig, options?: GetStateOptions) {\n return this.#graph.getState(config, options) as never;\n }\n /**\n * @internal\n */\n getStateHistory(config: RunnableConfig, options?: CheckpointListOptions) {\n return this.#graph.getStateHistory(config, options) as never;\n }\n /**\n * @internal\n */\n getSubgraphs(namespace?: string, recurse?: boolean) {\n return this.#graph.getSubgraphs(namespace, recurse) as never;\n }\n /**\n * @internal\n */\n getSubgraphsAsync(namespace?: string, recurse?: boolean) {\n return this.#graph.getSubgraphsAsync(namespace, recurse) as never;\n }\n /**\n * @internal\n */\n updateState(\n inputConfig: LangGraphRunnableConfig,\n values: Record<string, unknown> | unknown,\n asNode?: string\n ) {\n return this.#graph.updateState(inputConfig, values, asNode) as never;\n }\n\n /**\n * @internal\n */\n get builder() {\n return this.#graph.builder;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReactAgent.js","names":["builtInState","agentConfig"],"sources":["../../src/agents/ReactAgent.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\nimport { InteropZodObject } from \"@langchain/core/utils/types\";\n\nimport {\n StateGraph,\n END,\n START,\n Send,\n Command,\n CompiledStateGraph,\n isCommand,\n type GetStateOptions,\n type LangGraphRunnableConfig,\n type StreamMode,\n type StreamOutputMap,\n type PregelOptions,\n type StreamTransformer,\n} from \"@langchain/langgraph\";\nimport type {\n BaseCheckpointSaver,\n BaseStore,\n CheckpointListOptions,\n} from \"@langchain/langgraph-checkpoint\";\nimport {\n ToolMessage,\n AIMessage,\n MessageStructure,\n} from \"@langchain/core/messages\";\nimport { IterableReadableStream } from \"@langchain/core/utils/stream\";\nimport {\n mergeConfigs,\n type Runnable,\n type RunnableConfig,\n} from \"@langchain/core/runnables\";\nimport type { StreamEvent } from \"@langchain/core/tracers/log_stream\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\nimport { createAgentState } from \"./annotation.js\";\nimport {\n isClientTool,\n validateLLMHasNoBoundTools,\n wrapToolCall,\n normalizeSystemPrompt,\n} from \"./utils.js\";\n\nimport { AgentNode, AGENT_NODE_NAME } from \"./nodes/AgentNode.js\";\nimport { ToolNode, TOOLS_NODE_NAME } from \"./nodes/ToolNode.js\";\nimport { BeforeAgentNode } from \"./nodes/BeforeAgentNode.js\";\nimport { BeforeModelNode } from \"./nodes/BeforeModelNode.js\";\nimport { AfterModelNode } from \"./nodes/AfterModelNode.js\";\nimport { AfterAgentNode } from \"./nodes/AfterAgentNode.js\";\nimport {\n initializeMiddlewareStates,\n parseJumpToTarget,\n} from \"./nodes/utils.js\";\nimport {\n createToolCallTransformer,\n createSubagentTransformer,\n type AgentRunStream,\n type InferStreamExtensions,\n} from \"./transformers/index.js\";\n\nimport type {\n WithStateGraphNodes,\n AgentTypeConfig,\n CreateAgentParams,\n ToolsToMessageToolSet,\n} from \"./types.js\";\n\nimport type { BuiltInState, JumpTo, UserInput } from \"./types.js\";\nimport type { InvokeConfiguration, StreamConfiguration } from \"./runtime.js\";\nimport type {\n AgentMiddleware,\n AnyAgentMiddleware,\n InferMiddlewareContextInputs,\n InferMiddlewareStates,\n InferMiddlewareInputStates,\n InferContextInput,\n AnyAnnotationRoot,\n InferSchemaValue,\n ToAnnotationRoot,\n} from \"./middleware/types.js\";\nimport { type ResponseFormatUndefined } from \"./responses.js\";\nimport { getHookConstraint } from \"./middleware/utils.js\";\nimport { toGraphDefaultConfig } from \"./utils.js\";\n\n/**\n * In the ReAct pattern we have three main nodes:\n * - model_request: The node that makes the model call.\n * - tools: The node that calls the tools.\n * - END: The end of the graph.\n *\n * These are the only nodes that can be jumped to from other nodes.\n */\ntype BaseGraphDestination =\n | typeof TOOLS_NODE_NAME\n | typeof AGENT_NODE_NAME\n | typeof END;\n\n// Helper type to get the state definition with middleware states\ntype MergedAgentState<Types extends AgentTypeConfig> = InferSchemaValue<\n Types[\"State\"]\n> &\n (Types[\"Response\"] extends ResponseFormatUndefined\n ? Omit<\n BuiltInState<MessageStructure<ToolsToMessageToolSet<Types[\"Tools\"]>>>,\n \"jumpTo\"\n >\n : Omit<\n BuiltInState<MessageStructure<ToolsToMessageToolSet<Types[\"Tools\"]>>>,\n \"jumpTo\"\n > & {\n structuredResponse: Types[\"Response\"];\n }) &\n InferMiddlewareStates<Types[\"Middleware\"]>;\n\ntype InvokeStateParameter<Types extends AgentTypeConfig> =\n | (UserInput<Types[\"State\"]> &\n InferMiddlewareInputStates<Types[\"Middleware\"]>)\n | Command<any, any, any>\n | null;\n\ntype AgentGraph<Types extends AgentTypeConfig> = CompiledStateGraph<\n any,\n any,\n any,\n any,\n MergedAgentState<Types>,\n ToAnnotationRoot<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n >[\"spec\"],\n unknown\n>;\n\n/**\n * ReactAgent is a production-ready ReAct (Reasoning + Acting) agent that combines\n * language models with tools and middleware.\n *\n * The agent is parameterized by a single type bag `Types` that encapsulates all\n * type information:\n *\n * @typeParam Types - An {@link AgentTypeConfig} that bundles:\n * - `Response`: The structured response type\n * - `State`: The custom state schema type\n * - `Context`: The context schema type\n * - `Middleware`: The middleware array type\n * - `Tools`: The combined tools type from agent and middleware\n *\n * @example\n * ```typescript\n * // Using the type bag pattern\n * type MyTypes = AgentTypeConfig<\n * { name: string }, // Response\n * typeof myState, // State\n * typeof myContext, // Context\n * typeof middleware, // Middleware\n * typeof tools // Tools\n * >;\n *\n * const agent: ReactAgent<MyTypes> = createAgent({ ... });\n * ```\n */\nexport class ReactAgent<\n Types extends AgentTypeConfig = AgentTypeConfig<\n Record<string, any>,\n undefined,\n AnyAnnotationRoot,\n readonly AnyAgentMiddleware[],\n readonly (ClientTool | ServerTool)[],\n ReadonlyArray<() => StreamTransformer<any>>\n >,\n> {\n /**\n * Type marker for extracting the AgentTypeConfig from a ReactAgent instance.\n * This is a phantom property used only for type inference.\n * @internal\n */\n declare readonly \"~agentTypes\": Types;\n\n #graph: CompiledStateGraph<any, any, any, any, any, any, unknown>;\n\n #toolBehaviorVersion: \"v1\" | \"v2\" = \"v2\";\n\n #agentNode: AgentNode<any, AnyAnnotationRoot>;\n\n #defaultConfig: RunnableConfig;\n\n constructor(\n public options: CreateAgentParams<\n Types[\"Response\"],\n Types[\"State\"],\n Types[\"Context\"]\n >,\n defaultConfig?: RunnableConfig\n ) {\n this.#defaultConfig = mergeConfigs(defaultConfig ?? {}, {\n metadata: { ls_integration: \"langchain_create_agent\" },\n configurable: { ls_agent_type: \"root\" },\n });\n if (options.name) {\n this.#defaultConfig = mergeConfigs(this.#defaultConfig, {\n metadata: { lc_agent_name: options.name },\n });\n }\n this.#toolBehaviorVersion = options.version ?? this.#toolBehaviorVersion;\n\n /**\n * validate that model option is provided\n */\n if (!options.model) {\n throw new Error(\"`model` option is required to create an agent.\");\n }\n\n /**\n * Check if the LLM already has bound tools and throw if it does.\n */\n if (typeof options.model !== \"string\") {\n validateLLMHasNoBoundTools(options.model);\n }\n\n /**\n * define complete list of tools based on options and middleware\n */\n const middlewareTools = (this.options.middleware\n ?.filter((m) => m.tools)\n .flatMap((m) => m.tools) ?? []) as (ClientTool | ServerTool)[];\n const toolClasses = [...(options.tools ?? []), ...middlewareTools];\n\n /**\n * If any of the tools are configured to return_directly after running,\n * our graph needs to check if these were called\n */\n const shouldReturnDirect = new Set(\n toolClasses\n .filter(isClientTool)\n .filter((tool) => \"returnDirect\" in tool && tool.returnDirect)\n .map((tool) => tool.name)\n );\n\n /**\n * Create a schema that merges agent base schema with middleware state schemas\n * Using Zod with withLangGraph ensures LangGraph Studio gets proper metadata\n */\n const hasDynamicStructuredResponse = Boolean(\n this.options.middleware?.some((middleware) => middleware.wrapModelCall)\n );\n const { state, input, output } = createAgentState<\n Types[\"State\"],\n Types[\"Middleware\"]\n >(\n this.options.responseFormat !== undefined || hasDynamicStructuredResponse,\n this.options.stateSchema as Types[\"State\"],\n this.options.middleware as Types[\"Middleware\"]\n );\n\n const workflow = new StateGraph(state, {\n input,\n output,\n context: this.options.contextSchema,\n });\n\n const allNodeWorkflows = workflow as WithStateGraphNodes<\n typeof TOOLS_NODE_NAME | typeof AGENT_NODE_NAME | string,\n typeof workflow\n >;\n\n // Generate node names for middleware nodes that have hooks\n const beforeAgentNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const beforeModelNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const afterModelNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const afterAgentNodes: {\n index: number;\n name: string;\n allowed?: string[];\n }[] = [];\n const wrapModelCallHookMiddleware: AgentMiddleware[] = [];\n\n this.#agentNode = new AgentNode({\n model: this.options.model,\n systemMessage: normalizeSystemPrompt(this.options.systemPrompt),\n includeAgentName: this.options.includeAgentName,\n name: this.options.name,\n responseFormat: this.options.responseFormat,\n middleware: this.options.middleware,\n toolClasses,\n shouldReturnDirect,\n signal: this.options.signal,\n wrapModelCallHookMiddleware,\n });\n\n const middlewareNames = new Set<string>();\n const middleware = this.options.middleware ?? [];\n for (let i = 0; i < middleware.length; i++) {\n let beforeAgentNode: BeforeAgentNode | undefined;\n let beforeModelNode: BeforeModelNode | undefined;\n let afterModelNode: AfterModelNode | undefined;\n let afterAgentNode: AfterAgentNode | undefined;\n const m = middleware[i];\n if (middlewareNames.has(m.name)) {\n throw new Error(`Middleware ${m.name} is defined multiple times`);\n }\n\n middlewareNames.add(m.name);\n if (m.beforeAgent) {\n beforeAgentNode = new BeforeAgentNode(m);\n const name = `${m.name}.before_agent`;\n beforeAgentNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.beforeAgent),\n });\n allNodeWorkflows.addNode(\n name,\n beforeAgentNode,\n beforeAgentNode.nodeOptions\n );\n }\n if (m.beforeModel) {\n beforeModelNode = new BeforeModelNode(m);\n const name = `${m.name}.before_model`;\n beforeModelNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.beforeModel),\n });\n allNodeWorkflows.addNode(\n name,\n beforeModelNode,\n beforeModelNode.nodeOptions\n );\n }\n if (m.afterModel) {\n afterModelNode = new AfterModelNode(m);\n const name = `${m.name}.after_model`;\n afterModelNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.afterModel),\n });\n allNodeWorkflows.addNode(\n name,\n afterModelNode,\n afterModelNode.nodeOptions\n );\n }\n if (m.afterAgent) {\n afterAgentNode = new AfterAgentNode(m);\n const name = `${m.name}.after_agent`;\n afterAgentNodes.push({\n index: i,\n name,\n allowed: getHookConstraint(m.afterAgent),\n });\n allNodeWorkflows.addNode(\n name,\n afterAgentNode,\n afterAgentNode.nodeOptions\n );\n }\n\n if (m.wrapModelCall) {\n wrapModelCallHookMiddleware.push(m);\n }\n }\n\n /**\n * Add Nodes\n */\n allNodeWorkflows.addNode(AGENT_NODE_NAME, this.#agentNode);\n\n /**\n * Check if any middleware has wrapToolCall defined.\n * If so, we need to create a ToolNode even without pre-registered tools\n * to allow middleware to handle dynamically registered tools.\n */\n const hasWrapToolCallMiddleware = middleware.some((m) => m.wrapToolCall);\n if (\n this.#toolBehaviorVersion === \"v1\" &&\n middleware.some(\n (m) => m.name === \"HumanInTheLoopMiddleware\" && m.wrapToolCall\n )\n ) {\n throw new Error(\n 'humanInTheLoopMiddleware({ interruptMode: \"per_call\" }) requires createAgent version \"v2\" (the default). Version \"v1\" runs every tool call in one task, so per-call interrupts would share an ID.'\n );\n }\n const clientTools = toolClasses.filter(isClientTool);\n\n /**\n * Create ToolNode if we have client-side tools OR if middleware defines wrapToolCall\n * (which may handle dynamically registered tools)\n */\n if (clientTools.length > 0 || hasWrapToolCallMiddleware) {\n const toolNode = new ToolNode(clientTools, {\n signal: this.options.signal,\n wrapToolCall: wrapToolCall(middleware),\n stateKeys: Object.keys(workflow.channels).filter(\n (key) => key !== \"jumpTo\"\n ),\n });\n allNodeWorkflows.addNode(TOOLS_NODE_NAME, toolNode);\n }\n\n /**\n * Add Edges\n */\n // Determine the entry node (runs once at start): before_agent -> before_model -> model_request\n let entryNode: string;\n if (beforeAgentNodes.length > 0) {\n entryNode = beforeAgentNodes[0].name;\n } else if (beforeModelNodes.length > 0) {\n entryNode = beforeModelNodes[0].name;\n } else {\n entryNode = AGENT_NODE_NAME;\n }\n\n // Determine the loop entry node (beginning of agent loop, excludes before_agent)\n // This is where tools will loop back to for the next iteration\n const loopEntryNode =\n beforeModelNodes.length > 0 ? beforeModelNodes[0].name : AGENT_NODE_NAME;\n\n // Determine the exit node (runs once at end): after_agent or END\n const exitNode =\n afterAgentNodes.length > 0\n ? afterAgentNodes[afterAgentNodes.length - 1].name\n : END;\n\n allNodeWorkflows.addEdge(START, entryNode);\n\n /**\n * Determine if we have tools available for routing.\n * This includes both registered client tools AND dynamic tools via middleware.\n */\n const hasToolsAvailable =\n clientTools.length > 0 || hasWrapToolCallMiddleware;\n\n // Connect beforeAgent nodes (run once at start)\n for (let i = 0; i < beforeAgentNodes.length; i++) {\n const node = beforeAgentNodes[i];\n const current = node.name;\n const isLast = i === beforeAgentNodes.length - 1;\n const nextDefault = isLast ? loopEntryNode : beforeAgentNodes[i + 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n // Replace END with exitNode (which could be an afterAgent node)\n const destinations = Array.from(\n new Set([\n nextDefault,\n ...allowedMapped.map((dest) => (dest === END ? exitNode : dest)),\n ])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createBeforeAgentRouter(\n clientTools,\n nextDefault,\n exitNode,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect beforeModel nodes; add conditional routing ONLY if allowed jumps are specified\n for (let i = 0; i < beforeModelNodes.length; i++) {\n const node = beforeModelNodes[i];\n const current = node.name;\n const isLast = i === beforeModelNodes.length - 1;\n const nextDefault = isLast\n ? AGENT_NODE_NAME\n : beforeModelNodes[i + 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n const destinations = Array.from(\n new Set([nextDefault, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createBeforeModelRouter(\n clientTools,\n nextDefault,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect agent to last afterModel node (for reverse order execution)\n const lastAfterModelNode = afterModelNodes.at(-1);\n if (afterModelNodes.length > 0 && lastAfterModelNode) {\n allNodeWorkflows.addEdge(AGENT_NODE_NAME, lastAfterModelNode.name);\n } else {\n // If no afterModel nodes, connect model_request directly to model paths\n const modelPaths = this.#getModelPaths(\n clientTools,\n false,\n hasToolsAvailable\n );\n // Replace END with exitNode in destinations, since exitNode might be an afterAgent node\n const destinations = modelPaths.map((p) =>\n p === END ? exitNode : p\n ) as BaseGraphDestination[];\n if (destinations.length === 1) {\n allNodeWorkflows.addEdge(AGENT_NODE_NAME, destinations[0]);\n } else {\n allNodeWorkflows.addConditionalEdges(\n AGENT_NODE_NAME,\n this.#createModelRouter(exitNode),\n destinations\n );\n }\n }\n\n // Connect afterModel nodes in reverse sequence; add conditional routing ONLY if allowed jumps are specified per node\n for (let i = afterModelNodes.length - 1; i > 0; i--) {\n const node = afterModelNodes[i];\n const current = node.name;\n const nextDefault = afterModelNodes[i - 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n const destinations = Array.from(\n new Set([nextDefault, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createAfterModelSequenceRouter(\n clientTools,\n node.allowed,\n nextDefault,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect first afterModel node (last to execute) to model paths with jumpTo support\n if (afterModelNodes.length > 0) {\n const firstAfterModel = afterModelNodes[0];\n const firstAfterModelNode = firstAfterModel.name;\n\n // Include exitNode in the paths since afterModel should be able to route to after_agent or END\n const modelPaths = this.#getModelPaths(\n clientTools,\n true,\n hasToolsAvailable\n ).filter((p) => p !== TOOLS_NODE_NAME || hasToolsAvailable);\n\n const allowJump = Boolean(\n firstAfterModel.allowed && firstAfterModel.allowed.length > 0\n );\n\n // Replace END with exitNode in destinations, since exitNode might be an afterAgent node\n const destinations = modelPaths.map((p) =>\n p === END ? exitNode : p\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n firstAfterModelNode,\n this.#createAfterModelRouter(\n clientTools,\n allowJump,\n exitNode,\n hasToolsAvailable\n ),\n destinations\n );\n }\n\n // Connect afterAgent nodes (run once at end, in reverse order like afterModel)\n for (let i = afterAgentNodes.length - 1; i > 0; i--) {\n const node = afterAgentNodes[i];\n const current = node.name;\n const nextDefault = afterAgentNodes[i - 1].name;\n\n if (node.allowed && node.allowed.length > 0) {\n const allowedMapped = node.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n const destinations = Array.from(\n new Set([nextDefault, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n current,\n this.#createAfterModelSequenceRouter(\n clientTools,\n node.allowed,\n nextDefault,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(current, nextDefault);\n }\n }\n\n // Connect the first afterAgent node (last to execute) to END\n if (afterAgentNodes.length > 0) {\n const firstAfterAgent = afterAgentNodes[0];\n const firstAfterAgentNode = firstAfterAgent.name;\n\n if (firstAfterAgent.allowed && firstAfterAgent.allowed.length > 0) {\n const allowedMapped = firstAfterAgent.allowed\n .map((t) => parseJumpToTarget(t))\n .filter((dest) => dest !== TOOLS_NODE_NAME || hasToolsAvailable);\n\n /**\n * For after_agent, only use explicitly allowed destinations (don't add loopEntryNode)\n * The default destination (when no jump occurs) should be END\n */\n const destinations = Array.from(\n new Set([END, ...allowedMapped])\n ) as BaseGraphDestination[];\n\n allNodeWorkflows.addConditionalEdges(\n firstAfterAgentNode,\n this.#createAfterModelSequenceRouter(\n clientTools,\n firstAfterAgent.allowed,\n END as string,\n hasToolsAvailable\n ),\n destinations\n );\n } else {\n allNodeWorkflows.addEdge(firstAfterAgentNode, END);\n }\n }\n\n /**\n * add edges for tools node (includes both registered tools and dynamic tools via middleware)\n */\n if (hasToolsAvailable) {\n // Tools should return to loop entry node (not including before_agent)\n const toolReturnTarget = loopEntryNode;\n\n if (shouldReturnDirect.size > 0) {\n allNodeWorkflows.addConditionalEdges(\n TOOLS_NODE_NAME,\n this.#createToolsRouter(\n shouldReturnDirect,\n exitNode,\n toolReturnTarget\n ),\n [toolReturnTarget, exitNode as string]\n );\n } else {\n allNodeWorkflows.addEdge(TOOLS_NODE_NAME, toolReturnTarget);\n }\n }\n\n /**\n * compile the graph with native + user-defined stream transformers\n */\n const middlewareStreamTransformers = (\n this.options.middleware ?? []\n ).flatMap((m) => m.streamTransformers ?? []);\n const compileTransformers = [\n /* built-in stream transformers */\n createToolCallTransformer([]),\n createSubagentTransformer([]),\n /* middleware stream transformers */\n ...middlewareStreamTransformers,\n /* user-defined stream transformers */\n ...(this.options.streamTransformers ?? []),\n ];\n\n this.#graph = allNodeWorkflows.compile({\n checkpointer: this.options.checkpointer,\n store: this.options.store,\n name: this.options.name,\n description: this.options.description,\n transformers: compileTransformers,\n }) as unknown as AgentGraph<Types>;\n\n /**\n * LangGraph API resolves exported agents by unwrapping ReactAgent to the\n * inner compiled graph (see langgraph-api load.utils `afterResolve`) and\n * calls streamEvents on that pregel directly. That path only sees config\n * baked into the graph via `.withConfig()`, not ReactAgent's #defaultConfig\n * merged at invoke/stream time — so propagate static defaults here.\n */\n const graphDefaultConfig = toGraphDefaultConfig(this.#defaultConfig);\n if (Object.keys(graphDefaultConfig).length > 0) {\n this.#graph = this.#graph.withConfig(graphDefaultConfig);\n }\n }\n\n /**\n * Get the compiled {@link https://docs.langchain.com/oss/javascript/langgraph/use-graph-api | StateGraph}.\n */\n get graph(): AgentGraph<Types> {\n return this.#graph;\n }\n\n get checkpointer(): BaseCheckpointSaver | boolean | undefined {\n return this.#graph.checkpointer;\n }\n\n set checkpointer(value: BaseCheckpointSaver | boolean | undefined) {\n this.#graph.checkpointer = value;\n }\n\n get store(): BaseStore | undefined {\n return this.#graph.store;\n }\n\n set store(value: BaseStore | undefined) {\n this.#graph.store = value;\n }\n\n /**\n * Creates a new ReactAgent with the given config merged into the existing config.\n * Follows the same pattern as LangGraph's Pregel.withConfig().\n *\n * The merged config is applied as a default that gets merged with any config\n * passed at invocation time (invoke/stream). Invocation-time config takes precedence.\n *\n * @param config - Configuration to merge with existing config\n * @returns A new ReactAgent instance with the merged configuration\n *\n * @example\n * ```typescript\n * const agent = createAgent({ model: \"gpt-4o\", tools: [...] });\n *\n * // Set a default recursion limit\n * const configuredAgent = agent.withConfig({ recursionLimit: 1000 });\n *\n * // Chain multiple configs\n * const debugAgent = agent\n * .withConfig({ recursionLimit: 1000 })\n * .withConfig({ tags: [\"debug\"] });\n * ```\n */\n withConfig(\n config: Omit<RunnableConfig, \"store\" | \"writer\" | \"interrupt\">\n ): ReactAgent<Types> {\n return new ReactAgent(\n this.options,\n mergeConfigs(this.#defaultConfig, config)\n );\n }\n\n #getGraphConfig(config?: RunnableConfig) {\n return mergeConfigs(\n { ...this.#defaultConfig, callbacks: undefined },\n config\n );\n }\n\n /**\n * Get possible edge destinations from model node.\n * @param toolClasses names of tools to call\n * @param includeModelRequest whether to include \"model_request\" as a valid path (for jumpTo routing)\n * @param hasToolsAvailable whether tools are available (includes dynamic tools via middleware)\n * @returns list of possible edge destinations\n */\n #getModelPaths(\n toolClasses: (ClientTool | ServerTool)[],\n includeModelRequest: boolean = false,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ): BaseGraphDestination[] {\n const paths: BaseGraphDestination[] = [];\n if (hasToolsAvailable) {\n paths.push(TOOLS_NODE_NAME);\n }\n\n if (includeModelRequest) {\n paths.push(AGENT_NODE_NAME);\n }\n\n paths.push(END);\n\n return paths;\n }\n\n /**\n * Create routing function for tools node conditional edges.\n */\n #createToolsRouter(\n shouldReturnDirect: Set<string>,\n exitNode: string | typeof END,\n toolReturnTarget: string\n ) {\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n const messages = builtInState.messages;\n const lastMessage = messages[messages.length - 1];\n\n // Check if we just executed a returnDirect tool successfully. A failed\n // call goes back to the model so it can correct itself and retry.\n if (\n ToolMessage.isInstance(lastMessage) &&\n lastMessage.name &&\n lastMessage.status !== \"error\" &&\n shouldReturnDirect.has(lastMessage.name)\n ) {\n // If we have a response format, route to agent to generate structured response\n // Otherwise, return directly to exit node (could be after_agent or END)\n return this.options.responseFormat ? toolReturnTarget : exitNode;\n }\n\n // For non-returnDirect tools, route back to loop entry node (could be middleware or agent)\n return toolReturnTarget;\n };\n }\n\n /**\n * Create routing function for model node conditional edges.\n * @param exitNode - The exit node to route to (could be after_agent or END)\n */\n #createModelRouter(exitNode: string | typeof END = END) {\n /**\n * determine if the agent should continue or not\n */\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n const messages = builtInState.messages;\n const lastMessage = messages.at(-1);\n\n if (\n !AIMessage.isInstance(lastMessage) ||\n !lastMessage.tool_calls ||\n lastMessage.tool_calls.length === 0\n ) {\n return exitNode;\n }\n\n // Check if all tool calls are for structured response extraction\n const hasOnlyStructuredResponseCalls = lastMessage.tool_calls.every(\n (toolCall) => toolCall.name.startsWith(\"extract-\")\n );\n\n if (hasOnlyStructuredResponseCalls) {\n // If all tool calls are for structured response extraction, go to exit node\n // The AgentNode will handle these internally and return the structured response\n return exitNode;\n }\n\n /**\n * The tool node processes a single message.\n */\n if (this.#toolBehaviorVersion === \"v1\") {\n return TOOLS_NODE_NAME;\n }\n\n /**\n * Route to tools node (filter out any structured response tool calls)\n */\n const regularToolCalls = lastMessage.tool_calls.filter(\n (toolCall) => !toolCall.name.startsWith(\"extract-\")\n );\n\n if (regularToolCalls.length === 0) {\n return exitNode;\n }\n\n return regularToolCalls.map(\n (toolCall) => new Send(TOOLS_NODE_NAME, { lg_tool_call: toolCall })\n );\n };\n }\n\n /**\n * Create routing function for jumpTo functionality after afterModel hooks.\n *\n * This router checks if the `jumpTo` property is set in the state after afterModel middleware\n * execution. If set, it routes to the specified target (\"model_request\" or \"tools\").\n * If not set, it falls back to the normal model routing logic for afterModel context.\n *\n * The jumpTo property is automatically cleared after use to prevent infinite loops.\n *\n * @param toolClasses - Available tool classes for validation\n * @param allowJump - Whether jumping is allowed\n * @param exitNode - The exit node to route to (could be after_agent or END)\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n * @returns Router function that handles jumpTo logic and normal routing\n */\n #createAfterModelRouter(\n toolClasses: (ClientTool | ServerTool)[],\n allowJump: boolean,\n exitNode: string | typeof END,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n const hasStructuredResponse = Boolean(this.options.responseFormat);\n\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as Omit<BuiltInState, \"jumpTo\"> & {\n jumpTo?: JumpTo;\n };\n // First, check if we just processed a structured response\n // If so, ignore any existing jumpTo and go to exitNode\n const messages = builtInState.messages;\n const lastMessage = messages.at(-1);\n if (\n AIMessage.isInstance(lastMessage) &&\n (!lastMessage.tool_calls || lastMessage.tool_calls.length === 0)\n ) {\n return exitNode;\n }\n\n // Check if jumpTo is set in the state and allowed\n if (allowJump && builtInState.jumpTo) {\n const destination = parseJumpToTarget(builtInState.jumpTo);\n if (destination === END) {\n return exitNode;\n }\n if (destination === TOOLS_NODE_NAME) {\n // If trying to jump to tools but no tools are available, go to exitNode\n if (!hasToolsAvailable) {\n return exitNode;\n }\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n // destination === \"model_request\"\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n }\n\n // check if there are pending tool calls\n const toolMessages = messages.filter(ToolMessage.isInstance);\n const lastAiMessage = messages.filter(AIMessage.isInstance).at(-1);\n const pendingToolCalls = lastAiMessage?.tool_calls?.filter(\n (call) => !toolMessages.some((m) => m.tool_call_id === call.id)\n );\n if (pendingToolCalls && pendingToolCalls.length > 0) {\n /**\n * v1: route the full message to the ToolNode; it filters already-processed\n * calls internally and runs the remaining ones via Promise.all.\n * v2: dispatch each pending call as a separate Send task.\n */\n if (this.#toolBehaviorVersion === \"v1\") {\n return TOOLS_NODE_NAME;\n }\n return pendingToolCalls.map(\n (toolCall) => new Send(TOOLS_NODE_NAME, { lg_tool_call: toolCall })\n );\n }\n\n // if we exhausted all tool calls, but still have no structured response tool calls,\n // go back to model_request\n const hasStructuredResponseCalls = lastAiMessage?.tool_calls?.some(\n (toolCall) => toolCall.name.startsWith(\"extract-\")\n );\n\n if (\n pendingToolCalls &&\n pendingToolCalls.length === 0 &&\n !hasStructuredResponseCalls &&\n hasStructuredResponse\n ) {\n return AGENT_NODE_NAME;\n }\n\n if (\n !AIMessage.isInstance(lastMessage) ||\n !lastMessage.tool_calls ||\n lastMessage.tool_calls.length === 0\n ) {\n return exitNode;\n }\n\n // Check if all tool calls are for structured response extraction\n const hasOnlyStructuredResponseCalls = lastMessage.tool_calls.every(\n (toolCall) => toolCall.name.startsWith(\"extract-\")\n );\n\n // Check if there are any regular tool calls (non-structured response)\n const hasRegularToolCalls = lastMessage.tool_calls.some(\n (toolCall) => !toolCall.name.startsWith(\"extract-\")\n );\n\n if (hasOnlyStructuredResponseCalls || !hasRegularToolCalls) {\n return exitNode;\n }\n\n /**\n * v1: route the full AIMessage to a single ToolNode invocation so all\n * tool calls run concurrently via Promise.all.\n *\n * v2: dispatch each regular tool call as a separate Send task, matching\n * the behaviour of #createModelRouter when no afterModel middleware is\n * present.\n */\n if (this.#toolBehaviorVersion === \"v1\") {\n return TOOLS_NODE_NAME;\n }\n\n const regularToolCalls = (lastMessage as AIMessage).tool_calls!.filter(\n (toolCall) => !toolCall.name.startsWith(\"extract-\")\n );\n\n if (regularToolCalls.length === 0) {\n return exitNode;\n }\n\n return regularToolCalls.map(\n (toolCall) => new Send(TOOLS_NODE_NAME, { lg_tool_call: toolCall })\n );\n };\n }\n\n /**\n * Router for afterModel sequence nodes (connecting later middlewares to earlier ones),\n * honoring allowed jump targets and defaulting to the next node.\n * @param toolClasses - Available tool classes for validation\n * @param allowed - List of allowed jump targets\n * @param nextDefault - Default node to route to\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n */\n #createAfterModelSequenceRouter(\n toolClasses: (ClientTool | ServerTool)[],\n allowed: string[],\n nextDefault: string,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n const allowedSet = new Set(allowed.map((t) => parseJumpToTarget(t)));\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n if (builtInState.jumpTo) {\n const dest = parseJumpToTarget(builtInState.jumpTo);\n if (dest === END && allowedSet.has(END)) {\n return END;\n }\n if (dest === TOOLS_NODE_NAME && allowedSet.has(TOOLS_NODE_NAME)) {\n if (!hasToolsAvailable) return END;\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n if (dest === AGENT_NODE_NAME && allowedSet.has(AGENT_NODE_NAME)) {\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n }\n }\n return nextDefault;\n };\n }\n\n /**\n * Create routing function for jumpTo functionality after beforeAgent hooks.\n * Falls back to the default next node if no jumpTo is present.\n * When jumping to END, routes to exitNode (which could be an afterAgent node).\n * @param toolClasses - Available tool classes for validation\n * @param nextDefault - Default node to route to\n * @param exitNode - Exit node to route to (could be after_agent or END)\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n */\n #createBeforeAgentRouter(\n toolClasses: (ClientTool | ServerTool)[],\n nextDefault: string,\n exitNode: string | typeof END,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n if (!builtInState.jumpTo) {\n return nextDefault;\n }\n const destination = parseJumpToTarget(builtInState.jumpTo);\n if (destination === END) {\n /**\n * When beforeAgent jumps to END, route to exitNode (first afterAgent node)\n */\n return exitNode;\n }\n if (destination === TOOLS_NODE_NAME) {\n if (!hasToolsAvailable) {\n return exitNode;\n }\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n };\n }\n\n /**\n * Create routing function for jumpTo functionality after beforeModel hooks.\n * Falls back to the default next node if no jumpTo is present.\n * @param toolClasses - Available tool classes for validation\n * @param nextDefault - Default node to route to\n * @param hasToolsAvailable - Whether tools are available (includes dynamic tools via middleware)\n */\n #createBeforeModelRouter(\n toolClasses: (ClientTool | ServerTool)[],\n nextDefault: string,\n hasToolsAvailable: boolean = toolClasses.length > 0\n ) {\n return (state: Record<string, unknown>) => {\n const builtInState = state as unknown as BuiltInState;\n if (!builtInState.jumpTo) {\n return nextDefault;\n }\n const destination = parseJumpToTarget(builtInState.jumpTo);\n if (destination === END) {\n return END;\n }\n if (destination === TOOLS_NODE_NAME) {\n if (!hasToolsAvailable) {\n return END;\n }\n return new Send(TOOLS_NODE_NAME, { ...state, jumpTo: undefined });\n }\n return new Send(AGENT_NODE_NAME, { ...state, jumpTo: undefined });\n };\n }\n\n /**\n * Initialize middleware states if not already present in the input state.\n */\n async #initializeMiddlewareStates(\n state: InvokeStateParameter<Types>,\n config: RunnableConfig\n ): Promise<InvokeStateParameter<Types>> {\n if (\n !this.options.middleware ||\n this.options.middleware.length === 0 ||\n isCommand(state) ||\n !state\n ) {\n return state;\n }\n\n const defaultStates = await initializeMiddlewareStates(\n this.options.middleware,\n state\n );\n const threadState = await this.#graph\n .getState(config)\n .catch(() => ({ values: {} }));\n const updatedState = {\n ...threadState.values,\n ...state,\n } as InvokeStateParameter<Types>;\n if (!updatedState) {\n return updatedState;\n }\n\n // Only add defaults for keys that don't exist in current state\n for (const [key, value] of Object.entries(defaultStates)) {\n if (!(key in updatedState)) {\n updatedState[key as keyof typeof updatedState] = value;\n }\n }\n\n return updatedState;\n }\n\n /**\n * Executes the agent with the given state and returns the final state after all processing.\n *\n * This method runs the agent's entire workflow synchronously, including:\n * - Processing the input messages through any configured middleware\n * - Calling the language model to generate responses\n * - Executing any tool calls made by the model\n * - Running all middleware hooks (beforeModel, afterModel, etc.)\n *\n * @param state - The initial state for the agent execution. Can be:\n * - An object containing `messages` array and any middleware-specific state properties\n * - A Command object for more advanced control flow\n *\n * @param config - Optional runtime configuration including:\n * @param config.context - The context for the agent execution.\n * @param config.configurable - LangGraph configuration options like `thread_id`, `run_id`, etc.\n * @param config.store - The store for the agent execution for persisting state, see more in {@link https://docs.langchain.com/oss/javascript/langgraph/memory#memory-storage | Memory storage}.\n * @param config.signal - An optional {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | `AbortSignal`} for the agent execution.\n * @param config.recursionLimit - The recursion limit for the agent execution.\n *\n * @returns A Promise that resolves to the final agent state after execution completes.\n * The returned state includes:\n * - a `messages` property containing an array with all messages (input, AI responses, tool calls/results)\n * - a `structuredResponse` property containing the structured response (if configured)\n * - all state values defined in the middleware\n *\n * @example\n * ```typescript\n * const agent = new ReactAgent({\n * llm: myModel,\n * tools: [calculator, webSearch],\n * responseFormat: z.object({\n * weather: z.string(),\n * }),\n * });\n *\n * const result = await agent.invoke({\n * messages: [{ role: \"human\", content: \"What's the weather in Paris?\" }]\n * });\n *\n * console.log(result.structuredResponse.weather); // outputs: \"It's sunny and 75°F.\"\n * ```\n */\n async invoke(\n state: InvokeStateParameter<Types>,\n config?: InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n >\n ) {\n type FullState = MergedAgentState<Types>;\n const mergedConfig = this.#getGraphConfig(config);\n const initializedState = await this.#initializeMiddlewareStates(\n state,\n mergedConfig as RunnableConfig\n );\n\n return this.#graph.invoke(\n initializedState,\n mergedConfig\n ) as Promise<FullState>;\n }\n\n /**\n * Executes the agent with streaming, returning an async iterable of state updates as they occur.\n *\n * This method runs the agent's workflow similar to `invoke`, but instead of waiting for\n * completion, it streams high-level state updates in real-time. This allows you to:\n * - Display intermediate results to users as they're generated\n * - Monitor the agent's progress through each step\n * - React to state changes as nodes complete\n *\n * For more granular event-level streaming (like individual LLM tokens), use `streamEvents` instead.\n *\n * @param state - The initial state for the agent execution. Can be:\n * - An object containing `messages` array and any middleware-specific state properties\n * - A Command object for more advanced control flow\n *\n * @param config - Optional runtime configuration including:\n * @param config.context - The context for the agent execution.\n * @param config.configurable - LangGraph configuration options like `thread_id`, `run_id`, etc.\n * @param config.store - The store for the agent execution for persisting state, see more in {@link https://docs.langchain.com/oss/javascript/langgraph/memory#memory-storage | Memory storage}.\n * @param config.signal - An optional {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | `AbortSignal`} for the agent execution.\n * @param config.streamMode - The streaming mode for the agent execution, see more in {@link https://docs.langchain.com/oss/javascript/langgraph/streaming#supported-stream-modes | Supported stream modes}.\n * @param config.recursionLimit - The recursion limit for the agent execution.\n *\n * @returns A Promise that resolves to an IterableReadableStream of state updates.\n * Each update contains the current state after a node completes.\n *\n * @example\n * ```typescript\n * const agent = new ReactAgent({\n * llm: myModel,\n * tools: [calculator, webSearch]\n * });\n *\n * const stream = await agent.stream({\n * messages: [{ role: \"human\", content: \"What's 2+2 and the weather in NYC?\" }]\n * });\n *\n * for await (const chunk of stream) {\n * console.log(chunk); // State update from each node\n * }\n * ```\n */\n async stream<\n TStreamMode extends StreamMode | StreamMode[] | undefined,\n TSubgraphs extends boolean,\n TEncoding extends \"text/event-stream\" | undefined,\n >(\n state: InvokeStateParameter<Types>,\n config?: StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n TStreamMode,\n TSubgraphs,\n TEncoding\n >\n ) {\n const mergedConfig = this.#getGraphConfig(config);\n const initializedState = await this.#initializeMiddlewareStates(\n state,\n mergedConfig as RunnableConfig\n );\n return this.#graph.stream(initializedState, mergedConfig) as Promise<\n IterableReadableStream<\n StreamOutputMap<\n TStreamMode,\n TSubgraphs,\n MergedAgentState<Types>,\n MergedAgentState<Types>,\n string,\n unknown,\n unknown,\n TEncoding\n >\n >\n >;\n }\n\n /**\n * Executes the agent with the v3 streaming interface, returning an\n * {@link AgentRunStream} that provides ergonomic, typed projections for\n * messages, tool calls, and middleware events — without requiring knowledge\n * of Pregel channels, stream modes, or namespace routing.\n *\n * Pass `version: \"v3\"` to opt into this projection-oriented stream. Omitting\n * `version` preserves the legacy internal LangGraph event-stream behavior\n * for compatibility with LangGraph Platform integrations.\n *\n * This v3 stream is experimental and its API may change in future releases.\n * It will become the default in a future major release.\n *\n * @param state - The initial state for the agent execution. Can be:\n * - An object containing `messages` array and any middleware-specific state properties\n * - A Command object for more advanced control flow\n *\n * @param config - Runtime configuration including:\n * @param config.version - Must be `\"v3\"` to use the {@link AgentRunStream}\n * interface. The default legacy event stream is maintained for internal\n * integrations and should not be used for new user-facing agent streaming.\n * @param config.context - The context for the agent execution.\n * @param config.configurable - LangGraph configuration options like `thread_id`, `run_id`, etc.\n * @param config.store - The store for the agent execution for persisting state.\n * @param config.signal - An optional AbortSignal for the agent execution.\n * @param config.recursionLimit - The recursion limit for the agent execution.\n * @param config.transformers - Additional call-site stream transformers. These\n * run after the built-in agent transformers and any transformers registered\n * at creation time via `createAgent({ streamTransformers })`.\n *\n * @returns A Promise that resolves to an {@link AgentRunStream} providing:\n * - `run.messages` — all AI message lifecycles with streaming `.text` and `.reasoning`\n * - `run.toolCalls` — individual tool call streams with `.input`, `.output`, `.status`\n * - `run.middleware` — middleware lifecycle events (before/after agent/model)\n * - `run.values` — state snapshots (async iterable + promise-like)\n * - `run.output` — final agent state when the run completes\n * - `run.subgraphs` — child subgraph run streams\n * - `run.extensions` — merged projections from user-supplied transformers\n *\n * @example\n * ```typescript\n * const run = await agent.streamEvents(\n * {\n * messages: [{ role: \"user\", content: \"What's the weather in Paris?\" }],\n * },\n * { version: \"v3\" }\n * );\n *\n * // Stream all messages\n * for await (const msg of run.messages) {\n * for await (const token of msg.text) {\n * process.stdout.write(token);\n * }\n * }\n *\n * // Observe tool calls\n * for await (const call of run.toolCalls) {\n * console.log(`Tool: ${call.name}`, call.input);\n * console.log(`Result:`, await call.output);\n * }\n *\n * // Get final state\n * const state = await run.output;\n * ```\n */\n streamEvents(\n state: InvokeStateParameter<Types>,\n config: InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n > & {\n version: \"v3\";\n transformers?: ReadonlyArray<() => StreamTransformer<any>>;\n }\n ): Promise<\n AgentRunStream<\n MergedAgentState<Types>,\n Types[\"Tools\"],\n InferStreamExtensions<Types[\"StreamTransformers\"]>\n >\n >;\n\n streamEvents(\n state: InvokeStateParameter<Types>,\n config?: StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\" | undefined\n > & { version?: \"v1\" | \"v2\" },\n streamOptions?: Parameters<Runnable[\"streamEvents\"]>[2]\n ): IterableReadableStream<StreamEvent>;\n\n streamEvents(\n state: InvokeStateParameter<Types>,\n config:\n | (StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\" | undefined\n > & { version?: \"v1\" | \"v2\" })\n | undefined,\n streamOptions: Parameters<Runnable[\"streamEvents\"]>[2]\n ): IterableReadableStream<StreamEvent>;\n\n streamEvents(\n state: InvokeStateParameter<Types>,\n config?:\n | (InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n > & {\n version: \"v3\";\n transformers?: ReadonlyArray<() => StreamTransformer<any>>;\n })\n | (StreamConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\" | undefined\n > & { version?: \"v1\" | \"v2\" }),\n streamOptions?: Parameters<Runnable[\"streamEvents\"]>[2]\n ):\n | Promise<\n AgentRunStream<\n MergedAgentState<Types>,\n Types[\"Tools\"],\n InferStreamExtensions<Types[\"StreamTransformers\"]>\n >\n >\n | IterableReadableStream<StreamEvent> {\n if (config?.version !== \"v3\" || streamOptions != null) {\n const mergedConfig = this.#getGraphConfig(config);\n const version =\n config?.version === \"v1\" || config?.version === \"v2\"\n ? config.version\n : \"v2\";\n return this.#graph.streamEvents(\n state,\n {\n ...(mergedConfig as Partial<\n PregelOptions<\n any,\n any,\n any,\n StreamMode | StreamMode[] | undefined,\n boolean,\n \"text/event-stream\"\n >\n >),\n version,\n },\n streamOptions\n );\n }\n\n return (async () => {\n type FullState = MergedAgentState<Types>;\n const agentConfig = config as InvokeConfiguration<\n InferContextInput<\n Types[\"Context\"] extends AnyAnnotationRoot | InteropZodObject\n ? Types[\"Context\"]\n : AnyAnnotationRoot\n > &\n InferMiddlewareContextInputs<Types[\"Middleware\"]>\n > & {\n version: \"v3\";\n transformers?: ReadonlyArray<() => StreamTransformer<any>>;\n };\n\n const {\n transformers: callSiteTransformers,\n version: _version,\n ...restConfig\n } = agentConfig ?? {};\n const mergedConfig = this.#getGraphConfig(restConfig);\n const initializedState = await this.#initializeMiddlewareStates(\n state,\n mergedConfig as RunnableConfig\n );\n\n return (await this.#graph.streamEvents(initializedState, {\n ...(mergedConfig as Record<string, any>),\n version: \"v3\",\n transformers: callSiteTransformers,\n })) as unknown as AgentRunStream<\n FullState,\n Types[\"Tools\"],\n InferStreamExtensions<Types[\"StreamTransformers\"]>\n >;\n })();\n }\n\n /**\n * Visualize the graph as a PNG image.\n * @param params - Parameters for the drawMermaidPng method.\n * @param params.withStyles - Whether to include styles in the graph.\n * @param params.curveStyle - The style of the graph's curves.\n * @param params.nodeColors - The colors of the graph's nodes.\n * @param params.wrapLabelNWords - The maximum number of words to wrap in a node's label.\n * @param params.backgroundColor - The background color of the graph.\n * @returns PNG image as a buffer\n */\n async drawMermaidPng(params?: {\n withStyles?: boolean;\n curveStyle?: string;\n nodeColors?: Record<string, string>;\n wrapLabelNWords?: number;\n backgroundColor?: string;\n }) {\n const representation = await this.#graph.getGraphAsync();\n const image = await representation.drawMermaidPng(params);\n const arrayBuffer = await image.arrayBuffer();\n const buffer = new Uint8Array(arrayBuffer);\n return buffer;\n }\n\n /**\n * Draw the graph as a Mermaid string.\n * @param params - Parameters for the drawMermaid method.\n * @param params.withStyles - Whether to include styles in the graph.\n * @param params.curveStyle - The style of the graph's curves.\n * @param params.nodeColors - The colors of the graph's nodes.\n * @param params.wrapLabelNWords - The maximum number of words to wrap in a node's label.\n * @param params.backgroundColor - The background color of the graph.\n * @returns Mermaid string\n */\n async drawMermaid(params?: {\n withStyles?: boolean;\n curveStyle?: string;\n nodeColors?: Record<string, string>;\n wrapLabelNWords?: number;\n backgroundColor?: string;\n }) {\n const representation = await this.#graph.getGraphAsync();\n return representation.drawMermaid(params);\n }\n\n /**\n * The following are internal methods to enable support for LangGraph Platform.\n * They are not part of the createAgent public API.\n *\n * Note: we intentionally return as `never` to avoid type errors due to type inference.\n */\n /**\n * @internal\n */\n getGraphAsync(config?: RunnableConfig) {\n return this.#graph.getGraphAsync(config) as never;\n }\n /**\n * @internal\n */\n getState(config: RunnableConfig, options?: GetStateOptions) {\n return this.#graph.getState(config, options) as never;\n }\n /**\n * @internal\n */\n getStateHistory(config: RunnableConfig, options?: CheckpointListOptions) {\n return this.#graph.getStateHistory(config, options) as never;\n }\n /**\n * @internal\n */\n getSubgraphs(namespace?: string, recurse?: boolean) {\n return this.#graph.getSubgraphs(namespace, recurse) as never;\n }\n /**\n * @internal\n */\n getSubgraphsAsync(namespace?: string, recurse?: boolean) {\n return this.#graph.getSubgraphsAsync(namespace, recurse) as never;\n }\n /**\n * @internal\n */\n updateState(\n inputConfig: LangGraphRunnableConfig,\n values: Record<string, unknown> | unknown,\n asNode?: string\n ) {\n return this.#graph.updateState(inputConfig, values, asNode) as never;\n }\n\n /**\n * @internal\n */\n get builder() {\n return this.#graph.builder;\n }\n}\n"],"mappings":"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"}
@@ -9,223 +9,76 @@ let zod_v3 = require("zod/v3");
9
9
  * Description for the write_todos tool
10
10
  * Ported exactly from Python WRITE_TODOS_DESCRIPTION
11
11
  */
12
- const WRITE_TODOS_DESCRIPTION = `Use this tool to create and manage a structured task list for your current work session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
13
- It also helps the user understand the progress of the task and overall progress of their requests.
12
+ const WRITE_TODOS_DESCRIPTION = `Use this tool to create and manage a structured task list for your current work session. This helps you track progress and organize complex tasks.
13
+
14
14
  Only use this tool if you think it will be helpful in staying organized. If the user's request is trivial and takes less than 3 steps, it is better to NOT use this tool and just do the task directly.
15
15
 
16
16
  ## When to Use This Tool
17
+
17
18
  Use this tool in these scenarios:
18
19
 
19
20
  1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
20
21
  2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
21
22
  3. User explicitly requests todo list - When the user directly asks you to use the todo list
22
23
  4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
23
- 5. The plan may need future revisions or updates based on results from the first few steps. Keeping track of this in a list is helpful.
24
+ 5. The plan may need future revisions or updates based on results from the first few steps
24
25
 
25
26
  ## How to Use This Tool
27
+
26
28
  1. When you start working on a task - Mark it as in_progress BEFORE beginning work.
27
29
  2. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation.
28
30
  3. You can also update future tasks, such as deleting them if they are no longer necessary, or adding new tasks that are necessary. Don't change previously completed tasks.
29
31
  4. You can make several updates to the todo list at once. For example, when you complete a task, you can mark the next task you need to start as in_progress.
30
32
 
31
33
  ## When NOT to Use This Tool
34
+
32
35
  It is important to skip using this tool when:
33
36
  1. There is only a single, straightforward task
34
37
  2. The task is trivial and tracking it provides no benefit
35
38
  3. The task can be completed in less than 3 trivial steps
36
39
  4. The task is purely conversational or informational
37
40
 
38
- ## Examples of When to Use the Todo List
39
-
40
- <example>
41
- User: I want to add a dark mode toggle to the application settings. Make sure you run the tests and build when you're done!
42
- Assistant: I'll help add a dark mode toggle to your application settings. Let me create a todo list to track this implementation.
43
- *Creates todo list with the following items:*
44
- 1. Create dark mode toggle component in Settings page
45
- 2. Add dark mode state management (context/store)
46
- 3. Implement CSS-in-JS styles for dark theme
47
- 4. Update existing components to support theme switching
48
- 5. Run tests and build process, addressing any failures or errors that occur
49
- *Begins working on the first task*
50
-
51
- <reasoning>
52
- The assistant used the todo list because:
53
- 1. Adding dark mode in it of itself is a multi-step feature requiring UI, state management, and styling changes
54
- 2. The assistant inferred that tests and build need to pass by adding "Ensure tests and build succeed" as the final task
55
- 3. Both of the user's requests are complex and require multiple steps to complete.
56
- </reasoning>
57
- </example>
58
-
59
- <example>
60
- User: Help me plan a comprehensive marketing campaign for our new product launch, including social media, email marketing, and press releases.
61
- Assistant: I'll help you plan a comprehensive marketing campaign for your product launch. Let me create a todo list to organize all the components.
62
- *Creates todo list with the following items:*
63
- 1. Define target audience and key messaging
64
- 2. Create social media content calendar and posting schedule
65
- 3. Design email marketing sequence and automation flows
66
- 4. Draft press release and identify media contacts
67
- 5. Set up tracking and analytics for campaign performance
68
- 6. Create visual assets and brand materials
69
- 7. Coordinate launch timeline and deliverables
70
- *Begins working on the first task*
71
-
72
- <reasoning>
73
- The assistant used the todo list because:
74
- 1. Marketing campaign planning involves multiple distinct channels and activities
75
- 2. Each component requires careful coordination and planning
76
- 3. The systematic approach ensures all aspects of the launch are covered
77
- </reasoning>
78
- </example>
79
-
80
- <example>
81
- User: Help me rename the function getCwd to getCurrentWorkingDirectory across my project
82
- Assistant: Let me first search through your codebase to find all occurrences of 'getCwd'.
83
- *Uses search tools to locate all instances of getCwd in the codebase*
84
- Assistant: I've found 15 instances of 'getCwd' across 8 different files. Let me create a todo list to track these changes.
85
- *Creates todo list with specific items for each file that needs updating*
86
-
87
- <reasoning>
88
- The assistant used the todo list because:
89
- 1. The assistant searched to understand the scope of the task
90
- 2. Upon finding multiple occurrences across different files, it determined this was a complex task with multiple steps (>3)
91
- 3. The todo list helps ensure every instance is tracked and updated systematically
92
- 4. This approach prevents missing any occurrences and maintains consistency.
93
- </reasoning>
94
- </example>
95
-
96
- <example>
97
- User: I need help organizing my home office: decluttering the desk, setting up a filing system, organizing digital files, and creating a daily workflow.
98
- Assistant: I'll help you organize your home office systematically. Let me create a todo list to track each area of organization.
99
- *Creates todo list with items like: 1) Sort and declutter desk items, 2) Set up physical filing system for documents, 3) Organize digital files and folders, 4) Create daily workflow and productivity systems, 5) Establish maintenance routines*
100
- Let's start with decluttering your desk space to create a clean foundation for the other organizational systems.
101
-
102
- <reasoning>
103
- The assistant used the todo list because:
104
- 1. The user provided multiple distinct organizational tasks
105
- 2. Each area requires different approaches and careful planning
106
- 3. Home organization benefits from systematic, step-by-step completion
107
- 4. Progress tracking ensures all areas are addressed thoroughly
108
- </reasoning>
109
- </example>
110
-
111
- ## Examples of When NOT to Use the Todo List
112
-
113
- <example>
114
- User: How do I print 'Hello World' in Python?
115
- Assistant: In Python, you can print "Hello World" with this simple code:
116
-
117
- \`\`\`python
118
- print("Hello World")
119
- \`\`\`
120
-
121
- This will output the text "Hello World" to the console when executed.</assistant>
122
-
123
- <reasoning>
124
- The assistant did not use the todo list because this is a single, trivial task that can be completed in one step. There's no need to track multiple tasks or steps for such a straightforward request.
125
- </reasoning>
126
- </example>
127
-
128
- <example>
129
- User: What's the best way to water houseplants?
130
- Assistant: The best way to water houseplants depends on the specific plant type, but here are some general guidelines:
131
-
132
- - Check soil moisture by inserting your finger about 1-2 inches into the soil
133
- - Water thoroughly when the top inch feels dry, allowing water to drain from the bottom
134
- - Use room temperature water and water in the morning when possible
135
- - Avoid overwatering, which is more harmful than underwatering for most plants
136
-
137
- Different plants have different needs, so it's important to research your specific varieties for optimal care.
138
-
139
- <reasoning>
140
- The assistant did not use the todo list because this is an informational request with no actual tasks to complete. The user is simply asking for advice and explanation, not for the assistant to perform multiple steps or activities.
141
- </reasoning>
142
- </example>
143
-
144
- <example>
145
- User: Can you add a comment to the calculateTotal function to explain what it does?
146
- Assistant: Sure, let me add a comment to the calculateTotal function to explain what it does.
147
- * Uses the Edit tool to add a comment to the calculateTotal function *
148
-
149
- <reasoning>
150
- The assistant did not use the todo list because this is a single, straightforward task confined to one location. Adding a comment doesn't require tracking multiple steps or systematic organization.
151
- </reasoning>
152
- </example>
153
-
154
- <example>
155
- User: What time is it in Tokyo right now?
156
- Assistant: I'll check the current time in Tokyo for you.
157
-
158
- *Searches for current time in Tokyo*
159
-
160
- The current time in Tokyo, Japan is [current time]. Tokyo is in the Japan Standard Time (JST) zone, which is UTC+9.
161
-
162
- <reasoning>
163
- The assistant did not use the todo list because this is a single information lookup with immediate results. There are no multiple steps to track or organize, making the todo list unnecessary for this straightforward request.
164
- </reasoning>
165
- </example>
166
-
167
- <example>
168
- User: I need to write a function that checks if a number is prime and then test it out.
169
- Assistant: I'll help you write a function that checks if a number is prime and then test it out.
170
- *Writes function that checks if a number is prime*
171
- *Tests the function*
172
-
173
- <reasoning>
174
- Even though this is a multi-step task, it is very straightforward and can be completed in two trivial steps (which is less than 3 steps!). Using the todo list here is overkill and wastes time and tokens.
175
- </reasoning>
176
- </example>
177
-
178
- <example>
179
- User: I want you to order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway.
180
- Assistant: I'll help you order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway.
181
- *Orders a pizza from Dominos*
182
- *Orders a burger from McDonald's*
183
- *Orders a salad from Subway*
184
-
185
- <reasoning>
186
- Even though this is a multi-step task, assuming the assistant has the ability to order from these restaurants, it is very straightforward and can be completed in three trivial tool calls.
187
- Using the todo list here is overkill and wastes time and tokens. These three tool calls should be made in parallel, in fact.
188
- </reasoning>
189
- </example>
190
-
191
-
192
41
  ## Task States and Management
193
42
 
194
43
  1. **Task States**: Use these states to track progress:
195
- - pending: Task not yet started
196
- - in_progress: Currently working on (you can have multiple tasks in_progress at a time if they are not related to each other and can be run in parallel)
197
- - completed: Task finished successfully
44
+ - pending: Task not yet started
45
+ - in_progress: Currently working on (you can have multiple tasks in_progress at a time if they are not related to each other and can be run in parallel)
46
+ - completed: Task finished successfully
198
47
 
199
48
  2. **Task Management**:
200
- - Update task status in real-time as you work
201
- - Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
202
- - Complete current tasks before starting new ones
203
- - Remove tasks that are no longer relevant from the list entirely
204
- - IMPORTANT: When you write this todo list, you should mark your first task (or tasks) as in_progress immediately!.
205
- - IMPORTANT: Unless all tasks are completed, you should always have at least one task in_progress to show the user that you are working on something.
49
+ - Update task status in real-time as you work
50
+ - Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
51
+ - Complete current tasks before starting new ones
52
+ - Remove tasks that are no longer relevant from the list entirely
53
+ - IMPORTANT: When you write this todo list, you should mark your first task (or tasks) as in_progress immediately!.
54
+ - IMPORTANT: Unless all tasks are completed, you should always have at least one task in_progress.
206
55
 
207
56
  3. **Task Completion Requirements**:
208
- - ONLY mark a task as completed when you have FULLY accomplished it
209
- - If you encounter errors, blockers, or cannot finish, keep the task as in_progress
210
- - When blocked, create a new task describing what needs to be resolved
211
- - Never mark a task as completed if:
212
- - There are unresolved issues or errors
213
- - Work is partial or incomplete
214
- - You encountered blockers that prevent completion
215
- - You couldn't find necessary resources or dependencies
216
- - Quality standards haven't been met
57
+ - ONLY mark a task as completed when you have FULLY accomplished it
58
+ - If you encounter errors, blockers, or cannot finish, keep the task as in_progress
59
+ - When blocked, create a new task describing what needs to be resolved
60
+ - Never mark a task as completed if:
61
+ - There are unresolved issues or errors
62
+ - Work is partial or incomplete
63
+ - You encountered blockers that prevent completion
64
+ - You couldn't find necessary resources or dependencies
65
+ - Quality standards haven't been met
217
66
 
218
67
  4. **Task Breakdown**:
219
- - Create specific, actionable items
220
- - Break complex tasks into smaller, manageable steps
221
- - Use clear, descriptive task names
68
+ - Create specific, actionable items
69
+ - Break complex tasks into smaller, manageable steps
70
+ - Use clear, descriptive task names
71
+
72
+ Being proactive with task management ensures you complete all requirements successfully
73
+ Remember: If you only need to make a few tool calls to complete a task, and it is clear what you need to do, it is better to just do the task directly and NOT call this tool at all.
222
74
 
223
- Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully
224
- Remember: If you only need to make a few tool calls to complete a task, and it is clear what you need to do, it is better to just do the task directly and NOT call this tool at all.`;
75
+ ## When You Finish
76
+
77
+ \`write_todos\` tracks your work; it does not deliver the answer. Whatever the user asked for — computations, summaries, comparisons, data — must appear as text content in a message after your final \`write_todos\` call. Marking the last todo complete is not itself an answer to the user.`;
225
78
  const TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT = `## \`write_todos\`
226
79
 
227
- You have access to the \`write_todos\` tool to help you manage and plan complex objectives.
228
- Use this tool for complex objectives to ensure that you are tracking each necessary step and giving the user visibility into your progress.
80
+ You have access to the \`write_todos\` tool to help you manage and plan complex objectives.
81
+ Use this tool for complex objectives to ensure that you are tracking each necessary step.
229
82
  This tool is very helpful for planning complex objectives, and for breaking down these larger complex objectives into smaller steps.
230
83
 
231
84
  It is critical that you mark todos as completed as soon as you are done with a step. Do not batch up multiple steps before marking them as completed.
@@ -233,8 +86,13 @@ For simple objectives that only require a few steps, it is better to just comple
233
86
  Writing todos takes time and tokens, use it when it is helpful for managing complex many-step problems! But not for simple few-step requests.
234
87
 
235
88
  ## Important To-Do List Usage Notes to Remember
89
+
236
90
  - The \`write_todos\` tool should never be called multiple times in parallel.
237
- - Don't be afraid to revise the To-Do list as you go. New information may reveal new tasks that need to be done, or old tasks that are irrelevant.`;
91
+ - Don't be afraid to revise the To-Do list as you go. New information may reveal new tasks that need to be done, or old tasks that are irrelevant.
92
+
93
+ ## Finishing a task
94
+
95
+ When you finish all work, write your final answer in the message AFTER your last \`write_todos\` call — not in the same turn as that call. Start the final message with the substantive content the user asked for — the data, computation, summary, or analysis. The user wants the result, not confirmation that the work is done.`;
238
96
  const TodoStatus = zod_v3.z.enum([
239
97
  "pending",
240
98
  "in_progress",