@assistant-ui/ai-sdk 0.0.1 → 0.0.3
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.
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/toCreateMessage.d.ts.map +1 -1
- package/dist/converters/toCreateMessage.js +6 -2
- package/dist/converters/toCreateMessage.js.map +1 -1
- package/dist/model-context/injectInteractableContext.d.ts +1 -1
- package/dist/model-context/injectInteractableContext.js +1 -1
- package/dist/model-context/injectInteractableContext.js.map +1 -1
- package/dist/model-context/injectQuoteContext.d.ts +1 -1
- package/dist/model-context/injectQuoteContext.js +1 -1
- package/dist/model-context/injectQuoteContext.js.map +1 -1
- package/dist/runtime/useAISDKRuntime.d.ts +16 -3
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +29 -6
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.d.ts +7 -1
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +9 -3
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +10 -0
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/package.json +11 -11
- package/src/converters/toCreateMessage.ts +6 -5
- package/src/model-context/injectInteractableContext.ts +1 -1
- package/src/model-context/injectQuoteContext.ts +1 -1
- package/src/runtime/useAISDKRuntime.denied-tool.test.tsx +122 -0
- package/src/runtime/useAISDKRuntime.test.ts +191 -7
- package/src/runtime/useAISDKRuntime.ts +110 -51
- package/src/runtime/useChatRuntime.test.ts +16 -0
- package/src/runtime/useChatThread.ts +15 -0
- package/src/runtime/useExternalHistory.test.ts +79 -1
- package/src/runtime/useExternalHistory.ts +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertMessage.d.ts","names":[],"sources":["../../src/converters/convertMessage.ts"],"mappings":";;;;;KAiCY,gCACV,4BAA4B;EAC1B,wBAAwB,YAAY;EACpC,qBAAqB,YAAY;EACjC,sBAAsB,YAAY;;EAElC;;cA+VS;;;;;;;;
|
|
1
|
+
{"version":3,"file":"convertMessage.d.ts","names":[],"sources":["../../src/converters/convertMessage.ts"],"mappings":";;;;;KAiCY,gCACV,4BAA4B;EAC1B,wBAAwB,YAAY;EACpC,qBAAqB,YAAY;EACjC,sBAAsB,YAAY;;EAElC;;cA+VS;;;;;;;;EAtWmB,qBAAA,oCAAA,2CAAA,6CAAA;EAES,oBAAA,oCAAA,2CAAA,6CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCreateMessage.d.ts","names":[],"sources":["../../src/converters/toCreateMessage.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"toCreateMessage.d.ts","names":[],"sources":["../../src/converters/toCreateMessage.ts"],"mappings":";;;cAoBa,kBAAmB,mBAAmB,YAAY,WAC7D,SAAS,kBACR,gBAAgB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveFileMediaType, resolveFilePartSource, resolveImageMediaType, toMediaWireUrl } from "@assistant-ui/core/internal";
|
|
2
2
|
//#region src/converters/toCreateMessage.ts
|
|
3
3
|
const toCreateMessage = (message) => {
|
|
4
4
|
const parts = [...message.content, ...message.attachments?.flatMap((a) => a.content.map((c) => ({
|
|
@@ -32,9 +32,13 @@ const toCreateMessage = (message) => {
|
|
|
32
32
|
case "audio": {
|
|
33
33
|
const mediaType = `audio/${part.audio.format}`;
|
|
34
34
|
const data = part.audio.data;
|
|
35
|
+
const source = resolveFilePartSource({
|
|
36
|
+
data,
|
|
37
|
+
mimeType: mediaType
|
|
38
|
+
});
|
|
35
39
|
return {
|
|
36
40
|
type: "file",
|
|
37
|
-
url:
|
|
41
|
+
url: source.kind === "url" ? source.url : `data:${mediaType};base64,${source.data}`,
|
|
38
42
|
mediaType,
|
|
39
43
|
...part.filename && { filename: part.filename }
|
|
40
44
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCreateMessage.js","names":["AppendMessage","
|
|
1
|
+
{"version":3,"file":"toCreateMessage.js","names":["AppendMessage","resolveFileMediaType","resolveFilePartSource","resolveImageMediaType","toMediaWireUrl","CreateUIMessage","UIDataTypes","UIMessage","UIMessagePart","UITools","InputPart","contentType","filename","toCreateMessage","message","UI_MESSAGE","inputParts","content","attachments","flatMap","a","map","c","name","parts","part","type","text","mediaType","image","url","data","mimeType","sourceType","audio","format","source","kind","Error","role","metadata"],"sources":["../../src/converters/toCreateMessage.ts"],"sourcesContent":["import type { AppendMessage } from \"@assistant-ui/core\";\nimport {\n resolveFileMediaType,\n resolveFilePartSource,\n resolveImageMediaType,\n toMediaWireUrl,\n} from \"@assistant-ui/core/internal\";\nimport type {\n CreateUIMessage,\n UIDataTypes,\n UIMessage,\n UIMessagePart,\n UITools,\n} from \"ai\";\n\ntype InputPart = AppendMessage[\"content\"][number] & {\n readonly contentType?: string | undefined;\n readonly filename?: string | undefined;\n};\n\nexport const toCreateMessage = <UI_MESSAGE extends UIMessage = UIMessage>(\n message: AppendMessage,\n): CreateUIMessage<UI_MESSAGE> => {\n const inputParts: InputPart[] = [\n ...message.content,\n ...(message.attachments?.flatMap((a) =>\n a.content.map((c) => ({\n ...c,\n filename: a.name,\n contentType: a.contentType,\n })),\n ) ?? []),\n ];\n\n const parts = inputParts.map((part): UIMessagePart<UIDataTypes, UITools> => {\n switch (part.type) {\n case \"text\":\n return {\n type: \"text\",\n text: part.text,\n };\n case \"image\": {\n const mediaType = resolveImageMediaType(part.image, part.contentType);\n return {\n type: \"file\",\n url: toMediaWireUrl(part.image, mediaType),\n ...(part.filename && { filename: part.filename }),\n mediaType,\n };\n }\n case \"file\": {\n // `mimeType` is a plain string, and an adapter reading `file.type` on a\n // file the OS cannot type yields \"\". Same ladder as images: declared,\n // then the envelope, then the floor.\n const mediaType = resolveFileMediaType(part.data, part.mimeType);\n return {\n type: \"file\",\n // An `id` reference is an opaque provider handle, not base64, and\n // this adapter has no way to send one. Left unwrapped so it fails\n // loudly upstream rather than shipping a corrupt payload.\n url:\n part.sourceType === \"id\"\n ? part.data\n : toMediaWireUrl(part.data, mediaType),\n mediaType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n case \"audio\": {\n // A data URL's own media type wins over `mediaType` downstream, so the\n // envelope is rebuilt from the typed format rather than forwarded.\n const mediaType = `audio/${part.audio.format}`;\n const data = part.audio.data;\n const source = resolveFilePartSource({ data, mimeType: mediaType });\n return {\n type: \"file\",\n url:\n source.kind === \"url\"\n ? source.url\n : `data:${mediaType};base64,${source.data}`,\n mediaType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n case \"data\":\n return {\n type: `data-${part.name}`,\n data: part.data,\n };\n default:\n throw new Error(`Unsupported part type: ${part.type}`);\n }\n });\n\n return {\n role: message.role,\n parts,\n metadata: message.metadata,\n } satisfies CreateUIMessage<UIMessage> as CreateUIMessage<UI_MESSAGE>;\n};\n"],"mappings":";;AAoBA,MAAaa,mBACXC,YACgC;CAYhC,MAAMU,QAAQR,CAVZ,GAAGF,QAAQG,SACX,GAAIH,QAAQI,aAAaC,SAASC,MAChCA,EAAEH,QAAQI,KAAKC,OAAO;EACpB,GAAGA;EACHV,UAAUQ,EAAEG;EACZZ,aAAaS,EAAET;CACjB,EAAE,CACJ,KAAK,CAAA,CAGOK,CAAU,CAACK,KAAKI,SAA8C;EAC1E,QAAQA,KAAKC,MAAb;GACE,KAAK,QACH,OAAO;IACLA,MAAM;IACNC,MAAMF,KAAKE;GACb;GACF,KAAK,SAAS;IACZ,MAAMC,YAAYzB,sBAAsBsB,KAAKI,OAAOJ,KAAKd,WAAW;IACpE,OAAO;KACLe,MAAM;KACNI,KAAK1B,eAAeqB,KAAKI,OAAOD,SAAS;KACzC,GAAIH,KAAKb,YAAY,EAAEA,UAAUa,KAAKb,SAAS;KAC/CgB;IACF;GACF;GACA,KAAK,QAAQ;IAIX,MAAMA,YAAY3B,qBAAqBwB,KAAKM,MAAMN,KAAKO,QAAQ;IAC/D,OAAO;KACLN,MAAM;KAINI,KACEL,KAAKQ,eAAe,OAChBR,KAAKM,OACL3B,eAAeqB,KAAKM,MAAMH,SAAS;KACzCA;KACA,GAAIH,KAAKb,YAAY,EAAEA,UAAUa,KAAKb,SAAS;IACjD;GACF;GACA,KAAK,SAAS;IAGZ,MAAMgB,YAAY,SAASH,KAAKS,MAAMC;IACtC,MAAMJ,OAAON,KAAKS,MAAMH;IACxB,MAAMK,SAASlC,sBAAsB;KAAE6B;KAAMC,UAAUJ;IAAU,CAAC;IAClE,OAAO;KACLF,MAAM;KACNI,KACEM,OAAOC,SAAS,QACZD,OAAON,MACP,QAAQF,UAAS,UAAWQ,OAAOL;KACzCH;KACA,GAAIH,KAAKb,YAAY,EAAEA,UAAUa,KAAKb,SAAS;IACjD;GACF;GACA,KAAK,QACH,OAAO;IACLc,MAAM,QAAQD,KAAKF;IACnBQ,MAAMN,KAAKM;GACb;GACF,SACE,MAAM,IAAIO,MAAM,0BAA0Bb,KAAKC,MAAM;EACzD;CACF,CAAC;CAED,OAAO;EACLa,MAAMzB,QAAQyB;EACdf;EACAgB,UAAU1B,QAAQ0B;CACpB;AACF"}
|
|
@@ -19,7 +19,7 @@ import { Unstable_InteractableSnapshotEntry } from "@assistant-ui/core";
|
|
|
19
19
|
* @example
|
|
20
20
|
* ```ts
|
|
21
21
|
* import { convertToModelMessages, streamText } from "ai";
|
|
22
|
-
* import { unstable_injectInteractableContext } from "@assistant-ui/
|
|
22
|
+
* import { unstable_injectInteractableContext } from "@assistant-ui/ai-sdk";
|
|
23
23
|
*
|
|
24
24
|
* export async function POST(req: Request) {
|
|
25
25
|
* const { messages } = await req.json();
|
|
@@ -18,7 +18,7 @@ import { unstable_formatInteractableSnapshot, unstable_getInteractableSnapshots
|
|
|
18
18
|
* @example
|
|
19
19
|
* ```ts
|
|
20
20
|
* import { convertToModelMessages, streamText } from "ai";
|
|
21
|
-
* import { unstable_injectInteractableContext } from "@assistant-ui/
|
|
21
|
+
* import { unstable_injectInteractableContext } from "@assistant-ui/ai-sdk";
|
|
22
22
|
*
|
|
23
23
|
* export async function POST(req: Request) {
|
|
24
24
|
* const { messages } = await req.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injectInteractableContext.js","names":["UIMessage","unstable_formatInteractableSnapshot","unstable_getInteractableSnapshots","Unstable_InteractableSnapshotEntry","unstable_injectInteractableContext","messages","format","item","map","msg","role","items","length","text","join","alreadyInjected","parts","type","const"],"sources":["../../src/model-context/injectInteractableContext.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport {\n unstable_formatInteractableSnapshot,\n unstable_getInteractableSnapshots,\n type Unstable_InteractableSnapshotEntry,\n} from \"@assistant-ui/core\";\n\n/**\n * Injects interactable state snapshots into messages as model-visible text.\n *\n * Mirrors {@link injectQuoteContext}: reads the frozen snapshot stamped on a user\n * message's `metadata.custom.interactables` (by the interactables scope at send\n * time) and prepends a text part. Run this in your route handler before\n * `convertToModelMessages`, which otherwise ignores `metadata.custom`.\n *\n * Wording is consumer-owned — pass `format` to control how each snapshot reads.\n * A snapshot may originate from a user edit or an agent `update_*` call, so the\n * default phrasing is neutral. Keep the instance id visible in custom wording:\n * the model needs it to address the `update_*` tool's `id` parameter. A custom\n * `format` must also handle entries with `partial: true`, whose `state` carries\n * only the fields that changed since the model's last known state.\n *\n * @example\n * ```ts\n * import { convertToModelMessages, streamText } from \"ai\";\n * import { unstable_injectInteractableContext } from \"@assistant-ui/
|
|
1
|
+
{"version":3,"file":"injectInteractableContext.js","names":["UIMessage","unstable_formatInteractableSnapshot","unstable_getInteractableSnapshots","Unstable_InteractableSnapshotEntry","unstable_injectInteractableContext","messages","format","item","map","msg","role","items","length","text","join","alreadyInjected","parts","type","const"],"sources":["../../src/model-context/injectInteractableContext.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport {\n unstable_formatInteractableSnapshot,\n unstable_getInteractableSnapshots,\n type Unstable_InteractableSnapshotEntry,\n} from \"@assistant-ui/core\";\n\n/**\n * Injects interactable state snapshots into messages as model-visible text.\n *\n * Mirrors {@link injectQuoteContext}: reads the frozen snapshot stamped on a user\n * message's `metadata.custom.interactables` (by the interactables scope at send\n * time) and prepends a text part. Run this in your route handler before\n * `convertToModelMessages`, which otherwise ignores `metadata.custom`.\n *\n * Wording is consumer-owned — pass `format` to control how each snapshot reads.\n * A snapshot may originate from a user edit or an agent `update_*` call, so the\n * default phrasing is neutral. Keep the instance id visible in custom wording:\n * the model needs it to address the `update_*` tool's `id` parameter. A custom\n * `format` must also handle entries with `partial: true`, whose `state` carries\n * only the fields that changed since the model's last known state.\n *\n * @example\n * ```ts\n * import { convertToModelMessages, streamText } from \"ai\";\n * import { unstable_injectInteractableContext } from \"@assistant-ui/ai-sdk\";\n *\n * export async function POST(req: Request) {\n * const { messages } = await req.json();\n * const result = streamText({\n * model: myModel,\n * messages: await convertToModelMessages(unstable_injectInteractableContext(messages)),\n * });\n * return result.toUIMessageStreamResponse();\n * }\n * ```\n */\nexport function unstable_injectInteractableContext(\n messages: UIMessage[],\n format: (\n item: Unstable_InteractableSnapshotEntry,\n ) => string = unstable_formatInteractableSnapshot,\n): UIMessage[] {\n return messages.map((msg) => {\n if (msg.role !== \"user\") return msg;\n\n const items = unstable_getInteractableSnapshots(msg);\n if (!items?.length) return msg;\n\n const text = `${items.map(format).join(\"\\n\")}\\n\\n`;\n\n const alreadyInjected =\n msg.parts?.[0]?.type === \"text\" && msg.parts[0].text === text;\n if (alreadyInjected) return msg;\n\n return {\n ...msg,\n parts: [{ type: \"text\" as const, text }, ...(msg.parts ?? [])],\n };\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgBI,mCACdC,UACAC,SAEcL,qCACD;CACb,OAAOI,SAASG,KAAKC,QAAQ;EAC3B,IAAIA,IAAIC,SAAS,QAAQ,OAAOD;EAEhC,MAAME,QAAQT,kCAAkCO,GAAG;EACnD,IAAI,CAACE,OAAOC,QAAQ,OAAOH;EAE3B,MAAMI,OAAO,GAAGF,MAAMH,IAAIF,MAAM,CAAC,CAACQ,KAAK,IAAI,EAAC;EAI5C,IADEL,IAAIO,QAAQ,EAAE,EAAEC,SAAS,UAAUR,IAAIO,MAAM,EAAE,CAACH,SAASA,MACtC,OAAOJ;EAE5B,OAAO;GACL,GAAGA;GACHO,OAAO,CAAC;IAAEC,MAAM;IAAiBJ;GAAK,GAAG,GAAIJ,IAAIO,SAAS,CAAA,CAAG;EAC/D;CACF,CAAC;AACH"}
|
|
@@ -9,7 +9,7 @@ import { UIMessage } from "ai";
|
|
|
9
9
|
* @example
|
|
10
10
|
* ```ts
|
|
11
11
|
* import { convertToModelMessages, streamText } from "ai";
|
|
12
|
-
* import { injectQuoteContext } from "@assistant-ui/
|
|
12
|
+
* import { injectQuoteContext } from "@assistant-ui/ai-sdk";
|
|
13
13
|
*
|
|
14
14
|
* export async function POST(req: Request) {
|
|
15
15
|
* const { messages } = await req.json();
|
|
@@ -17,7 +17,7 @@ const getQuoteText = (metadata) => {
|
|
|
17
17
|
* @example
|
|
18
18
|
* ```ts
|
|
19
19
|
* import { convertToModelMessages, streamText } from "ai";
|
|
20
|
-
* import { injectQuoteContext } from "@assistant-ui/
|
|
20
|
+
* import { injectQuoteContext } from "@assistant-ui/ai-sdk";
|
|
21
21
|
*
|
|
22
22
|
* export async function POST(req: Request) {
|
|
23
23
|
* const { messages } = await req.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injectQuoteContext.js","names":["UIMessage","getQuoteText","metadata","undefined","custom","Record","quote","text","injectQuoteContext","messages","map","msg","role","blockquote","split","line","join","alreadyInjected","parts","type","const"],"sources":["../../src/model-context/injectQuoteContext.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\n\nconst getQuoteText = (metadata: unknown): string | undefined => {\n if (!metadata || typeof metadata !== \"object\") return undefined;\n\n const custom = (metadata as Record<string, unknown>).custom;\n if (!custom || typeof custom !== \"object\") return undefined;\n\n const quote = (custom as Record<string, unknown>).quote;\n if (!quote || typeof quote !== \"object\") return undefined;\n\n const text = (quote as Record<string, unknown>).text;\n return typeof text === \"string\" ? text : undefined;\n};\n\n/**\n * Injects quote context into messages as markdown blockquotes.\n *\n * Use this in your route handler before `convertToModelMessages` so the LLM\n * sees the quoted text that the user is referring to.\n *\n * @example\n * ```ts\n * import { convertToModelMessages, streamText } from \"ai\";\n * import { injectQuoteContext } from \"@assistant-ui/
|
|
1
|
+
{"version":3,"file":"injectQuoteContext.js","names":["UIMessage","getQuoteText","metadata","undefined","custom","Record","quote","text","injectQuoteContext","messages","map","msg","role","blockquote","split","line","join","alreadyInjected","parts","type","const"],"sources":["../../src/model-context/injectQuoteContext.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\n\nconst getQuoteText = (metadata: unknown): string | undefined => {\n if (!metadata || typeof metadata !== \"object\") return undefined;\n\n const custom = (metadata as Record<string, unknown>).custom;\n if (!custom || typeof custom !== \"object\") return undefined;\n\n const quote = (custom as Record<string, unknown>).quote;\n if (!quote || typeof quote !== \"object\") return undefined;\n\n const text = (quote as Record<string, unknown>).text;\n return typeof text === \"string\" ? text : undefined;\n};\n\n/**\n * Injects quote context into messages as markdown blockquotes.\n *\n * Use this in your route handler before `convertToModelMessages` so the LLM\n * sees the quoted text that the user is referring to.\n *\n * @example\n * ```ts\n * import { convertToModelMessages, streamText } from \"ai\";\n * import { injectQuoteContext } from \"@assistant-ui/ai-sdk\";\n *\n * export async function POST(req: Request) {\n * const { messages } = await req.json();\n * const result = streamText({\n * model: myModel,\n * messages: await convertToModelMessages(injectQuoteContext(messages)),\n * });\n * return result.toUIMessageStreamResponse();\n * }\n * ```\n */\nexport function injectQuoteContext(messages: UIMessage[]): UIMessage[] {\n return messages.map((msg) => {\n if (msg.role !== \"user\") return msg;\n\n const text = getQuoteText(msg.metadata);\n if (!text) return msg;\n\n const blockquote = text\n .split(/\\r?\\n/)\n .map((line) => `> ${line}`)\n .join(\"\\n\");\n\n const alreadyInjected =\n msg.parts?.[0]?.type === \"text\" &&\n msg.parts[0].text === `${blockquote}\\n\\n`;\n if (alreadyInjected) return msg;\n\n return {\n ...msg,\n parts: [\n { type: \"text\" as const, text: `${blockquote}\\n\\n` },\n ...(msg.parts ?? []),\n ],\n };\n });\n}\n"],"mappings":";AAEA,MAAMC,gBAAgBC,aAA0C;CAC9D,IAAI,CAACA,YAAY,OAAOA,aAAa,UAAU,OAAOC,KAAAA;CAEtD,MAAMC,SAAUF,SAAqCE;CACrD,IAAI,CAACA,UAAU,OAAOA,WAAW,UAAU,OAAOD,KAAAA;CAElD,MAAMG,QAASF,OAAmCE;CAClD,IAAI,CAACA,SAAS,OAAOA,UAAU,UAAU,OAAOH,KAAAA;CAEhD,MAAMI,OAAQD,MAAkCC;CAChD,OAAO,OAAOA,SAAS,WAAWA,OAAOJ,KAAAA;AAC3C;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgBK,mBAAmBC,UAAoC;CACrE,OAAOA,SAASC,KAAKC,QAAQ;EAC3B,IAAIA,IAAIC,SAAS,QAAQ,OAAOD;EAEhC,MAAMJ,OAAON,aAAaU,IAAIT,QAAQ;EACtC,IAAI,CAACK,MAAM,OAAOI;EAElB,MAAME,aAAaN,KAChBO,MAAM,OAAO,CAAC,CACdJ,KAAKK,SAAS,KAAKA,MAAM,CAAC,CAC1BC,KAAK,IAAI;EAKZ,IAFEL,IAAIO,QAAQ,EAAE,EAAEC,SAAS,UACzBR,IAAIO,MAAM,EAAE,CAACX,SAAS,GAAGM,WAAU,OAChB,OAAOF;EAE5B,OAAO;GACL,GAAGA;GACHO,OAAO,CACL;IAAEC,MAAM;IAAiBZ,MAAM,GAAGM,WAAU;GAAO,GACnD,GAAIF,IAAIO,SAAS,CAAA,CAAG;EAExB;CACF,CAAC;AACH"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { JoinStrategy } from "@assistant-ui/core/react";
|
|
2
|
-
import { AppendMessage, AssistantRuntime, ExternalStoreAdapter, ExternalStoreSharedOptions, SuggestionAdapter, ThreadHistoryAdapter } from "@assistant-ui/core";
|
|
2
|
+
import { AppendMessage, AssistantRuntime, ExternalStoreAdapter, ExternalStoreSharedOptions, MessageFormatRepository, SuggestionAdapter, ThreadHistoryAdapter } from "@assistant-ui/core";
|
|
3
3
|
import { CreateUIMessage, UIMessage, useChat } from "@ai-sdk/react";
|
|
4
4
|
//#region src/runtime/useAISDKRuntime.d.ts
|
|
5
5
|
type CustomToCreateMessageFunction = <UI_MESSAGE extends UIMessage = UIMessage>(message: AppendMessage) => CreateUIMessage<UI_MESSAGE>;
|
|
6
|
-
type AISDKRuntimeAdapter = ExternalStoreSharedOptions & {
|
|
6
|
+
type AISDKRuntimeAdapter<UI_MESSAGE extends UIMessage = UIMessage> = ExternalStoreSharedOptions & {
|
|
7
7
|
adapters?: (NonNullable<ExternalStoreAdapter["adapters"]> & {
|
|
8
8
|
history?: ThreadHistoryAdapter | undefined;
|
|
9
9
|
suggestion?: SuggestionAdapter | undefined;
|
|
@@ -42,8 +42,21 @@ type AISDKRuntimeAdapter = ExternalStoreSharedOptions & {
|
|
|
42
42
|
* as separate entries.
|
|
43
43
|
*/
|
|
44
44
|
joinStrategy?: JoinStrategy | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* A branch-aware AI SDK message tree seeded once when `useChat` is empty.
|
|
47
|
+
* After that seed, live updates come only from `useChat`. A later empty
|
|
48
|
+
* chat or a new object identity does not reload the tree.
|
|
49
|
+
*/
|
|
50
|
+
messageRepository?: MessageFormatRepository<UI_MESSAGE>;
|
|
51
|
+
/**
|
|
52
|
+
* Called after an explicit `switchToBranch` (for example a BranchPicker
|
|
53
|
+
* click). Complements `setMessages` and does not enable switching by itself.
|
|
54
|
+
*
|
|
55
|
+
* @deprecated This API is still under active development and might change without notice.
|
|
56
|
+
*/
|
|
57
|
+
unstable_onBranchChange?: ExternalStoreAdapter["unstable_onBranchChange"];
|
|
45
58
|
};
|
|
46
|
-
declare const useAISDKRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>, adapter?: AISDKRuntimeAdapter) => AssistantRuntime;
|
|
59
|
+
declare const useAISDKRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>, adapter?: AISDKRuntimeAdapter<UI_MESSAGE>) => AssistantRuntime;
|
|
47
60
|
//#endregion
|
|
48
61
|
export { AISDKRuntimeAdapter, CustomToCreateMessageFunction, useAISDKRuntime };
|
|
49
62
|
//# sourceMappingURL=useAISDKRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAISDKRuntime.d.ts","names":[],"sources":["../../src/runtime/useAISDKRuntime.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"useAISDKRuntime.d.ts","names":[],"sources":["../../src/runtime/useAISDKRuntime.ts"],"mappings":";;;;KA2DY,iCACV,mBAAmB,YAAY,WAE/B,SAAS,kBACN,gBAAgB;KAYT,oBAAoB,mBAAmB,YAAY,aAC7D;EACE,YACK,YAAY;IACX,UAAU;IACV,aAAa;;EAGnB,kBAAkB;;;;;;;;;EASlB;;;;;;;;EAQA,WAAW;;;;;;;EAOX,mBAAmB;;;;;;;;;EASnB,eAAe;;;;;;EAMf,oBAAoB,wBAAwB;;;;;;;EAO5C,0BAA0B;;cA8EjB,kBAAmB,mBAAmB,YAAY,WAC7D,aAAa,kBAAkB,QAAQ,cACvC,UAAS,oBAAoB,gBAAgB"}
|
|
@@ -13,7 +13,7 @@ import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/
|
|
|
13
13
|
import { useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
14
14
|
import { generateId, isToolUIPart } from "ai";
|
|
15
15
|
import { getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
16
|
-
import { consumeSuggestionResult } from "@assistant-ui/core/internal";
|
|
16
|
+
import { MessageRepository, consumeSuggestionResult } from "@assistant-ui/core/internal";
|
|
17
17
|
//#region src/runtime/useAISDKRuntime.ts
|
|
18
18
|
const toUIMessage = (createMessage, fallbackRole) => ({
|
|
19
19
|
...createMessage,
|
|
@@ -76,7 +76,7 @@ const useGeneratedSuggestions = (suggestionAdapter, messages, isRunning) => {
|
|
|
76
76
|
return suggestions;
|
|
77
77
|
};
|
|
78
78
|
const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
79
|
-
const { adapters, toCreateMessage: customToCreateMessage, cancelPendingToolCallsOnSend = true, onResume, onResumeToolCall, joinStrategy } = adapter;
|
|
79
|
+
const { adapters, toCreateMessage: customToCreateMessage, cancelPendingToolCallsOnSend = true, onResume, onResumeToolCall, joinStrategy, messageRepository, unstable_onBranchChange } = adapter;
|
|
80
80
|
const suggestionAdapter = adapters?.suggestion;
|
|
81
81
|
const contextAdapters = useRuntimeAdapters();
|
|
82
82
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
@@ -85,7 +85,8 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
85
85
|
const mcpAppMetadataCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
86
86
|
const lastRunConfigRef = useRef(void 0);
|
|
87
87
|
const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
|
|
88
|
-
const
|
|
88
|
+
const providerIsRunning = chatHelpers.status === "submitted" || chatHelpers.status === "streaming";
|
|
89
|
+
const isRunning = providerIsRunning || hasExecutingTools;
|
|
89
90
|
const messageTiming = useStreamingTiming$1(chatHelpers.messages, isRunning);
|
|
90
91
|
const lastMessage = chatHelpers.messages.at(-1);
|
|
91
92
|
const optimisticMessageId = isRunning && lastMessage?.role === "assistant" ? lastMessage.id : void 0;
|
|
@@ -108,6 +109,11 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
108
109
|
chatHelpers.error
|
|
109
110
|
])
|
|
110
111
|
});
|
|
112
|
+
const exportedMessageRepository = useMemo(() => {
|
|
113
|
+
if (!messageRepository) return void 0;
|
|
114
|
+
const converted = toExportedMessageRepository(AISDKMessageConverter.toThreadMessages, messageRepository);
|
|
115
|
+
return converted.messages.length > 0 ? converted : void 0;
|
|
116
|
+
}, [messageRepository]);
|
|
111
117
|
const generatedSuggestions = useGeneratedSuggestions(suggestionAdapter, messages, isRunning);
|
|
112
118
|
const [runtimeRef] = useState(() => ({ get current() {
|
|
113
119
|
return runtime;
|
|
@@ -133,7 +139,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
133
139
|
let hasChanges = false;
|
|
134
140
|
const parts = lastMessage_0.parts?.map((part) => {
|
|
135
141
|
if (!isToolUIPart(part)) return part;
|
|
136
|
-
if (part.state === "output-available" || part.state === "output-error") return part;
|
|
142
|
+
if (part.state === "output-available" || part.state === "output-error" || part.state === "output-denied") return part;
|
|
137
143
|
hasChanges = true;
|
|
138
144
|
const { approval: _approval, ...rest } = part;
|
|
139
145
|
return {
|
|
@@ -149,9 +155,11 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
149
155
|
}];
|
|
150
156
|
});
|
|
151
157
|
};
|
|
158
|
+
const hasSeededRepositoryRef = useRef(false);
|
|
159
|
+
const shouldFeedRepository = exportedMessageRepository != null && !hasSeededRepositoryRef.current && messages.length === 0;
|
|
152
160
|
const runtime = useExternalStoreRuntime({
|
|
153
|
-
isRunning,
|
|
154
|
-
messages,
|
|
161
|
+
isRunning: providerIsRunning,
|
|
162
|
+
...shouldFeedRepository ? { messageRepository: exportedMessageRepository } : { messages },
|
|
155
163
|
unstable_enableToolInvocations: true,
|
|
156
164
|
setToolStatuses,
|
|
157
165
|
setMessages: (messages_2) => chatHelpers.setMessages(messages_2.map(getVercelAIMessages).filter(Boolean).flat()),
|
|
@@ -250,6 +258,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
250
258
|
...suggestionAdapter ? { suggestions: generatedSuggestions } : {},
|
|
251
259
|
...onResume && { onResume },
|
|
252
260
|
...onResumeToolCall && { onResumeToolCall },
|
|
261
|
+
...unstable_onBranchChange && { unstable_onBranchChange },
|
|
253
262
|
adapters: {
|
|
254
263
|
attachments: vercelAttachmentAdapter,
|
|
255
264
|
...contextAdapters,
|
|
@@ -258,6 +267,20 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
258
267
|
extras,
|
|
259
268
|
isLoading
|
|
260
269
|
});
|
|
270
|
+
const setMessagesRef = useRef(chatHelpers.setMessages);
|
|
271
|
+
setMessagesRef.current = chatHelpers.setMessages;
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
if (hasSeededRepositoryRef.current) return;
|
|
274
|
+
if (!exportedMessageRepository) return;
|
|
275
|
+
if (chatHelpers.messages.length > 0) {
|
|
276
|
+
hasSeededRepositoryRef.current = true;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const tempRepo = new MessageRepository();
|
|
280
|
+
tempRepo.import(exportedMessageRepository);
|
|
281
|
+
setMessagesRef.current(tempRepo.getMessages().flatMap(getExternalStoreMessages));
|
|
282
|
+
hasSeededRepositoryRef.current = true;
|
|
283
|
+
}, [exportedMessageRepository, chatHelpers.messages.length]);
|
|
261
284
|
return runtime;
|
|
262
285
|
};
|
|
263
286
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAISDKRuntime.js","names":["useEffect","useMemo","useRef","useState","UIMessage","useChat","CreateUIMessage","UseChatHelpers","isToolUIPart","generateId","useExternalStoreRuntime","useRuntimeAdapters","JoinStrategy","SuggestionAdapter","ThreadSuggestion","ToolExecutionStatus","ExternalStoreAdapter","ExternalStoreSharedOptions","ThreadHistoryAdapter","AssistantRuntime","ThreadMessage","MessageFormatAdapter","MessageFormatItem","MessageFormatRepository","AppendMessage","RunConfig","McpAppMetadata","getExternalStoreMessages","pickExternalStoreSharedOptions","consumeSuggestionResult","ReadonlyJSONObject","sliceMessagesUntil","toCreateMessage","vercelAttachmentAdapter","getVercelAIMessages","AISDKMessageConverter","wrapModelContentEnvelope","AISDKStorageFormat","aiSDKV6FormatAdapter","useExternalHistory","toExportedMessageRepository","useStreamingTiming","aiSDKExtras","CustomToCreateMessageFunction","message","UI_MESSAGE","toUIMessage","createMessage","fallbackRole","id","role","AISDKRuntimeAdapter","adapters","NonNullable","history","suggestion","cancelPendingToolCallsOnSend","onResume","onResumeToolCall","joinStrategy","EMPTY_SUGGESTIONS","useGeneratedSuggestions","suggestionAdapter","messages","isRunning","suggestions","setSuggestions","controllerRef","AbortController","wasRunningRef","messagesRef","current","adapterRef","hasAdapter","clearSuggestions","abort","prev","length","adapter","currentMessages","last","at","status","type","controller","signal","promiseOrGenerator","generate","onUpdate","useAISDKRuntime","chatHelpers","ReturnType","customToCreateMessage","contextAdapters","toolStatuses","setToolStatuses","Record","toolArgsKeyOrderCacheRef","Map","toolLastInputCacheRef","mcpAppMetadataCacheRef","lastRunConfigRef","undefined","hasExecutingTools","Object","values","some","s","messageTiming","lastMessage","optimisticMessageId","useThreadMessages","metadata","toolArgsKeyOrderCache","toolLastInputCache","mcpAppMetadataCache","error","generatedSuggestions","runtimeRef","runtime","isLoading","deleteMessage","deleteHistoryMessage","toThreadMessages","setMessages","chatId","chatMessages","chatStatus","extras","provide","chat","completePendingToolCalls","hasChanges","parts","map","part","state","approval","_approval","rest","const","errorText","slice","unstable_enableToolInvocations","filter","Boolean","flat","onImport","onExportExternalState","exported","thread","export","expandedMessages","lastInnerIdMap","item","innerMessages","parentId","get","innerMessage","push","getId","set","result","headId","onLoadExternalState","repo","exportedRepo","import","onCancel","stop","Error","name","onNew","startRun","runConfig","sendMessage","onEdit","onDelete","messageId","threadMessages","getState","messageIndex","findIndex","deleteIds","Set","has","onReload","config","newMessages","regenerate","onAddToolResult","toolCallId","toolName","isError","modelContent","options","Promise","resolve","addToolOutput","tool","JSON","stringify","output","onRespondToToolApproval","approvalId","approved","reason","addToolApprovalResponse","attachments"],"sources":["../../src/runtime/useAISDKRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type {\n UIMessage,\n useChat,\n CreateUIMessage,\n UseChatHelpers,\n} from \"@ai-sdk/react\";\nimport { isToolUIPart, generateId } from \"ai\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n type JoinStrategy,\n} from \"@assistant-ui/core/react\";\nimport type {\n SuggestionAdapter,\n ThreadSuggestion,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport type {\n ExternalStoreAdapter,\n ExternalStoreSharedOptions,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatItem,\n MessageFormatRepository,\n AppendMessage,\n RunConfig,\n McpAppMetadata,\n} from \"@assistant-ui/core\";\nimport {\n getExternalStoreMessages,\n pickExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport { consumeSuggestionResult } from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../converters/toCreateMessage\";\nimport { vercelAttachmentAdapter } from \"../adapters/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../utils/getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../converters/convertMessage\";\nimport { wrapModelContentEnvelope } from \"../converters/modelContentEnvelope\";\nimport {\n type AISDKStorageFormat,\n aiSDKV6FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport {\n useExternalHistory,\n toExportedMessageRepository,\n} from \"./useExternalHistory\";\nimport { useStreamingTiming } from \"./useStreamingTiming\";\nimport { aiSDKExtras } from \"../aiSDKExtras\";\n\nexport type CustomToCreateMessageFunction = <\n UI_MESSAGE extends UIMessage = UIMessage,\n>(\n message: AppendMessage,\n) => CreateUIMessage<UI_MESSAGE>;\n\nconst toUIMessage = <UI_MESSAGE extends UIMessage>(\n createMessage: CreateUIMessage<UI_MESSAGE>,\n fallbackRole: UI_MESSAGE[\"role\"],\n): UI_MESSAGE =>\n ({\n ...createMessage,\n id: createMessage.id ?? generateId(),\n role: createMessage.role ?? fallbackRole,\n }) as UI_MESSAGE;\n\nexport type AISDKRuntimeAdapter = ExternalStoreSharedOptions & {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n suggestion?: SuggestionAdapter | undefined;\n })\n | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n /**\n * Whether to automatically cancel pending interactive tool calls when the user sends a new message.\n *\n * When enabled (default), the pending tool calls will be marked as failed with an error message\n * indicating the user cancelled the tool call by sending a new message.\n *\n * @default true\n */\n cancelPendingToolCallsOnSend?: boolean | undefined;\n /**\n * Called when `runtime.thread.resumeRun(config)` is invoked.\n *\n * When omitted, `resumeRun` throws `\"Runtime does not support resuming runs.\"`.\n * Provide this to bridge resume invocations into a custom replay channel\n * (for example, an SSE reconnect endpoint keyed by turn id).\n */\n onResume?: ExternalStoreAdapter[\"onResume\"];\n /**\n * Called when `runtime.thread.resumeToolCall(options)` is invoked for a tool call the in-process tracker does not own.\n *\n * When omitted, `resumeToolCall` throws `\"Tool call ${toolCallId} is not waiting for resume.\"`.\n * Provide this to bridge resume-tool-call invocations into a custom handler.\n */\n onResumeToolCall?: ExternalStoreAdapter[\"onResumeToolCall\"];\n /**\n * How consecutive assistant messages are rendered.\n *\n * `\"concat-content\"` (the default) merges them into a single thread message.\n * `\"none\"` keeps each assistant message as its own thread message, which is\n * useful when a backend persists proactive or consecutive assistant messages\n * as separate entries.\n */\n joinStrategy?: JoinStrategy | undefined;\n};\n\nconst EMPTY_SUGGESTIONS: readonly ThreadSuggestion[] = [];\n\nconst useGeneratedSuggestions = (\n suggestionAdapter: SuggestionAdapter | undefined,\n messages: readonly ThreadMessage[],\n isRunning: boolean,\n): readonly ThreadSuggestion[] => {\n const [suggestions, setSuggestions] =\n useState<readonly ThreadSuggestion[]>(EMPTY_SUGGESTIONS);\n const controllerRef = useRef<AbortController | null>(null);\n const wasRunningRef = useRef(false);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const adapterRef = useRef(suggestionAdapter);\n adapterRef.current = suggestionAdapter;\n const hasAdapter = suggestionAdapter != null;\n\n useEffect(() => {\n const clearSuggestions = () => {\n controllerRef.current?.abort();\n controllerRef.current = null;\n setSuggestions((prev) => (prev.length === 0 ? prev : EMPTY_SUGGESTIONS));\n };\n\n const adapter = adapterRef.current;\n if (!adapter) {\n clearSuggestions();\n wasRunningRef.current = isRunning;\n return;\n }\n\n if (isRunning) {\n if (!wasRunningRef.current) {\n clearSuggestions();\n }\n wasRunningRef.current = true;\n return;\n }\n\n if (!wasRunningRef.current) return;\n wasRunningRef.current = false;\n\n const currentMessages = messagesRef.current;\n const last = currentMessages.at(-1);\n if (last?.role !== \"assistant\") return;\n if (last.status?.type === \"requires-action\") return;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const { signal } = controller;\n\n void (async () => {\n try {\n const promiseOrGenerator = adapter.generate({\n messages: currentMessages,\n signal,\n });\n\n await consumeSuggestionResult(promiseOrGenerator, {\n signal,\n onUpdate: setSuggestions,\n });\n } catch {}\n })();\n }, [hasAdapter, isRunning]);\n\n useEffect(() => {\n return () => {\n controllerRef.current?.abort();\n };\n }, []);\n\n return suggestions;\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n adapter: AISDKRuntimeAdapter = {},\n) => {\n const {\n adapters,\n toCreateMessage: customToCreateMessage,\n cancelPendingToolCallsOnSend = true,\n onResume,\n onResumeToolCall,\n joinStrategy,\n } = adapter;\n const suggestionAdapter = adapters?.suggestion;\n const contextAdapters = useRuntimeAdapters();\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const toolArgsKeyOrderCacheRef = useRef<Map<string, Map<string, string[]>>>(\n new Map(),\n );\n const toolLastInputCacheRef = useRef<Map<string, ReadonlyJSONObject>>(\n new Map(),\n );\n const mcpAppMetadataCacheRef = useRef<Map<string, McpAppMetadata>>(new Map());\n const lastRunConfigRef = useRef<RunConfig | undefined>(undefined);\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const isRunning =\n chatHelpers.status === \"submitted\" ||\n chatHelpers.status === \"streaming\" ||\n hasExecutingTools;\n\n const messageTiming = useStreamingTiming(chatHelpers.messages, isRunning);\n\n // Flag the streaming message optimistic: its id can be swapped for a server\n // id mid-run, and the repository then drops the orphaned pre-swap id (#4037).\n const lastMessage = chatHelpers.messages.at(-1);\n const optimisticMessageId =\n isRunning && lastMessage?.role === \"assistant\" ? lastMessage.id : undefined;\n\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning,\n messages: chatHelpers.messages,\n joinStrategy,\n metadata: useMemo(\n () => ({\n toolStatuses,\n messageTiming,\n toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,\n toolLastInputCache: toolLastInputCacheRef.current,\n mcpAppMetadataCache: mcpAppMetadataCacheRef.current,\n ...(optimisticMessageId && { optimisticMessageId }),\n ...(chatHelpers.error && { error: chatHelpers.error.message }),\n }),\n [toolStatuses, messageTiming, optimisticMessageId, chatHelpers.error],\n ),\n });\n\n const generatedSuggestions = useGeneratedSuggestions(\n suggestionAdapter,\n messages,\n isRunning,\n );\n\n const [runtimeRef] = useState(() => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }));\n\n const { isLoading, deleteMessage: deleteHistoryMessage } = useExternalHistory(\n runtimeRef,\n adapters?.history ?? contextAdapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV6FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const {\n id: chatId,\n messages: chatMessages,\n status: chatStatus,\n error,\n } = chatHelpers;\n const extras = useMemo(\n () =>\n aiSDKExtras.provide({\n chat: chatHelpers as unknown as UseChatHelpers<UIMessage>,\n error,\n }),\n // oxlint-disable-next-line react/exhaustive-deps -- keyed on the chat's identity and reactive snapshots; useChat re-mints the helpers object every render while its remaining fields are instance-bound methods, and a render-stable extras identity is what lets the external-store core dedupe adapter updates\n [chatId, chatMessages, chatStatus, error],\n );\n\n const completePendingToolCalls = async () => {\n if (!cancelPendingToolCallsOnSend) return;\n\n // The runtime auto-aborts in-flight tool invocations when a new run\n // is dispatched (append() / startRun()). All we need to do here is\n // mark any tool without a result as cancelled in the UI message list.\n\n // Mark any tool without a result as cancelled (uses setMessages to avoid triggering sendAutomaticallyWhen)\n chatHelpers.setMessages((messages) => {\n const lastMessage = messages.at(-1);\n if (lastMessage?.role !== \"assistant\") return messages;\n\n let hasChanges = false;\n const parts = lastMessage.parts?.map((part) => {\n if (!isToolUIPart(part)) return part;\n if (part.state === \"output-available\" || part.state === \"output-error\")\n return part;\n\n hasChanges = true;\n const { approval: _approval, ...rest } = part;\n return {\n ...rest,\n state: \"output-error\" as const,\n errorText: \"User cancelled tool call by sending a new message.\",\n };\n });\n\n if (!hasChanges) return messages;\n return [...messages.slice(0, -1), { ...lastMessage, parts }];\n });\n };\n\n const runtime = useExternalStoreRuntime({\n isRunning,\n messages,\n unstable_enableToolInvocations: true,\n setToolStatuses,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onImport: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onExportExternalState: (): MessageFormatRepository<UI_MESSAGE> => {\n const exported = runtimeRef.current.thread.export();\n\n const expandedMessages: MessageFormatItem<UI_MESSAGE>[] = [];\n const lastInnerIdMap = new Map<string, string>();\n\n for (const item of exported.messages) {\n const innerMessages = getExternalStoreMessages<UI_MESSAGE>(\n item.message,\n );\n let parentId =\n item.parentId != null\n ? (lastInnerIdMap.get(item.parentId) ?? item.parentId)\n : null;\n for (const innerMessage of innerMessages) {\n expandedMessages.push({ parentId, message: innerMessage });\n parentId = aiSDKV6FormatAdapter.getId(innerMessage as UIMessage);\n }\n if (innerMessages.length > 0) {\n lastInnerIdMap.set(\n item.message.id,\n aiSDKV6FormatAdapter.getId(\n innerMessages[innerMessages.length - 1]! as UIMessage,\n ),\n );\n }\n }\n\n const result: MessageFormatRepository<UI_MESSAGE> = {\n messages: expandedMessages,\n };\n\n if (exported.headId != null) {\n result.headId = lastInnerIdMap.get(exported.headId) ?? exported.headId;\n }\n\n return result;\n },\n onLoadExternalState: (repo: MessageFormatRepository<UI_MESSAGE>) => {\n // Convert MessageFormatRepository to ExportedMessageRepository\n const exportedRepo = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages,\n repo,\n );\n\n // Import into the thread's MessageRepository\n runtimeRef.current.thread.import(exportedRepo);\n },\n onCancel: async () => {\n try {\n await chatHelpers.stop();\n } catch (error) {\n if (!(error instanceof Error && error.name === \"AbortError\")) {\n throw error;\n }\n }\n },\n onNew: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...current,\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n await completePendingToolCalls();\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...sliceMessagesUntil(current, message.parentId),\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n chatHelpers.setMessages((current) =>\n sliceMessagesUntil(current, message.parentId),\n );\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onDelete: async (messageId) => {\n const threadMessages = runtimeRef.current.thread.getState().messages;\n const messageIndex = threadMessages.findIndex(\n (message) => message.id === messageId,\n );\n if (messageIndex === -1) return;\n\n await deleteHistoryMessage(messageId);\n\n const deleteIds = new Set(\n getExternalStoreMessages<UI_MESSAGE>(threadMessages[messageIndex]!).map(\n (message) => message.id,\n ),\n );\n chatHelpers.setMessages((current) =>\n current.filter((message) => !deleteIds.has(message.id)),\n );\n },\n onReload: async (parentId: string | null, config) => {\n lastRunConfigRef.current = config.runConfig;\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({\n toolCallId,\n toolName,\n result,\n isError,\n modelContent,\n }) => {\n const options = { metadata: lastRunConfigRef.current };\n if (isError) {\n return Promise.resolve(\n chatHelpers.addToolOutput({\n state: \"output-error\",\n tool: toolName ?? toolCallId,\n toolCallId,\n errorText:\n typeof result === \"string\" ? result : JSON.stringify(result),\n options,\n }),\n );\n } else {\n const output =\n modelContent !== undefined\n ? wrapModelContentEnvelope(result, modelContent)\n : result;\n return Promise.resolve(\n chatHelpers.addToolOutput({\n tool: toolName,\n toolCallId,\n output,\n options,\n }),\n );\n }\n },\n onRespondToToolApproval: ({ approvalId, approved, reason }) =>\n Promise.resolve(\n chatHelpers.addToolApprovalResponse({\n id: approvalId,\n approved,\n ...(reason != null && { reason }),\n options: { metadata: lastRunConfigRef.current },\n }),\n ),\n ...pickExternalStoreSharedOptions(adapter),\n ...(suggestionAdapter ? { suggestions: generatedSuggestions } : {}),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapters,\n },\n extras,\n isLoading,\n });\n\n return runtime;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAISDKRuntime.js","names":["useEffect","useMemo","useRef","useState","UIMessage","useChat","CreateUIMessage","UseChatHelpers","isToolUIPart","generateId","useExternalStoreRuntime","useRuntimeAdapters","JoinStrategy","SuggestionAdapter","ThreadSuggestion","ToolExecutionStatus","ExternalStoreAdapter","ExternalStoreSharedOptions","ThreadHistoryAdapter","AssistantRuntime","ThreadMessage","MessageFormatAdapter","MessageFormatItem","MessageFormatRepository","AppendMessage","RunConfig","McpAppMetadata","getExternalStoreMessages","pickExternalStoreSharedOptions","consumeSuggestionResult","MessageRepository","ReadonlyJSONObject","sliceMessagesUntil","toCreateMessage","vercelAttachmentAdapter","getVercelAIMessages","AISDKMessageConverter","wrapModelContentEnvelope","AISDKStorageFormat","aiSDKV6FormatAdapter","useExternalHistory","toExportedMessageRepository","useStreamingTiming","aiSDKExtras","CustomToCreateMessageFunction","message","UI_MESSAGE","toUIMessage","createMessage","fallbackRole","id","role","AISDKRuntimeAdapter","adapters","NonNullable","history","suggestion","cancelPendingToolCallsOnSend","onResume","onResumeToolCall","joinStrategy","messageRepository","unstable_onBranchChange","EMPTY_SUGGESTIONS","useGeneratedSuggestions","suggestionAdapter","messages","isRunning","suggestions","setSuggestions","controllerRef","AbortController","wasRunningRef","messagesRef","current","adapterRef","hasAdapter","clearSuggestions","abort","prev","length","adapter","currentMessages","last","at","status","type","controller","signal","promiseOrGenerator","generate","onUpdate","useAISDKRuntime","chatHelpers","ReturnType","customToCreateMessage","contextAdapters","toolStatuses","setToolStatuses","Record","toolArgsKeyOrderCacheRef","Map","toolLastInputCacheRef","mcpAppMetadataCacheRef","lastRunConfigRef","undefined","hasExecutingTools","Object","values","some","s","providerIsRunning","messageTiming","lastMessage","optimisticMessageId","useThreadMessages","metadata","toolArgsKeyOrderCache","toolLastInputCache","mcpAppMetadataCache","error","exportedMessageRepository","converted","toThreadMessages","generatedSuggestions","runtimeRef","runtime","isLoading","deleteMessage","deleteHistoryMessage","setMessages","chatId","chatMessages","chatStatus","extras","provide","chat","completePendingToolCalls","hasChanges","parts","map","part","state","approval","_approval","rest","const","errorText","slice","hasSeededRepositoryRef","shouldFeedRepository","unstable_enableToolInvocations","filter","Boolean","flat","onImport","onExportExternalState","exported","thread","export","expandedMessages","lastInnerIdMap","item","innerMessages","parentId","get","innerMessage","push","getId","set","result","headId","onLoadExternalState","repo","exportedRepo","import","onCancel","stop","Error","name","onNew","startRun","runConfig","sendMessage","onEdit","onDelete","messageId","threadMessages","getState","messageIndex","findIndex","deleteIds","Set","has","onReload","config","newMessages","regenerate","onAddToolResult","toolCallId","toolName","isError","modelContent","options","Promise","resolve","addToolOutput","tool","JSON","stringify","output","onRespondToToolApproval","approvalId","approved","reason","addToolApprovalResponse","attachments","setMessagesRef","tempRepo","getMessages","flatMap"],"sources":["../../src/runtime/useAISDKRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type {\n UIMessage,\n useChat,\n CreateUIMessage,\n UseChatHelpers,\n} from \"@ai-sdk/react\";\nimport { isToolUIPart, generateId } from \"ai\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n type JoinStrategy,\n} from \"@assistant-ui/core/react\";\nimport type {\n SuggestionAdapter,\n ThreadSuggestion,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport type {\n ExternalStoreAdapter,\n ExternalStoreSharedOptions,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatItem,\n MessageFormatRepository,\n AppendMessage,\n RunConfig,\n McpAppMetadata,\n} from \"@assistant-ui/core\";\nimport {\n getExternalStoreMessages,\n pickExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n consumeSuggestionResult,\n MessageRepository,\n} from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../converters/toCreateMessage\";\nimport { vercelAttachmentAdapter } from \"../adapters/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../utils/getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../converters/convertMessage\";\nimport { wrapModelContentEnvelope } from \"../converters/modelContentEnvelope\";\nimport {\n type AISDKStorageFormat,\n aiSDKV6FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport {\n useExternalHistory,\n toExportedMessageRepository,\n} from \"./useExternalHistory\";\nimport { useStreamingTiming } from \"./useStreamingTiming\";\nimport { aiSDKExtras } from \"../aiSDKExtras\";\n\nexport type CustomToCreateMessageFunction = <\n UI_MESSAGE extends UIMessage = UIMessage,\n>(\n message: AppendMessage,\n) => CreateUIMessage<UI_MESSAGE>;\n\nconst toUIMessage = <UI_MESSAGE extends UIMessage>(\n createMessage: CreateUIMessage<UI_MESSAGE>,\n fallbackRole: UI_MESSAGE[\"role\"],\n): UI_MESSAGE =>\n ({\n ...createMessage,\n id: createMessage.id ?? generateId(),\n role: createMessage.role ?? fallbackRole,\n }) as UI_MESSAGE;\n\nexport type AISDKRuntimeAdapter<UI_MESSAGE extends UIMessage = UIMessage> =\n ExternalStoreSharedOptions & {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n suggestion?: SuggestionAdapter | undefined;\n })\n | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n /**\n * Whether to automatically cancel pending interactive tool calls when the user sends a new message.\n *\n * When enabled (default), the pending tool calls will be marked as failed with an error message\n * indicating the user cancelled the tool call by sending a new message.\n *\n * @default true\n */\n cancelPendingToolCallsOnSend?: boolean | undefined;\n /**\n * Called when `runtime.thread.resumeRun(config)` is invoked.\n *\n * When omitted, `resumeRun` throws `\"Runtime does not support resuming runs.\"`.\n * Provide this to bridge resume invocations into a custom replay channel\n * (for example, an SSE reconnect endpoint keyed by turn id).\n */\n onResume?: ExternalStoreAdapter[\"onResume\"];\n /**\n * Called when `runtime.thread.resumeToolCall(options)` is invoked for a tool call the in-process tracker does not own.\n *\n * When omitted, `resumeToolCall` throws `\"Tool call ${toolCallId} is not waiting for resume.\"`.\n * Provide this to bridge resume-tool-call invocations into a custom handler.\n */\n onResumeToolCall?: ExternalStoreAdapter[\"onResumeToolCall\"];\n /**\n * How consecutive assistant messages are rendered.\n *\n * `\"concat-content\"` (the default) merges them into a single thread message.\n * `\"none\"` keeps each assistant message as its own thread message, which is\n * useful when a backend persists proactive or consecutive assistant messages\n * as separate entries.\n */\n joinStrategy?: JoinStrategy | undefined;\n /**\n * A branch-aware AI SDK message tree seeded once when `useChat` is empty.\n * After that seed, live updates come only from `useChat`. A later empty\n * chat or a new object identity does not reload the tree.\n */\n messageRepository?: MessageFormatRepository<UI_MESSAGE>;\n /**\n * Called after an explicit `switchToBranch` (for example a BranchPicker\n * click). Complements `setMessages` and does not enable switching by itself.\n *\n * @deprecated This API is still under active development and might change without notice.\n */\n unstable_onBranchChange?: ExternalStoreAdapter[\"unstable_onBranchChange\"];\n };\n\nconst EMPTY_SUGGESTIONS: readonly ThreadSuggestion[] = [];\n\nconst useGeneratedSuggestions = (\n suggestionAdapter: SuggestionAdapter | undefined,\n messages: readonly ThreadMessage[],\n isRunning: boolean,\n): readonly ThreadSuggestion[] => {\n const [suggestions, setSuggestions] =\n useState<readonly ThreadSuggestion[]>(EMPTY_SUGGESTIONS);\n const controllerRef = useRef<AbortController | null>(null);\n const wasRunningRef = useRef(false);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const adapterRef = useRef(suggestionAdapter);\n adapterRef.current = suggestionAdapter;\n const hasAdapter = suggestionAdapter != null;\n\n useEffect(() => {\n const clearSuggestions = () => {\n controllerRef.current?.abort();\n controllerRef.current = null;\n setSuggestions((prev) => (prev.length === 0 ? prev : EMPTY_SUGGESTIONS));\n };\n\n const adapter = adapterRef.current;\n if (!adapter) {\n clearSuggestions();\n wasRunningRef.current = isRunning;\n return;\n }\n\n if (isRunning) {\n if (!wasRunningRef.current) {\n clearSuggestions();\n }\n wasRunningRef.current = true;\n return;\n }\n\n if (!wasRunningRef.current) return;\n wasRunningRef.current = false;\n\n const currentMessages = messagesRef.current;\n const last = currentMessages.at(-1);\n if (last?.role !== \"assistant\") return;\n if (last.status?.type === \"requires-action\") return;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const { signal } = controller;\n\n void (async () => {\n try {\n const promiseOrGenerator = adapter.generate({\n messages: currentMessages,\n signal,\n });\n\n await consumeSuggestionResult(promiseOrGenerator, {\n signal,\n onUpdate: setSuggestions,\n });\n } catch {}\n })();\n }, [hasAdapter, isRunning]);\n\n useEffect(() => {\n return () => {\n controllerRef.current?.abort();\n };\n }, []);\n\n return suggestions;\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n adapter: AISDKRuntimeAdapter<UI_MESSAGE> = {},\n) => {\n const {\n adapters,\n toCreateMessage: customToCreateMessage,\n cancelPendingToolCallsOnSend = true,\n onResume,\n onResumeToolCall,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n } = adapter;\n const suggestionAdapter = adapters?.suggestion;\n const contextAdapters = useRuntimeAdapters();\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const toolArgsKeyOrderCacheRef = useRef<Map<string, Map<string, string[]>>>(\n new Map(),\n );\n const toolLastInputCacheRef = useRef<Map<string, ReadonlyJSONObject>>(\n new Map(),\n );\n const mcpAppMetadataCacheRef = useRef<Map<string, McpAppMetadata>>(new Map());\n const lastRunConfigRef = useRef<RunConfig | undefined>(undefined);\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const providerIsRunning =\n chatHelpers.status === \"submitted\" || chatHelpers.status === \"streaming\";\n const isRunning = providerIsRunning || hasExecutingTools;\n\n const messageTiming = useStreamingTiming(chatHelpers.messages, isRunning);\n\n // Flag the streaming message optimistic: its id can be swapped for a server\n // id mid-run, and the repository then drops the orphaned pre-swap id (#4037).\n const lastMessage = chatHelpers.messages.at(-1);\n const optimisticMessageId =\n isRunning && lastMessage?.role === \"assistant\" ? lastMessage.id : undefined;\n\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning,\n messages: chatHelpers.messages,\n joinStrategy,\n metadata: useMemo(\n () => ({\n toolStatuses,\n messageTiming,\n toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,\n toolLastInputCache: toolLastInputCacheRef.current,\n mcpAppMetadataCache: mcpAppMetadataCacheRef.current,\n ...(optimisticMessageId && { optimisticMessageId }),\n ...(chatHelpers.error && { error: chatHelpers.error.message }),\n }),\n [toolStatuses, messageTiming, optimisticMessageId, chatHelpers.error],\n ),\n });\n\n const exportedMessageRepository = useMemo(() => {\n if (!messageRepository) return undefined;\n const converted = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n messageRepository,\n );\n return converted.messages.length > 0 ? converted : undefined;\n }, [messageRepository]);\n\n const generatedSuggestions = useGeneratedSuggestions(\n suggestionAdapter,\n messages,\n isRunning,\n );\n\n const [runtimeRef] = useState(() => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }));\n\n const { isLoading, deleteMessage: deleteHistoryMessage } = useExternalHistory(\n runtimeRef,\n adapters?.history ?? contextAdapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV6FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const {\n id: chatId,\n messages: chatMessages,\n status: chatStatus,\n error,\n } = chatHelpers;\n const extras = useMemo(\n () =>\n aiSDKExtras.provide({\n chat: chatHelpers as unknown as UseChatHelpers<UIMessage>,\n error,\n }),\n // oxlint-disable-next-line react/exhaustive-deps -- keyed on the chat's identity and reactive snapshots; useChat re-mints the helpers object every render while its remaining fields are instance-bound methods, and a render-stable extras identity is what lets the external-store core dedupe adapter updates\n [chatId, chatMessages, chatStatus, error],\n );\n\n const completePendingToolCalls = async () => {\n if (!cancelPendingToolCallsOnSend) return;\n\n // The runtime auto-aborts in-flight tool invocations when a new run\n // is dispatched (append() / startRun()). All we need to do here is\n // mark any tool without a result as cancelled in the UI message list.\n\n // Mark any tool without a result as cancelled (uses setMessages to avoid triggering sendAutomaticallyWhen)\n chatHelpers.setMessages((messages) => {\n const lastMessage = messages.at(-1);\n if (lastMessage?.role !== \"assistant\") return messages;\n\n let hasChanges = false;\n const parts = lastMessage.parts?.map((part) => {\n if (!isToolUIPart(part)) return part;\n if (\n part.state === \"output-available\" ||\n part.state === \"output-error\" ||\n part.state === \"output-denied\"\n )\n return part;\n\n hasChanges = true;\n const { approval: _approval, ...rest } = part;\n return {\n ...rest,\n state: \"output-error\" as const,\n errorText: \"User cancelled tool call by sending a new message.\",\n };\n });\n\n if (!hasChanges) return messages;\n return [...messages.slice(0, -1), { ...lastMessage, parts }];\n });\n };\n\n const hasSeededRepositoryRef = useRef(false);\n const shouldFeedRepository =\n exportedMessageRepository != null &&\n !hasSeededRepositoryRef.current &&\n messages.length === 0;\n\n const runtime = useExternalStoreRuntime({\n isRunning: providerIsRunning,\n ...(shouldFeedRepository\n ? { messageRepository: exportedMessageRepository }\n : { messages }),\n unstable_enableToolInvocations: true,\n setToolStatuses,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onImport: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onExportExternalState: (): MessageFormatRepository<UI_MESSAGE> => {\n const exported = runtimeRef.current.thread.export();\n\n const expandedMessages: MessageFormatItem<UI_MESSAGE>[] = [];\n const lastInnerIdMap = new Map<string, string>();\n\n for (const item of exported.messages) {\n const innerMessages = getExternalStoreMessages<UI_MESSAGE>(\n item.message,\n );\n let parentId =\n item.parentId != null\n ? (lastInnerIdMap.get(item.parentId) ?? item.parentId)\n : null;\n for (const innerMessage of innerMessages) {\n expandedMessages.push({ parentId, message: innerMessage });\n parentId = aiSDKV6FormatAdapter.getId(innerMessage as UIMessage);\n }\n if (innerMessages.length > 0) {\n lastInnerIdMap.set(\n item.message.id,\n aiSDKV6FormatAdapter.getId(\n innerMessages[innerMessages.length - 1]! as UIMessage,\n ),\n );\n }\n }\n\n const result: MessageFormatRepository<UI_MESSAGE> = {\n messages: expandedMessages,\n };\n\n if (exported.headId != null) {\n result.headId = lastInnerIdMap.get(exported.headId) ?? exported.headId;\n }\n\n return result;\n },\n onLoadExternalState: (repo: MessageFormatRepository<UI_MESSAGE>) => {\n // Convert MessageFormatRepository to ExportedMessageRepository\n const exportedRepo = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages,\n repo,\n );\n\n // Import into the thread's MessageRepository\n runtimeRef.current.thread.import(exportedRepo);\n },\n onCancel: async () => {\n try {\n await chatHelpers.stop();\n } catch (error) {\n if (!(error instanceof Error && error.name === \"AbortError\")) {\n throw error;\n }\n }\n },\n onNew: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...current,\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n await completePendingToolCalls();\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...sliceMessagesUntil(current, message.parentId),\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n chatHelpers.setMessages((current) =>\n sliceMessagesUntil(current, message.parentId),\n );\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onDelete: async (messageId) => {\n const threadMessages = runtimeRef.current.thread.getState().messages;\n const messageIndex = threadMessages.findIndex(\n (message) => message.id === messageId,\n );\n if (messageIndex === -1) return;\n\n await deleteHistoryMessage(messageId);\n\n const deleteIds = new Set(\n getExternalStoreMessages<UI_MESSAGE>(threadMessages[messageIndex]!).map(\n (message) => message.id,\n ),\n );\n chatHelpers.setMessages((current) =>\n current.filter((message) => !deleteIds.has(message.id)),\n );\n },\n onReload: async (parentId: string | null, config) => {\n lastRunConfigRef.current = config.runConfig;\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({\n toolCallId,\n toolName,\n result,\n isError,\n modelContent,\n }) => {\n const options = { metadata: lastRunConfigRef.current };\n if (isError) {\n return Promise.resolve(\n chatHelpers.addToolOutput({\n state: \"output-error\",\n tool: toolName ?? toolCallId,\n toolCallId,\n errorText:\n typeof result === \"string\" ? result : JSON.stringify(result),\n options,\n }),\n );\n } else {\n const output =\n modelContent !== undefined\n ? wrapModelContentEnvelope(result, modelContent)\n : result;\n return Promise.resolve(\n chatHelpers.addToolOutput({\n tool: toolName,\n toolCallId,\n output,\n options,\n }),\n );\n }\n },\n onRespondToToolApproval: ({ approvalId, approved, reason }) =>\n Promise.resolve(\n chatHelpers.addToolApprovalResponse({\n id: approvalId,\n approved,\n ...(reason != null && { reason }),\n options: { metadata: lastRunConfigRef.current },\n }),\n ),\n ...pickExternalStoreSharedOptions(adapter),\n ...(suggestionAdapter ? { suggestions: generatedSuggestions } : {}),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(unstable_onBranchChange && { unstable_onBranchChange }),\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapters,\n },\n extras,\n isLoading,\n });\n\n const setMessagesRef = useRef(chatHelpers.setMessages);\n setMessagesRef.current = chatHelpers.setMessages;\n\n useEffect(() => {\n if (hasSeededRepositoryRef.current) return;\n if (!exportedMessageRepository) return;\n if (chatHelpers.messages.length > 0) {\n hasSeededRepositoryRef.current = true;\n return;\n }\n const tempRepo = new MessageRepository();\n tempRepo.import(exportedMessageRepository);\n setMessagesRef.current(\n tempRepo.getMessages().flatMap(getExternalStoreMessages<UI_MESSAGE>),\n );\n hasSeededRepositoryRef.current = true;\n }, [exportedMessageRepository, chatHelpers.messages.length]);\n return runtime;\n};\n"],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { AssistantRuntime, ExternalStoreSharedOptions } from "@assistant-ui/core
|
|
|
5
5
|
import { Chat, UIMessage as UIMessage$1 } from "@ai-sdk/react";
|
|
6
6
|
//#region src/runtime/useChatThread.d.ts
|
|
7
7
|
type ChatThreadOptions<UI_MESSAGE extends UIMessage$1 = UIMessage$1> = ChatInit<UI_MESSAGE> & ExternalStoreSharedOptions & {
|
|
8
|
+
throttle?: number | undefined;
|
|
8
9
|
adapters?: AISDKRuntimeAdapter["adapters"] | undefined;
|
|
9
10
|
toCreateMessage?: CustomToCreateMessageFunction;
|
|
10
11
|
onResume?: AISDKRuntimeAdapter["onResume"];
|
|
@@ -17,6 +18,8 @@ type ChatThreadOptions<UI_MESSAGE extends UIMessage$1 = UIMessage$1> = ChatInit<
|
|
|
17
18
|
*/
|
|
18
19
|
onResumeError?: ((error: unknown) => void) | undefined;
|
|
19
20
|
joinStrategy?: AISDKRuntimeAdapter["joinStrategy"];
|
|
21
|
+
messageRepository?: AISDKRuntimeAdapter<UI_MESSAGE>["messageRepository"];
|
|
22
|
+
unstable_onBranchChange?: AISDKRuntimeAdapter["unstable_onBranchChange"];
|
|
20
23
|
};
|
|
21
24
|
type ChatThreadEnvironment<UI_MESSAGE extends UIMessage$1 = UIMessage$1> = {
|
|
22
25
|
id: string;
|
|
@@ -48,6 +51,7 @@ declare const splitChatThreadOptions: <UI_MESSAGE extends UIMessage$1>(options:
|
|
|
48
51
|
suggestion?: import("@assistant-ui/core").SuggestionAdapter | undefined;
|
|
49
52
|
}) | undefined;
|
|
50
53
|
transport: ChatTransport<UI_MESSAGE> | undefined;
|
|
54
|
+
throttle: number | undefined;
|
|
51
55
|
toCreateMessage: CustomToCreateMessageFunction | undefined;
|
|
52
56
|
onResume: ((config: import("@assistant-ui/core").ResumeRunConfig) => Promise<void>) | undefined;
|
|
53
57
|
onResumeToolCall: ((options: {
|
|
@@ -56,9 +60,11 @@ declare const splitChatThreadOptions: <UI_MESSAGE extends UIMessage$1>(options:
|
|
|
56
60
|
}) => void) | undefined;
|
|
57
61
|
onResumeError: ((error: unknown) => void) | undefined;
|
|
58
62
|
joinStrategy: import("@assistant-ui/core/store").JoinStrategy | undefined;
|
|
63
|
+
messageRepository: import("@assistant-ui/core").MessageFormatRepository<UI_MESSAGE> | undefined;
|
|
64
|
+
unstable_onBranchChange: ((event: import("@assistant-ui/core").ExternalStoreBranchChange) => void) | undefined;
|
|
59
65
|
chatInit: {
|
|
60
66
|
id?: string;
|
|
61
|
-
messageMetadataSchema?: import("ai").FlexibleSchema<UI_MESSAGE
|
|
67
|
+
messageMetadataSchema?: import("ai").FlexibleSchema<UI_MESSAGE["metadata"]>;
|
|
62
68
|
dataPartSchemas?: (UI_MESSAGE extends UIMessage$1<unknown, infer DATA_TYPES extends import("ai").UIDataTypes, import("ai").UITools> ? DATA_TYPES : import("ai").UIDataTypes) extends (infer T extends import("ai").UIDataTypes) ? { [K in keyof T]: import("ai").FlexibleSchema<T[K]>; } : never;
|
|
63
69
|
messages?: UI_MESSAGE[];
|
|
64
70
|
generateId?: import("ai").IdGenerator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatThread.d.ts","names":[],"sources":["../../src/runtime/useChatThread.ts"],"mappings":";;;;;;KA+BY,kBAAkB,mBAAmB,cAAY,eAC3D,SAAS,cACP;EACE,WAAW;EACX,kBAAkB;EAClB,WAAW;EACX,mBAAmB;;;;;;;EAOnB,kBAAkB;EAClB,eAAe;;
|
|
1
|
+
{"version":3,"file":"useChatThread.d.ts","names":[],"sources":["../../src/runtime/useChatThread.ts"],"mappings":";;;;;;KA+BY,kBAAkB,mBAAmB,cAAY,eAC3D,SAAS,cACP;EACE;EACA,WAAW;EACX,kBAAkB;EAClB,WAAW;EACX,mBAAmB;;;;;;;EAOnB,kBAAkB;EAClB,eAAe;EACf,oBAAoB,oBAAoB;EACxC,0BAA0B;;KAGpB,sBAAsB,mBAAmB,cAAY;EAC/D;EACA;EACA,yBAAyB;EACzB;;;;;;EAMA,OAAO,KAAK;;;;;;;cA4DD,yBAA0B,mBAAmB,aACxD,SAAS,kBAAkB;;;;;;;;;;;;;;;;;;;;EA7EE,iBAAA;;;;;;;;;;;;;;;;;;;cAoHlB,gBAAiB,mBAAmB,cAAY,aAC3D,SAAS,kBAAkB,yBAC3B,KAAK,sBAAsB,gBAC1B"}
|
|
@@ -39,20 +39,23 @@ const getResumedStreamIds = (storage) => {
|
|
|
39
39
|
* same fields `useChat` would.
|
|
40
40
|
*/
|
|
41
41
|
const splitChatThreadOptions = (options) => {
|
|
42
|
-
const { adapters, transport, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, onResumeToolCall, onResumeError, joinStrategy, ...chatInit } = options ?? {};
|
|
42
|
+
const { adapters, transport, throttle, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, onResumeToolCall, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, ...chatInit } = options ?? {};
|
|
43
43
|
return {
|
|
44
44
|
adapters,
|
|
45
45
|
transport,
|
|
46
|
+
throttle,
|
|
46
47
|
toCreateMessage,
|
|
47
48
|
onResume,
|
|
48
49
|
onResumeToolCall,
|
|
49
50
|
onResumeError,
|
|
50
51
|
joinStrategy,
|
|
52
|
+
messageRepository,
|
|
53
|
+
unstable_onBranchChange,
|
|
51
54
|
chatInit
|
|
52
55
|
};
|
|
53
56
|
};
|
|
54
57
|
const useChatThread = (options, env) => {
|
|
55
|
-
const { adapters, transport: transportOptions, toCreateMessage, onResume, onResumeToolCall, onResumeError, joinStrategy, chatInit: chatOptions } = splitChatThreadOptions(options);
|
|
58
|
+
const { adapters, transport: transportOptions, throttle, toCreateMessage, onResume, onResumeToolCall, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, chatInit: chatOptions } = splitChatThreadOptions(options);
|
|
56
59
|
const { id, isMainThread, getThreadListItem, stopOnClientDestroy = false, chat: externalChat } = env;
|
|
57
60
|
const defaultTransport = useMemo(() => new AssistantChatTransport(), []);
|
|
58
61
|
const sourceTransport = transportOptions ?? defaultTransport;
|
|
@@ -61,6 +64,7 @@ const useChatThread = (options, env) => {
|
|
|
61
64
|
...chatOptions,
|
|
62
65
|
id,
|
|
63
66
|
transport,
|
|
67
|
+
...throttle !== void 0 && { throttle },
|
|
64
68
|
...externalChat !== void 0 && { chat: externalChat }
|
|
65
69
|
});
|
|
66
70
|
useResourceCleanup(stopOnClientDestroy, () => {
|
|
@@ -72,7 +76,9 @@ const useChatThread = (options, env) => {
|
|
|
72
76
|
...toCreateMessage && { toCreateMessage },
|
|
73
77
|
...onResume && { onResume },
|
|
74
78
|
...onResumeToolCall && { onResumeToolCall },
|
|
75
|
-
...joinStrategy && { joinStrategy }
|
|
79
|
+
...joinStrategy && { joinStrategy },
|
|
80
|
+
...messageRepository && { messageRepository },
|
|
81
|
+
...unstable_onBranchChange && { unstable_onBranchChange }
|
|
76
82
|
});
|
|
77
83
|
if (sourceTransport instanceof AssistantChatTransport) {
|
|
78
84
|
sourceTransport.setRuntime(runtime);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatThread.js","names":["useChat","Chat","UIMessage","pickExternalStoreSharedOptions","AssistantRuntime","ExternalStoreSharedOptions","useAISDKRuntime","AISDKRuntimeAdapter","CustomToCreateMessageFunction","ChatInit","ChatTransport","AssistantChatTransport","InitializableThreadListItem","AssistantChatResumableOptions","ResumableClientStorage","useCallback","useEffect","useMemo","useRef","useSyncExternalStore","useResourceCleanup","ChatThreadOptions","UI_MESSAGE","adapters","toCreateMessage","onResume","onResumeToolCall","onResumeError","error","joinStrategy","ChatThreadEnvironment","id","isMainThread","getThreadListItem","stopOnClientDestroy","chat","useDynamicChatTransport","transport","transportRef","current","dynamicTransport","Proxy","get","_","prop","res","bind","getResumableAdapter","candidate","undefined","call","getNoPendingStreamId","resumedStreamIdsByStorage","WeakMap","Set","getResumedStreamIds","storage","resumedStreamIds","set","splitChatThreadOptions","options","isDisabled","_isDisabled","isSendDisabled","_isSendDisabled","unstable_capabilities","_unstable_capabilities","suggestions","_suggestions","chatInit","useChatThread","env","transportOptions","chatOptions","externalChat","defaultTransport","sourceTransport","stop","catch","runtime","setRuntime","__internal_setGetThreadListItem","subscribeToRuntime","callback","thread","subscribe","getHistoryLoadingSnapshot","getState","isLoading","isLoadingHistory","resumableStorage","subscribeToResumableStorage","getPendingStreamId","getStreamId","pendingStreamId","isChatRunning","status","onResumeErrorRef","has","add","resumeStream","err","console","warn","callbackError","clear"],"sources":["../../src/runtime/useChatThread.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat, type Chat, type UIMessage } from \"@ai-sdk/react\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit, ChatTransport } from \"ai\";\nimport {\n AssistantChatTransport,\n type InitializableThreadListItem,\n} from \"../transport/AssistantChatTransport\";\nimport type {\n AssistantChatResumableOptions,\n ResumableClientStorage,\n} from \"../transport/resumable\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { useResourceCleanup } from \"./useResourceCleanup\";\n\nexport type ChatThreadOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> &\n ExternalStoreSharedOptions & {\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n onResumeToolCall?: AISDKRuntimeAdapter[\"onResumeToolCall\"];\n /**\n * Called when an automatic resumable stream reconnect fails. Use this to\n * surface a toast, report telemetry, or mark the thread as needing a\n * retry. The failed stream id is cleared after the callback unless a\n * newer id has replaced it.\n */\n onResumeError?: ((error: unknown) => void) | undefined;\n joinStrategy?: AISDKRuntimeAdapter[\"joinStrategy\"];\n };\n\nexport type ChatThreadEnvironment<UI_MESSAGE extends UIMessage = UIMessage> = {\n id: string;\n isMainThread: boolean;\n getThreadListItem: () => InitializableThreadListItem | undefined;\n stopOnClientDestroy?: boolean;\n /**\n * An externally owned chat instance. State lives on the instance, so it\n * survives the hosting resource unmounting; construction options are read\n * from the instance.\n */\n chat?: Chat<UI_MESSAGE> | undefined;\n};\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst getResumableAdapter = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): AssistantChatResumableOptions | undefined => {\n if (transport instanceof AssistantChatTransport) {\n return transport.getResumableAdapter();\n }\n const candidate = (transport as { getResumableAdapter?: () => unknown })\n .getResumableAdapter;\n if (typeof candidate !== \"function\") return undefined;\n return candidate.call(transport) as AssistantChatResumableOptions | undefined;\n};\n\nconst getNoPendingStreamId = () => null;\n\nconst resumedStreamIdsByStorage = new WeakMap<\n ResumableClientStorage,\n Set<string>\n>();\n\nconst getResumedStreamIds = (storage: ResumableClientStorage | undefined) => {\n if (!storage) return new Set<string>();\n let resumedStreamIds = resumedStreamIdsByStorage.get(storage);\n if (!resumedStreamIds) {\n resumedStreamIds = new Set();\n resumedStreamIdsByStorage.set(storage, resumedStreamIds);\n }\n return resumedStreamIds;\n};\n\n/**\n * Splits the combined options into the assistant-ui side and the `ChatInit`\n * remainder the AI SDK consumes, so external `Chat` construction forwards the\n * same fields `useChat` would.\n */\nexport const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n) => {\n const {\n adapters,\n transport,\n toCreateMessage,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n unstable_capabilities: _unstable_capabilities,\n suggestions: _suggestions,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n ...chatInit\n } = options ?? {};\n // peel guard: any shared key left in `chatInit` collapses this to `never`\n true satisfies keyof typeof chatInit &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n return {\n adapters,\n transport,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n chatInit,\n };\n};\n\nexport const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n env: ChatThreadEnvironment<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n chatInit: chatOptions,\n } = splitChatThreadOptions(options);\n\n const {\n id,\n isMainThread,\n getThreadListItem,\n stopOnClientDestroy = false,\n chat: externalChat,\n } = env;\n\n const defaultTransport = useMemo(() => new AssistantChatTransport(), []);\n const sourceTransport = transportOptions ?? defaultTransport;\n const transport = useDynamicChatTransport(sourceTransport);\n\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n ...(externalChat !== undefined && { chat: externalChat }),\n });\n\n useResourceCleanup(stopOnClientDestroy, () => {\n void chat.stop().catch(() => {});\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(joinStrategy && { joinStrategy }),\n });\n\n if (sourceTransport instanceof AssistantChatTransport) {\n sourceTransport.setRuntime(runtime);\n sourceTransport.__internal_setGetThreadListItem(getThreadListItem);\n }\n\n const subscribeToRuntime = useCallback(\n (callback: () => void) => runtime.thread.subscribe(callback),\n [runtime],\n );\n const getHistoryLoadingSnapshot = useCallback(\n () => runtime.thread.getState().isLoading,\n [runtime],\n );\n const isLoadingHistory = useSyncExternalStore(\n subscribeToRuntime,\n getHistoryLoadingSnapshot,\n getHistoryLoadingSnapshot,\n );\n\n const resumableStorage = useMemo(\n () => getResumableAdapter(sourceTransport)?.storage,\n [sourceTransport],\n );\n const subscribeToResumableStorage = useCallback(\n (callback: () => void) =>\n isMainThread\n ? (resumableStorage?.subscribe?.(callback, id) ?? (() => {}))\n : () => {},\n [id, isMainThread, resumableStorage],\n );\n const getPendingStreamId = useCallback(\n () => (isMainThread ? (resumableStorage?.getStreamId(id) ?? null) : null),\n [id, isMainThread, resumableStorage],\n );\n const pendingStreamId = useSyncExternalStore(\n subscribeToResumableStorage,\n getPendingStreamId,\n getNoPendingStreamId,\n );\n const isChatRunning =\n chat.status === \"submitted\" || chat.status === \"streaming\";\n\n const resumedStreamIds = useMemo(\n () => getResumedStreamIds(resumableStorage),\n [resumableStorage],\n );\n const onResumeErrorRef = useRef(onResumeError);\n useEffect(() => {\n onResumeErrorRef.current = onResumeError;\n });\n useEffect(() => {\n if (!pendingStreamId || resumedStreamIds.has(pendingStreamId)) {\n return;\n }\n if (isChatRunning) {\n resumedStreamIds.add(pendingStreamId);\n return;\n }\n if (isLoadingHistory) return;\n resumedStreamIds.add(pendingStreamId);\n chat.resumeStream().catch((err: unknown) => {\n console.warn(\"[assistant-ui] resumable: resume failed\", err);\n try {\n onResumeErrorRef.current?.(err);\n } catch (callbackError) {\n console.error(\n \"[assistant-ui] resumable: onResumeError callback failed\",\n callbackError,\n );\n } finally {\n if (resumableStorage?.getStreamId(id) === pendingStreamId) {\n resumableStorage.clear(id);\n }\n }\n });\n }, [\n chat,\n id,\n isChatRunning,\n isLoadingHistory,\n pendingStreamId,\n resumableStorage,\n resumedStreamIds,\n ]);\n\n return runtime;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useChatThread.js","names":["useChat","Chat","UIMessage","pickExternalStoreSharedOptions","AssistantRuntime","ExternalStoreSharedOptions","useAISDKRuntime","AISDKRuntimeAdapter","CustomToCreateMessageFunction","ChatInit","ChatTransport","AssistantChatTransport","InitializableThreadListItem","AssistantChatResumableOptions","ResumableClientStorage","useCallback","useEffect","useMemo","useRef","useSyncExternalStore","useResourceCleanup","ChatThreadOptions","UI_MESSAGE","throttle","adapters","toCreateMessage","onResume","onResumeToolCall","onResumeError","error","joinStrategy","messageRepository","unstable_onBranchChange","ChatThreadEnvironment","id","isMainThread","getThreadListItem","stopOnClientDestroy","chat","useDynamicChatTransport","transport","transportRef","current","dynamicTransport","Proxy","get","_","prop","res","bind","getResumableAdapter","candidate","undefined","call","getNoPendingStreamId","resumedStreamIdsByStorage","WeakMap","Set","getResumedStreamIds","storage","resumedStreamIds","set","splitChatThreadOptions","options","isDisabled","_isDisabled","isSendDisabled","_isSendDisabled","unstable_capabilities","_unstable_capabilities","suggestions","_suggestions","chatInit","useChatThread","env","transportOptions","chatOptions","externalChat","defaultTransport","sourceTransport","stop","catch","runtime","setRuntime","__internal_setGetThreadListItem","subscribeToRuntime","callback","thread","subscribe","getHistoryLoadingSnapshot","getState","isLoading","isLoadingHistory","resumableStorage","subscribeToResumableStorage","getPendingStreamId","getStreamId","pendingStreamId","isChatRunning","status","onResumeErrorRef","has","add","resumeStream","err","console","warn","callbackError","clear"],"sources":["../../src/runtime/useChatThread.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat, type Chat, type UIMessage } from \"@ai-sdk/react\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit, ChatTransport } from \"ai\";\nimport {\n AssistantChatTransport,\n type InitializableThreadListItem,\n} from \"../transport/AssistantChatTransport\";\nimport type {\n AssistantChatResumableOptions,\n ResumableClientStorage,\n} from \"../transport/resumable\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { useResourceCleanup } from \"./useResourceCleanup\";\n\nexport type ChatThreadOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> &\n ExternalStoreSharedOptions & {\n throttle?: number | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n onResumeToolCall?: AISDKRuntimeAdapter[\"onResumeToolCall\"];\n /**\n * Called when an automatic resumable stream reconnect fails. Use this to\n * surface a toast, report telemetry, or mark the thread as needing a\n * retry. The failed stream id is cleared after the callback unless a\n * newer id has replaced it.\n */\n onResumeError?: ((error: unknown) => void) | undefined;\n joinStrategy?: AISDKRuntimeAdapter[\"joinStrategy\"];\n messageRepository?: AISDKRuntimeAdapter<UI_MESSAGE>[\"messageRepository\"];\n unstable_onBranchChange?: AISDKRuntimeAdapter[\"unstable_onBranchChange\"];\n };\n\nexport type ChatThreadEnvironment<UI_MESSAGE extends UIMessage = UIMessage> = {\n id: string;\n isMainThread: boolean;\n getThreadListItem: () => InitializableThreadListItem | undefined;\n stopOnClientDestroy?: boolean;\n /**\n * An externally owned chat instance. State lives on the instance, so it\n * survives the hosting resource unmounting; construction options are read\n * from the instance.\n */\n chat?: Chat<UI_MESSAGE> | undefined;\n};\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst getResumableAdapter = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): AssistantChatResumableOptions | undefined => {\n if (transport instanceof AssistantChatTransport) {\n return transport.getResumableAdapter();\n }\n const candidate = (transport as { getResumableAdapter?: () => unknown })\n .getResumableAdapter;\n if (typeof candidate !== \"function\") return undefined;\n return candidate.call(transport) as AssistantChatResumableOptions | undefined;\n};\n\nconst getNoPendingStreamId = () => null;\n\nconst resumedStreamIdsByStorage = new WeakMap<\n ResumableClientStorage,\n Set<string>\n>();\n\nconst getResumedStreamIds = (storage: ResumableClientStorage | undefined) => {\n if (!storage) return new Set<string>();\n let resumedStreamIds = resumedStreamIdsByStorage.get(storage);\n if (!resumedStreamIds) {\n resumedStreamIds = new Set();\n resumedStreamIdsByStorage.set(storage, resumedStreamIds);\n }\n return resumedStreamIds;\n};\n\n/**\n * Splits the combined options into the assistant-ui side and the `ChatInit`\n * remainder the AI SDK consumes, so external `Chat` construction forwards the\n * same fields `useChat` would.\n */\nexport const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n) => {\n const {\n adapters,\n transport,\n throttle,\n toCreateMessage,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n unstable_capabilities: _unstable_capabilities,\n suggestions: _suggestions,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n ...chatInit\n } = options ?? {};\n // peel guard: any shared key left in `chatInit` collapses this to `never`\n true satisfies keyof typeof chatInit &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n return {\n adapters,\n transport,\n throttle,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit,\n };\n};\n\nexport const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n env: ChatThreadEnvironment<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n throttle,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit: chatOptions,\n } = splitChatThreadOptions(options);\n\n const {\n id,\n isMainThread,\n getThreadListItem,\n stopOnClientDestroy = false,\n chat: externalChat,\n } = env;\n\n const defaultTransport = useMemo(() => new AssistantChatTransport(), []);\n const sourceTransport = transportOptions ?? defaultTransport;\n const transport = useDynamicChatTransport(sourceTransport);\n\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n ...(throttle !== undefined && { throttle }),\n ...(externalChat !== undefined && { chat: externalChat }),\n });\n\n useResourceCleanup(stopOnClientDestroy, () => {\n void chat.stop().catch(() => {});\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(joinStrategy && { joinStrategy }),\n ...(messageRepository && { messageRepository }),\n ...(unstable_onBranchChange && { unstable_onBranchChange }),\n });\n\n if (sourceTransport instanceof AssistantChatTransport) {\n sourceTransport.setRuntime(runtime);\n sourceTransport.__internal_setGetThreadListItem(getThreadListItem);\n }\n\n const subscribeToRuntime = useCallback(\n (callback: () => void) => runtime.thread.subscribe(callback),\n [runtime],\n );\n const getHistoryLoadingSnapshot = useCallback(\n () => runtime.thread.getState().isLoading,\n [runtime],\n );\n const isLoadingHistory = useSyncExternalStore(\n subscribeToRuntime,\n getHistoryLoadingSnapshot,\n getHistoryLoadingSnapshot,\n );\n\n const resumableStorage = useMemo(\n () => getResumableAdapter(sourceTransport)?.storage,\n [sourceTransport],\n );\n const subscribeToResumableStorage = useCallback(\n (callback: () => void) =>\n isMainThread\n ? (resumableStorage?.subscribe?.(callback, id) ?? (() => {}))\n : () => {},\n [id, isMainThread, resumableStorage],\n );\n const getPendingStreamId = useCallback(\n () => (isMainThread ? (resumableStorage?.getStreamId(id) ?? null) : null),\n [id, isMainThread, resumableStorage],\n );\n const pendingStreamId = useSyncExternalStore(\n subscribeToResumableStorage,\n getPendingStreamId,\n getNoPendingStreamId,\n );\n const isChatRunning =\n chat.status === \"submitted\" || chat.status === \"streaming\";\n\n const resumedStreamIds = useMemo(\n () => getResumedStreamIds(resumableStorage),\n [resumableStorage],\n );\n const onResumeErrorRef = useRef(onResumeError);\n useEffect(() => {\n onResumeErrorRef.current = onResumeError;\n });\n useEffect(() => {\n if (!pendingStreamId || resumedStreamIds.has(pendingStreamId)) {\n return;\n }\n if (isChatRunning) {\n resumedStreamIds.add(pendingStreamId);\n return;\n }\n if (isLoadingHistory) return;\n resumedStreamIds.add(pendingStreamId);\n chat.resumeStream().catch((err: unknown) => {\n console.warn(\"[assistant-ui] resumable: resume failed\", err);\n try {\n onResumeErrorRef.current?.(err);\n } catch (callbackError) {\n console.error(\n \"[assistant-ui] resumable: onResumeError callback failed\",\n callbackError,\n );\n } finally {\n if (resumableStorage?.getStreamId(id) === pendingStreamId) {\n resumableStorage.clear(id);\n }\n }\n });\n }, [\n chat,\n id,\n isChatRunning,\n isLoadingHistory,\n pendingStreamId,\n resumableStorage,\n resumedStreamIds,\n ]);\n\n return runtime;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../src/runtime/useExternalHistory.ts"],"mappings":";;;cAsBa,8BAA+B,UAC1C,mBAAmB,UAAU,eAAe,iBAC5C,UAAU,wBAAwB,cACjC;cAoCU,qBAAsB,UACjC,YAAY,UAAU,mBACtB,gBAAgB,kCAChB,mBAAmB,UAAU,eAAe,iBAC5C,sBAAsB,qBAAqB,gBAC3C,gBAAgB,UAAU;;
|
|
1
|
+
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../src/runtime/useExternalHistory.ts"],"mappings":";;;cAsBa,8BAA+B,UAC1C,mBAAmB,UAAU,eAAe,iBAC5C,UAAU,wBAAwB,cACjC;cAoCU,qBAAsB,UACjC,YAAY,UAAU,mBACtB,gBAAgB,kCAChB,mBAAmB,UAAU,eAAe,iBAC5C,sBAAsB,qBAAqB,gBAC3C,gBAAgB,UAAU;;EAmVN,gBAAA,sBAAM"}
|