{"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\n/**\n * Skip wrapper `task` tool events scoped to a subagent namespace.\n *\n * Deep-agent subagents are discovered from root-level `task` tool calls;\n * replaying the same dispatch tool inside the worker namespace would\n * otherwise surface as a spurious entry in `sub.toolCalls`.\n */\nexport function shouldIgnoreScopedTaskToolEvent(\n  scopeNamespace: readonly string[],\n  event: ToolsEvent\n): boolean {\n  const data = event.params.data;\n  return (\n    scopeNamespace.length > 0 &&\n    event.params.namespace.length === scopeNamespace.length &&\n    event.params.namespace.every(\n      (segment, index) => segment === scopeNamespace[index]\n    ) &&\n    \"tool_name\" in data &&\n    data.tool_name === \"task\"\n  );\n}\n\nfunction getWireMessageField(message: unknown, field: string): unknown {\n  if (!message || typeof message !== \"object\" || Array.isArray(message)) {\n    return undefined;\n  }\n  const record = message as Record<string, unknown>;\n  if (field in record) return record[field];\n  const kwargs = record.kwargs as Record<string, unknown> | undefined;\n  if (kwargs != null && field in kwargs) return kwargs[field];\n  const lcKwargs = record.lc_kwargs as Record<string, unknown> | undefined;\n  if (lcKwargs != null && field in lcKwargs) return lcKwargs[field];\n  return undefined;\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  const type = getWireMessageField(value, \"type\");\n  if (type === \"tool\") return true;\n  return (\n    typeof getWireMessageField(value, \"tool_call_id\") === \"string\" &&\n    getWireMessageField(value, \"content\") !== undefined\n  );\n}\n\nfunction isCommandLike(\n  value: unknown\n): value is Record<string, unknown> & { update?: unknown } {\n  return (\n    !!value &&\n    typeof value === \"object\" &&\n    (value as Record<string, unknown>).lg_name === \"Command\"\n  );\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\nfunction parseToolMessageRecord(message: unknown): unknown | null {\n  const content = getWireMessageField(message, \"content\");\n  return parseToolResultContent(content);\n}\n\ntype ParsedCommandToolOutput =\n  | { found: true; value: unknown | null }\n  | { found: false };\n\nfunction parseCommandToolOutput(\n  command: Record<string, unknown> & { update?: unknown },\n  toolCallId?: string\n): ParsedCommandToolOutput {\n  const update = command.update;\n  if (update == null || typeof update !== \"object\" || Array.isArray(update)) {\n    return { found: false };\n  }\n\n  const messages = (update as Record<string, unknown>).messages;\n  if (!Array.isArray(messages)) return { found: false };\n\n  const toolMessages = messages.filter((message) => isToolMessageLike(message));\n  if (toolMessages.length === 0) return { found: false };\n\n  if (toolCallId != null) {\n    for (const message of toolMessages) {\n      const callId = getWireMessageField(message, \"tool_call_id\");\n      if (callId !== toolCallId) continue;\n      return { found: true, value: parseToolMessageRecord(message) };\n    }\n    return { found: false };\n  }\n\n  if (toolMessages.length === 1) {\n    return { found: true, value: parseToolMessageRecord(toolMessages[0]) };\n  }\n\n  for (let i = toolMessages.length - 1; i >= 0; i -= 1) {\n    const parsed = parseToolMessageRecord(toolMessages[i]);\n    if (parsed != null) return { found: true, value: parsed };\n  }\n\n  return { found: true, value: 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: \"...\" }`) or a LangGraph\n * {@link Command} whose `update.messages` carries the ToolMessage.\n * This unwraps those envelopes, JSON-decodes string content when possible,\n * and leaves plain strings as-is. Returns `null` when a ToolMessage envelope\n * is present but its content cannot be normalised.\n */\nexport function parseToolOutput(\n  value: unknown,\n  toolCallId?: string\n): unknown | null {\n  const parsed = parseToolPayload(value);\n  if (isCommandLike(parsed)) {\n    const commandOutput = parseCommandToolOutput(parsed, toolCallId);\n    return commandOutput.found ? commandOutput.value : parsed;\n  }\n  if (isToolMessageLike(parsed)) {\n    return parseToolResultContent(getWireMessageField(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, data.tool_call_id);\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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"}