@assistant-ui/react-langgraph 0.5.12 → 0.6.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"LangGraphMessageAccumulator.d.ts","sourceRoot":"","sources":["../src/LangGraphMessageAccumulator.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,+BAA+B,CAAC,QAAQ,IAAI;IACtD,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ,KAAK,QAAQ,CAAC;CAC1E,CAAC;AAEF,qBAAa,2BAA2B,CAAC,QAAQ,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE;IACvE,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,aAAa,CAGP;gBAEF,EACV,eAAoB,EACpB,aAGa,GACd,GAAE,+BAA+B,CAAC,QAAQ,CAAM;IAKjD,OAAO,CAAC,eAAe;IAIhB,WAAW,CAAC,WAAW,EAAE,QAAQ,EAAE;IAenC,WAAW,IAAI,QAAQ,EAAE;IAIzB,KAAK;CAGb"}
1
+ {"version":3,"file":"LangGraphMessageAccumulator.d.ts","sourceRoot":"","sources":["../src/LangGraphMessageAccumulator.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,+BAA+B,CAAC,QAAQ,IAAI;IACtD,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ,KAAK,QAAQ,CAAC;CAC1E,CAAC;AAEF,qBAAa,2BAA2B,CAAC,QAAQ,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE;IACvE,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,aAAa,CAGP;gBAEF,EACV,eAAoB,EACpB,aAGa,GACd,GAAE,+BAA+B,CAAC,QAAQ,CAAM;IAKjD,OAAO,CAAC,eAAe;IAIhB,WAAW,CAAC,WAAW,EAAE,QAAQ,EAAE;IAWnC,WAAW,IAAI,QAAQ,EAAE;IAIzB,KAAK;CAGb"}
@@ -16,11 +16,9 @@ var LangGraphMessageAccumulator = class {
16
16
  addMessages(newMessages) {
17
17
  if (newMessages.length === 0) return this.getMessages();
18
18
  for (const message of newMessages.map(this.ensureMessageId)) {
19
- const previous = message.id ? this.messagesMap.get(message.id) : void 0;
20
- this.messagesMap.set(
21
- message.id ?? uuidv4(),
22
- this.appendMessage(previous, message)
23
- );
19
+ const messageId = message.id;
20
+ const previous = this.messagesMap.get(messageId);
21
+ this.messagesMap.set(messageId, this.appendMessage(previous, message));
24
22
  }
25
23
  return this.getMessages();
26
24
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LangGraphMessageAccumulator.ts"],"sourcesContent":["import { v4 as uuidv4 } from \"uuid\";\n\nexport type LangGraphStateAccumulatorConfig<TMessage> = {\n initialMessages?: TMessage[];\n appendMessage?: (prev: TMessage | undefined, curr: TMessage) => TMessage;\n};\n\nexport class LangGraphMessageAccumulator<TMessage extends { id?: string }> {\n private messagesMap = new Map<string, TMessage>();\n private appendMessage: (\n prev: TMessage | undefined,\n curr: TMessage,\n ) => TMessage;\n\n constructor({\n initialMessages = [],\n appendMessage = ((_: TMessage | undefined, curr: TMessage) => curr) as (\n prev: TMessage | undefined,\n curr: TMessage,\n ) => TMessage,\n }: LangGraphStateAccumulatorConfig<TMessage> = {}) {\n this.appendMessage = appendMessage;\n this.addMessages(initialMessages);\n }\n\n private ensureMessageId(message: TMessage): TMessage {\n return message.id ? message : { ...message, id: uuidv4() };\n }\n\n public addMessages(newMessages: TMessage[]) {\n if (newMessages.length === 0) return this.getMessages();\n\n for (const message of newMessages.map(this.ensureMessageId)) {\n const previous = message.id\n ? this.messagesMap.get(message.id)\n : undefined;\n this.messagesMap.set(\n message.id ?? uuidv4(),\n this.appendMessage(previous, message),\n );\n }\n return this.getMessages();\n }\n\n public getMessages(): TMessage[] {\n return [...this.messagesMap.values()];\n }\n\n public clear() {\n this.messagesMap.clear();\n }\n}\n"],"mappings":";AAAA,SAAS,MAAM,cAAc;AAOtB,IAAM,8BAAN,MAAoE;AAAA,EACjE,cAAc,oBAAI,IAAsB;AAAA,EACxC;AAAA,EAKR,YAAY;AAAA,IACV,kBAAkB,CAAC;AAAA,IACnB,iBAAiB,CAAC,GAAyB,SAAmB;AAAA,EAIhE,IAA+C,CAAC,GAAG;AACjD,SAAK,gBAAgB;AACrB,SAAK,YAAY,eAAe;AAAA,EAClC;AAAA,EAEQ,gBAAgB,SAA6B;AACnD,WAAO,QAAQ,KAAK,UAAU,EAAE,GAAG,SAAS,IAAI,OAAO,EAAE;AAAA,EAC3D;AAAA,EAEO,YAAY,aAAyB;AAC1C,QAAI,YAAY,WAAW,EAAG,QAAO,KAAK,YAAY;AAEtD,eAAW,WAAW,YAAY,IAAI,KAAK,eAAe,GAAG;AAC3D,YAAM,WAAW,QAAQ,KACrB,KAAK,YAAY,IAAI,QAAQ,EAAE,IAC/B;AACJ,WAAK,YAAY;AAAA,QACf,QAAQ,MAAM,OAAO;AAAA,QACrB,KAAK,cAAc,UAAU,OAAO;AAAA,MACtC;AAAA,IACF;AACA,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEO,cAA0B;AAC/B,WAAO,CAAC,GAAG,KAAK,YAAY,OAAO,CAAC;AAAA,EACtC;AAAA,EAEO,QAAQ;AACb,SAAK,YAAY,MAAM;AAAA,EACzB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/LangGraphMessageAccumulator.ts"],"sourcesContent":["import { v4 as uuidv4 } from \"uuid\";\n\nexport type LangGraphStateAccumulatorConfig<TMessage> = {\n initialMessages?: TMessage[];\n appendMessage?: (prev: TMessage | undefined, curr: TMessage) => TMessage;\n};\n\nexport class LangGraphMessageAccumulator<TMessage extends { id?: string }> {\n private messagesMap = new Map<string, TMessage>();\n private appendMessage: (\n prev: TMessage | undefined,\n curr: TMessage,\n ) => TMessage;\n\n constructor({\n initialMessages = [],\n appendMessage = ((_: TMessage | undefined, curr: TMessage) => curr) as (\n prev: TMessage | undefined,\n curr: TMessage,\n ) => TMessage,\n }: LangGraphStateAccumulatorConfig<TMessage> = {}) {\n this.appendMessage = appendMessage;\n this.addMessages(initialMessages);\n }\n\n private ensureMessageId(message: TMessage): TMessage {\n return message.id ? message : { ...message, id: uuidv4() };\n }\n\n public addMessages(newMessages: TMessage[]) {\n if (newMessages.length === 0) return this.getMessages();\n\n for (const message of newMessages.map(this.ensureMessageId)) {\n const messageId = message.id!; // ensureMessageId guarantees id exists\n const previous = this.messagesMap.get(messageId);\n this.messagesMap.set(messageId, this.appendMessage(previous, message));\n }\n return this.getMessages();\n }\n\n public getMessages(): TMessage[] {\n return [...this.messagesMap.values()];\n }\n\n public clear() {\n this.messagesMap.clear();\n }\n}\n"],"mappings":";AAAA,SAAS,MAAM,cAAc;AAOtB,IAAM,8BAAN,MAAoE;AAAA,EACjE,cAAc,oBAAI,IAAsB;AAAA,EACxC;AAAA,EAKR,YAAY;AAAA,IACV,kBAAkB,CAAC;AAAA,IACnB,iBAAiB,CAAC,GAAyB,SAAmB;AAAA,EAIhE,IAA+C,CAAC,GAAG;AACjD,SAAK,gBAAgB;AACrB,SAAK,YAAY,eAAe;AAAA,EAClC;AAAA,EAEQ,gBAAgB,SAA6B;AACnD,WAAO,QAAQ,KAAK,UAAU,EAAE,GAAG,SAAS,IAAI,OAAO,EAAE;AAAA,EAC3D;AAAA,EAEO,YAAY,aAAyB;AAC1C,QAAI,YAAY,WAAW,EAAG,QAAO,KAAK,YAAY;AAEtD,eAAW,WAAW,YAAY,IAAI,KAAK,eAAe,GAAG;AAC3D,YAAM,YAAY,QAAQ;AAC1B,YAAM,WAAW,KAAK,YAAY,IAAI,SAAS;AAC/C,WAAK,YAAY,IAAI,WAAW,KAAK,cAAc,UAAU,OAAO,CAAC;AAAA,IACvE;AACA,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEO,cAA0B;AAC/B,WAAO,CAAC,GAAG,KAAK,YAAY,OAAO,CAAC;AAAA,EACtC;AAAA,EAEO,QAAQ;AACb,SAAK,YAAY,MAAM;AAAA,EACzB;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"useLangGraphRuntime.d.ts","sourceRoot":"","sources":["../src/useLangGraphRuntime.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAEhB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAQjB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,0BAA0B,EAC1B,uBAAuB,EAExB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AA0E7D,eAAO,MAAM,0BAA0B,2CAGtC,CAAC;AAEF,eAAO,MAAM,gBAAgB,mBAxBf,gBAAgB,EAAE,UACpB,0BAA0B,KAC/B,OAAO,CAAC,IAAI,CAyBlB,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAE1B,SAAS,gBAAgB,kBAClC,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,kLASjC;IACD;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,CAAC;IAClD;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QAC/C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,uBAAuB,EAAE,CAAC;KACxC,CAAC,CAAC;IACH,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,MAAM,CAAC,EAAE,sBAAsB,CAAC;QAChC,QAAQ,CAAC,EAAE,eAAe,CAAC;KAC5B,GACD,SAAS,CAAC;IACd;;OAEG;IACH,aAAa,CAAC,EACV;QACE;;WAEG;QACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;QACrC;;WAEG;QACH,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B;;WAEG;QACH,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAC/B;;WAEG;QACH,aAAa,CAAC,EAAE,qBAAqB,CAAC;KACvC,GACD,SAAS,CAAC;CACf,mDA+IA,CAAC"}
1
+ {"version":3,"file":"useLangGraphRuntime.d.ts","sourceRoot":"","sources":["../src/useLangGraphRuntime.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAEhB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAQjB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,0BAA0B,EAC1B,uBAAuB,EAExB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AA0E7D,eAAO,MAAM,0BAA0B,2CAKtC,CAAC;AAEF,eAAO,MAAM,gBAAgB,mBA1Bf,gBAAgB,EAAE,UACpB,0BAA0B,KAC/B,OAAO,CAAC,IAAI,CA6BlB,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAE1B,SAAS,gBAAgB,kBAClC,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,kLASjC;IACD;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,CAAC;IAClD;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QAC/C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,uBAAuB,EAAE,CAAC;KACxC,CAAC,CAAC;IACH,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,MAAM,CAAC,EAAE,sBAAsB,CAAC;QAChC,QAAQ,CAAC,EAAE,eAAe,CAAC;KAC5B,GACD,SAAS,CAAC;IACd;;OAEG;IACH,aAAa,CAAC,EACV;QACE;;WAEG;QACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;QACrC;;WAEG;QACH,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B;;WAEG;QACH,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAC/B;;WAEG;QACH,aAAa,CAAC,EAAE,qBAAqB,CAAC;KACvC,GACD,SAAS,CAAC;CACf,mDA+IA,CAAC"}
@@ -1,10 +1,10 @@
1
1
  // src/useLangGraphRuntime.ts
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import {
4
+ useAssistantState,
5
+ useAssistantApi,
4
6
  useExternalMessageConverter,
5
- useExternalStoreRuntime,
6
- useThread,
7
- useThreadListItemRuntime
7
+ useExternalStoreRuntime
8
8
  } from "@assistant-ui/react";
9
9
  import { convertLangChainMessages } from "./convertLangChainMessages.js";
10
10
  import {
@@ -60,11 +60,15 @@ var asLangGraphRuntimeExtras = (extras) => {
60
60
  return extras;
61
61
  };
62
62
  var useLangGraphInterruptState = () => {
63
- const { interrupt } = useThread((t) => asLangGraphRuntimeExtras(t.extras));
63
+ const { interrupt } = useAssistantState(
64
+ ({ thread }) => asLangGraphRuntimeExtras(thread.extras)
65
+ );
64
66
  return interrupt;
65
67
  };
66
68
  var useLangGraphSend = () => {
67
- const { send } = useThread((t) => asLangGraphRuntimeExtras(t.extras));
69
+ const { send } = useAssistantState(
70
+ ({ thread }) => asLangGraphRuntimeExtras(thread.extras)
71
+ );
68
72
  return send;
69
73
  };
70
74
  var useLangGraphSendCommand = () => {
@@ -124,10 +128,10 @@ var useLangGraphRuntime = ({
124
128
  onSwitchToThread: switchToThread
125
129
  };
126
130
  const loadingRef = useRef(false);
127
- const threadListItemRuntime = useThreadListItemRuntime({ optional: true });
131
+ const api = useAssistantApi();
128
132
  useEffect(() => {
129
- if (!threadListItemRuntime || !switchToThread || loadingRef.current) return;
130
- const externalId = threadListItemRuntime.getState().externalId;
133
+ if (!switchToThread || loadingRef.current) return;
134
+ const externalId = api.threadListItem().getState().externalId;
131
135
  if (externalId) {
132
136
  loadingRef.current = true;
133
137
  switchToThread(externalId).finally(() => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useLangGraphRuntime.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n LangChainMessage,\n LangChainToolCall,\n OnCustomEventCallback,\n OnErrorEventCallback,\n OnInfoEventCallback,\n OnMetadataEventCallback,\n} from \"./types\";\nimport {\n useExternalMessageConverter,\n useExternalStoreRuntime,\n useThread,\n useThreadListItemRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangChainMessages } from \"./convertLangChainMessages\";\nimport {\n LangGraphCommand,\n LangGraphInterruptState,\n LangGraphSendMessageConfig,\n LangGraphStreamCallback,\n useLangGraphMessages,\n} from \"./useLangGraphMessages\";\nimport { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { AppendMessage } from \"@assistant-ui/react\";\nimport { ExternalStoreAdapter } from \"@assistant-ui/react\";\nimport { FeedbackAdapter } from \"@assistant-ui/react\";\nimport { SpeechSynthesisAdapter } from \"@assistant-ui/react\";\nimport { appendLangChainChunk } from \"./appendLangChainChunk\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nconst getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default:\n const _exhaustiveCheck: \"reasoning\" | \"source\" | \"file\" | \"audio\" =\n type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n\n return content;\n};\n\nconst symbolLangGraphRuntimeExtras = Symbol(\"langgraph-runtime-extras\");\ntype LangGraphRuntimeExtras = {\n [symbolLangGraphRuntimeExtras]: true;\n send: (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => Promise<void>;\n interrupt: LangGraphInterruptState | undefined;\n};\n\nconst asLangGraphRuntimeExtras = (extras: unknown): LangGraphRuntimeExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolLangGraphRuntimeExtras in extras)\n )\n throw new Error(\n \"This method can only be called when you are using useLangGraphRuntime\",\n );\n\n return extras as LangGraphRuntimeExtras;\n};\n\nexport const useLangGraphInterruptState = () => {\n const { interrupt } = useThread((t) => asLangGraphRuntimeExtras(t.extras));\n return interrupt;\n};\n\nexport const useLangGraphSend = () => {\n const { send } = useThread((t) => asLangGraphRuntimeExtras(t.extras));\n return send;\n};\n\nexport const useLangGraphSendCommand = () => {\n const send = useLangGraphSend();\n return (command: LangGraphCommand) => send([], { command });\n};\n\nexport const useLangGraphRuntime = ({\n autoCancelPendingToolCalls,\n adapters: { attachments, feedback, speech } = {},\n unstable_allowCancellation,\n stream,\n threadId,\n onSwitchToNewThread,\n onSwitchToThread,\n eventHandlers,\n}: {\n /**\n * @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.\n */\n threadId?: string | undefined;\n autoCancelPendingToolCalls?: boolean | undefined;\n unstable_allowCancellation?: boolean | undefined;\n stream: LangGraphStreamCallback<LangChainMessage>;\n /**\n * @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.\n */\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (threadId: string) => Promise<{\n messages: LangChainMessage[];\n interrupts?: LangGraphInterruptState[];\n }>;\n adapters?:\n | {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n feedback?: FeedbackAdapter;\n }\n | undefined;\n /**\n * Event handlers for various LangGraph stream events\n */\n eventHandlers?:\n | {\n /**\n * Called when metadata is received from the LangGraph stream\n */\n onMetadata?: OnMetadataEventCallback;\n /**\n * Called when informational messages are received from the LangGraph stream\n */\n onInfo?: OnInfoEventCallback;\n /**\n * Called when errors occur during LangGraph stream processing\n */\n onError?: OnErrorEventCallback;\n /**\n * Called when custom events are received from the LangGraph stream\n */\n onCustomEvent?: OnCustomEventCallback;\n }\n | undefined;\n}) => {\n const {\n interrupt,\n setInterrupt,\n messages,\n sendMessage,\n cancel,\n setMessages,\n } = useLangGraphMessages({\n appendMessage: appendLangChainChunk,\n stream,\n ...(eventHandlers && { eventHandlers }),\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => {\n try {\n setIsRunning(true);\n await sendMessage(messages, config);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangChainMessages,\n messages,\n isRunning,\n });\n\n const switchToThread = !onSwitchToThread\n ? undefined\n : async (externalId: string) => {\n const { messages, interrupts } = await onSwitchToThread(externalId);\n setMessages(messages);\n setInterrupt(interrupts?.[0]);\n };\n\n const threadList: NonNullable<\n ExternalStoreAdapter[\"adapters\"]\n >[\"threadList\"] = {\n threadId,\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n setInterrupt(undefined);\n },\n onSwitchToThread: switchToThread,\n };\n\n const loadingRef = useRef(false);\n const threadListItemRuntime = useThreadListItemRuntime({ optional: true });\n useEffect(() => {\n if (!threadListItemRuntime || !switchToThread || loadingRef.current) return;\n\n const externalId = threadListItemRuntime.getState().externalId;\n if (externalId) {\n loadingRef.current = true;\n switchToThread(externalId).finally(() => {\n loadingRef.current = false;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return useExternalStoreRuntime({\n isRunning,\n messages: threadMessages,\n adapters: {\n attachments,\n feedback,\n speech,\n threadList,\n },\n extras: {\n [symbolLangGraphRuntimeExtras]: true,\n interrupt,\n send: handleSendMessage,\n } satisfies LangGraphRuntimeExtras,\n onNew: (msg) => {\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\",\n }) satisfies LangChainMessage & { type: \"tool\" },\n )\n : [];\n\n return handleSendMessage(\n [\n ...cancellations,\n {\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n {\n runConfig: msg.runConfig,\n },\n );\n },\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n // TODO parallel human in the loop calls\n await handleSendMessage(\n [\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n artifact,\n status: isError ? \"error\" : \"success\",\n },\n ],\n // TODO reuse runconfig here!\n {},\n );\n },\n onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n });\n};\n"],"mappings":"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","names":["messages"]}
1
+ {"version":3,"sources":["../src/useLangGraphRuntime.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n LangChainMessage,\n LangChainToolCall,\n OnCustomEventCallback,\n OnErrorEventCallback,\n OnInfoEventCallback,\n OnMetadataEventCallback,\n} from \"./types\";\nimport {\n useAssistantState,\n useAssistantApi,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangChainMessages } from \"./convertLangChainMessages\";\nimport {\n LangGraphCommand,\n LangGraphInterruptState,\n LangGraphSendMessageConfig,\n LangGraphStreamCallback,\n useLangGraphMessages,\n} from \"./useLangGraphMessages\";\nimport { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { AppendMessage } from \"@assistant-ui/react\";\nimport { ExternalStoreAdapter } from \"@assistant-ui/react\";\nimport { FeedbackAdapter } from \"@assistant-ui/react\";\nimport { SpeechSynthesisAdapter } from \"@assistant-ui/react\";\nimport { appendLangChainChunk } from \"./appendLangChainChunk\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nconst getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default:\n const _exhaustiveCheck: \"reasoning\" | \"source\" | \"file\" | \"audio\" =\n type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n\n return content;\n};\n\nconst symbolLangGraphRuntimeExtras = Symbol(\"langgraph-runtime-extras\");\ntype LangGraphRuntimeExtras = {\n [symbolLangGraphRuntimeExtras]: true;\n send: (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => Promise<void>;\n interrupt: LangGraphInterruptState | undefined;\n};\n\nconst asLangGraphRuntimeExtras = (extras: unknown): LangGraphRuntimeExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolLangGraphRuntimeExtras in extras)\n )\n throw new Error(\n \"This method can only be called when you are using useLangGraphRuntime\",\n );\n\n return extras as LangGraphRuntimeExtras;\n};\n\nexport const useLangGraphInterruptState = () => {\n const { interrupt } = useAssistantState(({ thread }) =>\n asLangGraphRuntimeExtras(thread.extras),\n );\n return interrupt;\n};\n\nexport const useLangGraphSend = () => {\n const { send } = useAssistantState(({ thread }) =>\n asLangGraphRuntimeExtras(thread.extras),\n );\n return send;\n};\n\nexport const useLangGraphSendCommand = () => {\n const send = useLangGraphSend();\n return (command: LangGraphCommand) => send([], { command });\n};\n\nexport const useLangGraphRuntime = ({\n autoCancelPendingToolCalls,\n adapters: { attachments, feedback, speech } = {},\n unstable_allowCancellation,\n stream,\n threadId,\n onSwitchToNewThread,\n onSwitchToThread,\n eventHandlers,\n}: {\n /**\n * @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.\n */\n threadId?: string | undefined;\n autoCancelPendingToolCalls?: boolean | undefined;\n unstable_allowCancellation?: boolean | undefined;\n stream: LangGraphStreamCallback<LangChainMessage>;\n /**\n * @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.\n */\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (threadId: string) => Promise<{\n messages: LangChainMessage[];\n interrupts?: LangGraphInterruptState[];\n }>;\n adapters?:\n | {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n feedback?: FeedbackAdapter;\n }\n | undefined;\n /**\n * Event handlers for various LangGraph stream events\n */\n eventHandlers?:\n | {\n /**\n * Called when metadata is received from the LangGraph stream\n */\n onMetadata?: OnMetadataEventCallback;\n /**\n * Called when informational messages are received from the LangGraph stream\n */\n onInfo?: OnInfoEventCallback;\n /**\n * Called when errors occur during LangGraph stream processing\n */\n onError?: OnErrorEventCallback;\n /**\n * Called when custom events are received from the LangGraph stream\n */\n onCustomEvent?: OnCustomEventCallback;\n }\n | undefined;\n}) => {\n const {\n interrupt,\n setInterrupt,\n messages,\n sendMessage,\n cancel,\n setMessages,\n } = useLangGraphMessages({\n appendMessage: appendLangChainChunk,\n stream,\n ...(eventHandlers && { eventHandlers }),\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => {\n try {\n setIsRunning(true);\n await sendMessage(messages, config);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangChainMessages,\n messages,\n isRunning,\n });\n\n const switchToThread = !onSwitchToThread\n ? undefined\n : async (externalId: string) => {\n const { messages, interrupts } = await onSwitchToThread(externalId);\n setMessages(messages);\n setInterrupt(interrupts?.[0]);\n };\n\n const threadList: NonNullable<\n ExternalStoreAdapter[\"adapters\"]\n >[\"threadList\"] = {\n threadId,\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n setInterrupt(undefined);\n },\n onSwitchToThread: switchToThread,\n };\n\n const loadingRef = useRef(false);\n const api = useAssistantApi();\n useEffect(() => {\n if (!switchToThread || loadingRef.current) return;\n\n const externalId = api.threadListItem().getState().externalId;\n if (externalId) {\n loadingRef.current = true;\n switchToThread(externalId).finally(() => {\n loadingRef.current = false;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return useExternalStoreRuntime({\n isRunning,\n messages: threadMessages,\n adapters: {\n attachments,\n feedback,\n speech,\n threadList,\n },\n extras: {\n [symbolLangGraphRuntimeExtras]: true,\n interrupt,\n send: handleSendMessage,\n } satisfies LangGraphRuntimeExtras,\n onNew: (msg) => {\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\",\n }) satisfies LangChainMessage & { type: \"tool\" },\n )\n : [];\n\n return handleSendMessage(\n [\n ...cancellations,\n {\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n {\n runConfig: msg.runConfig,\n },\n );\n },\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n // TODO parallel human in the loop calls\n await handleSendMessage(\n [\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n artifact,\n status: isError ? \"error\" : \"success\",\n },\n ],\n // TODO reuse runconfig here!\n {},\n );\n },\n onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n });\n};\n"],"mappings":"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","names":["messages"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-langgraph",
3
- "version": "0.5.12",
3
+ "version": "0.6.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -23,7 +23,7 @@
23
23
  "zod": "^4.0.17"
24
24
  },
25
25
  "peerDependencies": {
26
- "@assistant-ui/react": "^0.10.42",
26
+ "@assistant-ui/react": "^0.11.2",
27
27
  "@types/react": "*",
28
28
  "react": "^18 || ^19 || ^19.0.0-rc"
29
29
  },
@@ -44,7 +44,7 @@
44
44
  "react": "19.1.1",
45
45
  "tsx": "^4.20.4",
46
46
  "vitest": "^3.2.4",
47
- "@assistant-ui/react": "0.10.42",
47
+ "@assistant-ui/react": "0.11.2",
48
48
  "@assistant-ui/x-buildutils": "0.0.1"
49
49
  },
50
50
  "publishConfig": {
@@ -31,13 +31,9 @@ export class LangGraphMessageAccumulator<TMessage extends { id?: string }> {
31
31
  if (newMessages.length === 0) return this.getMessages();
32
32
 
33
33
  for (const message of newMessages.map(this.ensureMessageId)) {
34
- const previous = message.id
35
- ? this.messagesMap.get(message.id)
36
- : undefined;
37
- this.messagesMap.set(
38
- message.id ?? uuidv4(),
39
- this.appendMessage(previous, message),
40
- );
34
+ const messageId = message.id!; // ensureMessageId guarantees id exists
35
+ const previous = this.messagesMap.get(messageId);
36
+ this.messagesMap.set(messageId, this.appendMessage(previous, message));
41
37
  }
42
38
  return this.getMessages();
43
39
  }
@@ -672,4 +672,38 @@ describe("useLangGraphMessages", {}, () => {
672
672
  }
673
673
  });
674
674
  });
675
+
676
+ it("ensures consistent message IDs in accumulator", async () => {
677
+ const mockStreamCallback = mockStreamCallbackFactory([metadataEvent]);
678
+
679
+ const { result } = renderHook(() =>
680
+ useLangGraphMessages({
681
+ stream: mockStreamCallback,
682
+ appendMessage: appendLangChainChunk,
683
+ }),
684
+ );
685
+
686
+ // Test that messages without IDs get properly assigned IDs
687
+ act(() => {
688
+ result.current.sendMessage(
689
+ [
690
+ {
691
+ type: "human" as const,
692
+ content: "Test message without ID",
693
+ // Note: no id field provided
694
+ },
695
+ ],
696
+ {},
697
+ );
698
+ });
699
+
700
+ await waitFor(() => {
701
+ expect(result.current.messages).toHaveLength(1);
702
+ const message = result.current.messages[0];
703
+ expect(message.id).toBeDefined();
704
+ expect(message.id).toMatch(
705
+ /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
706
+ ); // UUID v4 format
707
+ });
708
+ });
675
709
  });
@@ -8,10 +8,10 @@ import {
8
8
  OnMetadataEventCallback,
9
9
  } from "./types";
10
10
  import {
11
+ useAssistantState,
12
+ useAssistantApi,
11
13
  useExternalMessageConverter,
12
14
  useExternalStoreRuntime,
13
- useThread,
14
- useThreadListItemRuntime,
15
15
  } from "@assistant-ui/react";
16
16
  import { convertLangChainMessages } from "./convertLangChainMessages";
17
17
  import {
@@ -100,12 +100,16 @@ const asLangGraphRuntimeExtras = (extras: unknown): LangGraphRuntimeExtras => {
100
100
  };
101
101
 
102
102
  export const useLangGraphInterruptState = () => {
103
- const { interrupt } = useThread((t) => asLangGraphRuntimeExtras(t.extras));
103
+ const { interrupt } = useAssistantState(({ thread }) =>
104
+ asLangGraphRuntimeExtras(thread.extras),
105
+ );
104
106
  return interrupt;
105
107
  };
106
108
 
107
109
  export const useLangGraphSend = () => {
108
- const { send } = useThread((t) => asLangGraphRuntimeExtras(t.extras));
110
+ const { send } = useAssistantState(({ thread }) =>
111
+ asLangGraphRuntimeExtras(thread.extras),
112
+ );
109
113
  return send;
110
114
  };
111
115
 
@@ -227,11 +231,11 @@ export const useLangGraphRuntime = ({
227
231
  };
228
232
 
229
233
  const loadingRef = useRef(false);
230
- const threadListItemRuntime = useThreadListItemRuntime({ optional: true });
234
+ const api = useAssistantApi();
231
235
  useEffect(() => {
232
- if (!threadListItemRuntime || !switchToThread || loadingRef.current) return;
236
+ if (!switchToThread || loadingRef.current) return;
233
237
 
234
- const externalId = threadListItemRuntime.getState().externalId;
238
+ const externalId = api.threadListItem().getState().externalId;
235
239
  if (externalId) {
236
240
  loadingRef.current = true;
237
241
  switchToThread(externalId).finally(() => {