@langchain/langgraph-sdk 1.8.4 → 1.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/headless-tools.cjs +114 -0
  2. package/dist/headless-tools.cjs.map +1 -0
  3. package/dist/headless-tools.d.cts +72 -0
  4. package/dist/headless-tools.d.cts.map +1 -0
  5. package/dist/headless-tools.d.ts +72 -0
  6. package/dist/headless-tools.d.ts.map +1 -0
  7. package/dist/headless-tools.js +108 -0
  8. package/dist/headless-tools.js.map +1 -0
  9. package/dist/index.cjs +8 -0
  10. package/dist/index.d.cts +2 -1
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.js +2 -1
  13. package/dist/react/index.cjs +8 -0
  14. package/dist/react/index.d.cts +2 -1
  15. package/dist/react/index.d.ts +2 -1
  16. package/dist/react/index.js +2 -1
  17. package/dist/react/stream.custom.cjs +20 -5
  18. package/dist/react/stream.custom.cjs.map +1 -1
  19. package/dist/react/stream.custom.d.cts.map +1 -1
  20. package/dist/react/stream.custom.d.ts.map +1 -1
  21. package/dist/react/stream.custom.js +21 -6
  22. package/dist/react/stream.custom.js.map +1 -1
  23. package/dist/react/stream.lgp.cjs +25 -7
  24. package/dist/react/stream.lgp.cjs.map +1 -1
  25. package/dist/react/stream.lgp.js +26 -8
  26. package/dist/react/stream.lgp.js.map +1 -1
  27. package/dist/ui/class-messages.d.cts +26 -5
  28. package/dist/ui/class-messages.d.cts.map +1 -1
  29. package/dist/ui/class-messages.d.ts +26 -5
  30. package/dist/ui/class-messages.d.ts.map +1 -1
  31. package/dist/ui/index.cjs +2 -0
  32. package/dist/ui/index.d.cts +2 -2
  33. package/dist/ui/index.d.ts +2 -2
  34. package/dist/ui/index.js +2 -2
  35. package/dist/ui/interrupts.cjs +25 -3
  36. package/dist/ui/interrupts.cjs.map +1 -1
  37. package/dist/ui/interrupts.d.cts +3 -1
  38. package/dist/ui/interrupts.d.cts.map +1 -1
  39. package/dist/ui/interrupts.d.ts +3 -1
  40. package/dist/ui/interrupts.d.ts.map +1 -1
  41. package/dist/ui/interrupts.js +24 -4
  42. package/dist/ui/interrupts.js.map +1 -1
  43. package/dist/ui/messages.cjs.map +1 -1
  44. package/dist/ui/messages.d.cts +5 -3
  45. package/dist/ui/messages.d.cts.map +1 -1
  46. package/dist/ui/messages.d.ts +5 -3
  47. package/dist/ui/messages.d.ts.map +1 -1
  48. package/dist/ui/messages.js.map +1 -1
  49. package/dist/ui/orchestrator-custom.cjs +15 -5
  50. package/dist/ui/orchestrator-custom.cjs.map +1 -1
  51. package/dist/ui/orchestrator-custom.d.cts.map +1 -1
  52. package/dist/ui/orchestrator-custom.d.ts.map +1 -1
  53. package/dist/ui/orchestrator-custom.js +16 -6
  54. package/dist/ui/orchestrator-custom.js.map +1 -1
  55. package/dist/ui/orchestrator.cjs +23 -7
  56. package/dist/ui/orchestrator.cjs.map +1 -1
  57. package/dist/ui/orchestrator.d.cts.map +1 -1
  58. package/dist/ui/orchestrator.d.ts.map +1 -1
  59. package/dist/ui/orchestrator.js +24 -8
  60. package/dist/ui/orchestrator.js.map +1 -1
  61. package/dist/ui/stream/index.d.cts +0 -1
  62. package/dist/ui/stream/index.d.cts.map +1 -1
  63. package/dist/ui/stream/index.d.ts +0 -1
  64. package/dist/ui/stream/index.d.ts.map +1 -1
  65. package/dist/ui/subagents.cjs +6 -9
  66. package/dist/ui/subagents.cjs.map +1 -1
  67. package/dist/ui/subagents.d.cts +5 -8
  68. package/dist/ui/subagents.d.cts.map +1 -1
  69. package/dist/ui/subagents.d.ts +5 -8
  70. package/dist/ui/subagents.d.ts.map +1 -1
  71. package/dist/ui/subagents.js +6 -9
  72. package/dist/ui/subagents.js.map +1 -1
  73. package/dist/ui/types.d.cts +15 -1
  74. package/dist/ui/types.d.cts.map +1 -1
  75. package/dist/ui/types.d.ts +15 -1
  76. package/dist/ui/types.d.ts.map +1 -1
  77. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"interrupts.js","names":[],"sources":["../../src/ui/interrupts.ts"],"sourcesContent":["import { normalizeHitlInterruptPayload } from \"./hitl-interrupt-payload.js\";\nimport { Interrupt, ThreadState } from \"../schema.js\";\n\n/**\n * Normalizes HITL interrupt payloads to expose camelCase fields plus deprecated\n * snake_case aliases for compatibility during migration.\n */\nexport function normalizeInterruptForClient<T = unknown>(\n interrupt: Interrupt<T>\n): Interrupt<T> {\n if (interrupt.value === undefined) {\n return interrupt;\n }\n return {\n ...interrupt,\n value: normalizeHitlInterruptPayload(interrupt.value) as T,\n };\n}\n\n/**\n * Applies {@link normalizeInterruptForClient} to each interrupt.\n */\nexport function normalizeInterruptsList<T = unknown>(\n interrupts: Interrupt<T>[]\n): Interrupt<T>[] {\n return interrupts.map((i) => normalizeInterruptForClient(i));\n}\n\nexport function extractInterrupts<InterruptType = unknown>(\n values: unknown,\n options?: {\n isLoading: boolean;\n threadState: ThreadState | undefined;\n error: unknown;\n }\n): Interrupt<InterruptType> | undefined {\n if (\n typeof values === \"object\" &&\n values != null &&\n \"__interrupt__\" in values &&\n Array.isArray(values.__interrupt__)\n ) {\n const valueInterrupts = values.__interrupt__ as Interrupt<InterruptType>[];\n if (valueInterrupts.length === 0) return { when: \"breakpoint\" };\n if (valueInterrupts.length === 1) {\n return normalizeInterruptForClient(valueInterrupts[0]);\n }\n\n // TODO: fix the typing of interrupts if multiple interrupts are returned\n const normalized = valueInterrupts.map((i) =>\n normalizeInterruptForClient(i)\n );\n return normalized as unknown as Interrupt<InterruptType> | undefined;\n }\n\n // If we're deferring to old interrupt detection logic, don't show the interrupt if the stream is loading\n if (options?.isLoading) return undefined;\n\n const interrupts = options?.threadState?.tasks?.at(-1)?.interrupts;\n if (interrupts == null || interrupts.length === 0) {\n // check if there's a next task present\n const next = options?.threadState?.next ?? [];\n if (!next.length || options?.error != null) return undefined;\n return { when: \"breakpoint\" };\n }\n\n // Return only the current interrupt\n return normalizeInterruptForClient(\n interrupts.at(-1) as Interrupt<InterruptType>\n );\n}\n"],"mappings":";;;;;;AAOA,SAAgB,4BACd,WACc;AACd,KAAI,UAAU,UAAU,KAAA,EACtB,QAAO;AAET,QAAO;EACL,GAAG;EACH,OAAO,8BAA8B,UAAU,MAAM;EACtD;;;;;AAMH,SAAgB,wBACd,YACgB;AAChB,QAAO,WAAW,KAAK,MAAM,4BAA4B,EAAE,CAAC;;AAG9D,SAAgB,kBACd,QACA,SAKsC;AACtC,KACE,OAAO,WAAW,YAClB,UAAU,QACV,mBAAmB,UACnB,MAAM,QAAQ,OAAO,cAAc,EACnC;EACA,MAAM,kBAAkB,OAAO;AAC/B,MAAI,gBAAgB,WAAW,EAAG,QAAO,EAAE,MAAM,cAAc;AAC/D,MAAI,gBAAgB,WAAW,EAC7B,QAAO,4BAA4B,gBAAgB,GAAG;AAOxD,SAHmB,gBAAgB,KAAK,MACtC,4BAA4B,EAAE,CAC/B;;AAKH,KAAI,SAAS,UAAW,QAAO,KAAA;CAE/B,MAAM,aAAa,SAAS,aAAa,OAAO,GAAG,GAAG,EAAE;AACxD,KAAI,cAAc,QAAQ,WAAW,WAAW,GAAG;AAGjD,MAAI,EADS,SAAS,aAAa,QAAQ,EAAE,EACnC,UAAU,SAAS,SAAS,KAAM,QAAO,KAAA;AACnD,SAAO,EAAE,MAAM,cAAc;;AAI/B,QAAO,4BACL,WAAW,GAAG,GAAG,CAClB"}
1
+ {"version":3,"file":"interrupts.js","names":[],"sources":["../../src/ui/interrupts.ts"],"sourcesContent":["import { normalizeHitlInterruptPayload } from \"./hitl-interrupt-payload.js\";\nimport { filterOutHeadlessToolInterrupts } from \"../headless-tools.js\";\nimport { Interrupt, ThreadState } from \"../schema.js\";\n\n/**\n * Normalizes HITL interrupt payloads to expose camelCase fields plus deprecated\n * snake_case aliases for compatibility during migration.\n */\nexport function normalizeInterruptForClient<T = unknown>(\n interrupt: Interrupt<T>\n): Interrupt<T> {\n if (interrupt.value === undefined) {\n return interrupt;\n }\n return {\n ...interrupt,\n value: normalizeHitlInterruptPayload(interrupt.value) as T,\n };\n}\n\n/**\n * Applies {@link normalizeInterruptForClient} to each interrupt.\n */\nexport function normalizeInterruptsList<T = unknown>(\n interrupts: Interrupt<T>[]\n): Interrupt<T>[] {\n return interrupts.map((i) => normalizeInterruptForClient(i));\n}\n\nexport function userFacingInterruptsFromValuesArray<InterruptType = unknown>(\n valueInterrupts: Interrupt<InterruptType>[]\n): Interrupt<InterruptType>[] {\n if (valueInterrupts.length === 0) return [{ when: \"breakpoint\" }];\n\n const filtered = filterOutHeadlessToolInterrupts(valueInterrupts);\n if (filtered.length === 0) return [];\n\n return normalizeInterruptsList(filtered as Interrupt<InterruptType>[]);\n}\n\nexport function userFacingInterruptsFromThreadTasks<InterruptType = unknown>(\n allInterrupts: Interrupt<InterruptType>[]\n): Interrupt<InterruptType>[] | null {\n if (allInterrupts.length === 0) return null;\n\n const filtered = filterOutHeadlessToolInterrupts(allInterrupts);\n if (filtered.length === 0) return [];\n\n return normalizeInterruptsList(filtered as Interrupt<InterruptType>[]);\n}\n\nexport function extractInterrupts<InterruptType = unknown>(\n values: unknown,\n options?: {\n isLoading: boolean;\n threadState: ThreadState | undefined;\n error: unknown;\n }\n): Interrupt<InterruptType> | undefined {\n if (\n typeof values === \"object\" &&\n values != null &&\n \"__interrupt__\" in values &&\n Array.isArray(values.__interrupt__)\n ) {\n const valueInterrupts = values.__interrupt__ as Interrupt<InterruptType>[];\n if (valueInterrupts.length === 0) return { when: \"breakpoint\" };\n\n const filtered = filterOutHeadlessToolInterrupts(valueInterrupts);\n if (filtered.length === 0) return undefined;\n if (filtered.length === 1) {\n return normalizeInterruptForClient(\n filtered[0] as Interrupt<InterruptType>\n );\n }\n\n // TODO: fix the typing of interrupts if multiple interrupts are returned\n const normalized = filtered.map((i) => normalizeInterruptForClient(i));\n return normalized as unknown as Interrupt<InterruptType> | undefined;\n }\n\n // If we're deferring to old interrupt detection logic, don't show the interrupt if the stream is loading\n if (options?.isLoading) return undefined;\n\n const interrupts = options?.threadState?.tasks?.at(-1)?.interrupts;\n if (interrupts == null || interrupts.length === 0) {\n // check if there's a next task present\n const next = options?.threadState?.next ?? [];\n if (!next.length || options?.error != null) return undefined;\n return { when: \"breakpoint\" };\n }\n\n const filtered = filterOutHeadlessToolInterrupts(\n interrupts as Interrupt<InterruptType>[]\n );\n if (filtered.length === 0) {\n const next = options?.threadState?.next ?? [];\n if (!next.length || options?.error != null) return undefined;\n return { when: \"breakpoint\" };\n }\n\n // Return only the current interrupt\n return normalizeInterruptForClient(\n filtered.at(-1) as Interrupt<InterruptType>\n );\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,4BACd,WACc;AACd,KAAI,UAAU,UAAU,KAAA,EACtB,QAAO;AAET,QAAO;EACL,GAAG;EACH,OAAO,8BAA8B,UAAU,MAAM;EACtD;;;;;AAMH,SAAgB,wBACd,YACgB;AAChB,QAAO,WAAW,KAAK,MAAM,4BAA4B,EAAE,CAAC;;AAG9D,SAAgB,oCACd,iBAC4B;AAC5B,KAAI,gBAAgB,WAAW,EAAG,QAAO,CAAC,EAAE,MAAM,cAAc,CAAC;CAEjE,MAAM,WAAW,gCAAgC,gBAAgB;AACjE,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;AAEpC,QAAO,wBAAwB,SAAuC;;AAGxE,SAAgB,oCACd,eACmC;AACnC,KAAI,cAAc,WAAW,EAAG,QAAO;CAEvC,MAAM,WAAW,gCAAgC,cAAc;AAC/D,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;AAEpC,QAAO,wBAAwB,SAAuC;;AAGxE,SAAgB,kBACd,QACA,SAKsC;AACtC,KACE,OAAO,WAAW,YAClB,UAAU,QACV,mBAAmB,UACnB,MAAM,QAAQ,OAAO,cAAc,EACnC;EACA,MAAM,kBAAkB,OAAO;AAC/B,MAAI,gBAAgB,WAAW,EAAG,QAAO,EAAE,MAAM,cAAc;EAE/D,MAAM,WAAW,gCAAgC,gBAAgB;AACjE,MAAI,SAAS,WAAW,EAAG,QAAO,KAAA;AAClC,MAAI,SAAS,WAAW,EACtB,QAAO,4BACL,SAAS,GACV;AAKH,SADmB,SAAS,KAAK,MAAM,4BAA4B,EAAE,CAAC;;AAKxE,KAAI,SAAS,UAAW,QAAO,KAAA;CAE/B,MAAM,aAAa,SAAS,aAAa,OAAO,GAAG,GAAG,EAAE;AACxD,KAAI,cAAc,QAAQ,WAAW,WAAW,GAAG;AAGjD,MAAI,EADS,SAAS,aAAa,QAAQ,EAAE,EACnC,UAAU,SAAS,SAAS,KAAM,QAAO,KAAA;AACnD,SAAO,EAAE,MAAM,cAAc;;CAG/B,MAAM,WAAW,gCACf,WACD;AACD,KAAI,SAAS,WAAW,GAAG;AAEzB,MAAI,EADS,SAAS,aAAa,QAAQ,EAAE,EACnC,UAAU,SAAS,SAAS,KAAM,QAAO,KAAA;AACnD,SAAO,EAAE,MAAM,cAAc;;AAI/B,QAAO,4BACL,SAAS,GAAG,GAAG,CAChB"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.cjs","names":["HumanMessageChunk","AIMessageChunk","SystemMessageChunk","ToolMessageChunk","RemoveMessage"],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n RemoveMessage,\n convertToChunk,\n coerceMessageLikeToMessage,\n isBaseMessageChunk,\n HumanMessageChunk,\n SystemMessageChunk,\n AIMessageChunk,\n ToolMessageChunk,\n} from \"@langchain/core/messages\";\n\nimport type { Message } from \"../types.messages.js\";\nimport type { ThreadState } from \"../schema.js\";\n\n/**\n * Replaces the `messages` property in a state type with `BaseMessage[]`.\n * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`\n * converts plain message objects to class instances at runtime.\n */\nexport type StateWithBaseMessages<S> =\n S extends Record<string, unknown>\n ? \"messages\" extends keyof S\n ? Omit<S, \"messages\"> & { messages: BaseMessage[] }\n : S\n : S;\n\n/**\n * Maps a `ThreadState<StateType>[]` so that the `messages` field inside\n * `values` is typed as `BaseMessage[]` instead of `Message[]`.\n */\nexport type HistoryWithBaseMessages<T> = T extends ThreadState<infer S>[]\n ? ThreadState<StateWithBaseMessages<S>>[]\n : T;\n\nexport function tryConvertToChunk(\n message: BaseMessage | BaseMessageChunk\n): BaseMessageChunk | null {\n try {\n if (isBaseMessageChunk(message)) return message;\n return convertToChunk(message);\n } catch {\n return null;\n }\n}\n\nexport function tryCoerceMessageLikeToMessage(\n message: Omit<Message, \"type\"> & { type: string }\n): BaseMessage | BaseMessageChunk {\n if (message.type === \"human\" || message.type === \"user\") {\n return new HumanMessageChunk(message);\n }\n\n if (message.type === \"ai\" || message.type === \"assistant\") {\n return new AIMessageChunk(message);\n }\n\n if (message.type === \"system\") {\n return new SystemMessageChunk(message);\n }\n\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n return new ToolMessageChunk({\n ...message,\n tool_call_id: message.tool_call_id as string,\n });\n }\n\n if (message.type === \"remove\" && message.id != null) {\n return new RemoveMessage({ ...message, id: message.id });\n }\n\n return coerceMessageLikeToMessage(message);\n}\n\nexport class MessageTupleManager {\n chunks: Record<\n string,\n {\n chunk?: BaseMessageChunk | BaseMessage;\n metadata?: Record<string, unknown>;\n index?: number;\n }\n > = {};\n\n constructor() {\n this.chunks = {};\n }\n\n add(\n serialized: Message,\n metadata: Record<string, unknown> | undefined\n ): string | null {\n // TODO: this is sometimes sent from the API\n // figure out how to prevent this or move this to LC.js\n if (serialized.type.endsWith(\"MessageChunk\")) {\n // eslint-disable-next-line no-param-reassign\n serialized.type = serialized.type\n .slice(0, -\"MessageChunk\".length)\n .toLowerCase() as Message[\"type\"];\n }\n\n const message = tryCoerceMessageLikeToMessage(serialized);\n const chunk = tryConvertToChunk(message);\n\n const { id } = chunk ?? message;\n if (!id) {\n console.warn(\n \"No message ID found for chunk, ignoring in state\",\n serialized\n );\n return null;\n }\n\n this.chunks[id] ??= {};\n this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;\n if (chunk) {\n const prev = this.chunks[id].chunk;\n this.chunks[id].chunk =\n (isBaseMessageChunk(prev) ? prev : null)?.concat(chunk) ?? chunk;\n } else {\n this.chunks[id].chunk = message;\n }\n\n return id;\n }\n\n clear() {\n this.chunks = {};\n }\n\n get(id: string | null | undefined, defaultIndex?: number) {\n if (id == null) return null;\n if (this.chunks[id] == null) return null;\n if (defaultIndex != null) this.chunks[id].index ??= defaultIndex;\n return this.chunks[id];\n }\n}\n\nexport const toMessageDict = (chunk: BaseMessage): Message => {\n const { type, data } = chunk.toDict();\n return { ...data, type } as Message;\n};\n\n/**\n * Identity converter that keeps @langchain/core class instances.\n * Used by framework SDKs to expose BaseMessage instances instead of plain dicts.\n */\nexport const toMessageClass = (chunk: BaseMessage): BaseMessage => chunk;\n\n/**\n * Ensures all messages in an array are BaseMessage class instances.\n * Messages that are already class instances pass through unchanged.\n * Plain message objects (e.g. from API values/history) are converted\n * via {@link tryCoerceMessageLikeToMessage}.\n */\nexport function ensureMessageInstances(\n messages: (Message | BaseMessage)[]\n): (BaseMessage | BaseMessageChunk)[] {\n return messages.map((msg) => {\n if (typeof (msg as BaseMessage).getType === \"function\") {\n return msg as BaseMessage;\n }\n return tryCoerceMessageLikeToMessage(\n msg as Omit<Message, \"type\"> & { type: string }\n );\n });\n}\n\n/**\n * Converts plain message objects within each history state's values\n * to proper BaseMessage class instances. Returns a new array with\n * shallow-copied states whose messages have been coerced.\n */\nexport function ensureHistoryMessageInstances<\n StateType extends Record<string, unknown>,\n>(\n history: ThreadState<StateType>[],\n messagesKey: string = \"messages\"\n): ThreadState<StateType>[] {\n return history.map((state) => {\n if (state.values == null) return state;\n const messages = state.values[messagesKey];\n if (!Array.isArray(messages)) return state;\n return {\n ...state,\n values: {\n ...state.values,\n [messagesKey]: ensureMessageInstances(messages),\n },\n };\n });\n}\n"],"mappings":";;;AAoCA,SAAgB,kBACd,SACyB;AACzB,KAAI;AACF,OAAA,GAAA,yBAAA,oBAAuB,QAAQ,CAAE,QAAO;AACxC,UAAA,GAAA,yBAAA,gBAAsB,QAAQ;SACxB;AACN,SAAO;;;AAIX,SAAgB,8BACd,SACgC;AAChC,KAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,OAC/C,QAAO,IAAIA,yBAAAA,kBAAkB,QAAQ;AAGvC,KAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,YAC5C,QAAO,IAAIC,yBAAAA,eAAe,QAAQ;AAGpC,KAAI,QAAQ,SAAS,SACnB,QAAO,IAAIC,yBAAAA,mBAAmB,QAAQ;AAGxC,KAAI,QAAQ,SAAS,UAAU,kBAAkB,QAC/C,QAAO,IAAIC,yBAAAA,iBAAiB;EAC1B,GAAG;EACH,cAAc,QAAQ;EACvB,CAAC;AAGJ,KAAI,QAAQ,SAAS,YAAY,QAAQ,MAAM,KAC7C,QAAO,IAAIC,yBAAAA,cAAc;EAAE,GAAG;EAAS,IAAI,QAAQ;EAAI,CAAC;AAG1D,SAAA,GAAA,yBAAA,4BAAkC,QAAQ;;AAG5C,IAAa,sBAAb,MAAiC;CAC/B,SAOI,EAAE;CAEN,cAAc;AACZ,OAAK,SAAS,EAAE;;CAGlB,IACE,YACA,UACe;AAGf,MAAI,WAAW,KAAK,SAAS,eAAe,CAE1C,YAAW,OAAO,WAAW,KAC1B,MAAM,GAAG,IAAuB,CAChC,aAAa;EAGlB,MAAM,UAAU,8BAA8B,WAAW;EACzD,MAAM,QAAQ,kBAAkB,QAAQ;EAExC,MAAM,EAAE,OAAO,SAAS;AACxB,MAAI,CAAC,IAAI;AACP,WAAQ,KACN,oDACA,WACD;AACD,UAAO;;AAGT,OAAK,OAAO,QAAQ,EAAE;AACtB,OAAK,OAAO,IAAI,WAAW,YAAY,KAAK,OAAO,IAAI;AACvD,MAAI,OAAO;GACT,MAAM,OAAO,KAAK,OAAO,IAAI;AAC7B,QAAK,OAAO,IAAI,UAAA,GAAA,yBAAA,oBACM,KAAK,GAAG,OAAO,OAAO,OAAO,MAAM,IAAI;QAE7D,MAAK,OAAO,IAAI,QAAQ;AAG1B,SAAO;;CAGT,QAAQ;AACN,OAAK,SAAS,EAAE;;CAGlB,IAAI,IAA+B,cAAuB;AACxD,MAAI,MAAM,KAAM,QAAO;AACvB,MAAI,KAAK,OAAO,OAAO,KAAM,QAAO;AACpC,MAAI,gBAAgB,KAAM,MAAK,OAAO,IAAI,UAAU;AACpD,SAAO,KAAK,OAAO;;;AAIvB,MAAa,iBAAiB,UAAgC;CAC5D,MAAM,EAAE,MAAM,SAAS,MAAM,QAAQ;AACrC,QAAO;EAAE,GAAG;EAAM;EAAM;;;;;;AAO1B,MAAa,kBAAkB,UAAoC;;;;;;;AAQnE,SAAgB,uBACd,UACoC;AACpC,QAAO,SAAS,KAAK,QAAQ;AAC3B,MAAI,OAAQ,IAAoB,YAAY,WAC1C,QAAO;AAET,SAAO,8BACL,IACD;GACD;;;;;;;AAQJ,SAAgB,8BAGd,SACA,cAAsB,YACI;AAC1B,QAAO,QAAQ,KAAK,UAAU;AAC5B,MAAI,MAAM,UAAU,KAAM,QAAO;EACjC,MAAM,WAAW,MAAM,OAAO;AAC9B,MAAI,CAAC,MAAM,QAAQ,SAAS,CAAE,QAAO;AACrC,SAAO;GACL,GAAG;GACH,QAAQ;IACN,GAAG,MAAM;KACR,cAAc,uBAAuB,SAAS;IAChD;GACF;GACD"}
1
+ {"version":3,"file":"messages.cjs","names":["HumanMessageChunk","AIMessageChunk","SystemMessageChunk","ToolMessageChunk","RemoveMessage"],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n RemoveMessage,\n convertToChunk,\n coerceMessageLikeToMessage,\n isBaseMessageChunk,\n HumanMessageChunk,\n SystemMessageChunk,\n AIMessageChunk,\n ToolMessageChunk,\n} from \"@langchain/core/messages\";\n\nimport type { Message } from \"../types.messages.js\";\nimport type { ThreadState } from \"../schema.js\";\n\n/**\n * Replaces the `messages` property in a state type with `BaseMessage[]`.\n * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`\n * converts plain message objects to class instances at runtime.\n */\nexport type StateWithBaseMessages<S> = S extends { messages: unknown }\n ? Omit<S, \"messages\"> & { messages: BaseMessage[] }\n : S;\n\n/**\n * Maps a `ThreadState<StateType>[]` so that the `messages` field inside\n * `values` is typed as `BaseMessage[]` instead of `Message[]`.\n */\nexport type HistoryWithBaseMessages<T> = T extends ThreadState<infer S>[]\n ? ThreadState<StateWithBaseMessages<S>>[]\n : T;\n\nexport function tryConvertToChunk(\n message: BaseMessage | BaseMessageChunk\n): BaseMessageChunk | null {\n try {\n if (isBaseMessageChunk(message)) return message;\n return convertToChunk(message);\n } catch {\n return null;\n }\n}\n\nexport function tryCoerceMessageLikeToMessage(\n message: Omit<Message, \"type\"> & { type: string }\n): BaseMessage | BaseMessageChunk {\n if (message.type === \"human\" || message.type === \"user\") {\n return new HumanMessageChunk(message);\n }\n\n if (message.type === \"ai\" || message.type === \"assistant\") {\n return new AIMessageChunk(message);\n }\n\n if (message.type === \"system\") {\n return new SystemMessageChunk(message);\n }\n\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n return new ToolMessageChunk({\n ...message,\n tool_call_id: message.tool_call_id as string,\n });\n }\n\n if (message.type === \"remove\" && message.id != null) {\n return new RemoveMessage({ ...message, id: message.id });\n }\n\n return coerceMessageLikeToMessage(message);\n}\n\nexport class MessageTupleManager {\n chunks: Record<\n string,\n {\n chunk?: BaseMessageChunk | BaseMessage;\n metadata?: Record<string, unknown>;\n index?: number;\n }\n > = {};\n\n constructor() {\n this.chunks = {};\n }\n\n add(\n serialized: Message,\n metadata: Record<string, unknown> | undefined\n ): string | null {\n // TODO: this is sometimes sent from the API\n // figure out how to prevent this or move this to LC.js\n if (serialized.type.endsWith(\"MessageChunk\")) {\n // eslint-disable-next-line no-param-reassign\n serialized.type = serialized.type\n .slice(0, -\"MessageChunk\".length)\n .toLowerCase() as Message[\"type\"];\n }\n\n const message = tryCoerceMessageLikeToMessage(serialized);\n const chunk = tryConvertToChunk(message);\n\n const { id } = chunk ?? message;\n if (!id) {\n console.warn(\n \"No message ID found for chunk, ignoring in state\",\n serialized\n );\n return null;\n }\n\n this.chunks[id] ??= {};\n this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;\n if (chunk) {\n const prev = this.chunks[id].chunk;\n this.chunks[id].chunk =\n (isBaseMessageChunk(prev) ? prev : null)?.concat(chunk) ?? chunk;\n } else {\n this.chunks[id].chunk = message;\n }\n\n return id;\n }\n\n clear() {\n this.chunks = {};\n }\n\n get(id: string | null | undefined, defaultIndex?: number) {\n if (id == null) return null;\n if (this.chunks[id] == null) return null;\n if (defaultIndex != null) this.chunks[id].index ??= defaultIndex;\n return this.chunks[id];\n }\n}\n\nexport const toMessageDict = (chunk: BaseMessage): Message => {\n const { type, data } = chunk.toDict();\n return { ...data, type } as Message;\n};\n\n/**\n * Identity converter that keeps @langchain/core class instances.\n * Used by framework SDKs to expose BaseMessage instances instead of plain dicts.\n */\nexport const toMessageClass = (chunk: BaseMessage): BaseMessage => chunk;\n\n/**\n * Ensures all messages in an array are BaseMessage class instances.\n * Messages that are already class instances pass through unchanged.\n * Plain message objects (e.g. from API values/history) are converted\n * via {@link tryCoerceMessageLikeToMessage}.\n */\nexport function ensureMessageInstances(\n messages: (Message | BaseMessage)[]\n): (BaseMessage | BaseMessageChunk)[] {\n return messages.map((msg) => {\n if (typeof (msg as BaseMessage).getType === \"function\") {\n return msg as BaseMessage;\n }\n return tryCoerceMessageLikeToMessage(\n msg as Omit<Message, \"type\"> & { type: string }\n );\n });\n}\n\n/**\n * Converts plain message objects within each history state's values\n * to proper BaseMessage class instances. Returns a new array with\n * shallow-copied states whose messages have been coerced.\n */\nexport function ensureHistoryMessageInstances<\n StateType extends Record<string, unknown>,\n>(\n history: ThreadState<StateType>[],\n messagesKey: string = \"messages\"\n): ThreadState<StateType>[] {\n return history.map((state) => {\n if (state.values == null) return state;\n const messages = state.values[messagesKey];\n if (!Array.isArray(messages)) return state;\n return {\n ...state,\n values: {\n ...state.values,\n [messagesKey]: ensureMessageInstances(messages),\n },\n };\n });\n}\n"],"mappings":";;;AAiCA,SAAgB,kBACd,SACyB;AACzB,KAAI;AACF,OAAA,GAAA,yBAAA,oBAAuB,QAAQ,CAAE,QAAO;AACxC,UAAA,GAAA,yBAAA,gBAAsB,QAAQ;SACxB;AACN,SAAO;;;AAIX,SAAgB,8BACd,SACgC;AAChC,KAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,OAC/C,QAAO,IAAIA,yBAAAA,kBAAkB,QAAQ;AAGvC,KAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,YAC5C,QAAO,IAAIC,yBAAAA,eAAe,QAAQ;AAGpC,KAAI,QAAQ,SAAS,SACnB,QAAO,IAAIC,yBAAAA,mBAAmB,QAAQ;AAGxC,KAAI,QAAQ,SAAS,UAAU,kBAAkB,QAC/C,QAAO,IAAIC,yBAAAA,iBAAiB;EAC1B,GAAG;EACH,cAAc,QAAQ;EACvB,CAAC;AAGJ,KAAI,QAAQ,SAAS,YAAY,QAAQ,MAAM,KAC7C,QAAO,IAAIC,yBAAAA,cAAc;EAAE,GAAG;EAAS,IAAI,QAAQ;EAAI,CAAC;AAG1D,SAAA,GAAA,yBAAA,4BAAkC,QAAQ;;AAG5C,IAAa,sBAAb,MAAiC;CAC/B,SAOI,EAAE;CAEN,cAAc;AACZ,OAAK,SAAS,EAAE;;CAGlB,IACE,YACA,UACe;AAGf,MAAI,WAAW,KAAK,SAAS,eAAe,CAE1C,YAAW,OAAO,WAAW,KAC1B,MAAM,GAAG,IAAuB,CAChC,aAAa;EAGlB,MAAM,UAAU,8BAA8B,WAAW;EACzD,MAAM,QAAQ,kBAAkB,QAAQ;EAExC,MAAM,EAAE,OAAO,SAAS;AACxB,MAAI,CAAC,IAAI;AACP,WAAQ,KACN,oDACA,WACD;AACD,UAAO;;AAGT,OAAK,OAAO,QAAQ,EAAE;AACtB,OAAK,OAAO,IAAI,WAAW,YAAY,KAAK,OAAO,IAAI;AACvD,MAAI,OAAO;GACT,MAAM,OAAO,KAAK,OAAO,IAAI;AAC7B,QAAK,OAAO,IAAI,UAAA,GAAA,yBAAA,oBACM,KAAK,GAAG,OAAO,OAAO,OAAO,MAAM,IAAI;QAE7D,MAAK,OAAO,IAAI,QAAQ;AAG1B,SAAO;;CAGT,QAAQ;AACN,OAAK,SAAS,EAAE;;CAGlB,IAAI,IAA+B,cAAuB;AACxD,MAAI,MAAM,KAAM,QAAO;AACvB,MAAI,KAAK,OAAO,OAAO,KAAM,QAAO;AACpC,MAAI,gBAAgB,KAAM,MAAK,OAAO,IAAI,UAAU;AACpD,SAAO,KAAK,OAAO;;;AAIvB,MAAa,iBAAiB,UAAgC;CAC5D,MAAM,EAAE,MAAM,SAAS,MAAM,QAAQ;AACrC,QAAO;EAAE,GAAG;EAAM;EAAM;;;;;;AAO1B,MAAa,kBAAkB,UAAoC;;;;;;;AAQnE,SAAgB,uBACd,UACoC;AACpC,QAAO,SAAS,KAAK,QAAQ;AAC3B,MAAI,OAAQ,IAAoB,YAAY,WAC1C,QAAO;AAET,SAAO,8BACL,IACD;GACD;;;;;;;AAQJ,SAAgB,8BAGd,SACA,cAAsB,YACI;AAC1B,QAAO,QAAQ,KAAK,UAAU;AAC5B,MAAI,MAAM,UAAU,KAAM,QAAO;EACjC,MAAM,WAAW,MAAM,OAAO;AAC9B,MAAI,CAAC,MAAM,QAAQ,SAAS,CAAE,QAAO;AACrC,SAAO;GACL,GAAG;GACH,QAAQ;IACN,GAAG,MAAM;KACR,cAAc,uBAAuB,SAAS;IAChD;GACF;GACD"}
@@ -9,9 +9,11 @@ import { BaseMessage, BaseMessageChunk } from "@langchain/core/messages";
9
9
  * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`
10
10
  * converts plain message objects to class instances at runtime.
11
11
  */
12
- type StateWithBaseMessages<S> = S extends Record<string, unknown> ? "messages" extends keyof S ? Omit<S, "messages"> & {
12
+ type StateWithBaseMessages<S> = S extends {
13
+ messages: unknown;
14
+ } ? Omit<S, "messages"> & {
13
15
  messages: BaseMessage[];
14
- } : S : S;
16
+ } : S;
15
17
  /**
16
18
  * Maps a `ThreadState<StateType>[]` so that the `messages` field inside
17
19
  * `values` is typed as `BaseMessage[]` instead of `Message[]`.
@@ -52,5 +54,5 @@ declare function ensureMessageInstances(messages: (Message | BaseMessage)[]): (B
52
54
  */
53
55
  declare function ensureHistoryMessageInstances<StateType extends Record<string, unknown>>(history: ThreadState<StateType>[], messagesKey?: string): ThreadState<StateType>[];
54
56
  //#endregion
55
- export { HistoryWithBaseMessages, MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict };
57
+ export { HistoryWithBaseMessages, MessageTupleManager, StateWithBaseMessages, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict };
56
58
  //# sourceMappingURL=messages.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.cts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;;AAqBA;;KAAY,qBAAA,MACV,CAAA,SAAU,MAAA,6CACmB,CAAA,GACvB,IAAA,CAAK,CAAA;EAAmB,QAAA,EAAU,WAAA;AAAA,IAClC,CAAA,GACF,CAAA;;;;;KAMM,uBAAA,MAA6B,CAAA,SAAU,WAAA,cAC/C,WAAA,CAAY,qBAAA,CAAsB,CAAA,OAClC,CAAA;AAAA,cA0CS,mBAAA;EACX,MAAA,EAAQ,MAAA;IAGJ,KAAA,GAAQ,gBAAA,GAAmB,WAAA;IAC3B,QAAA,GAAW,MAAA;IACX,KAAA;EAAA;EAIJ,WAAA,CAAA;EAIA,GAAA,CACE,UAAA,EAAY,OAAA,EACZ,QAAA,EAAU,MAAA;EAoCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAxCjB,yBAAA,CAAA,cAAA;;;;;cAgDP,aAAA,GAAa,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAGzB,yBAAA,CAHyB,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,OAAA;;;;;cASb,cAAA,GAAc,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAA6C,yBAAA,CAA7C,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAAA,yBAAA,CAAA,cAAA,GAAA,yBAAA,CAAA,WAAA;;;;;;;iBAQX,sBAAA,CACd,QAAA,GAAW,OAAA,GAAU,WAAA,OACnB,WAAA,GAAc,gBAAA;;;;;AAnFlB;iBAmGgB,6BAAA,mBACI,MAAA,kBAAA,CAElB,OAAA,EAAS,WAAA,CAAY,SAAA,KACrB,WAAA,YACC,WAAA,CAAY,SAAA"}
1
+ {"version":3,"file":"messages.d.cts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;;AAqBA;;KAAY,qBAAA,MAA2B,CAAA;EAAY,QAAA;AAAA,IAC/C,IAAA,CAAK,CAAA;EAAmB,QAAA,EAAU,WAAA;AAAA,IAClC,CAAA;;;;;KAMQ,uBAAA,MAA6B,CAAA,SAAU,WAAA,cAC/C,WAAA,CAAY,qBAAA,CAAsB,CAAA,OAClC,CAAA;AAAA,cA0CS,mBAAA;EACX,MAAA,EAAQ,MAAA;IAGJ,KAAA,GAAQ,gBAAA,GAAmB,WAAA;IAC3B,QAAA,GAAW,MAAA;IACX,KAAA;EAAA;EAIJ,WAAA,CAAA;EAIA,GAAA,CACE,UAAA,EAAY,OAAA,EACZ,QAAA,EAAU,MAAA;EAoCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAxCjB,yBAAA,CAAA,cAAA;;;;;cAgDP,aAAA,GAAa,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAGzB,yBAAA,CAHyB,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,OAAA;;;;;cASb,cAAA,GAAc,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAA6C,yBAAA,CAA7C,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAAA,yBAAA,CAAA,cAAA,GAAA,yBAAA,CAAA,WAAA;;;;;AAzE3B;;iBAiFgB,sBAAA,CACd,QAAA,GAAW,OAAA,GAAU,WAAA,OACnB,WAAA,GAAc,gBAAA;;;;;;iBAgBF,6BAAA,mBACI,MAAA,kBAAA,CAElB,OAAA,EAAS,WAAA,CAAY,SAAA,KACrB,WAAA,YACC,WAAA,CAAY,SAAA"}
@@ -9,9 +9,11 @@ import { BaseMessage, BaseMessageChunk } from "@langchain/core/messages";
9
9
  * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`
10
10
  * converts plain message objects to class instances at runtime.
11
11
  */
12
- type StateWithBaseMessages<S> = S extends Record<string, unknown> ? "messages" extends keyof S ? Omit<S, "messages"> & {
12
+ type StateWithBaseMessages<S> = S extends {
13
+ messages: unknown;
14
+ } ? Omit<S, "messages"> & {
13
15
  messages: BaseMessage[];
14
- } : S : S;
16
+ } : S;
15
17
  /**
16
18
  * Maps a `ThreadState<StateType>[]` so that the `messages` field inside
17
19
  * `values` is typed as `BaseMessage[]` instead of `Message[]`.
@@ -52,5 +54,5 @@ declare function ensureMessageInstances(messages: (Message | BaseMessage)[]): (B
52
54
  */
53
55
  declare function ensureHistoryMessageInstances<StateType extends Record<string, unknown>>(history: ThreadState<StateType>[], messagesKey?: string): ThreadState<StateType>[];
54
56
  //#endregion
55
- export { HistoryWithBaseMessages, MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict };
57
+ export { HistoryWithBaseMessages, MessageTupleManager, StateWithBaseMessages, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict };
56
58
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;;AAqBA;;KAAY,qBAAA,MACV,CAAA,SAAU,MAAA,6CACmB,CAAA,GACvB,IAAA,CAAK,CAAA;EAAmB,QAAA,EAAU,WAAA;AAAA,IAClC,CAAA,GACF,CAAA;;;;;KAMM,uBAAA,MAA6B,CAAA,SAAU,WAAA,cAC/C,WAAA,CAAY,qBAAA,CAAsB,CAAA,OAClC,CAAA;AAAA,cA0CS,mBAAA;EACX,MAAA,EAAQ,MAAA;IAGJ,KAAA,GAAQ,gBAAA,GAAmB,WAAA;IAC3B,QAAA,GAAW,MAAA;IACX,KAAA;EAAA;EAIJ,WAAA,CAAA;EAIA,GAAA,CACE,UAAA,EAAY,OAAA,EACZ,QAAA,EAAU,MAAA;EAoCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAxCjB,yBAAA,CAAA,cAAA;;;;;cAgDP,aAAA,GAAa,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAGzB,yBAAA,CAHyB,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,OAAA;;;;;cASb,cAAA,GAAc,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAA6C,yBAAA,CAA7C,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAAA,yBAAA,CAAA,cAAA,GAAA,yBAAA,CAAA,WAAA;;;;;;;iBAQX,sBAAA,CACd,QAAA,GAAW,OAAA,GAAU,WAAA,OACnB,WAAA,GAAc,gBAAA;;;;;AAnFlB;iBAmGgB,6BAAA,mBACI,MAAA,kBAAA,CAElB,OAAA,EAAS,WAAA,CAAY,SAAA,KACrB,WAAA,YACC,WAAA,CAAY,SAAA"}
1
+ {"version":3,"file":"messages.d.ts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;;AAqBA;;KAAY,qBAAA,MAA2B,CAAA;EAAY,QAAA;AAAA,IAC/C,IAAA,CAAK,CAAA;EAAmB,QAAA,EAAU,WAAA;AAAA,IAClC,CAAA;;;;;KAMQ,uBAAA,MAA6B,CAAA,SAAU,WAAA,cAC/C,WAAA,CAAY,qBAAA,CAAsB,CAAA,OAClC,CAAA;AAAA,cA0CS,mBAAA;EACX,MAAA,EAAQ,MAAA;IAGJ,KAAA,GAAQ,gBAAA,GAAmB,WAAA;IAC3B,QAAA,GAAW,MAAA;IACX,KAAA;EAAA;EAIJ,WAAA,CAAA;EAIA,GAAA,CACE,UAAA,EAAY,OAAA,EACZ,QAAA,EAAU,MAAA;EAoCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAxCjB,yBAAA,CAAA,cAAA;;;;;cAgDP,aAAA,GAAa,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAGzB,yBAAA,CAHyB,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,OAAA;;;;;cASb,cAAA,GAAc,KAAA,EAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAA6C,yBAAA,CAA7C,cAAA,GAAA,yBAAA,CAAA,WAAA,MAAA,WAAA,CAAA,yBAAA,CAAA,gBAAA,CAAA,yBAAA,CAAA,cAAA,GAAA,yBAAA,CAAA,WAAA;;;;;AAzE3B;;iBAiFgB,sBAAA,CACd,QAAA,GAAW,OAAA,GAAU,WAAA,OACnB,WAAA,GAAc,gBAAA;;;;;;iBAgBF,6BAAA,mBACI,MAAA,kBAAA,CAElB,OAAA,EAAS,WAAA,CAAY,SAAA,KACrB,WAAA,YACC,WAAA,CAAY,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","names":[],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n RemoveMessage,\n convertToChunk,\n coerceMessageLikeToMessage,\n isBaseMessageChunk,\n HumanMessageChunk,\n SystemMessageChunk,\n AIMessageChunk,\n ToolMessageChunk,\n} from \"@langchain/core/messages\";\n\nimport type { Message } from \"../types.messages.js\";\nimport type { ThreadState } from \"../schema.js\";\n\n/**\n * Replaces the `messages` property in a state type with `BaseMessage[]`.\n * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`\n * converts plain message objects to class instances at runtime.\n */\nexport type StateWithBaseMessages<S> =\n S extends Record<string, unknown>\n ? \"messages\" extends keyof S\n ? Omit<S, \"messages\"> & { messages: BaseMessage[] }\n : S\n : S;\n\n/**\n * Maps a `ThreadState<StateType>[]` so that the `messages` field inside\n * `values` is typed as `BaseMessage[]` instead of `Message[]`.\n */\nexport type HistoryWithBaseMessages<T> = T extends ThreadState<infer S>[]\n ? ThreadState<StateWithBaseMessages<S>>[]\n : T;\n\nexport function tryConvertToChunk(\n message: BaseMessage | BaseMessageChunk\n): BaseMessageChunk | null {\n try {\n if (isBaseMessageChunk(message)) return message;\n return convertToChunk(message);\n } catch {\n return null;\n }\n}\n\nexport function tryCoerceMessageLikeToMessage(\n message: Omit<Message, \"type\"> & { type: string }\n): BaseMessage | BaseMessageChunk {\n if (message.type === \"human\" || message.type === \"user\") {\n return new HumanMessageChunk(message);\n }\n\n if (message.type === \"ai\" || message.type === \"assistant\") {\n return new AIMessageChunk(message);\n }\n\n if (message.type === \"system\") {\n return new SystemMessageChunk(message);\n }\n\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n return new ToolMessageChunk({\n ...message,\n tool_call_id: message.tool_call_id as string,\n });\n }\n\n if (message.type === \"remove\" && message.id != null) {\n return new RemoveMessage({ ...message, id: message.id });\n }\n\n return coerceMessageLikeToMessage(message);\n}\n\nexport class MessageTupleManager {\n chunks: Record<\n string,\n {\n chunk?: BaseMessageChunk | BaseMessage;\n metadata?: Record<string, unknown>;\n index?: number;\n }\n > = {};\n\n constructor() {\n this.chunks = {};\n }\n\n add(\n serialized: Message,\n metadata: Record<string, unknown> | undefined\n ): string | null {\n // TODO: this is sometimes sent from the API\n // figure out how to prevent this or move this to LC.js\n if (serialized.type.endsWith(\"MessageChunk\")) {\n // eslint-disable-next-line no-param-reassign\n serialized.type = serialized.type\n .slice(0, -\"MessageChunk\".length)\n .toLowerCase() as Message[\"type\"];\n }\n\n const message = tryCoerceMessageLikeToMessage(serialized);\n const chunk = tryConvertToChunk(message);\n\n const { id } = chunk ?? message;\n if (!id) {\n console.warn(\n \"No message ID found for chunk, ignoring in state\",\n serialized\n );\n return null;\n }\n\n this.chunks[id] ??= {};\n this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;\n if (chunk) {\n const prev = this.chunks[id].chunk;\n this.chunks[id].chunk =\n (isBaseMessageChunk(prev) ? prev : null)?.concat(chunk) ?? chunk;\n } else {\n this.chunks[id].chunk = message;\n }\n\n return id;\n }\n\n clear() {\n this.chunks = {};\n }\n\n get(id: string | null | undefined, defaultIndex?: number) {\n if (id == null) return null;\n if (this.chunks[id] == null) return null;\n if (defaultIndex != null) this.chunks[id].index ??= defaultIndex;\n return this.chunks[id];\n }\n}\n\nexport const toMessageDict = (chunk: BaseMessage): Message => {\n const { type, data } = chunk.toDict();\n return { ...data, type } as Message;\n};\n\n/**\n * Identity converter that keeps @langchain/core class instances.\n * Used by framework SDKs to expose BaseMessage instances instead of plain dicts.\n */\nexport const toMessageClass = (chunk: BaseMessage): BaseMessage => chunk;\n\n/**\n * Ensures all messages in an array are BaseMessage class instances.\n * Messages that are already class instances pass through unchanged.\n * Plain message objects (e.g. from API values/history) are converted\n * via {@link tryCoerceMessageLikeToMessage}.\n */\nexport function ensureMessageInstances(\n messages: (Message | BaseMessage)[]\n): (BaseMessage | BaseMessageChunk)[] {\n return messages.map((msg) => {\n if (typeof (msg as BaseMessage).getType === \"function\") {\n return msg as BaseMessage;\n }\n return tryCoerceMessageLikeToMessage(\n msg as Omit<Message, \"type\"> & { type: string }\n );\n });\n}\n\n/**\n * Converts plain message objects within each history state's values\n * to proper BaseMessage class instances. Returns a new array with\n * shallow-copied states whose messages have been coerced.\n */\nexport function ensureHistoryMessageInstances<\n StateType extends Record<string, unknown>,\n>(\n history: ThreadState<StateType>[],\n messagesKey: string = \"messages\"\n): ThreadState<StateType>[] {\n return history.map((state) => {\n if (state.values == null) return state;\n const messages = state.values[messagesKey];\n if (!Array.isArray(messages)) return state;\n return {\n ...state,\n values: {\n ...state.values,\n [messagesKey]: ensureMessageInstances(messages),\n },\n };\n });\n}\n"],"mappings":";;AAoCA,SAAgB,kBACd,SACyB;AACzB,KAAI;AACF,MAAI,mBAAmB,QAAQ,CAAE,QAAO;AACxC,SAAO,eAAe,QAAQ;SACxB;AACN,SAAO;;;AAIX,SAAgB,8BACd,SACgC;AAChC,KAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,OAC/C,QAAO,IAAI,kBAAkB,QAAQ;AAGvC,KAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,YAC5C,QAAO,IAAI,eAAe,QAAQ;AAGpC,KAAI,QAAQ,SAAS,SACnB,QAAO,IAAI,mBAAmB,QAAQ;AAGxC,KAAI,QAAQ,SAAS,UAAU,kBAAkB,QAC/C,QAAO,IAAI,iBAAiB;EAC1B,GAAG;EACH,cAAc,QAAQ;EACvB,CAAC;AAGJ,KAAI,QAAQ,SAAS,YAAY,QAAQ,MAAM,KAC7C,QAAO,IAAI,cAAc;EAAE,GAAG;EAAS,IAAI,QAAQ;EAAI,CAAC;AAG1D,QAAO,2BAA2B,QAAQ;;AAG5C,IAAa,sBAAb,MAAiC;CAC/B,SAOI,EAAE;CAEN,cAAc;AACZ,OAAK,SAAS,EAAE;;CAGlB,IACE,YACA,UACe;AAGf,MAAI,WAAW,KAAK,SAAS,eAAe,CAE1C,YAAW,OAAO,WAAW,KAC1B,MAAM,GAAG,IAAuB,CAChC,aAAa;EAGlB,MAAM,UAAU,8BAA8B,WAAW;EACzD,MAAM,QAAQ,kBAAkB,QAAQ;EAExC,MAAM,EAAE,OAAO,SAAS;AACxB,MAAI,CAAC,IAAI;AACP,WAAQ,KACN,oDACA,WACD;AACD,UAAO;;AAGT,OAAK,OAAO,QAAQ,EAAE;AACtB,OAAK,OAAO,IAAI,WAAW,YAAY,KAAK,OAAO,IAAI;AACvD,MAAI,OAAO;GACT,MAAM,OAAO,KAAK,OAAO,IAAI;AAC7B,QAAK,OAAO,IAAI,SACb,mBAAmB,KAAK,GAAG,OAAO,OAAO,OAAO,MAAM,IAAI;QAE7D,MAAK,OAAO,IAAI,QAAQ;AAG1B,SAAO;;CAGT,QAAQ;AACN,OAAK,SAAS,EAAE;;CAGlB,IAAI,IAA+B,cAAuB;AACxD,MAAI,MAAM,KAAM,QAAO;AACvB,MAAI,KAAK,OAAO,OAAO,KAAM,QAAO;AACpC,MAAI,gBAAgB,KAAM,MAAK,OAAO,IAAI,UAAU;AACpD,SAAO,KAAK,OAAO;;;AAIvB,MAAa,iBAAiB,UAAgC;CAC5D,MAAM,EAAE,MAAM,SAAS,MAAM,QAAQ;AACrC,QAAO;EAAE,GAAG;EAAM;EAAM;;;;;;AAO1B,MAAa,kBAAkB,UAAoC;;;;;;;AAQnE,SAAgB,uBACd,UACoC;AACpC,QAAO,SAAS,KAAK,QAAQ;AAC3B,MAAI,OAAQ,IAAoB,YAAY,WAC1C,QAAO;AAET,SAAO,8BACL,IACD;GACD;;;;;;;AAQJ,SAAgB,8BAGd,SACA,cAAsB,YACI;AAC1B,QAAO,QAAQ,KAAK,UAAU;AAC5B,MAAI,MAAM,UAAU,KAAM,QAAO;EACjC,MAAM,WAAW,MAAM,OAAO;AAC9B,MAAI,CAAC,MAAM,QAAQ,SAAS,CAAE,QAAO;AACrC,SAAO;GACL,GAAG;GACH,QAAQ;IACN,GAAG,MAAM;KACR,cAAc,uBAAuB,SAAS;IAChD;GACF;GACD"}
1
+ {"version":3,"file":"messages.js","names":[],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n RemoveMessage,\n convertToChunk,\n coerceMessageLikeToMessage,\n isBaseMessageChunk,\n HumanMessageChunk,\n SystemMessageChunk,\n AIMessageChunk,\n ToolMessageChunk,\n} from \"@langchain/core/messages\";\n\nimport type { Message } from \"../types.messages.js\";\nimport type { ThreadState } from \"../schema.js\";\n\n/**\n * Replaces the `messages` property in a state type with `BaseMessage[]`.\n * Used by framework SDKs to reflect that `ensureHistoryMessageInstances`\n * converts plain message objects to class instances at runtime.\n */\nexport type StateWithBaseMessages<S> = S extends { messages: unknown }\n ? Omit<S, \"messages\"> & { messages: BaseMessage[] }\n : S;\n\n/**\n * Maps a `ThreadState<StateType>[]` so that the `messages` field inside\n * `values` is typed as `BaseMessage[]` instead of `Message[]`.\n */\nexport type HistoryWithBaseMessages<T> = T extends ThreadState<infer S>[]\n ? ThreadState<StateWithBaseMessages<S>>[]\n : T;\n\nexport function tryConvertToChunk(\n message: BaseMessage | BaseMessageChunk\n): BaseMessageChunk | null {\n try {\n if (isBaseMessageChunk(message)) return message;\n return convertToChunk(message);\n } catch {\n return null;\n }\n}\n\nexport function tryCoerceMessageLikeToMessage(\n message: Omit<Message, \"type\"> & { type: string }\n): BaseMessage | BaseMessageChunk {\n if (message.type === \"human\" || message.type === \"user\") {\n return new HumanMessageChunk(message);\n }\n\n if (message.type === \"ai\" || message.type === \"assistant\") {\n return new AIMessageChunk(message);\n }\n\n if (message.type === \"system\") {\n return new SystemMessageChunk(message);\n }\n\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n return new ToolMessageChunk({\n ...message,\n tool_call_id: message.tool_call_id as string,\n });\n }\n\n if (message.type === \"remove\" && message.id != null) {\n return new RemoveMessage({ ...message, id: message.id });\n }\n\n return coerceMessageLikeToMessage(message);\n}\n\nexport class MessageTupleManager {\n chunks: Record<\n string,\n {\n chunk?: BaseMessageChunk | BaseMessage;\n metadata?: Record<string, unknown>;\n index?: number;\n }\n > = {};\n\n constructor() {\n this.chunks = {};\n }\n\n add(\n serialized: Message,\n metadata: Record<string, unknown> | undefined\n ): string | null {\n // TODO: this is sometimes sent from the API\n // figure out how to prevent this or move this to LC.js\n if (serialized.type.endsWith(\"MessageChunk\")) {\n // eslint-disable-next-line no-param-reassign\n serialized.type = serialized.type\n .slice(0, -\"MessageChunk\".length)\n .toLowerCase() as Message[\"type\"];\n }\n\n const message = tryCoerceMessageLikeToMessage(serialized);\n const chunk = tryConvertToChunk(message);\n\n const { id } = chunk ?? message;\n if (!id) {\n console.warn(\n \"No message ID found for chunk, ignoring in state\",\n serialized\n );\n return null;\n }\n\n this.chunks[id] ??= {};\n this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;\n if (chunk) {\n const prev = this.chunks[id].chunk;\n this.chunks[id].chunk =\n (isBaseMessageChunk(prev) ? prev : null)?.concat(chunk) ?? chunk;\n } else {\n this.chunks[id].chunk = message;\n }\n\n return id;\n }\n\n clear() {\n this.chunks = {};\n }\n\n get(id: string | null | undefined, defaultIndex?: number) {\n if (id == null) return null;\n if (this.chunks[id] == null) return null;\n if (defaultIndex != null) this.chunks[id].index ??= defaultIndex;\n return this.chunks[id];\n }\n}\n\nexport const toMessageDict = (chunk: BaseMessage): Message => {\n const { type, data } = chunk.toDict();\n return { ...data, type } as Message;\n};\n\n/**\n * Identity converter that keeps @langchain/core class instances.\n * Used by framework SDKs to expose BaseMessage instances instead of plain dicts.\n */\nexport const toMessageClass = (chunk: BaseMessage): BaseMessage => chunk;\n\n/**\n * Ensures all messages in an array are BaseMessage class instances.\n * Messages that are already class instances pass through unchanged.\n * Plain message objects (e.g. from API values/history) are converted\n * via {@link tryCoerceMessageLikeToMessage}.\n */\nexport function ensureMessageInstances(\n messages: (Message | BaseMessage)[]\n): (BaseMessage | BaseMessageChunk)[] {\n return messages.map((msg) => {\n if (typeof (msg as BaseMessage).getType === \"function\") {\n return msg as BaseMessage;\n }\n return tryCoerceMessageLikeToMessage(\n msg as Omit<Message, \"type\"> & { type: string }\n );\n });\n}\n\n/**\n * Converts plain message objects within each history state's values\n * to proper BaseMessage class instances. Returns a new array with\n * shallow-copied states whose messages have been coerced.\n */\nexport function ensureHistoryMessageInstances<\n StateType extends Record<string, unknown>,\n>(\n history: ThreadState<StateType>[],\n messagesKey: string = \"messages\"\n): ThreadState<StateType>[] {\n return history.map((state) => {\n if (state.values == null) return state;\n const messages = state.values[messagesKey];\n if (!Array.isArray(messages)) return state;\n return {\n ...state,\n values: {\n ...state.values,\n [messagesKey]: ensureMessageInstances(messages),\n },\n };\n });\n}\n"],"mappings":";;AAiCA,SAAgB,kBACd,SACyB;AACzB,KAAI;AACF,MAAI,mBAAmB,QAAQ,CAAE,QAAO;AACxC,SAAO,eAAe,QAAQ;SACxB;AACN,SAAO;;;AAIX,SAAgB,8BACd,SACgC;AAChC,KAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,OAC/C,QAAO,IAAI,kBAAkB,QAAQ;AAGvC,KAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,YAC5C,QAAO,IAAI,eAAe,QAAQ;AAGpC,KAAI,QAAQ,SAAS,SACnB,QAAO,IAAI,mBAAmB,QAAQ;AAGxC,KAAI,QAAQ,SAAS,UAAU,kBAAkB,QAC/C,QAAO,IAAI,iBAAiB;EAC1B,GAAG;EACH,cAAc,QAAQ;EACvB,CAAC;AAGJ,KAAI,QAAQ,SAAS,YAAY,QAAQ,MAAM,KAC7C,QAAO,IAAI,cAAc;EAAE,GAAG;EAAS,IAAI,QAAQ;EAAI,CAAC;AAG1D,QAAO,2BAA2B,QAAQ;;AAG5C,IAAa,sBAAb,MAAiC;CAC/B,SAOI,EAAE;CAEN,cAAc;AACZ,OAAK,SAAS,EAAE;;CAGlB,IACE,YACA,UACe;AAGf,MAAI,WAAW,KAAK,SAAS,eAAe,CAE1C,YAAW,OAAO,WAAW,KAC1B,MAAM,GAAG,IAAuB,CAChC,aAAa;EAGlB,MAAM,UAAU,8BAA8B,WAAW;EACzD,MAAM,QAAQ,kBAAkB,QAAQ;EAExC,MAAM,EAAE,OAAO,SAAS;AACxB,MAAI,CAAC,IAAI;AACP,WAAQ,KACN,oDACA,WACD;AACD,UAAO;;AAGT,OAAK,OAAO,QAAQ,EAAE;AACtB,OAAK,OAAO,IAAI,WAAW,YAAY,KAAK,OAAO,IAAI;AACvD,MAAI,OAAO;GACT,MAAM,OAAO,KAAK,OAAO,IAAI;AAC7B,QAAK,OAAO,IAAI,SACb,mBAAmB,KAAK,GAAG,OAAO,OAAO,OAAO,MAAM,IAAI;QAE7D,MAAK,OAAO,IAAI,QAAQ;AAG1B,SAAO;;CAGT,QAAQ;AACN,OAAK,SAAS,EAAE;;CAGlB,IAAI,IAA+B,cAAuB;AACxD,MAAI,MAAM,KAAM,QAAO;AACvB,MAAI,KAAK,OAAO,OAAO,KAAM,QAAO;AACpC,MAAI,gBAAgB,KAAM,MAAK,OAAO,IAAI,UAAU;AACpD,SAAO,KAAK,OAAO;;;AAIvB,MAAa,iBAAiB,UAAgC;CAC5D,MAAM,EAAE,MAAM,SAAS,MAAM,QAAQ;AACrC,QAAO;EAAE,GAAG;EAAM;EAAM;;;;;;AAO1B,MAAa,kBAAkB,UAAoC;;;;;;;AAQnE,SAAgB,uBACd,UACoC;AACpC,QAAO,SAAS,KAAK,QAAQ;AAC3B,MAAI,OAAQ,IAAoB,YAAY,WAC1C,QAAO;AAET,SAAO,8BACL,IACD;GACD;;;;;;;AAQJ,SAAgB,8BAGd,SACA,cAAsB,YACI;AAC1B,QAAO,QAAQ,KAAK,UAAU;AAC5B,MAAI,MAAM,UAAU,KAAM,QAAO;EACjC,MAAM,WAAW,MAAM,OAAO;AAC9B,MAAI,CAAC,MAAM,QAAQ,SAAS,CAAE,QAAO;AACrC,SAAO;GACL,GAAG;GACH,QAAQ;IACN,GAAG,MAAM;KACR,cAAc,uBAAuB,SAAS;IAChD;GACF;GACD"}
@@ -1,3 +1,4 @@
1
+ const require_headless_tools = require("../headless-tools.cjs");
1
2
  const require_messages = require("./messages.cjs");
2
3
  const require_tools = require("../utils/tools.cjs");
3
4
  const require_manager = require("./manager.cjs");
@@ -42,6 +43,7 @@ var CustomStreamOrchestrator = class {
42
43
  #version = 0;
43
44
  #streamUnsub = null;
44
45
  #disposed = false;
46
+ #handledHeadlessToolInterruptIds = /* @__PURE__ */ new Set();
45
47
  /**
46
48
  * Create a new {@link CustomStreamOrchestrator} instance.
47
49
  *
@@ -60,6 +62,7 @@ var CustomStreamOrchestrator = class {
60
62
  });
61
63
  this.#historyValues = options.initialValues ?? {};
62
64
  this.#streamUnsub = this.stream.subscribe(() => {
65
+ this.#flushPendingHeadlessToolInterrupts();
63
66
  this.#notify();
64
67
  });
65
68
  const historyMessages = this.#getMessages(this.#historyValues);
@@ -99,6 +102,7 @@ var CustomStreamOrchestrator = class {
99
102
  syncThreadId(newId) {
100
103
  if (newId !== this.#threadId) {
101
104
  this.#threadId = newId;
105
+ this.#handledHeadlessToolInterruptIds.clear();
102
106
  this.stream.clear();
103
107
  this.#notify();
104
108
  }
@@ -182,11 +186,7 @@ var CustomStreamOrchestrator = class {
182
186
  * present but empty, or an empty array when no interrupts exist.
183
187
  */
184
188
  get interrupts() {
185
- if (this.stream.values != null && "__interrupt__" in this.stream.values && Array.isArray(this.stream.values.__interrupt__)) {
186
- const valueInterrupts = this.stream.values.__interrupt__;
187
- if (valueInterrupts.length === 0) return [{ when: "breakpoint" }];
188
- return require_interrupts.normalizeInterruptsList(valueInterrupts);
189
- }
189
+ if (this.stream.values != null && "__interrupt__" in this.stream.values && Array.isArray(this.stream.values.__interrupt__)) return require_interrupts.userFacingInterruptsFromValuesArray(this.stream.values.__interrupt__);
190
190
  return [];
191
191
  }
192
192
  /**
@@ -274,6 +274,7 @@ var CustomStreamOrchestrator = class {
274
274
  switchThread(newThreadId) {
275
275
  if (newThreadId !== this.#threadId) {
276
276
  this.#threadId = newThreadId;
277
+ this.#handledHeadlessToolInterruptIds.clear();
277
278
  this.stream.clear();
278
279
  this.#notify();
279
280
  }
@@ -365,6 +366,15 @@ var CustomStreamOrchestrator = class {
365
366
  this.#streamUnsub = null;
366
367
  this.stream.stop(this.#historyValues, { onStop: this.#options.onStop });
367
368
  }
369
+ #flushPendingHeadlessToolInterrupts() {
370
+ require_headless_tools.flushPendingHeadlessToolInterrupts(this.stream.values, this.#options.tools, this.#handledHeadlessToolInterruptIds, {
371
+ onTool: this.#options.onTool,
372
+ defer: (run) => {
373
+ Promise.resolve().then(run);
374
+ },
375
+ resumeSubmit: (command) => this.submit(null, { command })
376
+ });
377
+ }
368
378
  };
369
379
  //#endregion
370
380
  exports.CustomStreamOrchestrator = CustomStreamOrchestrator;
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-custom.cjs","names":["#options","#historyValues","#threadId","MessageTupleManager","StreamManager","toMessageClass","#streamUnsub","#notify","#getMessages","#listeners","#version","#disposed","#branch","ensureMessageInstances","getToolCallsWithResults","normalizeInterruptsList","extractInterrupts","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport { extractInterrupts, normalizeInterruptsList } from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n const valueInterrupts = this.stream.values.__interrupt__;\n if (valueInterrupts.length === 0) return [{ when: \"breakpoint\" }];\n return normalizeInterruptsList(\n valueInterrupts as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator-custom.cjs","names":["#options","#historyValues","#threadId","MessageTupleManager","StreamManager","toMessageClass","#streamUnsub","#flushPendingHeadlessToolInterrupts","#notify","#getMessages","#listeners","#version","#disposed","#handledHeadlessToolInterruptIds","#branch","ensureMessageInstances","getToolCallsWithResults","userFacingInterruptsFromValuesArray","extractInterrupts","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport {\n extractInterrupts,\n userFacingInterruptsFromValuesArray,\n} from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { flushPendingHeadlessToolInterrupts } from \"../headless-tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n #handledHeadlessToolInterruptIds = new Set<string>();\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#flushPendingHeadlessToolInterrupts();\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n return userFacingInterruptsFromValuesArray<GetInterruptType<Bag>>(\n this.stream.values.__interrupt__ as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n #flushPendingHeadlessToolInterrupts(): void {\n flushPendingHeadlessToolInterrupts(\n this.stream.values as Record<string, unknown> | null,\n this.#options.tools,\n this.#handledHeadlessToolInterruptIds,\n {\n onTool: this.#options.onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n this.submit(null, {\n command,\n }),\n }\n );\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-custom.d.cts","names":[],"sources":["../../src/ui/orchestrator-custom.ts"],"mappings":";;;;;;;;;;;AAuDA;;;;cAAa,wBAAA,mBACO,MAAA,oBAA0B,MAAA,+BAChC,WAAA,GAAc,WAAA;EAAA;WAEjB,MAAA,EAAQ,aAAA,CAAc,SAAA,EAAW,GAAA;EAAA,SAEjC,cAAA,EAAgB,mBAAA;EAFiB;;;;;;EA0B1C,WAAA,CAAY,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,GAAA;EAmGnC;;;;;;EA9DpB,SAAA,GAAS,QAAA;EAmIoC;;;;;;EAtH7C,WAAA;EAwJmB;;;;;;;EAvInB,YAAA,CAAa,KAAA;EA+KkB;;;;EAAA,IAvJ3B,MAAA,CAAA,GAAU,SAAA;EAiKyB;;;;EAAA,IAzJnC,YAAA,CAAA,GAAgB,SAAA;EAmNiD;EAAA,IA9MjE,KAAA,CAAA;EA8Mc;EAAA,IAzMd,SAAA,CAAA;EAmSoB;EAAA,IA9RpB,MAAA,CAAA;EA8RM;;;;;EArRV,SAAA,CAAU,KAAA;EAuRA;;;;;EAAA,IA7QN,QAAA,CAAA,GAAY,WAAA;EAjKJ;;;;EAAA,IA4KR,SAAA,CAAA,GAAS,kBAAA,CAXc,eAAA;EA/JI;;;;;;EAqL/B,YAAA,CAAa,OAAA,EAAS,OAAA,GAAO,kBAAA,CAAA,eAAA;EA3J0B;;;;;EAAA,IAwKnD,UAAA,CAAA,GAAc,SAAA,CAAU,gBAAA,CAAiB,GAAA;EArGhC;;;;EAAA,IAwHT,SAAA,CAAA,GAAa,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAnFxC;;;;;;;;EA+FJ,mBAAA,CACE,OAAA,EAAS,OAAA,EACT,KAAA,YACC,eAAA,CAAgB,SAAA;EA1DN;EAAA,IAyET,SAAA,CAAA,GAAa,GAAA,SAAY,uBAAA;EA9DP;EAAA,IAmElB,eAAA,CAAA,GAAmB,uBAAA;EAnEM;;;;;;EA6E7B,WAAA,CAAY,UAAA,WAAkB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EA7Cb;;;;;;EAuDjB,kBAAA,CAAmB,IAAA,WAAY,uBAAA,CAAA,MAAA,mBAAA,eAAA;EAxC5B;;;;;;EAkDH,qBAAA,CAAsB,SAAA,WAAiB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EApBvC;;;;;EA6BA,4BAAA,CAAA;EAnBmB;;;;EAkCnB,IAAA,CAAA;EAxBsB;;;;;;EAoCtB,YAAA,CAAa,WAAA;EAAA;;;;;;;;;;;;EAoBP,YAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EAyFO;;;;;;;;;;EADJ,MAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EASI;;;;;EAAP,OAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"orchestrator-custom.d.cts","names":[],"sources":["../../src/ui/orchestrator-custom.ts"],"mappings":";;;;;;;;;;;AA2DA;;;;cAAa,wBAAA,mBACO,MAAA,oBAA0B,MAAA,+BAChC,WAAA,GAAc,WAAA;EAAA;WAEjB,MAAA,EAAQ,aAAA,CAAc,SAAA,EAAW,GAAA;EAAA,SAEjC,cAAA,EAAgB,mBAAA;EAFiB;;;;;;EA4B1C,WAAA,CAAY,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,GAAA;EAqGnC;;;;;;EA/DpB,SAAA,GAAS,QAAA;EAoIoC;;;;;;EAvH7C,WAAA;EAuJmB;;;;;;;EAtInB,YAAA,CAAa,KAAA;EA8KkB;;;;EAAA,IArJ3B,MAAA,CAAA,GAAU,SAAA;EA+JyB;;;;EAAA,IAvJnC,YAAA,CAAA,GAAgB,SAAA;EAkNiD;EAAA,IA7MjE,KAAA,CAAA;EA6Mc;EAAA,IAxMd,SAAA,CAAA;EAkSoB;EAAA,IA7RpB,MAAA,CAAA;EA6RM;;;;;EApRV,SAAA,CAAU,KAAA;EAsRA;;;;;EAAA,IA5QN,QAAA,CAAA,GAAY,WAAA;EArKJ;;;;EAAA,IAgLR,SAAA,CAAA,GAAS,kBAAA,CAXc,eAAA;EAnKI;;;;;;EAyL/B,YAAA,CAAa,OAAA,EAAS,OAAA,GAAO,kBAAA,CAAA,eAAA;EA7J0B;;;;;EAAA,IA0KnD,UAAA,CAAA,GAAc,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAtGhC;;;;EAAA,IAuHT,SAAA,CAAA,GAAa,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAjFxC;;;;;;;;EA6FJ,mBAAA,CACE,OAAA,EAAS,OAAA,EACT,KAAA,YACC,eAAA,CAAgB,SAAA;EAxDN;EAAA,IAuET,SAAA,CAAA,GAAa,GAAA,SAAY,uBAAA;EA5DP;EAAA,IAiElB,eAAA,CAAA,GAAmB,uBAAA;EAjEM;;;;;;EA2E7B,WAAA,CAAY,UAAA,WAAkB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EA7Cb;;;;;;EAuDjB,kBAAA,CAAmB,IAAA,WAAY,uBAAA,CAAA,MAAA,mBAAA,eAAA;EAxC5B;;;;;;EAkDH,qBAAA,CAAsB,SAAA,WAAiB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EApBvC;;;;;EA6BA,4BAAA,CAAA;EAnBmB;;;;EAkCnB,IAAA,CAAA;EAxBsB;;;;;;EAoCtB,YAAA,CAAa,WAAA;EAAA;;;;;;;;;;;;EAqBP,YAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EAyFO;;;;;;;;;;EADJ,MAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EASI;;;;;EAAP,OAAA,CAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-custom.d.ts","names":[],"sources":["../../src/ui/orchestrator-custom.ts"],"mappings":";;;;;;;;;;;AAuDA;;;;cAAa,wBAAA,mBACO,MAAA,oBAA0B,MAAA,+BAChC,WAAA,GAAc,WAAA;EAAA;WAEjB,MAAA,EAAQ,aAAA,CAAc,SAAA,EAAW,GAAA;EAAA,SAEjC,cAAA,EAAgB,mBAAA;EAFiB;;;;;;EA0B1C,WAAA,CAAY,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,GAAA;EAmGnC;;;;;;EA9DpB,SAAA,GAAS,QAAA;EAmIoC;;;;;;EAtH7C,WAAA;EAwJmB;;;;;;;EAvInB,YAAA,CAAa,KAAA;EA+KkB;;;;EAAA,IAvJ3B,MAAA,CAAA,GAAU,SAAA;EAiKyB;;;;EAAA,IAzJnC,YAAA,CAAA,GAAgB,SAAA;EAmNiD;EAAA,IA9MjE,KAAA,CAAA;EA8Mc;EAAA,IAzMd,SAAA,CAAA;EAmSoB;EAAA,IA9RpB,MAAA,CAAA;EA8RM;;;;;EArRV,SAAA,CAAU,KAAA;EAuRA;;;;;EAAA,IA7QN,QAAA,CAAA,GAAY,WAAA;EAjKJ;;;;EAAA,IA4KR,SAAA,CAAA,GAAS,kBAAA,CAXc,eAAA;EA/JI;;;;;;EAqL/B,YAAA,CAAa,OAAA,EAAS,OAAA,GAAO,kBAAA,CAAA,eAAA;EA3J0B;;;;;EAAA,IAwKnD,UAAA,CAAA,GAAc,SAAA,CAAU,gBAAA,CAAiB,GAAA;EArGhC;;;;EAAA,IAwHT,SAAA,CAAA,GAAa,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAnFxC;;;;;;;;EA+FJ,mBAAA,CACE,OAAA,EAAS,OAAA,EACT,KAAA,YACC,eAAA,CAAgB,SAAA;EA1DN;EAAA,IAyET,SAAA,CAAA,GAAa,GAAA,SAAY,uBAAA;EA9DP;EAAA,IAmElB,eAAA,CAAA,GAAmB,uBAAA;EAnEM;;;;;;EA6E7B,WAAA,CAAY,UAAA,WAAkB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EA7Cb;;;;;;EAuDjB,kBAAA,CAAmB,IAAA,WAAY,uBAAA,CAAA,MAAA,mBAAA,eAAA;EAxC5B;;;;;;EAkDH,qBAAA,CAAsB,SAAA,WAAiB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EApBvC;;;;;EA6BA,4BAAA,CAAA;EAnBmB;;;;EAkCnB,IAAA,CAAA;EAxBsB;;;;;;EAoCtB,YAAA,CAAa,WAAA;EAAA;;;;;;;;;;;;EAoBP,YAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EAyFO;;;;;;;;;;EADJ,MAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EASI;;;;;EAAP,OAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"orchestrator-custom.d.ts","names":[],"sources":["../../src/ui/orchestrator-custom.ts"],"mappings":";;;;;;;;;;;AA2DA;;;;cAAa,wBAAA,mBACO,MAAA,oBAA0B,MAAA,+BAChC,WAAA,GAAc,WAAA;EAAA;WAEjB,MAAA,EAAQ,aAAA,CAAc,SAAA,EAAW,GAAA;EAAA,SAEjC,cAAA,EAAgB,mBAAA;EAFiB;;;;;;EA4B1C,WAAA,CAAY,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,GAAA;EAqGnC;;;;;;EA/DpB,SAAA,GAAS,QAAA;EAoIoC;;;;;;EAvH7C,WAAA;EAuJmB;;;;;;;EAtInB,YAAA,CAAa,KAAA;EA8KkB;;;;EAAA,IArJ3B,MAAA,CAAA,GAAU,SAAA;EA+JyB;;;;EAAA,IAvJnC,YAAA,CAAA,GAAgB,SAAA;EAkNiD;EAAA,IA7MjE,KAAA,CAAA;EA6Mc;EAAA,IAxMd,SAAA,CAAA;EAkSoB;EAAA,IA7RpB,MAAA,CAAA;EA6RM;;;;;EApRV,SAAA,CAAU,KAAA;EAsRA;;;;;EAAA,IA5QN,QAAA,CAAA,GAAY,WAAA;EArKJ;;;;EAAA,IAgLR,SAAA,CAAA,GAAS,kBAAA,CAXc,eAAA;EAnKI;;;;;;EAyL/B,YAAA,CAAa,OAAA,EAAS,OAAA,GAAO,kBAAA,CAAA,eAAA;EA7J0B;;;;;EAAA,IA0KnD,UAAA,CAAA,GAAc,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAtGhC;;;;EAAA,IAuHT,SAAA,CAAA,GAAa,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAjFxC;;;;;;;;EA6FJ,mBAAA,CACE,OAAA,EAAS,OAAA,EACT,KAAA,YACC,eAAA,CAAgB,SAAA;EAxDN;EAAA,IAuET,SAAA,CAAA,GAAa,GAAA,SAAY,uBAAA;EA5DP;EAAA,IAiElB,eAAA,CAAA,GAAmB,uBAAA;EAjEM;;;;;;EA2E7B,WAAA,CAAY,UAAA,WAAkB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EA7Cb;;;;;;EAuDjB,kBAAA,CAAmB,IAAA,WAAY,uBAAA,CAAA,MAAA,mBAAA,eAAA;EAxC5B;;;;;;EAkDH,qBAAA,CAAsB,SAAA,WAAiB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EApBvC;;;;;EA6BA,4BAAA,CAAA;EAnBmB;;;;EAkCnB,IAAA,CAAA;EAxBsB;;;;;;EAoCtB,YAAA,CAAa,WAAA;EAAA;;;;;;;;;;;;EAqBP,YAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EAyFO;;;;;;;;;;EADJ,MAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EASI;;;;;EAAP,OAAA,CAAA;AAAA"}
@@ -1,7 +1,8 @@
1
+ import { flushPendingHeadlessToolInterrupts } from "../headless-tools.js";
1
2
  import { MessageTupleManager, ensureMessageInstances, toMessageClass } from "./messages.js";
2
3
  import { getToolCallsWithResults } from "../utils/tools.js";
3
4
  import { StreamManager } from "./manager.js";
4
- import { extractInterrupts, normalizeInterruptsList } from "./interrupts.js";
5
+ import { extractInterrupts, userFacingInterruptsFromValuesArray } from "./interrupts.js";
5
6
  //#region src/ui/orchestrator-custom.ts
6
7
  /**
7
8
  * Create a custom transport thread state.
@@ -42,6 +43,7 @@ var CustomStreamOrchestrator = class {
42
43
  #version = 0;
43
44
  #streamUnsub = null;
44
45
  #disposed = false;
46
+ #handledHeadlessToolInterruptIds = /* @__PURE__ */ new Set();
45
47
  /**
46
48
  * Create a new {@link CustomStreamOrchestrator} instance.
47
49
  *
@@ -60,6 +62,7 @@ var CustomStreamOrchestrator = class {
60
62
  });
61
63
  this.#historyValues = options.initialValues ?? {};
62
64
  this.#streamUnsub = this.stream.subscribe(() => {
65
+ this.#flushPendingHeadlessToolInterrupts();
63
66
  this.#notify();
64
67
  });
65
68
  const historyMessages = this.#getMessages(this.#historyValues);
@@ -99,6 +102,7 @@ var CustomStreamOrchestrator = class {
99
102
  syncThreadId(newId) {
100
103
  if (newId !== this.#threadId) {
101
104
  this.#threadId = newId;
105
+ this.#handledHeadlessToolInterruptIds.clear();
102
106
  this.stream.clear();
103
107
  this.#notify();
104
108
  }
@@ -182,11 +186,7 @@ var CustomStreamOrchestrator = class {
182
186
  * present but empty, or an empty array when no interrupts exist.
183
187
  */
184
188
  get interrupts() {
185
- if (this.stream.values != null && "__interrupt__" in this.stream.values && Array.isArray(this.stream.values.__interrupt__)) {
186
- const valueInterrupts = this.stream.values.__interrupt__;
187
- if (valueInterrupts.length === 0) return [{ when: "breakpoint" }];
188
- return normalizeInterruptsList(valueInterrupts);
189
- }
189
+ if (this.stream.values != null && "__interrupt__" in this.stream.values && Array.isArray(this.stream.values.__interrupt__)) return userFacingInterruptsFromValuesArray(this.stream.values.__interrupt__);
190
190
  return [];
191
191
  }
192
192
  /**
@@ -274,6 +274,7 @@ var CustomStreamOrchestrator = class {
274
274
  switchThread(newThreadId) {
275
275
  if (newThreadId !== this.#threadId) {
276
276
  this.#threadId = newThreadId;
277
+ this.#handledHeadlessToolInterruptIds.clear();
277
278
  this.stream.clear();
278
279
  this.#notify();
279
280
  }
@@ -365,6 +366,15 @@ var CustomStreamOrchestrator = class {
365
366
  this.#streamUnsub = null;
366
367
  this.stream.stop(this.#historyValues, { onStop: this.#options.onStop });
367
368
  }
369
+ #flushPendingHeadlessToolInterrupts() {
370
+ flushPendingHeadlessToolInterrupts(this.stream.values, this.#options.tools, this.#handledHeadlessToolInterruptIds, {
371
+ onTool: this.#options.onTool,
372
+ defer: (run) => {
373
+ Promise.resolve().then(run);
374
+ },
375
+ resumeSubmit: (command) => this.submit(null, { command })
376
+ });
377
+ }
368
378
  };
369
379
  //#endregion
370
380
  export { CustomStreamOrchestrator };
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-custom.js","names":["#options","#historyValues","#threadId","#streamUnsub","#notify","#getMessages","#listeners","#version","#disposed","#branch","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport { extractInterrupts, normalizeInterruptsList } from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n const valueInterrupts = this.stream.values.__interrupt__;\n if (valueInterrupts.length === 0) return [{ when: \"breakpoint\" }];\n return normalizeInterruptsList(\n valueInterrupts as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator-custom.js","names":["#options","#historyValues","#threadId","#streamUnsub","#flushPendingHeadlessToolInterrupts","#notify","#getMessages","#listeners","#version","#disposed","#handledHeadlessToolInterruptIds","#branch","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport {\n extractInterrupts,\n userFacingInterruptsFromValuesArray,\n} from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { flushPendingHeadlessToolInterrupts } from \"../headless-tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n #handledHeadlessToolInterruptIds = new Set<string>();\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#flushPendingHeadlessToolInterrupts();\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n return userFacingInterruptsFromValuesArray<GetInterruptType<Bag>>(\n this.stream.values.__interrupt__ as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n #flushPendingHeadlessToolInterrupts(): void {\n flushPendingHeadlessToolInterrupts(\n this.stream.values as Record<string, unknown> | null,\n this.#options.tools,\n this.#handledHeadlessToolInterruptIds,\n {\n onTool: this.#options.onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n this.submit(null, {\n command,\n }),\n }\n );\n }\n}\n"],"mappings":"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"}