{"version":3,"file":"headless.cjs","names":[],"sources":["../../src/tools/headless.ts"],"sourcesContent":["/**\n * Unified Tool Primitive for LangChain Agents\n *\n * This module re-exports the `tool` primitive from `@langchain/core/tools` with\n * an additional overload: when called without an implementation function, it\n * creates a **headless tool** that interrupts agent execution and delegates the\n * implementation to the client (e.g. via `useStream({ tools: [...] })`).\n *\n * @module\n */\n\nimport {\n  tool as coreTool,\n  DynamicStructuredTool,\n  type ToolRunnableConfig,\n} from \"@langchain/core/tools\";\nimport type {\n  InteropZodObject,\n  InferInteropZodInput,\n  InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\n\n/**\n * Configuration fields for creating a headless tool.\n */\nexport type HeadlessToolFields<\n  SchemaT extends InteropZodObject,\n  NameT extends string = string,\n> = {\n  /** The name of the tool. Used by the client to match implementations. */\n  name: NameT;\n  /** Description of what the tool does. */\n  description: string;\n  /** The Zod schema defining the tool's input. */\n  schema: SchemaT;\n};\n\n/**\n * A tool implementation that pairs a headless tool with its execution function.\n *\n * Created by calling `.implement()` on a {@link HeadlessTool}.\n * Pass to `useStream({ tools: [...] })` on the client side.\n */\nexport type HeadlessToolImplementation<\n  SchemaT extends InteropZodObject = InteropZodObject,\n  OutputT = unknown,\n  NameT extends string = string,\n> = {\n  tool: HeadlessTool<SchemaT, NameT>;\n  execute: (args: InferInteropZodOutput<SchemaT>) => Promise<OutputT>;\n};\n\n/**\n * A headless tool that always interrupts agent execution on the server.\n *\n * The implementation is provided separately on the client via\n * `useStream({ tools: [...] })` using `.implement()`.\n */\nexport type HeadlessTool<\n  SchemaT extends InteropZodObject = InteropZodObject,\n  NameT extends string = string,\n> = DynamicStructuredTool<\n  SchemaT,\n  InferInteropZodOutput<SchemaT>,\n  InferInteropZodInput<SchemaT>,\n  unknown,\n  unknown,\n  NameT\n> & {\n  /**\n   * Pairs this headless tool with a client-side implementation.\n   *\n   * The returned object should be passed to `useStream({ tools: [...] })`.\n   * The SDK matches the implementation to the tool by name and calls\n   * `execute` with the typed arguments from the interrupt payload.\n   *\n   * @param execute - The function that implements the tool on the client\n   */\n  implement: <OutputT>(\n    execute: (args: InferInteropZodOutput<SchemaT>) => Promise<OutputT>\n  ) => HeadlessToolImplementation<SchemaT, OutputT, NameT>;\n};\n\nfunction createHeadlessTool<\n  SchemaT extends InteropZodObject,\n  NameT extends string,\n>(fields: HeadlessToolFields<SchemaT, NameT>): HeadlessTool<SchemaT, NameT> {\n  const { name, description, schema } = fields;\n\n  const wrappedTool = coreTool(\n    async (\n      args: InferInteropZodOutput<SchemaT>,\n      config?: ToolRunnableConfig\n    ) => {\n      const { interrupt } = await import(\"@langchain/langgraph\");\n      return interrupt({\n        type: \"tool\",\n        toolCall: {\n          id: config?.toolCall?.id,\n          name,\n          args,\n        },\n      });\n    },\n    {\n      name,\n      description,\n      schema,\n      metadata: {\n        headlessTool: true,\n      },\n    }\n  );\n\n  const headlessTool: HeadlessTool<SchemaT, NameT> = Object.assign(\n    wrappedTool,\n    {\n      implement: <OutputT>(\n        execute: (args: InferInteropZodOutput<SchemaT>) => Promise<OutputT>\n      ): HeadlessToolImplementation<SchemaT, OutputT, NameT> => ({\n        tool: headlessTool,\n        execute,\n      }),\n    }\n  ) as HeadlessTool<SchemaT, NameT>;\n\n  return headlessTool;\n}\n\n/**\n * The headless overload signature added to the core `tool` function.\n *\n * When called **without** an implementation function — just `tool({ name, description, schema })` —\n * returns a {@link HeadlessTool} that interrupts on every agent invocation.\n * The client provides the implementation via `useStream({ tools: [...] })`.\n */\ntype HeadlessToolOverload = {\n  <SchemaT extends InteropZodObject, NameT extends string>(\n    fields: HeadlessToolFields<SchemaT, NameT>\n  ): HeadlessTool<SchemaT, NameT>;\n};\n\n/**\n * Unified tool primitive for LangChain agents.\n *\n * Enhances the `tool` function from `@langchain/core/tools` with a headless\n * overload: when called **without** an implementation function, the tool\n * interrupts agent execution and lets the client supply the implementation.\n *\n * ---\n *\n * **Normal tool** — pass an implementation function as the first argument:\n *\n * ```typescript\n * import { tool } from \"langchain/tools\";\n * import { z } from \"zod\";\n *\n * const getWeather = tool(\n *   async ({ city }) => `The weather in ${city} is sunny.`,\n *   {\n *     name: \"get_weather\",\n *     description: \"Get the weather for a city\",\n *     schema: z.object({ city: z.string() }),\n *   }\n * );\n * ```\n *\n * ---\n *\n * **Headless tool** — omit the implementation; the client provides it later:\n *\n * ```typescript\n * import { tool } from \"langchain/tools\";\n * import { z } from \"zod\";\n *\n * // Server: define the tool shape — no implementation needed\n * export const getLocation = tool({\n *   name: \"get_location\",\n *   description: \"Get the user's current GPS location\",\n *   schema: z.object({\n *     highAccuracy: z.boolean().optional().describe(\"Request high accuracy GPS\"),\n *   }),\n * });\n *\n * // Server: register with the agent\n * const agent = createAgent({\n *   model: \"openai:gpt-4o\",\n *   tools: [getLocation],\n * });\n *\n * // Client: provide the implementation in useStream\n * const stream = useStream({\n *   assistantId: \"agent\",\n *   tools: [\n *     getLocation.implement(async ({ highAccuracy }) => {\n *       return new Promise((resolve, reject) => {\n *         navigator.geolocation.getCurrentPosition(\n *           (pos) => resolve({\n *             latitude: pos.coords.latitude,\n *             longitude: pos.coords.longitude,\n *           }),\n *           (err) => reject(new Error(err.message)),\n *           { enableHighAccuracy: highAccuracy }\n *         );\n *       });\n *     }),\n *   ],\n * });\n * ```\n */\nexport const tool: HeadlessToolOverload & typeof coreTool = ((\n  funcOrFields: unknown,\n  fields?: unknown\n) => {\n  if (typeof funcOrFields !== \"function\") {\n    return createHeadlessTool(\n      funcOrFields as HeadlessToolFields<InteropZodObject, string>\n    );\n  }\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  return (coreTool as any)(funcOrFields, fields);\n}) as HeadlessToolOverload & typeof coreTool;\n"],"mappings":";;;;;;;;;;;;;AAmFA,SAAS,mBAGP,QAA0E;CAC1E,MAAM,EAAE,MAAM,aAAa,WAAW;CAEtC,MAAM,eAAA,GAAA,sBAAA,MACJ,OACE,MACA,WACG;EACH,MAAM,EAAE,cAAc,MAAM,OAAO;AACnC,SAAO,UAAU;GACf,MAAM;GACN,UAAU;IACR,IAAI,QAAQ,UAAU;IACtB;IACA;IACD;GACF,CAAC;IAEJ;EACE;EACA;EACA;EACA,UAAU,EACR,cAAc,MACf;EACF,CACF;CAED,MAAM,eAA6C,OAAO,OACxD,aACA,EACE,YACE,aACyD;EACzD,MAAM;EACN;EACD,GACF,CACF;AAED,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoFT,MAAa,SACX,cACA,WACG;AACH,KAAI,OAAO,iBAAiB,WAC1B,QAAO,mBACL,aACD;AAGH,SAAA,GAAA,sBAAA,MAAyB,cAAc,OAAO"}