@langchain/langgraph-sdk 1.9.16 → 1.9.18

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 (114) hide show
  1. package/dist/client/base.cjs +70 -4
  2. package/dist/client/base.cjs.map +1 -1
  3. package/dist/client/base.d.cts +3 -0
  4. package/dist/client/base.d.cts.map +1 -1
  5. package/dist/client/base.d.ts +3 -0
  6. package/dist/client/base.d.ts.map +1 -1
  7. package/dist/client/base.js +70 -4
  8. package/dist/client/base.js.map +1 -1
  9. package/dist/client/threads/index.cjs +4 -2
  10. package/dist/client/threads/index.cjs.map +1 -1
  11. package/dist/client/threads/index.d.cts.map +1 -1
  12. package/dist/client/threads/index.d.ts.map +1 -1
  13. package/dist/client/threads/index.js +4 -2
  14. package/dist/client/threads/index.js.map +1 -1
  15. package/dist/stream/controller.cjs +451 -32
  16. package/dist/stream/controller.cjs.map +1 -1
  17. package/dist/stream/controller.d.cts +15 -0
  18. package/dist/stream/controller.d.cts.map +1 -1
  19. package/dist/stream/controller.d.ts +15 -0
  20. package/dist/stream/controller.d.ts.map +1 -1
  21. package/dist/stream/controller.js +472 -32
  22. package/dist/stream/controller.js.map +1 -1
  23. package/dist/stream/discovery/index.cjs +2 -0
  24. package/dist/stream/discovery/index.js +3 -0
  25. package/dist/stream/discovery/namespace-from-history.cjs +207 -0
  26. package/dist/stream/discovery/namespace-from-history.cjs.map +1 -0
  27. package/dist/stream/discovery/namespace-from-history.js +204 -0
  28. package/dist/stream/discovery/namespace-from-history.js.map +1 -0
  29. package/dist/stream/discovery/subagents.cjs +56 -1
  30. package/dist/stream/discovery/subagents.cjs.map +1 -1
  31. package/dist/stream/discovery/subagents.d.cts +31 -0
  32. package/dist/stream/discovery/subagents.d.cts.map +1 -1
  33. package/dist/stream/discovery/subagents.d.ts +31 -0
  34. package/dist/stream/discovery/subagents.d.ts.map +1 -1
  35. package/dist/stream/discovery/subagents.js +56 -1
  36. package/dist/stream/discovery/subagents.js.map +1 -1
  37. package/dist/stream/discovery/subgraphs.cjs +24 -0
  38. package/dist/stream/discovery/subgraphs.cjs.map +1 -1
  39. package/dist/stream/discovery/subgraphs.d.cts +13 -0
  40. package/dist/stream/discovery/subgraphs.d.cts.map +1 -1
  41. package/dist/stream/discovery/subgraphs.d.ts +13 -0
  42. package/dist/stream/discovery/subgraphs.d.ts.map +1 -1
  43. package/dist/stream/discovery/subgraphs.js +24 -0
  44. package/dist/stream/discovery/subgraphs.js.map +1 -1
  45. package/dist/stream/index.cjs +1 -0
  46. package/dist/stream/index.js +1 -0
  47. package/dist/stream/message-coercion.cjs +101 -0
  48. package/dist/stream/message-coercion.cjs.map +1 -0
  49. package/dist/stream/message-coercion.d.ts +1 -0
  50. package/dist/stream/message-coercion.js +98 -0
  51. package/dist/stream/message-coercion.js.map +1 -0
  52. package/dist/stream/message-metadata-tracker.cjs +92 -0
  53. package/dist/stream/message-metadata-tracker.cjs.map +1 -1
  54. package/dist/stream/message-metadata-tracker.d.cts +23 -0
  55. package/dist/stream/message-metadata-tracker.d.cts.map +1 -1
  56. package/dist/stream/message-metadata-tracker.d.ts +23 -0
  57. package/dist/stream/message-metadata-tracker.d.ts.map +1 -1
  58. package/dist/stream/message-metadata-tracker.js +92 -0
  59. package/dist/stream/message-metadata-tracker.js.map +1 -1
  60. package/dist/stream/message-reconciliation.cjs +2 -2
  61. package/dist/stream/message-reconciliation.cjs.map +1 -1
  62. package/dist/stream/message-reconciliation.js +2 -2
  63. package/dist/stream/message-reconciliation.js.map +1 -1
  64. package/dist/stream/optimistic-input.cjs +86 -0
  65. package/dist/stream/optimistic-input.cjs.map +1 -0
  66. package/dist/stream/optimistic-input.d.ts +1 -0
  67. package/dist/stream/optimistic-input.js +86 -0
  68. package/dist/stream/optimistic-input.js.map +1 -0
  69. package/dist/stream/projections/channel.cjs +1 -0
  70. package/dist/stream/projections/channel.cjs.map +1 -1
  71. package/dist/stream/projections/channel.d.cts.map +1 -1
  72. package/dist/stream/projections/channel.d.ts.map +1 -1
  73. package/dist/stream/projections/channel.js +1 -0
  74. package/dist/stream/projections/channel.js.map +1 -1
  75. package/dist/stream/projections/messages.cjs +24 -14
  76. package/dist/stream/projections/messages.cjs.map +1 -1
  77. package/dist/stream/projections/messages.js +21 -11
  78. package/dist/stream/projections/messages.js.map +1 -1
  79. package/dist/stream/projections/tool-calls.cjs +22 -10
  80. package/dist/stream/projections/tool-calls.cjs.map +1 -1
  81. package/dist/stream/projections/tool-calls.js +22 -10
  82. package/dist/stream/projections/tool-calls.js.map +1 -1
  83. package/dist/stream/projections/values.cjs +2 -2
  84. package/dist/stream/projections/values.cjs.map +1 -1
  85. package/dist/stream/projections/values.js +1 -1
  86. package/dist/stream/projections/values.js.map +1 -1
  87. package/dist/stream/root-message-projection.cjs +130 -3
  88. package/dist/stream/root-message-projection.cjs.map +1 -1
  89. package/dist/stream/root-message-projection.js +130 -3
  90. package/dist/stream/root-message-projection.js.map +1 -1
  91. package/dist/stream/submit-coordinator.cjs +28 -6
  92. package/dist/stream/submit-coordinator.cjs.map +1 -1
  93. package/dist/stream/submit-coordinator.d.cts.map +1 -1
  94. package/dist/stream/submit-coordinator.d.ts +0 -1
  95. package/dist/stream/submit-coordinator.d.ts.map +1 -1
  96. package/dist/stream/submit-coordinator.js +28 -6
  97. package/dist/stream/submit-coordinator.js.map +1 -1
  98. package/dist/stream/tool-calls.cjs +32 -0
  99. package/dist/stream/tool-calls.cjs.map +1 -1
  100. package/dist/stream/tool-calls.js +32 -1
  101. package/dist/stream/tool-calls.js.map +1 -1
  102. package/dist/stream/types.d.cts +43 -0
  103. package/dist/stream/types.d.cts.map +1 -1
  104. package/dist/stream/types.d.ts +43 -0
  105. package/dist/stream/types.d.ts.map +1 -1
  106. package/dist/ui/index.d.cts +1 -1
  107. package/dist/ui/index.d.ts +1 -1
  108. package/dist/ui/messages.cjs +4 -50
  109. package/dist/ui/messages.cjs.map +1 -1
  110. package/dist/ui/messages.d.cts.map +1 -1
  111. package/dist/ui/messages.d.ts.map +1 -1
  112. package/dist/ui/messages.js +3 -48
  113. package/dist/ui/messages.js.map +1 -1
  114. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tool-calls.cjs","names":["ToolMessage","parseToolOutput"],"sources":["../../src/stream/tool-calls.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { AssembledToolCall } from \"../client/stream/handles/tools.js\";\nimport { parseToolOutput } from \"../client/stream/handles/tools.js\";\n\n/**\n * Insert or replace an assembled tool call by call id.\n *\n * ToolCallAssembler mutates its active handle in place as `tool-finished` /\n * `tool-error` events arrive. Publish a fresh object here so framework\n * adapters that pass individual tool calls as props (notably Vue's shallow\n * prop tracking) observe status/output changes.\n */\nexport function upsertToolCall(\n current: readonly AssembledToolCall[],\n next: AssembledToolCall\n): AssembledToolCall[] {\n const snapshot = { ...next };\n const idx = current.findIndex((toolCall) => toolCall.callId === next.callId);\n if (idx < 0) return [...current, snapshot];\n const updated = current.slice();\n updated[idx] = snapshot;\n return updated;\n}\n\n/**\n * Backfill unfinished tool-call handles from authoritative ToolMessages in a\n * values snapshot. This covers headless tools whose graph state contains the\n * result even when the `tools` channel omits a matching `tool-finished` event.\n */\nexport function reconcileToolCallsFromMessages(\n toolCalls: readonly AssembledToolCall[],\n messages: readonly BaseMessage[]\n): AssembledToolCall[] {\n let updated: AssembledToolCall[] | undefined;\n for (const message of messages) {\n if (!ToolMessage.isInstance(message)) continue;\n const callId = message.tool_call_id;\n if (typeof callId !== \"string\" || callId.length === 0) continue;\n\n const currentToolCalls = updated ?? toolCalls;\n const idx = currentToolCalls.findIndex(\n (toolCall) => toolCall.callId === callId\n );\n if (idx < 0) continue;\n\n const current = currentToolCalls[idx];\n if (current.status === \"finished\" && current.output != null) continue;\n\n const output = parseToolOutput(message.content);\n if (output == null) continue;\n\n updated = upsertToolCall(currentToolCalls, {\n ...current,\n output,\n status: \"finished\",\n error: undefined,\n });\n }\n return updated ?? (toolCalls as AssembledToolCall[]);\n}\n"],"mappings":";;;;;;;;;;;;AAaA,SAAgB,eACd,SACA,MACqB;CACrB,MAAM,WAAW,EAAE,GAAG,MAAM;CAC5B,MAAM,MAAM,QAAQ,WAAW,aAAa,SAAS,WAAW,KAAK,OAAO;AAC5E,KAAI,MAAM,EAAG,QAAO,CAAC,GAAG,SAAS,SAAS;CAC1C,MAAM,UAAU,QAAQ,OAAO;AAC/B,SAAQ,OAAO;AACf,QAAO;;;;;;;AAQT,SAAgB,+BACd,WACA,UACqB;CACrB,IAAI;AACJ,MAAK,MAAM,WAAW,UAAU;AAC9B,MAAI,CAACA,yBAAAA,YAAY,WAAW,QAAQ,CAAE;EACtC,MAAM,SAAS,QAAQ;AACvB,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG;EAEvD,MAAM,mBAAmB,WAAW;EACpC,MAAM,MAAM,iBAAiB,WAC1B,aAAa,SAAS,WAAW,OACnC;AACD,MAAI,MAAM,EAAG;EAEb,MAAM,UAAU,iBAAiB;AACjC,MAAI,QAAQ,WAAW,cAAc,QAAQ,UAAU,KAAM;EAE7D,MAAM,SAASC,cAAAA,gBAAgB,QAAQ,QAAQ;AAC/C,MAAI,UAAU,KAAM;AAEpB,YAAU,eAAe,kBAAkB;GACzC,GAAG;GACH;GACA,QAAQ;GACR,OAAO,KAAA;GACR,CAAC;;AAEJ,QAAO,WAAY"}
1
+ {"version":3,"file":"tool-calls.cjs","names":["ToolMessage","parseToolOutput"],"sources":["../../src/stream/tool-calls.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { AssembledToolCall } from \"../client/stream/handles/tools.js\";\nimport { parseToolOutput } from \"../client/stream/handles/tools.js\";\n\n/**\n * Insert or replace an assembled tool call by call id.\n *\n * ToolCallAssembler mutates its active handle in place as `tool-finished` /\n * `tool-error` events arrive. Publish a fresh object here so framework\n * adapters that pass individual tool calls as props (notably Vue's shallow\n * prop tracking) observe status/output changes.\n */\nexport function upsertToolCall(\n current: readonly AssembledToolCall[],\n next: AssembledToolCall\n): AssembledToolCall[] {\n const snapshot = { ...next };\n const idx = current.findIndex((toolCall) => toolCall.callId === next.callId);\n if (idx < 0) return [...current, snapshot];\n const updated = current.slice();\n updated[idx] = snapshot;\n return updated;\n}\n\n/**\n * Backfill unfinished tool-call handles from authoritative ToolMessages in a\n * values snapshot. This covers headless tools whose graph state contains the\n * result even when the `tools` channel omits a matching `tool-finished` event.\n */\nexport function reconcileToolCallsFromMessages(\n toolCalls: readonly AssembledToolCall[],\n messages: readonly BaseMessage[]\n): AssembledToolCall[] {\n let updated: AssembledToolCall[] | undefined;\n for (const message of messages) {\n if (!ToolMessage.isInstance(message)) continue;\n const callId = message.tool_call_id;\n if (typeof callId !== \"string\" || callId.length === 0) continue;\n\n const currentToolCalls = updated ?? toolCalls;\n const idx = currentToolCalls.findIndex(\n (toolCall) => toolCall.callId === callId\n );\n if (idx < 0) continue;\n\n const current = currentToolCalls[idx];\n if (current.status === \"finished\" && current.output != null) continue;\n\n const output = parseToolOutput(message.content);\n if (output == null) continue;\n\n updated = upsertToolCall(currentToolCalls, {\n ...current,\n output,\n status: \"finished\",\n error: undefined,\n });\n }\n return updated ?? (toolCalls as AssembledToolCall[]);\n}\n\n/**\n * Build completed scoped tool-call handles from an authoritative\n * `values.messages` snapshot. Used when an idle thread hydrates card panels\n * from checkpoint history instead of replaying scoped `/events`.\n */\nexport function seedToolCallsFromMessages(\n namespace: readonly string[],\n messages: readonly BaseMessage[]\n): AssembledToolCall[] {\n let toolCalls: AssembledToolCall[] = [];\n for (const message of messages) {\n const raw = (message as unknown as { tool_calls?: unknown }).tool_calls;\n if (!Array.isArray(raw)) continue;\n for (const toolCall of raw) {\n if (toolCall == null || typeof toolCall !== \"object\") continue;\n const record = toolCall as {\n id?: unknown;\n name?: unknown;\n args?: unknown;\n };\n if (typeof record.id !== \"string\" || record.id.length === 0) continue;\n if (typeof record.name !== \"string\" || record.name.length === 0) {\n continue;\n }\n // Mirrors `shouldIgnoreScopedTaskToolEvent`: the wrapper `task` call\n // is represented by the subagent card itself, not as an inner tool.\n if (namespace.length > 0 && record.name === \"task\") continue;\n toolCalls = upsertToolCall(toolCalls, {\n id: record.id,\n callId: record.id,\n name: record.name,\n namespace: [...namespace, `tools:${record.id}`],\n input: record.args ?? {},\n args: record.args ?? {},\n output: null,\n status: \"running\",\n error: undefined,\n });\n }\n }\n return reconcileToolCallsFromMessages(toolCalls, messages);\n}\n"],"mappings":";;;;;;;;;;;;AAaA,SAAgB,eACd,SACA,MACqB;CACrB,MAAM,WAAW,EAAE,GAAG,MAAM;CAC5B,MAAM,MAAM,QAAQ,WAAW,aAAa,SAAS,WAAW,KAAK,OAAO;AAC5E,KAAI,MAAM,EAAG,QAAO,CAAC,GAAG,SAAS,SAAS;CAC1C,MAAM,UAAU,QAAQ,OAAO;AAC/B,SAAQ,OAAO;AACf,QAAO;;;;;;;AAQT,SAAgB,+BACd,WACA,UACqB;CACrB,IAAI;AACJ,MAAK,MAAM,WAAW,UAAU;AAC9B,MAAI,CAACA,yBAAAA,YAAY,WAAW,QAAQ,CAAE;EACtC,MAAM,SAAS,QAAQ;AACvB,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG;EAEvD,MAAM,mBAAmB,WAAW;EACpC,MAAM,MAAM,iBAAiB,WAC1B,aAAa,SAAS,WAAW,OACnC;AACD,MAAI,MAAM,EAAG;EAEb,MAAM,UAAU,iBAAiB;AACjC,MAAI,QAAQ,WAAW,cAAc,QAAQ,UAAU,KAAM;EAE7D,MAAM,SAASC,cAAAA,gBAAgB,QAAQ,QAAQ;AAC/C,MAAI,UAAU,KAAM;AAEpB,YAAU,eAAe,kBAAkB;GACzC,GAAG;GACH;GACA,QAAQ;GACR,OAAO,KAAA;GACR,CAAC;;AAEJ,QAAO,WAAY;;;;;;;AAQrB,SAAgB,0BACd,WACA,UACqB;CACrB,IAAI,YAAiC,EAAE;AACvC,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,MAAO,QAAgD;AAC7D,MAAI,CAAC,MAAM,QAAQ,IAAI,CAAE;AACzB,OAAK,MAAM,YAAY,KAAK;AAC1B,OAAI,YAAY,QAAQ,OAAO,aAAa,SAAU;GACtD,MAAM,SAAS;AAKf,OAAI,OAAO,OAAO,OAAO,YAAY,OAAO,GAAG,WAAW,EAAG;AAC7D,OAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,WAAW,EAC5D;AAIF,OAAI,UAAU,SAAS,KAAK,OAAO,SAAS,OAAQ;AACpD,eAAY,eAAe,WAAW;IACpC,IAAI,OAAO;IACX,QAAQ,OAAO;IACf,MAAM,OAAO;IACb,WAAW,CAAC,GAAG,WAAW,SAAS,OAAO,KAAK;IAC/C,OAAO,OAAO,QAAQ,EAAE;IACxB,MAAM,OAAO,QAAQ,EAAE;IACvB,QAAQ;IACR,QAAQ;IACR,OAAO,KAAA;IACR,CAAC;;;AAGN,QAAO,+BAA+B,WAAW,SAAS"}
@@ -44,7 +44,38 @@ function reconcileToolCallsFromMessages(toolCalls, messages) {
44
44
  }
45
45
  return updated ?? toolCalls;
46
46
  }
47
+ /**
48
+ * Build completed scoped tool-call handles from an authoritative
49
+ * `values.messages` snapshot. Used when an idle thread hydrates card panels
50
+ * from checkpoint history instead of replaying scoped `/events`.
51
+ */
52
+ function seedToolCallsFromMessages(namespace, messages) {
53
+ let toolCalls = [];
54
+ for (const message of messages) {
55
+ const raw = message.tool_calls;
56
+ if (!Array.isArray(raw)) continue;
57
+ for (const toolCall of raw) {
58
+ if (toolCall == null || typeof toolCall !== "object") continue;
59
+ const record = toolCall;
60
+ if (typeof record.id !== "string" || record.id.length === 0) continue;
61
+ if (typeof record.name !== "string" || record.name.length === 0) continue;
62
+ if (namespace.length > 0 && record.name === "task") continue;
63
+ toolCalls = upsertToolCall(toolCalls, {
64
+ id: record.id,
65
+ callId: record.id,
66
+ name: record.name,
67
+ namespace: [...namespace, `tools:${record.id}`],
68
+ input: record.args ?? {},
69
+ args: record.args ?? {},
70
+ output: null,
71
+ status: "running",
72
+ error: void 0
73
+ });
74
+ }
75
+ }
76
+ return reconcileToolCallsFromMessages(toolCalls, messages);
77
+ }
47
78
  //#endregion
48
- export { reconcileToolCallsFromMessages, upsertToolCall };
79
+ export { reconcileToolCallsFromMessages, seedToolCallsFromMessages, upsertToolCall };
49
80
 
50
81
  //# sourceMappingURL=tool-calls.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-calls.js","names":[],"sources":["../../src/stream/tool-calls.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { AssembledToolCall } from \"../client/stream/handles/tools.js\";\nimport { parseToolOutput } from \"../client/stream/handles/tools.js\";\n\n/**\n * Insert or replace an assembled tool call by call id.\n *\n * ToolCallAssembler mutates its active handle in place as `tool-finished` /\n * `tool-error` events arrive. Publish a fresh object here so framework\n * adapters that pass individual tool calls as props (notably Vue's shallow\n * prop tracking) observe status/output changes.\n */\nexport function upsertToolCall(\n current: readonly AssembledToolCall[],\n next: AssembledToolCall\n): AssembledToolCall[] {\n const snapshot = { ...next };\n const idx = current.findIndex((toolCall) => toolCall.callId === next.callId);\n if (idx < 0) return [...current, snapshot];\n const updated = current.slice();\n updated[idx] = snapshot;\n return updated;\n}\n\n/**\n * Backfill unfinished tool-call handles from authoritative ToolMessages in a\n * values snapshot. This covers headless tools whose graph state contains the\n * result even when the `tools` channel omits a matching `tool-finished` event.\n */\nexport function reconcileToolCallsFromMessages(\n toolCalls: readonly AssembledToolCall[],\n messages: readonly BaseMessage[]\n): AssembledToolCall[] {\n let updated: AssembledToolCall[] | undefined;\n for (const message of messages) {\n if (!ToolMessage.isInstance(message)) continue;\n const callId = message.tool_call_id;\n if (typeof callId !== \"string\" || callId.length === 0) continue;\n\n const currentToolCalls = updated ?? toolCalls;\n const idx = currentToolCalls.findIndex(\n (toolCall) => toolCall.callId === callId\n );\n if (idx < 0) continue;\n\n const current = currentToolCalls[idx];\n if (current.status === \"finished\" && current.output != null) continue;\n\n const output = parseToolOutput(message.content);\n if (output == null) continue;\n\n updated = upsertToolCall(currentToolCalls, {\n ...current,\n output,\n status: \"finished\",\n error: undefined,\n });\n }\n return updated ?? (toolCalls as AssembledToolCall[]);\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,eACd,SACA,MACqB;CACrB,MAAM,WAAW,EAAE,GAAG,MAAM;CAC5B,MAAM,MAAM,QAAQ,WAAW,aAAa,SAAS,WAAW,KAAK,OAAO;AAC5E,KAAI,MAAM,EAAG,QAAO,CAAC,GAAG,SAAS,SAAS;CAC1C,MAAM,UAAU,QAAQ,OAAO;AAC/B,SAAQ,OAAO;AACf,QAAO;;;;;;;AAQT,SAAgB,+BACd,WACA,UACqB;CACrB,IAAI;AACJ,MAAK,MAAM,WAAW,UAAU;AAC9B,MAAI,CAAC,YAAY,WAAW,QAAQ,CAAE;EACtC,MAAM,SAAS,QAAQ;AACvB,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG;EAEvD,MAAM,mBAAmB,WAAW;EACpC,MAAM,MAAM,iBAAiB,WAC1B,aAAa,SAAS,WAAW,OACnC;AACD,MAAI,MAAM,EAAG;EAEb,MAAM,UAAU,iBAAiB;AACjC,MAAI,QAAQ,WAAW,cAAc,QAAQ,UAAU,KAAM;EAE7D,MAAM,SAAS,gBAAgB,QAAQ,QAAQ;AAC/C,MAAI,UAAU,KAAM;AAEpB,YAAU,eAAe,kBAAkB;GACzC,GAAG;GACH;GACA,QAAQ;GACR,OAAO,KAAA;GACR,CAAC;;AAEJ,QAAO,WAAY"}
1
+ {"version":3,"file":"tool-calls.js","names":[],"sources":["../../src/stream/tool-calls.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { AssembledToolCall } from \"../client/stream/handles/tools.js\";\nimport { parseToolOutput } from \"../client/stream/handles/tools.js\";\n\n/**\n * Insert or replace an assembled tool call by call id.\n *\n * ToolCallAssembler mutates its active handle in place as `tool-finished` /\n * `tool-error` events arrive. Publish a fresh object here so framework\n * adapters that pass individual tool calls as props (notably Vue's shallow\n * prop tracking) observe status/output changes.\n */\nexport function upsertToolCall(\n current: readonly AssembledToolCall[],\n next: AssembledToolCall\n): AssembledToolCall[] {\n const snapshot = { ...next };\n const idx = current.findIndex((toolCall) => toolCall.callId === next.callId);\n if (idx < 0) return [...current, snapshot];\n const updated = current.slice();\n updated[idx] = snapshot;\n return updated;\n}\n\n/**\n * Backfill unfinished tool-call handles from authoritative ToolMessages in a\n * values snapshot. This covers headless tools whose graph state contains the\n * result even when the `tools` channel omits a matching `tool-finished` event.\n */\nexport function reconcileToolCallsFromMessages(\n toolCalls: readonly AssembledToolCall[],\n messages: readonly BaseMessage[]\n): AssembledToolCall[] {\n let updated: AssembledToolCall[] | undefined;\n for (const message of messages) {\n if (!ToolMessage.isInstance(message)) continue;\n const callId = message.tool_call_id;\n if (typeof callId !== \"string\" || callId.length === 0) continue;\n\n const currentToolCalls = updated ?? toolCalls;\n const idx = currentToolCalls.findIndex(\n (toolCall) => toolCall.callId === callId\n );\n if (idx < 0) continue;\n\n const current = currentToolCalls[idx];\n if (current.status === \"finished\" && current.output != null) continue;\n\n const output = parseToolOutput(message.content);\n if (output == null) continue;\n\n updated = upsertToolCall(currentToolCalls, {\n ...current,\n output,\n status: \"finished\",\n error: undefined,\n });\n }\n return updated ?? (toolCalls as AssembledToolCall[]);\n}\n\n/**\n * Build completed scoped tool-call handles from an authoritative\n * `values.messages` snapshot. Used when an idle thread hydrates card panels\n * from checkpoint history instead of replaying scoped `/events`.\n */\nexport function seedToolCallsFromMessages(\n namespace: readonly string[],\n messages: readonly BaseMessage[]\n): AssembledToolCall[] {\n let toolCalls: AssembledToolCall[] = [];\n for (const message of messages) {\n const raw = (message as unknown as { tool_calls?: unknown }).tool_calls;\n if (!Array.isArray(raw)) continue;\n for (const toolCall of raw) {\n if (toolCall == null || typeof toolCall !== \"object\") continue;\n const record = toolCall as {\n id?: unknown;\n name?: unknown;\n args?: unknown;\n };\n if (typeof record.id !== \"string\" || record.id.length === 0) continue;\n if (typeof record.name !== \"string\" || record.name.length === 0) {\n continue;\n }\n // Mirrors `shouldIgnoreScopedTaskToolEvent`: the wrapper `task` call\n // is represented by the subagent card itself, not as an inner tool.\n if (namespace.length > 0 && record.name === \"task\") continue;\n toolCalls = upsertToolCall(toolCalls, {\n id: record.id,\n callId: record.id,\n name: record.name,\n namespace: [...namespace, `tools:${record.id}`],\n input: record.args ?? {},\n args: record.args ?? {},\n output: null,\n status: \"running\",\n error: undefined,\n });\n }\n }\n return reconcileToolCallsFromMessages(toolCalls, messages);\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,eACd,SACA,MACqB;CACrB,MAAM,WAAW,EAAE,GAAG,MAAM;CAC5B,MAAM,MAAM,QAAQ,WAAW,aAAa,SAAS,WAAW,KAAK,OAAO;AAC5E,KAAI,MAAM,EAAG,QAAO,CAAC,GAAG,SAAS,SAAS;CAC1C,MAAM,UAAU,QAAQ,OAAO;AAC/B,SAAQ,OAAO;AACf,QAAO;;;;;;;AAQT,SAAgB,+BACd,WACA,UACqB;CACrB,IAAI;AACJ,MAAK,MAAM,WAAW,UAAU;AAC9B,MAAI,CAAC,YAAY,WAAW,QAAQ,CAAE;EACtC,MAAM,SAAS,QAAQ;AACvB,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG;EAEvD,MAAM,mBAAmB,WAAW;EACpC,MAAM,MAAM,iBAAiB,WAC1B,aAAa,SAAS,WAAW,OACnC;AACD,MAAI,MAAM,EAAG;EAEb,MAAM,UAAU,iBAAiB;AACjC,MAAI,QAAQ,WAAW,cAAc,QAAQ,UAAU,KAAM;EAE7D,MAAM,SAAS,gBAAgB,QAAQ,QAAQ;AAC/C,MAAI,UAAU,KAAM;AAEpB,YAAU,eAAe,kBAAkB;GACzC,GAAG;GACH;GACA,QAAQ;GACR,OAAO,KAAA;GACR,CAAC;;AAEJ,QAAO,WAAY;;;;;;;AAQrB,SAAgB,0BACd,WACA,UACqB;CACrB,IAAI,YAAiC,EAAE;AACvC,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,MAAO,QAAgD;AAC7D,MAAI,CAAC,MAAM,QAAQ,IAAI,CAAE;AACzB,OAAK,MAAM,YAAY,KAAK;AAC1B,OAAI,YAAY,QAAQ,OAAO,aAAa,SAAU;GACtD,MAAM,SAAS;AAKf,OAAI,OAAO,OAAO,OAAO,YAAY,OAAO,GAAG,WAAW,EAAG;AAC7D,OAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,WAAW,EAC5D;AAIF,OAAI,UAAU,SAAS,KAAK,OAAO,SAAS,OAAQ;AACpD,eAAY,eAAe,WAAW;IACpC,IAAI,OAAO;IACX,QAAQ,OAAO;IACf,MAAM,OAAO;IACb,WAAW,CAAC,GAAG,WAAW,SAAS,OAAO,KAAK;IAC/C,OAAO,OAAO,QAAQ,EAAE;IACxB,MAAM,OAAO,QAAQ,EAAE;IACvB,QAAQ;IACR,QAAQ;IACR,OAAO,KAAA;IACR,CAAC;;;AAGN,QAAO,+BAA+B,WAAW,SAAS"}
@@ -103,6 +103,31 @@ interface UseStreamCommonOptions<StateType extends object, ThreadIdType = string
103
103
  tools?: AnyHeadlessToolImplementation[];
104
104
  /** Observe lifecycle events for registered {@link tools}. */
105
105
  onTool?: OnToolCallback;
106
+ /**
107
+ * Optimistic UI for `submit()`. When enabled (the default), the input
108
+ * passed to `submit()` is reflected in `values` / `messages`
109
+ * immediately — before the server responds — then reconciled against
110
+ * the authoritative server state as it streams in:
111
+ *
112
+ * - Messages in the input are appended right away. Any message
113
+ * without an `id` is assigned a stable client id (sent to the
114
+ * server, which `add_messages` preserves) so the server echo
115
+ * reconciles by id instead of duplicating. Per-message progress
116
+ * is exposed via `useMessageMetadata(stream, id).optimisticStatus`
117
+ * (`"pending"` → `"sent"`, or `"failed"` if the run errors before
118
+ * the message is echoed; failed optimistic messages are kept for
119
+ * retry UIs and dropped on the next `hydrate()`).
120
+ * - Other input keys are shallow-merged into `values` and converge
121
+ * to server truth on the first `values` event (or are rolled back
122
+ * if the run fails before any echo).
123
+ *
124
+ * Set to `false` to dispatch input verbatim with no client-side echo
125
+ * or id minting (server-authoritative only) — useful for non-chat
126
+ * state graphs or deterministic SSR/tests.
127
+ *
128
+ * @default true
129
+ */
130
+ optimistic?: boolean;
106
131
  }
107
132
  /**
108
133
  * Agent-server branch: caller points `useStream` at an assistant on a
@@ -169,6 +194,19 @@ interface RootEventBus {
169
194
  readonly channels: readonly Channel[];
170
195
  /** Subscribe; returns an unsubscribe handle. */
171
196
  subscribe(listener: (event: Event$1) => void): () => void;
197
+ /**
198
+ * Optional fast path for idle/stale threads: seed a scoped projection from
199
+ * checkpoint history instead of opening a replaying `/events` subscription.
200
+ * This produces a snapshot for finished-thread reconnects; active and
201
+ * interrupted threads return `false` so projections subscribe normally.
202
+ * Returns `false` when history cannot satisfy the projection and the caller
203
+ * should fall back to its normal subscription.
204
+ */
205
+ trySeedFromHistory?<T>(params: {
206
+ kind: "messages" | "toolCalls";
207
+ namespace: readonly string[];
208
+ store: StreamStore<T>;
209
+ }): Promise<boolean>;
172
210
  }
173
211
  /**
174
212
  * Always-on root snapshot surfaced by {@link StreamController.rootStore}.
@@ -233,6 +271,11 @@ interface StreamControllerOptions<StateType extends object = Record<string, unkn
233
271
  initialValues?: StateType;
234
272
  /** Key inside `values` that holds the message array. Defaults to `"messages"`. */
235
273
  messagesKey?: string;
274
+ /**
275
+ * Optimistic UI for `submit()`. Defaults to `true`. See
276
+ * {@link UseStreamCommonOptions.optimistic} for the full contract.
277
+ */
278
+ optimistic?: boolean;
236
279
  }
237
280
  interface StreamSubmitOptions<StateType extends object = Record<string, unknown>, ConfigurableType extends object = Record<string, unknown>> {
238
281
  config?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/stream/types.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/stream/types.ts"],"mappings":"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"}
@@ -103,6 +103,31 @@ interface UseStreamCommonOptions<StateType extends object, ThreadIdType = string
103
103
  tools?: AnyHeadlessToolImplementation[];
104
104
  /** Observe lifecycle events for registered {@link tools}. */
105
105
  onTool?: OnToolCallback;
106
+ /**
107
+ * Optimistic UI for `submit()`. When enabled (the default), the input
108
+ * passed to `submit()` is reflected in `values` / `messages`
109
+ * immediately — before the server responds — then reconciled against
110
+ * the authoritative server state as it streams in:
111
+ *
112
+ * - Messages in the input are appended right away. Any message
113
+ * without an `id` is assigned a stable client id (sent to the
114
+ * server, which `add_messages` preserves) so the server echo
115
+ * reconciles by id instead of duplicating. Per-message progress
116
+ * is exposed via `useMessageMetadata(stream, id).optimisticStatus`
117
+ * (`"pending"` → `"sent"`, or `"failed"` if the run errors before
118
+ * the message is echoed; failed optimistic messages are kept for
119
+ * retry UIs and dropped on the next `hydrate()`).
120
+ * - Other input keys are shallow-merged into `values` and converge
121
+ * to server truth on the first `values` event (or are rolled back
122
+ * if the run fails before any echo).
123
+ *
124
+ * Set to `false` to dispatch input verbatim with no client-side echo
125
+ * or id minting (server-authoritative only) — useful for non-chat
126
+ * state graphs or deterministic SSR/tests.
127
+ *
128
+ * @default true
129
+ */
130
+ optimistic?: boolean;
106
131
  }
107
132
  /**
108
133
  * Agent-server branch: caller points `useStream` at an assistant on a
@@ -169,6 +194,19 @@ interface RootEventBus {
169
194
  readonly channels: readonly Channel[];
170
195
  /** Subscribe; returns an unsubscribe handle. */
171
196
  subscribe(listener: (event: Event$1) => void): () => void;
197
+ /**
198
+ * Optional fast path for idle/stale threads: seed a scoped projection from
199
+ * checkpoint history instead of opening a replaying `/events` subscription.
200
+ * This produces a snapshot for finished-thread reconnects; active and
201
+ * interrupted threads return `false` so projections subscribe normally.
202
+ * Returns `false` when history cannot satisfy the projection and the caller
203
+ * should fall back to its normal subscription.
204
+ */
205
+ trySeedFromHistory?<T>(params: {
206
+ kind: "messages" | "toolCalls";
207
+ namespace: readonly string[];
208
+ store: StreamStore<T>;
209
+ }): Promise<boolean>;
172
210
  }
173
211
  /**
174
212
  * Always-on root snapshot surfaced by {@link StreamController.rootStore}.
@@ -233,6 +271,11 @@ interface StreamControllerOptions<StateType extends object = Record<string, unkn
233
271
  initialValues?: StateType;
234
272
  /** Key inside `values` that holds the message array. Defaults to `"messages"`. */
235
273
  messagesKey?: string;
274
+ /**
275
+ * Optimistic UI for `submit()`. Defaults to `true`. See
276
+ * {@link UseStreamCommonOptions.optimistic} for the full contract.
277
+ */
278
+ optimistic?: boolean;
236
279
  }
237
280
  interface StreamSubmitOptions<StateType extends object = Record<string, unknown>, ConfigurableType extends object = Record<string, unknown>> {
238
281
  config?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/stream/types.ts"],"mappings":";;;;;;;;;;;;;;KA4BY,kBAAA,qJAgBZ;;UALiB,gBAAA;EACf,KAAA;AAAA;;UAIe,iBAAA;EA4BJ;;;;;;EArBX,MAAA;AAAA;;;;;;;;AAqCF;;UAzBiB,uBAAA,mCACmB,MAAA;EAElC,MAAA;IACE,YAAA,GAAe,gBAAA;IACf,eAAA;IACA,IAAA;IAAA,CACC,GAAA;EAAA;EAEH,QAAA,GAAW,MAAA;AAAA;;;;;;AAmCb;;;;;;;;UAnBiB,oBAAA,mCACmB,MAAA,2BAC1B,uBAAA,CAAwB,gBAAA;EAiBa;;;;;;EAV7C,WAAA;EAkBqC;;;;;EAZrC,SAAA;AAAA;;UAIe,gBAAA,SAAyB,IAAA,CAAK,gBAAA;EAgCtB;EA9BvB,KAAA;EAQA;EANA,MAAA,EAAQ,kBAAA;AAAA;;UAIO,sBAAA;EAIf,QAAA,GAAW,YAAA;EACX,UAAA,IAAc,QAAA;EAMD;;;;;EAAb,SAAA,IAAa,IAAA,EAAM,gBAAA;EASnB;;;;;EAHA,WAAA,IAAe,IAAA,EAAM,gBAAA;EACrB,aAAA,GAAgB,SAAA;EAcD;EAZf,WAAA;EAYiC;EAVjC,KAAA,GAAQ,6BAAA;EAekC;EAb1C,MAAA,GAAS,cAAA;AAAA;;;;;;UAQM,kBAAA,mIAKP,sBAAA,CAAuB,SAAA,EAAW,YAAA;EAC1C,WAAA;EACA,MAAA,GAAS,MAAA;EACT,MAAA,GAAS,UAAA;EACT,MAAA,GAAS,UAAA;EACT,aAAA,GAAgB,YAAA;EAChB,cAAA,GAAiB,YAAA;EANT;EAQR,SAAA;EAR0C;EAU1C,KAAA,UAAe,KAAA;EARf;EAUA,gBAAA,IAAoB,GAAA,aAAgB,SAAA;AAAA;;;;;;UAQrB,oBAAA,gGAIP,sBAAA,CAAuB,SAAA,EAAW,YAAA;EAlBzB;;;;;EAwBjB,SAAA,EAAW,kBAAA;EAlByB;;;AAQtC;EAeE,WAAA,GAAc,qBAAA;EACd,MAAA;EACA,MAAA;EACA,MAAA;EACA,aAAA;EACA,cAAA;EACA,KAAA;EACA,gBAAA;AAAA;;;;;;;;;;KAYU,gBAAA,4BACiB,MAAA,oJAMzB,kBAAA,CAAmB,SAAA,EAAW,YAAA,EAAc,UAAA,EAAY,UAAA,IACxD,oBAAA,CAAqB,SAAA,EAAW,YAAA,EAAc,qBAAA;;;;;;;UAQjC,YAAA;EA5BC;EAAA,SA8BP,QAAA,WAAmB,OAAA;EAlBlB;EAoBV,SAAA,CAAU,QAAA,GAAW,KAAA,EAAO,OAAA;AAAA;;;;;;;;UAUb,YAAA,4BACY,MAAA;EAvBqB;EA2BhD,MAAA,EAAQ,SAAA;EA3Bc;EA6BtB,QAAA,EAAU,aAAA;EApCV;EAsCA,SAAA,EAAW,iBAAA;EArCX;EAuCA,UAAA,EAAY,SAAA,CAAU,aAAA;EArCtB;EAuCA,SAAA,EAAW,SAAA,CAAU,aAAA;EApCnB;EAsCF,SAAA;EAtCgC;EAwChC,eAAA;EAxC0D;EA0C1D,KAAA;EAzCuB;EA2CvB,QAAA;AAAA;AAAA,UAGe,uBAAA,4BACY,MAAA;EA/C0C;EAkDrE,WAAA;EA1C2B;EA4C3B,MAAA,EAAQ,MAAA,CAAO,SAAA;EAxCkB;EA0CjC,QAAA;EA5C4B;;;;;;EAmD5B,SAAA,GAAY,mBAAA;EAvCG;EAyCf,KAAA,UAAe,KAAA;EAzCY;EA2C3B,gBAAA,IAAoB,GAAA,aAAgB,SAAA;EAtC5B;EAwCR,UAAA,IAAc,QAAA;EApCH;;;;;EA0CX,SAAA,IAAa,IAAA,EAAM,gBAAA;EAtCC;;;;;EA4CpB,WAAA,IAAe,IAAA,EAAM,gBAAA;EAlDrB;EAoDA,aAAA,GAAgB,SAAA;EAlDhB;EAoDA,WAAA;AAAA;AAAA,UAGe,mBAAA,4BACY,MAAA,qDACO,MAAA;EAElC,MAAA;IACE,YAAA,GAAe,gBAAA;IACf,eAAA;IACA,IAAA;IAAA,CACC,GAAA;EAAA;EAEH,QAAA,GAAW,MAAA;EArDX;;;AAGF;;;;EA0DE,QAAA;EApDQ;;;;;;;;;;;;;;;;;;EAuER,iBAAA;EACA,MAAA,GAAS,WAAA;EA3DT;;;;;;;EAmEA,QAAA;EArDA;;;;;;;;AAOF;EAwDE,OAAA,IAAW,KAAA;EAEX,UAAA,GAAa,SAAA;AAAA;;;;;;;;;UAWE,yBAAA;EAnEf;EAAA,SAqES,EAAA;EAnET;EAAA,SAqES,IAAA;EApEQ;EAAA,SAsER,SAAA;EApEP;EAAA,SAsEO,QAAA;EAnET;EAAA,SAqES,KAAA;EA7DT;EAAA,SA+DS,MAAA;EA3CT;EAAA,SA6CS,SAAA;EArCT;EAAA,SAuCS,MAAA;EA7BE;EAAA,SA+BF,KAAA;EA7BI;EAAA,SA+BJ,SAAA,EAAW,IAAA;EA/BE;EAAA,SAiCb,WAAA,EAAa,IAAA;AAAA;;;;UAMP,yBAAA;EAAA,SACN,EAAA;EAAA,SACA,SAAA;EApBA;;;;;;;;EAAA,SA6BA,QAAA;EAAA,SACA,MAAA;EAAA,SACA,SAAA,EAAW,IAAA;EAAA,SACX,WAAA,EAAa,IAAA;AAAA;;;;;;;KASZ,MAAA;EAAA,SAAgC,SAAA;AAAA;;;;AAA5C;;;UAQiB,cAAA;EARoC;AAQrD;;;;EARqD,SAc1C,GAAA;EAcY;EAAA,SAZZ,SAAA;EAmBE;EAAA,SAjBF,OAAA,EAAS,CAAA;EAkBG;;;;;;;EAVrB,IAAA,CAAK,MAAA;IACH,MAAA,EAAQ,YAAA;IACR,KAAA,EAAO,WAAA,CAAY,CAAA;IAAnB;;;;;;IAOA,OAAA,EAAS,YAAA;EAAA,IACP,iBAAA;AAAA;AAAA,UAGW,iBAAA;EACf,OAAA,IAAW,OAAA;AAAA;;;AAQb;;;UAAiB,kBAAA;EAAA,SACN,KAAA,EAAO,WAAA,CAAY,CAAA;EAC5B,OAAA;AAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/stream/types.ts"],"mappings":"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"}
@@ -5,9 +5,9 @@ import { BaseStream, StateRecord } from "./stream/base.cjs";
5
5
  import { UseAgentStream, UseAgentStreamOptions } from "./stream/agent.cjs";
6
6
  import { UseDeepAgentStream, UseDeepAgentStreamOptions } from "./stream/deep-agent.cjs";
7
7
  import { InferBag, InferNodeNames, InferNodeReturnTypes, InferStateType, InferSubagentStates, InferToolCalls, ResolveStreamInterface, ResolveStreamOptions } from "./stream/index.cjs";
8
- import { HistoryWithBaseMessages, MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict } from "./messages.cjs";
9
8
  import { StreamError } from "./errors.cjs";
10
9
  import { SubagentManager, calculateDepthFromNamespace, extractParentIdFromNamespace, extractToolCallIdFromNamespace, isSubagentNamespace } from "./subagents.cjs";
10
+ import { HistoryWithBaseMessages, MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict } from "./messages.cjs";
11
11
  import { ClassSubagentStreamInterface, ClassToolCallWithResult, WithClassMessages } from "./class-messages.cjs";
12
12
  import { EventStreamEvent, StreamManager } from "./manager.cjs";
13
13
  import { extractInterrupts, normalizeInterruptForClient, normalizeInterruptsList, userFacingInterruptsFromThreadTasks, userFacingInterruptsFromValuesArray } from "./interrupts.cjs";
@@ -5,9 +5,9 @@ import { BaseStream, StateRecord } from "./stream/base.js";
5
5
  import { UseAgentStream, UseAgentStreamOptions } from "./stream/agent.js";
6
6
  import { UseDeepAgentStream, UseDeepAgentStreamOptions } from "./stream/deep-agent.js";
7
7
  import { InferBag, InferNodeNames, InferNodeReturnTypes, InferStateType, InferSubagentStates, InferToolCalls, ResolveStreamInterface, ResolveStreamOptions } from "./stream/index.js";
8
- import { HistoryWithBaseMessages, MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict } from "./messages.js";
9
8
  import { StreamError } from "./errors.js";
10
9
  import { SubagentManager, calculateDepthFromNamespace, extractParentIdFromNamespace, extractToolCallIdFromNamespace, isSubagentNamespace } from "./subagents.js";
10
+ import { HistoryWithBaseMessages, MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict } from "./messages.js";
11
11
  import { ClassSubagentStreamInterface, ClassToolCallWithResult, WithClassMessages } from "./class-messages.js";
12
12
  import { EventStreamEvent, StreamManager } from "./manager.js";
13
13
  import { extractInterrupts, normalizeInterruptForClient, normalizeInterruptsList, userFacingInterruptsFromThreadTasks, userFacingInterruptsFromValuesArray } from "./interrupts.js";
@@ -1,4 +1,5 @@
1
1
  require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_message_coercion = require("../stream/message-coercion.cjs");
2
3
  let _langchain_core_messages = require("@langchain/core/messages");
3
4
  //#region src/ui/messages.ts
4
5
  function tryConvertToChunk(message) {
@@ -9,61 +10,15 @@ function tryConvertToChunk(message) {
9
10
  return null;
10
11
  }
11
12
  }
12
- function tryCoerceMessageLikeToMessage(message) {
13
- if (message.type === "human" || message.type === "user") return new _langchain_core_messages.HumanMessage(message);
14
- if (message.type === "ai" || message.type === "assistant") return new _langchain_core_messages.AIMessage(normalizeAIMessageToolCalls(message));
15
- if (message.type === "system") return new _langchain_core_messages.SystemMessage(message);
16
- if (message.type === "tool" && "tool_call_id" in message) return new _langchain_core_messages.ToolMessage({
17
- ...message,
18
- tool_call_id: message.tool_call_id
19
- });
20
- if (message.type === "remove" && message.id != null) return new _langchain_core_messages.RemoveMessage({
21
- ...message,
22
- id: message.id
23
- });
24
- return (0, _langchain_core_messages.coerceMessageLikeToMessage)(message);
25
- }
26
13
  function tryCoerceMessageLikeToChunk(message) {
27
14
  if (message.type === "human" || message.type === "user") return new _langchain_core_messages.HumanMessageChunk(message);
28
- if (message.type === "ai" || message.type === "assistant") return new _langchain_core_messages.AIMessageChunk(normalizeAIMessageToolCalls(message));
15
+ if (message.type === "ai" || message.type === "assistant") return new _langchain_core_messages.AIMessageChunk(require_message_coercion.normalizeAIMessageToolCalls(message));
29
16
  if (message.type === "system") return new _langchain_core_messages.SystemMessageChunk(message);
30
17
  if (message.type === "tool" && "tool_call_id" in message) return new _langchain_core_messages.ToolMessageChunk({
31
18
  ...message,
32
19
  tool_call_id: message.tool_call_id
33
20
  });
34
- return tryCoerceMessageLikeToMessage(message);
35
- }
36
- function normalizeAIMessageToolCalls(message) {
37
- const record = message;
38
- if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) return message;
39
- const toolCalls = extractToolCallsFromContent(record.content);
40
- if (toolCalls.length === 0) return message;
41
- return {
42
- ...message,
43
- tool_calls: toolCalls
44
- };
45
- }
46
- function extractToolCallsFromContent(content) {
47
- if (!Array.isArray(content)) return [];
48
- return content.flatMap((block) => {
49
- if (block == null || typeof block !== "object") return [];
50
- const record = block;
51
- if (record.type !== "tool_call" && record.type !== "tool_use") return [];
52
- return [{
53
- id: record.id ?? "",
54
- name: record.name ?? "",
55
- args: normalizeToolCallArgs(record.args ?? record.input),
56
- type: "tool_call"
57
- }];
58
- });
59
- }
60
- function normalizeToolCallArgs(value) {
61
- if (value != null && typeof value === "object" && !Array.isArray(value)) return value;
62
- if (typeof value === "string" && value.length > 0) try {
63
- const parsed = JSON.parse(value);
64
- if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
65
- } catch {}
66
- return {};
21
+ return require_message_coercion.tryCoerceMessageLikeToMessage(message);
67
22
  }
68
23
  var MessageTupleManager = class {
69
24
  chunks = {};
@@ -118,7 +73,7 @@ const toMessageClass = (chunk) => chunk;
118
73
  function ensureMessageInstances(messages) {
119
74
  return messages.map((msg) => {
120
75
  if (typeof msg.getType === "function") return msg;
121
- return tryCoerceMessageLikeToMessage(msg);
76
+ return require_message_coercion.tryCoerceMessageLikeToMessage(msg);
122
77
  });
123
78
  }
124
79
  /**
@@ -146,6 +101,5 @@ exports.ensureHistoryMessageInstances = ensureHistoryMessageInstances;
146
101
  exports.ensureMessageInstances = ensureMessageInstances;
147
102
  exports.toMessageClass = toMessageClass;
148
103
  exports.toMessageDict = toMessageDict;
149
- exports.tryCoerceMessageLikeToMessage = tryCoerceMessageLikeToMessage;
150
104
 
151
105
  //# sourceMappingURL=messages.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.cjs","names":["BaseMessageChunk","HumanMessage","AIMessage","SystemMessage","ToolMessage","RemoveMessage","HumanMessageChunk","AIMessageChunk","SystemMessageChunk","ToolMessageChunk"],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n RemoveMessage,\n convertToChunk,\n coerceMessageLikeToMessage,\n HumanMessageChunk,\n HumanMessage,\n SystemMessageChunk,\n SystemMessage,\n AIMessageChunk,\n AIMessage,\n ToolMessageChunk,\n ToolMessage,\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 (BaseMessageChunk.isInstance(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 HumanMessage(message);\n }\n\n if (message.type === \"ai\" || message.type === \"assistant\") {\n return new AIMessage(normalizeAIMessageToolCalls(message));\n }\n\n if (message.type === \"system\") {\n return new SystemMessage(message);\n }\n\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n return new ToolMessage({\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\nfunction tryCoerceMessageLikeToChunk(\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(normalizeAIMessageToolCalls(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 return tryCoerceMessageLikeToMessage(message);\n}\n\ntype ToolCallLike = {\n id?: string;\n name?: string;\n args?: unknown;\n input?: unknown;\n};\n\nfunction normalizeAIMessageToolCalls<\n T extends Omit<Message, \"type\"> & { type: string },\n>(message: T): T {\n const record = message as T & {\n content?: unknown;\n tool_calls?: unknown;\n };\n if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) {\n return message;\n }\n\n const toolCalls = extractToolCallsFromContent(record.content);\n if (toolCalls.length === 0) return message;\n return {\n ...message,\n tool_calls: toolCalls,\n };\n}\n\nfunction extractToolCallsFromContent(content: unknown) {\n if (!Array.isArray(content)) return [];\n return content.flatMap(\n (\n block\n ): Array<{\n id: string;\n name: string;\n args: Record<string, unknown>;\n type: \"tool_call\";\n }> => {\n if (block == null || typeof block !== \"object\") return [];\n const record = block as ToolCallLike & { type?: unknown };\n if (record.type !== \"tool_call\" && record.type !== \"tool_use\") return [];\n return [\n {\n id: record.id ?? \"\",\n name: record.name ?? \"\",\n args: normalizeToolCallArgs(record.args ?? record.input),\n type: \"tool_call\",\n },\n ];\n }\n );\n}\n\nfunction normalizeToolCallArgs(value: unknown): Record<string, unknown> {\n if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value === \"string\" && value.length > 0) {\n try {\n const parsed = JSON.parse(value);\n if (\n parsed != null &&\n typeof parsed === \"object\" &&\n !Array.isArray(parsed)\n ) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Streaming input fragments are expected to be invalid until finalized.\n }\n }\n return {};\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 = tryCoerceMessageLikeToChunk(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 (BaseMessageChunk.isInstance(prev) ? prev : null)?.concat(chunk) ??\n 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":"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"}
1
+ {"version":3,"file":"messages.cjs","names":["BaseMessageChunk","HumanMessageChunk","AIMessageChunk","normalizeAIMessageToolCalls","SystemMessageChunk","ToolMessageChunk","tryCoerceMessageLikeToMessage"],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n convertToChunk,\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\";\nimport {\n normalizeAIMessageToolCalls,\n tryCoerceMessageLikeToMessage,\n} from \"../stream/message-coercion.js\";\n\nexport { tryCoerceMessageLikeToMessage };\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 (BaseMessageChunk.isInstance(message)) return message;\n return convertToChunk(message);\n } catch {\n return null;\n }\n}\n\nfunction tryCoerceMessageLikeToChunk(\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(normalizeAIMessageToolCalls(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 return tryCoerceMessageLikeToMessage(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 = tryCoerceMessageLikeToChunk(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 (BaseMessageChunk.isInstance(prev) ? prev : null)?.concat(chunk) ??\n 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,MAAIA,yBAAAA,iBAAiB,WAAW,QAAQ,CAAE,QAAO;AACjD,UAAA,GAAA,yBAAA,gBAAsB,QAAQ;SACxB;AACN,SAAO;;;AAIX,SAAS,4BACP,SACgC;AAChC,KAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,OAC/C,QAAO,IAAIC,yBAAAA,kBAAkB,QAAQ;AAGvC,KAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,YAC5C,QAAO,IAAIC,yBAAAA,eAAeC,yBAAAA,4BAA4B,QAAQ,CAAC;AAGjE,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,QAAOC,yBAAAA,8BAA8B,QAAQ;;AAG/C,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,4BAA4B,WAAW;EACvD,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,SACbN,yBAAAA,iBAAiB,WAAW,KAAK,GAAG,OAAO,OAAO,OAAO,MAAM,IAChE;QAEF,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,SAAOM,yBAAAA,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 +1 @@
1
- {"version":3,"file":"messages.d.cts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;;AAwBA;;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,cA4IS,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;EAqCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAzCjB,yBAAA,CAAA,cAAA;;;;;cAiDP,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;;;;;AA1E3B;;iBAkFgB,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
+ {"version":3,"file":"messages.d.cts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;AAwBA;;;;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,cAsCS,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;EAqCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAzCjB,yBAAA,CAAA,cAAA;;;;;cAiDP,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;;;;;;AA1E3B;iBAkFgB,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.d.ts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;;AAwBA;;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,cA4IS,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;EAqCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAzCjB,yBAAA,CAAA,cAAA;;;;;cAiDP,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;;;;;AA1E3B;;iBAkFgB,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
+ {"version":3,"file":"messages.d.ts","names":[],"sources":["../../src/ui/messages.ts"],"mappings":";;;;;;;;AAwBA;;;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,cAsCS,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;EAqCZ,KAAA,CAAA;EAIA,GAAA,CAAI,EAAA,6BAA+B,YAAA;mEAzCjB,yBAAA,CAAA,cAAA;;;;;cAiDP,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;;;;;;iBAgBF,6BAAA,mBACI,MAAA,kBAAA,CAElB,OAAA,EAAS,WAAA,CAAY,SAAA,KACrB,WAAA,YACC,WAAA,CAAY,SAAA"}
@@ -1,4 +1,5 @@
1
- import { AIMessage, AIMessageChunk, BaseMessageChunk, HumanMessage, HumanMessageChunk, RemoveMessage, SystemMessage, SystemMessageChunk, ToolMessage, ToolMessageChunk, coerceMessageLikeToMessage, convertToChunk } from "@langchain/core/messages";
1
+ import { normalizeAIMessageToolCalls, tryCoerceMessageLikeToMessage } from "../stream/message-coercion.js";
2
+ import { AIMessageChunk, BaseMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, convertToChunk } from "@langchain/core/messages";
2
3
  //#region src/ui/messages.ts
3
4
  function tryConvertToChunk(message) {
4
5
  try {
@@ -8,20 +9,6 @@ function tryConvertToChunk(message) {
8
9
  return null;
9
10
  }
10
11
  }
11
- function tryCoerceMessageLikeToMessage(message) {
12
- if (message.type === "human" || message.type === "user") return new HumanMessage(message);
13
- if (message.type === "ai" || message.type === "assistant") return new AIMessage(normalizeAIMessageToolCalls(message));
14
- if (message.type === "system") return new SystemMessage(message);
15
- if (message.type === "tool" && "tool_call_id" in message) return new ToolMessage({
16
- ...message,
17
- tool_call_id: message.tool_call_id
18
- });
19
- if (message.type === "remove" && message.id != null) return new RemoveMessage({
20
- ...message,
21
- id: message.id
22
- });
23
- return coerceMessageLikeToMessage(message);
24
- }
25
12
  function tryCoerceMessageLikeToChunk(message) {
26
13
  if (message.type === "human" || message.type === "user") return new HumanMessageChunk(message);
27
14
  if (message.type === "ai" || message.type === "assistant") return new AIMessageChunk(normalizeAIMessageToolCalls(message));
@@ -32,38 +19,6 @@ function tryCoerceMessageLikeToChunk(message) {
32
19
  });
33
20
  return tryCoerceMessageLikeToMessage(message);
34
21
  }
35
- function normalizeAIMessageToolCalls(message) {
36
- const record = message;
37
- if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) return message;
38
- const toolCalls = extractToolCallsFromContent(record.content);
39
- if (toolCalls.length === 0) return message;
40
- return {
41
- ...message,
42
- tool_calls: toolCalls
43
- };
44
- }
45
- function extractToolCallsFromContent(content) {
46
- if (!Array.isArray(content)) return [];
47
- return content.flatMap((block) => {
48
- if (block == null || typeof block !== "object") return [];
49
- const record = block;
50
- if (record.type !== "tool_call" && record.type !== "tool_use") return [];
51
- return [{
52
- id: record.id ?? "",
53
- name: record.name ?? "",
54
- args: normalizeToolCallArgs(record.args ?? record.input),
55
- type: "tool_call"
56
- }];
57
- });
58
- }
59
- function normalizeToolCallArgs(value) {
60
- if (value != null && typeof value === "object" && !Array.isArray(value)) return value;
61
- if (typeof value === "string" && value.length > 0) try {
62
- const parsed = JSON.parse(value);
63
- if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
64
- } catch {}
65
- return {};
66
- }
67
22
  var MessageTupleManager = class {
68
23
  chunks = {};
69
24
  constructor() {
@@ -140,6 +95,6 @@ function ensureHistoryMessageInstances(history, messagesKey = "messages") {
140
95
  });
141
96
  }
142
97
  //#endregion
143
- export { MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict, tryCoerceMessageLikeToMessage };
98
+ export { MessageTupleManager, ensureHistoryMessageInstances, ensureMessageInstances, toMessageClass, toMessageDict };
144
99
 
145
100
  //# sourceMappingURL=messages.js.map
@@ -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 HumanMessageChunk,\n HumanMessage,\n SystemMessageChunk,\n SystemMessage,\n AIMessageChunk,\n AIMessage,\n ToolMessageChunk,\n ToolMessage,\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 (BaseMessageChunk.isInstance(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 HumanMessage(message);\n }\n\n if (message.type === \"ai\" || message.type === \"assistant\") {\n return new AIMessage(normalizeAIMessageToolCalls(message));\n }\n\n if (message.type === \"system\") {\n return new SystemMessage(message);\n }\n\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n return new ToolMessage({\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\nfunction tryCoerceMessageLikeToChunk(\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(normalizeAIMessageToolCalls(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 return tryCoerceMessageLikeToMessage(message);\n}\n\ntype ToolCallLike = {\n id?: string;\n name?: string;\n args?: unknown;\n input?: unknown;\n};\n\nfunction normalizeAIMessageToolCalls<\n T extends Omit<Message, \"type\"> & { type: string },\n>(message: T): T {\n const record = message as T & {\n content?: unknown;\n tool_calls?: unknown;\n };\n if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) {\n return message;\n }\n\n const toolCalls = extractToolCallsFromContent(record.content);\n if (toolCalls.length === 0) return message;\n return {\n ...message,\n tool_calls: toolCalls,\n };\n}\n\nfunction extractToolCallsFromContent(content: unknown) {\n if (!Array.isArray(content)) return [];\n return content.flatMap(\n (\n block\n ): Array<{\n id: string;\n name: string;\n args: Record<string, unknown>;\n type: \"tool_call\";\n }> => {\n if (block == null || typeof block !== \"object\") return [];\n const record = block as ToolCallLike & { type?: unknown };\n if (record.type !== \"tool_call\" && record.type !== \"tool_use\") return [];\n return [\n {\n id: record.id ?? \"\",\n name: record.name ?? \"\",\n args: normalizeToolCallArgs(record.args ?? record.input),\n type: \"tool_call\",\n },\n ];\n }\n );\n}\n\nfunction normalizeToolCallArgs(value: unknown): Record<string, unknown> {\n if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value === \"string\" && value.length > 0) {\n try {\n const parsed = JSON.parse(value);\n if (\n parsed != null &&\n typeof parsed === \"object\" &&\n !Array.isArray(parsed)\n ) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Streaming input fragments are expected to be invalid until finalized.\n }\n }\n return {};\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 = tryCoerceMessageLikeToChunk(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 (BaseMessageChunk.isInstance(prev) ? prev : null)?.concat(chunk) ??\n 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":"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"}
1
+ {"version":3,"file":"messages.js","names":[],"sources":["../../src/ui/messages.ts"],"sourcesContent":["import {\n type BaseMessage,\n BaseMessageChunk,\n convertToChunk,\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\";\nimport {\n normalizeAIMessageToolCalls,\n tryCoerceMessageLikeToMessage,\n} from \"../stream/message-coercion.js\";\n\nexport { tryCoerceMessageLikeToMessage };\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 (BaseMessageChunk.isInstance(message)) return message;\n return convertToChunk(message);\n } catch {\n return null;\n }\n}\n\nfunction tryCoerceMessageLikeToChunk(\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(normalizeAIMessageToolCalls(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 return tryCoerceMessageLikeToMessage(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 = tryCoerceMessageLikeToChunk(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 (BaseMessageChunk.isInstance(prev) ? prev : null)?.concat(chunk) ??\n 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,iBAAiB,WAAW,QAAQ,CAAE,QAAO;AACjD,SAAO,eAAe,QAAQ;SACxB;AACN,SAAO;;;AAIX,SAAS,4BACP,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,4BAA4B,QAAQ,CAAC;AAGjE,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,QAAO,8BAA8B,QAAQ;;AAG/C,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,4BAA4B,WAAW;EACvD,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,iBAAiB,WAAW,KAAK,GAAG,OAAO,OAAO,OAAO,MAAM,IAChE;QAEF,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "1.9.16",
3
+ "version": "1.9.18",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "repository": {