{"version":3,"file":"subagent.cjs","names":["StreamChannel","createToolCallTransformer"],"sources":["../../../src/agents/transformers/subagent.ts"],"sourcesContent":["import {\n  StreamChannel,\n  createMessagesTransformer,\n  type NativeStreamTransformer,\n  type ProtocolEvent,\n  type Namespace,\n  type LifecycleCause,\n} from \"@langchain/langgraph\";\n\nimport { createToolCallTransformer } from \"./tool-call.js\";\nimport type { SubagentRunStream } from \"./types.js\";\n\ninterface SubagentProjection {\n  subagents: AsyncIterable<SubagentRunStream>;\n}\n\n/** Per-subagent transformer instances, driven manually by the parent. */\ntype MessagesTransformer = ReturnType<typeof createMessagesTransformer>;\ntype ToolCallTransformer = ReturnType<\n  ReturnType<typeof createToolCallTransformer>\n>;\ntype NestedSubagentTransformer = ReturnType<\n  ReturnType<typeof createSubagentTransformer>\n>;\n\ninterface SubagentHandle {\n  readonly key: string;\n  readonly path: Namespace;\n  readonly name: string;\n  readonly messages: MessagesTransformer;\n  readonly toolCall: ToolCallTransformer;\n  readonly nested: NestedSubagentTransformer;\n  readonly resolveOutput: (value: unknown) => void;\n  readonly rejectOutput: (error: unknown) => void;\n  latestValues: Record<string, unknown> | undefined;\n  done: boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Stable string key for a namespace. */\nfunction nsKey(ns: Namespace): string {\n  return ns.join(\"\\u0000\");\n}\n\n/** Tests whether `ns` starts with every segment in `prefix`. */\nfunction hasPrefix(ns: Namespace, prefix: Namespace): boolean {\n  if (prefix.length > ns.length) return false;\n  for (let i = 0; i < prefix.length; i += 1) {\n    if (ns[i] !== prefix[i]) return false;\n  }\n  return true;\n}\n\n/**\n * Creates a native transformer that surfaces nested named agents on\n * `run.subagents`.\n *\n * It watches `tasks` events to record each namespace's `lc_agent_name` (set by\n * `createAgent({ name })`) and the triggering tool call, then — for any nested\n * run one level below {@link scope} that carries an `lc_agent_name` — emits a\n * typed {@link SubagentRunStream} handle.\n *\n * Each handle is backed by its own per-subagent transformer instances\n * ({@link createMessagesTransformer}, {@link createToolCallTransformer}, and a\n * nested {@link createSubagentTransformer}) scoped to the subagent's namespace.\n * Every event in the subtree is fed straight into those transformers, which\n * self-filter by namespace; the subagent's final `output` is resolved from its\n * last `values` snapshot when its `lifecycle` completes.\n *\n * Marked `__native: true` — the `subagents` projection lands directly on the\n * `GraphRunStream` instance as `run.subagents`.\n *\n * @param scope - Namespace prefix this transformer is scoped to. The root agent\n *   uses `[]`; nested handles use their subagent's namespace, so grandchild\n *   subagents are discovered recursively.\n */\nexport function createSubagentTransformer(\n  scope: Namespace = []\n): () => NativeStreamTransformer<SubagentProjection> {\n  return () => {\n    const subagentsLog = StreamChannel.local<SubagentRunStream>();\n    /** `lc_agent_name` observed per namespace (first task event wins). */\n    const lcByNs = new Map<string, string | undefined>();\n    /** Triggering task id -> originating LLM `tool_call_id`. */\n    const pendingToolCalls = new Map<string, string>();\n    /**\n     * Namespace key -> the `tool_call_id` of the most recent tool to start\n     * executing there. A tool that invokes a subagent emits its `tool-started`\n     * at the tools-node namespace (`tools:<task_id>`) where the subagent then\n     * roots, so this is the tool call that caused the subagent.\n     */\n    const activeToolCallByNs = new Map<string, string>();\n    const handles = new Map<string, SubagentHandle>();\n    const depth = scope.length;\n\n    function recordIdentity(ns: Namespace, data: unknown): void {\n      const key = nsKey(ns);\n      if (lcByNs.has(key)) return;\n      const metadata =\n        isRecord(data) && isRecord(data.metadata) ? data.metadata : undefined;\n      const lc = metadata?.lc_agent_name;\n      lcByNs.set(key, typeof lc === \"string\" ? lc : undefined);\n    }\n\n    function recordPendingToolCalls(data: unknown): void {\n      if (!isRecord(data)) return;\n      const taskId = data.id;\n      if (typeof taskId !== \"string\") return;\n      const input = data.input;\n      let toolCallId: string | undefined;\n      if (isRecord(input) && isRecord(input.tool_call)) {\n        const candidate = input.tool_call.id;\n        if (typeof candidate === \"string\") toolCallId = candidate;\n      } else if (Array.isArray(input)) {\n        for (const toolCall of input) {\n          if (isRecord(toolCall) && typeof toolCall.id === \"string\") {\n            toolCallId = toolCall.id;\n            break;\n          }\n        }\n      }\n      if (toolCallId != null) pendingToolCalls.set(taskId, toolCallId);\n    }\n\n    /**\n     * Derive the `toolCall` cause for a named-subagent namespace.\n     *\n     * Primary signal: the tool whose `tool-started` event fired at the\n     * subagent's own namespace (the tools node it roots under). Fallback: the\n     * namespace segment's task id (`node:<task_id>`) joined to a tool call\n     * harvested from a `tool_call_with_context`-shaped task input, so the\n     * derivation stays correct if that shape reaches the stream in the future.\n     */\n    function deriveCause(ns: Namespace): LifecycleCause | undefined {\n      const active = activeToolCallByNs.get(nsKey(ns));\n      if (typeof active === \"string\" && active.length > 0) {\n        return { type: \"toolCall\", tool_call_id: active } as LifecycleCause;\n      }\n      const segment = ns[ns.length - 1];\n      const colon = segment.indexOf(\":\");\n      if (colon === -1) return undefined;\n      const triggerCallId = segment.slice(colon + 1);\n      if (triggerCallId.length === 0) return undefined;\n      const toolCallId = pendingToolCalls.get(triggerCallId);\n      if (typeof toolCallId !== \"string\" || toolCallId.length === 0) {\n        return undefined;\n      }\n      return { type: \"toolCall\", tool_call_id: toolCallId } as LifecycleCause;\n    }\n\n    function maybeStartSubagent(ns: Namespace): void {\n      if (ns.length !== depth + 1 || !hasPrefix(ns, scope)) return;\n      const key = nsKey(ns);\n      if (handles.has(key)) return;\n      const lc = lcByNs.get(key);\n      // Only surface nested runs carrying an `lc_agent_name`; plain subgraphs\n      // (no name) are excluded so `run.subagents` stays agent-only.\n      if (typeof lc !== \"string\" || lc.length === 0) return;\n\n      // Per-subagent transformers, each scoped to the subagent's namespace so\n      // they pick out only the subagent's own model node / tools / nested\n      // agents when fed the full event stream.\n      const messages = createMessagesTransformer(ns);\n      const messagesProjection = messages.init();\n      const toolCall = createToolCallTransformer(ns)();\n      const toolCallProjection = toolCall.init();\n      const nested = createSubagentTransformer(ns)();\n      const nestedProjection = nested.init();\n\n      let resolveOutput!: (value: unknown) => void;\n      let rejectOutput!: (error: unknown) => void;\n      const output = new Promise<Record<string, unknown>>((resolve, reject) => {\n        resolveOutput = resolve as (value: unknown) => void;\n        rejectOutput = reject;\n      });\n\n      handles.set(key, {\n        key,\n        path: ns,\n        name: lc,\n        messages,\n        toolCall,\n        nested,\n        resolveOutput,\n        rejectOutput,\n        latestValues: undefined,\n        done: false,\n      });\n\n      subagentsLog.push({\n        name: lc,\n        cause: deriveCause(ns),\n        output,\n        messages: messagesProjection.messages,\n        toolCalls: toolCallProjection.toolCalls,\n        subagents: nestedProjection.subagents,\n      });\n    }\n\n    function finishHandle(\n      handle: SubagentHandle,\n      outcome: { type: \"resolve\" } | { type: \"reject\"; error: unknown }\n    ): void {\n      if (handle.done) return;\n      handle.done = true;\n      if (outcome.type === \"resolve\") {\n        handle.resolveOutput(handle.latestValues);\n      } else {\n        handle.rejectOutput(outcome.error);\n      }\n      handle.messages.finalize?.();\n      handle.toolCall.finalize?.();\n      handle.nested.finalize?.();\n    }\n\n    return {\n      __native: true as const,\n\n      init: () => ({ subagents: subagentsLog }),\n\n      process(event: ProtocolEvent): boolean {\n        const ns = event.params.namespace;\n        const data = event.params.data;\n        const isTaskResult =\n          event.method === \"tasks\" && isRecord(data) && \"result\" in data;\n\n        // Track the tool currently executing at each namespace. A subagent's\n        // dispatching tool starts at the same namespace the subagent roots\n        // under, so this records the cause before the subagent is discovered.\n        if (\n          event.method === \"tools\" &&\n          isRecord(data) &&\n          data.event === \"tool-started\" &&\n          typeof data.tool_call_id === \"string\" &&\n          data.tool_call_id.length > 0\n        ) {\n          activeToolCallByNs.set(nsKey(ns), data.tool_call_id);\n        }\n\n        // A task start: record identity / tool call, then discover a subagent\n        // boundary *before* fanning out so the new handle receives its own\n        // subtree events (which Pregel emits after the parent-namespace task).\n        if (event.method === \"tasks\" && !isTaskResult) {\n          recordIdentity(ns, data);\n          recordPendingToolCalls(data);\n          maybeStartSubagent(ns);\n        }\n\n        // Fan the event out to every active subagent whose subtree contains it.\n        // The per-subagent transformers self-filter by namespace depth.\n        for (const handle of handles.values()) {\n          if (handle.done) continue;\n          if (!hasPrefix(ns, handle.path)) continue;\n\n          handle.messages.process(event);\n          handle.toolCall.process(event);\n          handle.nested.process(event);\n\n          // Track the subagent's own (root-level) state and resolve its\n          // `output` from the last snapshot when its lifecycle completes.\n          if (nsKey(ns) === handle.key) {\n            if (event.method === \"values\" && isRecord(data)) {\n              handle.latestValues = data;\n            } else if (event.method === \"lifecycle\" && isRecord(data)) {\n              const status = data.event;\n              if (status === \"completed\" || status === \"interrupted\") {\n                finishHandle(handle, { type: \"resolve\" });\n              } else if (status === \"failed\") {\n                finishHandle(handle, {\n                  type: \"reject\",\n                  error: new Error(`Subagent ${handle.name} failed`),\n                });\n              }\n            }\n          }\n        }\n\n        return true;\n      },\n\n      finalize(): void {\n        for (const handle of handles.values()) {\n          finishHandle(handle, { type: \"resolve\" });\n        }\n        subagentsLog.close();\n      },\n\n      fail(err: unknown): void {\n        for (const handle of handles.values()) {\n          finishHandle(handle, { type: \"reject\", error: err });\n        }\n        subagentsLog.fail(err);\n      },\n    };\n  };\n}\n"],"mappings":"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"}