{"version":3,"file":"messages.cjs","names":["StreamChannel","hasPrefix","CoreChatModelStream"],"sources":["../../../src/stream/transformers/messages.ts"],"sourcesContent":["import type { ChatModelStreamEvent } from \"@langchain/core/language_models/event\";\nimport { ChatModelStream as CoreChatModelStream } from \"@langchain/core/language_models/stream\";\nimport { hasPrefix } from \"../mux.js\";\nimport { StreamChannel } from \"../stream-channel.js\";\nimport type {\n  ChatModelStream,\n  MessagesEventData,\n  Namespace,\n  ProtocolEvent,\n  StreamTransformer,\n} from \"../types.js\";\nimport type { MessagesTransformerProjection } from \"./types.js\";\n\ntype ActiveMessageStream = {\n  source: StreamChannel<ChatModelStreamEvent>;\n  stream: ChatModelStream;\n};\n\nfunction getMessageStreamKey(data: MessagesEventData): string {\n  const record = data as unknown as Record<string, unknown>;\n  if (typeof record.run_id === \"string\") return `run:${record.run_id}`;\n  if (data.event === \"message-start\" && typeof record.id === \"string\") {\n    return `message:${record.id}`;\n  }\n  return \"__default__\";\n}\n\n/**\n * Creates a {@link StreamTransformer} that groups `messages` channel events into\n * per-message {@link ChatModelStream} instances.\n *\n * A new `ChatModelStream` is created on `message-start` and closed on\n * `message-finish`. Content-block events in between are forwarded to the\n * active stream. Only events whose namespace exactly matches {@link path}\n * are processed; child namespaces are ignored.\n *\n * @param path - Namespace prefix to match against incoming events.\n * @param nodeFilter - If provided, only events emitted by this graph node\n *   are processed; all others are skipped.\n * @returns A `StreamTransformer` whose projection contains the `messages`\n *   async iterable.\n */\nexport function createMessagesTransformer(\n  path: Namespace,\n  nodeFilter?: string\n): StreamTransformer<MessagesTransformerProjection> {\n  const log = StreamChannel.local<ChatModelStream>();\n  const active = new Map<string, ActiveMessageStream>();\n  const ignored = new Set<string>();\n\n  return {\n    init: () => ({\n      messages: log.toAsyncIterable(),\n    }),\n\n    process(event: ProtocolEvent): boolean {\n      if (event.method !== \"messages\") return true;\n      if (!hasPrefix(event.params.namespace, path)) return true;\n\n      // Only capture messages from this graph's own node executions,\n      // which sit exactly one namespace level deeper than `path`.\n      // Events at `path` itself are chain-level replays from the\n      // callback system (handleChainEnd re-emits finalized messages)\n      // and would duplicate the streamed content already captured\n      // at depth+1.\n      const depth = event.params.namespace.length;\n      if (depth !== path.length + 1) return true;\n\n      if (nodeFilter !== undefined && event.params.node !== nodeFilter) {\n        return true;\n      }\n\n      const data = event.params.data as MessagesEventData;\n\n      switch (data.event) {\n        case \"message-start\": {\n          const key = getMessageStreamKey(data);\n          const role = (data as unknown as Record<string, unknown>).role;\n          // Tool results belong on the tools stream and state snapshots, not\n          // the chat-token projection exposed as `run.messages`.\n          if (role === \"tool\") {\n            ignored.add(key);\n            break;\n          }\n          const source = StreamChannel.local<ChatModelStreamEvent>();\n          const stream = Object.assign(\n            new CoreChatModelStream(source.toAsyncIterable()),\n            {\n              namespace: event.params.namespace,\n              node: event.params.node,\n            }\n          ) as ChatModelStream;\n          active.set(key, { source, stream });\n          source.push(data as unknown as ChatModelStreamEvent);\n          log.push(stream);\n          break;\n        }\n\n        case \"content-block-start\":\n        case \"content-block-delta\":\n        case \"content-block-finish\":\n          if (ignored.has(getMessageStreamKey(data))) break;\n          active\n            .get(getMessageStreamKey(data))\n            ?.source.push(data as unknown as ChatModelStreamEvent);\n          break;\n\n        case \"message-finish\": {\n          const key = getMessageStreamKey(data);\n          if (ignored.delete(key)) break;\n          const stream = active.get(key);\n          if (stream) {\n            stream.source.push(data as unknown as ChatModelStreamEvent);\n            stream.source.close();\n            active.delete(key);\n          }\n          break;\n        }\n\n        case \"error\":\n          if (ignored.has(getMessageStreamKey(data))) break;\n          active\n            .get(getMessageStreamKey(data))\n            ?.source.push(data as unknown as ChatModelStreamEvent);\n          break;\n      }\n\n      return true;\n    },\n\n    finalize(): void {\n      for (const [key, stream] of active) {\n        stream.source.push({ event: \"message-finish\" });\n        stream.source.close();\n        active.delete(key);\n      }\n      ignored.clear();\n      log.close();\n    },\n\n    fail(err: unknown): void {\n      for (const [key, stream] of active) {\n        stream.source.fail(err);\n        active.delete(key);\n      }\n      ignored.clear();\n      log.fail(err);\n    },\n  };\n}\n"],"mappings":";;;;AAkBA,SAAS,oBAAoB,MAAiC;CAC5D,MAAM,SAAS;AACf,KAAI,OAAO,OAAO,WAAW,SAAU,QAAO,OAAO,OAAO;AAC5D,KAAI,KAAK,UAAU,mBAAmB,OAAO,OAAO,OAAO,SACzD,QAAO,WAAW,OAAO;AAE3B,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,0BACd,MACA,YACkD;CAClD,MAAM,MAAMA,uBAAAA,cAAc,OAAwB;CAClD,MAAM,yBAAS,IAAI,KAAkC;CACrD,MAAM,0BAAU,IAAI,KAAa;AAEjC,QAAO;EACL,aAAa,EACX,UAAU,IAAI,iBAAiB,EAChC;EAED,QAAQ,OAA+B;AACrC,OAAI,MAAM,WAAW,WAAY,QAAO;AACxC,OAAI,CAACC,YAAAA,UAAU,MAAM,OAAO,WAAW,KAAK,CAAE,QAAO;AASrD,OADc,MAAM,OAAO,UAAU,WACvB,KAAK,SAAS,EAAG,QAAO;AAEtC,OAAI,eAAe,KAAA,KAAa,MAAM,OAAO,SAAS,WACpD,QAAO;GAGT,MAAM,OAAO,MAAM,OAAO;AAE1B,WAAQ,KAAK,OAAb;IACE,KAAK,iBAAiB;KACpB,MAAM,MAAM,oBAAoB,KAAK;AAIrC,SAHc,KAA4C,SAG7C,QAAQ;AACnB,cAAQ,IAAI,IAAI;AAChB;;KAEF,MAAM,SAASD,uBAAAA,cAAc,OAA6B;KAC1D,MAAM,SAAS,OAAO,OACpB,IAAIE,uCAAAA,gBAAoB,OAAO,iBAAiB,CAAC,EACjD;MACE,WAAW,MAAM,OAAO;MACxB,MAAM,MAAM,OAAO;MACpB,CACF;AACD,YAAO,IAAI,KAAK;MAAE;MAAQ;MAAQ,CAAC;AACnC,YAAO,KAAK,KAAwC;AACpD,SAAI,KAAK,OAAO;AAChB;;IAGF,KAAK;IACL,KAAK;IACL,KAAK;AACH,SAAI,QAAQ,IAAI,oBAAoB,KAAK,CAAC,CAAE;AAC5C,YACG,IAAI,oBAAoB,KAAK,CAAC,EAC7B,OAAO,KAAK,KAAwC;AACxD;IAEF,KAAK,kBAAkB;KACrB,MAAM,MAAM,oBAAoB,KAAK;AACrC,SAAI,QAAQ,OAAO,IAAI,CAAE;KACzB,MAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,SAAI,QAAQ;AACV,aAAO,OAAO,KAAK,KAAwC;AAC3D,aAAO,OAAO,OAAO;AACrB,aAAO,OAAO,IAAI;;AAEpB;;IAGF,KAAK;AACH,SAAI,QAAQ,IAAI,oBAAoB,KAAK,CAAC,CAAE;AAC5C,YACG,IAAI,oBAAoB,KAAK,CAAC,EAC7B,OAAO,KAAK,KAAwC;AACxD;;AAGJ,UAAO;;EAGT,WAAiB;AACf,QAAK,MAAM,CAAC,KAAK,WAAW,QAAQ;AAClC,WAAO,OAAO,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAC/C,WAAO,OAAO,OAAO;AACrB,WAAO,OAAO,IAAI;;AAEpB,WAAQ,OAAO;AACf,OAAI,OAAO;;EAGb,KAAK,KAAoB;AACvB,QAAK,MAAM,CAAC,KAAK,WAAW,QAAQ;AAClC,WAAO,OAAO,KAAK,IAAI;AACvB,WAAO,OAAO,IAAI;;AAEpB,WAAQ,OAAO;AACf,OAAI,KAAK,IAAI;;EAEhB"}