{"version":3,"file":"tools.cjs","names":[],"sources":["../../../../src/client/stream/handles/tools.ts"],"sourcesContent":["import type {\n  ToolsEvent,\n  ToolStartedData,\n  ToolFinishedData,\n  ToolErrorData,\n} from \"@langchain/protocol\";\n\n/**\n * High-level outcome of a single tool call.\n */\nexport type ToolCallStatus = \"running\" | \"finished\" | \"error\";\n\n/** Shared metadata for assembled tool-call handles. */\ninterface ToolCallBase<TName extends string = string, TInput = unknown> {\n  readonly name: TName;\n  readonly callId: string;\n  /**\n   * Pre-v1 alias for {@link callId}. Matches `ToolCallWithResult.id` and\n   * `ToolCall.id` on message-level tool calls.\n   */\n  readonly id: string;\n  readonly namespace: string[];\n  readonly input: TInput;\n  /**\n   * Pre-v1 alias for {@link input}. Matches `ToolCallFromTool` `args`.\n   */\n  readonly args: TInput;\n}\n\n/**\n * Script-oriented tool handle from the client SDK (`ThreadStream.toolCalls`,\n * subagent/subgraph projections). Completion and errors are surfaced only\n * through {@link output}.\n */\nexport interface ClientAssembledToolCall<\n  TName extends string = string,\n  TInput = unknown,\n  TOutput = unknown,\n> extends ToolCallBase<TName, TInput> {\n  readonly output: Promise<TOutput>;\n}\n\n/**\n * Reactive tool handle for framework bindings (`stream.toolCalls`,\n * `useToolCalls`, `injectToolCalls`).\n *\n * {@link status}, {@link error}, and {@link output} are plain values that\n * the assembler updates in place as tool events arrive. That lets React,\n * Vue, Svelte, and Angular re-render from a snapshot on each store tick\n * without `await`, effects, or Suspense boundaries around a promise.\n * {@link ClientAssembledToolCall} keeps a promise-based {@link output}\n * instead for script consumers that read tool results sequentially.\n *\n * {@link output} is `null` while the call is running or after it fails;\n * successful completion sets it to the parsed tool return value (objects\n * and strings are unwrapped from ToolMessage wire envelopes when needed).\n */\nexport interface AssembledToolCall<\n  TName extends string = string,\n  TInput = unknown,\n  TOutput = unknown,\n> extends ToolCallBase<TName, TInput> {\n  readonly output: TOutput | null;\n  readonly status: ToolCallStatus;\n  readonly error: string | undefined;\n}\n\n/** @internal Mutable runtime handle shared by client and framework views. */\ntype MutableToolCallHandle = {\n  name: string;\n  callId: string;\n  id: string;\n  namespace: string[];\n  input: unknown;\n  args: unknown;\n  output: unknown | null;\n  status: ToolCallStatus;\n  error: string | undefined;\n  outputPromise: Promise<unknown>;\n};\n\n/**\n * Project a runtime handle to the client SDK surface (promise-only\n * {@link output}, no {@link status} / {@link error} fields).\n */\nexport function toClientAssembledToolCall(\n  handle: MutableToolCallHandle\n): ClientAssembledToolCall {\n  return {\n    name: handle.name,\n    callId: handle.callId,\n    id: handle.id,\n    namespace: handle.namespace,\n    input: handle.input,\n    args: handle.args,\n    output: handle.outputPromise as Promise<unknown>,\n  };\n}\n\n/**\n * Parse wire-format tool payloads into structured values.\n *\n * Tool events may carry JSON-encoded object strings on the wire; this\n * helper normalises them to plain objects for consumers. Non-JSON strings\n * are returned unchanged.\n */\nexport function parseToolPayload(value: unknown): unknown {\n  if (typeof value !== \"string\") return value;\n  const trimmed = value.trim();\n  if (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\")) {\n    return value;\n  }\n\n  try {\n    return JSON.parse(trimmed) as unknown;\n  } catch {\n    return value;\n  }\n}\n\nfunction isToolMessageLike(\n  value: unknown\n): value is Record<string, unknown> & { content: unknown } {\n  if (!value || typeof value !== \"object\") return false;\n  const record = value as Record<string, unknown>;\n  if (record.type === \"tool\") return true;\n  return typeof record.tool_call_id === \"string\" && \"content\" in record;\n}\n\nfunction textFromContentBlocks(content: unknown[]): string {\n  let out = \"\";\n  for (const block of content) {\n    if (!block || typeof block !== \"object\") continue;\n    const record = block as Record<string, unknown>;\n    if (record.type === \"text\" && typeof record.text === \"string\") {\n      out += record.text;\n    }\n  }\n  return out;\n}\n\n/**\n * Normalise tool-result `content` from a wire ToolMessage into the value\n * a tool implementation returned (object, string, etc.).\n */\nfunction parseToolResultContent(content: unknown): unknown | null {\n  if (content == null) return null;\n\n  if (typeof content === \"string\") {\n    const trimmed = content.trim();\n    if (trimmed.length === 0) return null;\n    return parseToolPayload(content);\n  }\n\n  if (Array.isArray(content)) {\n    const text = textFromContentBlocks(content);\n    if (text.length === 0) return null;\n    return parseToolPayload(text);\n  }\n\n  if (typeof content === \"object\") {\n    return content;\n  }\n\n  return null;\n}\n\n/**\n * Parse a `tool-finished` output payload into the tool's return value.\n *\n * Wire events often wrap structured tool results in a ToolMessage-shaped\n * object (`{ type: \"tool\", content: \"...\" }`). This unwraps that envelope,\n * JSON-decodes string content when possible, and leaves plain strings as-is.\n * Returns `null` when a ToolMessage envelope is present but its content\n * cannot be normalised.\n */\nexport function parseToolOutput(value: unknown): unknown | null {\n  const parsed = parseToolPayload(value);\n  if (isToolMessageLike(parsed)) {\n    return parseToolResultContent(parsed.content);\n  }\n  return parsed ?? null;\n}\n\ntype ActiveToolCall = {\n  handle: MutableToolCallHandle;\n  resolveOutput: (value: unknown) => void;\n  rejectOutput: (err: Error) => void;\n};\n\n/**\n * Incrementally assembles `tools` events into mutable tool-call handles.\n *\n * Framework consumers store the handle directly; client SDK consumers\n * should map with {@link toClientAssembledToolCall} before yielding.\n */\nexport class ToolCallAssembler {\n  private readonly active = new Map<string, ActiveToolCall>();\n\n  consume(event: ToolsEvent): MutableToolCallHandle | undefined {\n    const data = event.params.data;\n\n    if (data.event === \"tool-started\") {\n      return this.handleStarted(event, data);\n    }\n\n    if (data.event === \"tool-finished\") {\n      return this.handleFinished(data);\n    }\n\n    if (data.event === \"tool-error\") {\n      return this.handleError(data);\n    }\n\n    // tool-output-delta: no action needed at assembly level\n    return undefined;\n  }\n\n  /**\n   * Reject any in-flight tool calls (e.g. on session close).\n   */\n  failAll(reason: Error): void {\n    for (const entry of this.active.values()) {\n      entry.rejectOutput(reason);\n      entry.handle.status = \"error\";\n      entry.handle.error = reason.message;\n    }\n    this.active.clear();\n  }\n\n  private handleStarted(\n    event: ToolsEvent,\n    data: ToolStartedData\n  ): MutableToolCallHandle {\n    let resolveOutput!: (value: unknown) => void;\n    let rejectOutput!: (err: Error) => void;\n\n    const outputPromise = new Promise<unknown>((resolve, reject) => {\n      resolveOutput = resolve;\n      rejectOutput = reject;\n    });\n    // Attach a default no-op catch so if no consumer awaits\n    // `output` the eventual rejection on `tool-error` / `failAll`\n    // doesn't surface as an unhandled Promise rejection.\n    outputPromise.catch(() => undefined);\n\n    const input = parseToolPayload(data.input);\n    const name = data.tool_name;\n    const callId = data.tool_call_id;\n    const namespace = [...event.params.namespace];\n\n    const handle: MutableToolCallHandle = {\n      name,\n      callId,\n      id: callId,\n      namespace,\n      input,\n      args: input,\n      output: null,\n      status: \"running\",\n      error: undefined,\n      outputPromise,\n    };\n\n    this.active.set(callId, {\n      handle,\n      resolveOutput,\n      rejectOutput,\n    });\n\n    return handle;\n  }\n\n  private handleFinished(\n    data: ToolFinishedData\n  ): MutableToolCallHandle | undefined {\n    const entry = this.active.get(data.tool_call_id);\n    if (!entry) return undefined;\n    this.active.delete(data.tool_call_id);\n    const value = parseToolOutput(data.output);\n    entry.resolveOutput(value);\n    entry.handle.output = value;\n    entry.handle.status = \"finished\";\n    entry.handle.error = undefined;\n    return entry.handle;\n  }\n\n  private handleError(data: ToolErrorData): MutableToolCallHandle | undefined {\n    const entry = this.active.get(data.tool_call_id);\n    if (!entry) return undefined;\n    this.active.delete(data.tool_call_id);\n    entry.rejectOutput(new Error(data.message));\n    entry.handle.output = null;\n    entry.handle.status = \"error\";\n    entry.handle.error = data.message;\n    return entry.handle;\n  }\n}\n"],"mappings":"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"}