@assistant-ui/ai-sdk 0.0.7 → 0.0.9
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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/adapters/aiSDKFormatAdapter.d.ts +2 -2
- package/dist/adapters/aiSDKFormatAdapter.d.ts.map +1 -0
- package/dist/adapters/vercelAttachmentAdapter.d.ts +1 -3
- package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -1
- package/dist/adapters/vercelAttachmentAdapter.js +3 -3
- package/dist/adapters/vercelAttachmentAdapter.js.map +1 -1
- package/dist/aiSDKExtras.d.ts +4 -6
- package/dist/aiSDKExtras.d.ts.map +1 -1
- package/dist/converters/convertMessage.d.ts +34 -24
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +56 -12
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/converters/modelContentEnvelope.d.ts +6 -7
- package/dist/converters/modelContentEnvelope.d.ts.map +1 -1
- package/dist/converters/toCreateMessage.d.ts +2 -4
- package/dist/converters/toCreateMessage.d.ts.map +1 -1
- package/dist/converters/toolOutputConversion.d.ts +20 -22
- package/dist/converters/toolOutputConversion.d.ts.map +1 -1
- package/dist/hooks.d.ts +2 -4
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +17 -14
- package/dist/index.d.ts.map +1 -0
- package/dist/index.native.d.ts +15 -12
- package/dist/index.native.d.ts.map +1 -0
- package/dist/model-context/injectInteractableContext.d.ts +2 -4
- package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
- package/dist/model-context/injectQuoteContext.d.ts +1 -3
- package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
- package/dist/runtime/AISDKChat.d.ts +2 -4
- package/dist/runtime/AISDKChat.d.ts.map +1 -1
- package/dist/runtime/AISDKChat.js +1 -1
- package/dist/runtime/AISDKChat.js.map +1 -1
- package/dist/runtime/AISDKThreads.d.ts +29 -31
- package/dist/runtime/AISDKThreads.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.js +22 -23
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/sdkIdentity.d.ts +1 -3
- package/dist/runtime/sdkIdentity.d.ts.map +1 -1
- package/dist/runtime/sdkIdentity.js +1 -1
- package/dist/runtime/useAISDKRuntime.d.ts +76 -70
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +311 -77
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.d.ts +6 -8
- package/dist/runtime/useChatRuntime.d.ts.map +1 -1
- package/dist/runtime/useChatRuntime.js +14 -10
- package/dist/runtime/useChatRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.d.ts +94 -89
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +44 -15
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useExternalHistory.d.ts +7 -7
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +231 -60
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/dist/runtime/useResourceCleanup.d.ts +1 -3
- package/dist/runtime/useResourceCleanup.d.ts.map +1 -1
- package/dist/runtime/useResourceCleanup.js +38 -14
- package/dist/runtime/useResourceCleanup.js.map +1 -1
- package/dist/runtime/useStreamingTiming.d.ts +3 -5
- package/dist/runtime/useStreamingTiming.d.ts.map +1 -1
- package/dist/runtime/useStreamingTiming.js +1 -1
- package/dist/tools/frontendTools.d.ts +21 -23
- package/dist/tools/frontendTools.d.ts.map +1 -1
- package/dist/tools/generativeTools.d.ts +24 -26
- package/dist/tools/generativeTools.d.ts.map +1 -1
- package/dist/tools/mcp-stdio.node.d.ts +2 -2
- package/dist/tools/mcp-stdio.node.d.ts.map +1 -0
- package/dist/tools/mcp-stdio.unsupported.d.ts +2 -4
- package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -1
- package/dist/transport/AssistantChatTransport.d.ts +14 -16
- package/dist/transport/AssistantChatTransport.d.ts.map +1 -1
- package/dist/transport/AssistantChatTransport.js +9 -2
- package/dist/transport/AssistantChatTransport.js.map +1 -1
- package/dist/transport/resumable.d.ts +25 -27
- package/dist/transport/resumable.d.ts.map +1 -1
- package/dist/usage.d.ts +8 -10
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js.map +1 -1
- package/dist/utils/getVercelAIMessages.d.ts +2 -4
- package/dist/utils/getVercelAIMessages.d.ts.map +1 -1
- package/dist/utils/sliceMessagesUntil.d.ts +1 -3
- package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
- package/package.json +13 -9
- package/src/adapters/vercelAttachmentAdapter.test.ts +23 -0
- package/src/adapters/vercelAttachmentAdapter.ts +2 -2
- package/src/converters/convertMessage.test.ts +541 -3
- package/src/converters/convertMessage.ts +123 -15
- package/src/index.native.ts +1 -1
- package/src/index.ts +1 -1
- package/src/runtime/AISDKChat.ts +0 -4
- package/src/runtime/AISDKThreads.cloud.test.ts +60 -2
- package/src/runtime/AISDKThreads.test.ts +105 -46
- package/src/runtime/AISDKThreads.ts +1 -1
- package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +1639 -19
- package/src/runtime/useAISDKRuntime.approval.test.tsx +252 -9
- package/src/runtime/useAISDKRuntime.fast-refresh.test.tsx +182 -0
- package/src/runtime/useAISDKRuntime.test.ts +275 -5
- package/src/runtime/useAISDKRuntime.ts +533 -60
- package/src/runtime/useAISDKRuntime.voice.test.tsx +50 -1
- package/src/runtime/useChatRuntime.fast-refresh.test.tsx +94 -0
- package/src/runtime/useChatRuntime.integration.test.tsx +143 -65
- package/src/runtime/useChatRuntime.test.ts +11 -7
- package/src/runtime/useChatRuntime.ts +6 -2
- package/src/runtime/useChatThread.test.ts +166 -2
- package/src/runtime/useChatThread.transport.test.tsx +152 -0
- package/src/runtime/useChatThread.ts +89 -22
- package/src/runtime/useExternalHistory.test.ts +943 -3
- package/src/runtime/useExternalHistory.ts +378 -15
- package/src/runtime/useResourceCleanup.ts +41 -15
- package/src/transport/AssistantChatTransport.test.ts +164 -0
- package/src/transport/AssistantChatTransport.ts +22 -2
- package/src/usage.ts +1 -1
|
@@ -2,12 +2,12 @@ import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
|
2
2
|
import { useEffect, useRef } from "@assistant-ui/tap/react-shim";
|
|
3
3
|
import { useAssistantClientDestroySignal } from "@assistant-ui/store/internal";
|
|
4
4
|
//#region src/runtime/useResourceCleanup.ts
|
|
5
|
-
const useResourceCleanup = (enabled, cleanup) => {
|
|
6
|
-
const $ = c(
|
|
5
|
+
const useResourceCleanup = (enabled, cleanup, hostDestroySignal) => {
|
|
6
|
+
const $ = c(8);
|
|
7
7
|
const destroySignal = useAssistantClientDestroySignal();
|
|
8
8
|
const cleanupRef = useRef(cleanup);
|
|
9
9
|
const enabledRef = useRef(enabled);
|
|
10
|
-
const
|
|
10
|
+
const registrationRef = useRef(null);
|
|
11
11
|
let t0;
|
|
12
12
|
if ($[0] !== cleanup || $[1] !== enabled) {
|
|
13
13
|
t0 = () => {
|
|
@@ -21,23 +21,47 @@ const useResourceCleanup = (enabled, cleanup) => {
|
|
|
21
21
|
useEffect(t0);
|
|
22
22
|
let t1;
|
|
23
23
|
let t2;
|
|
24
|
-
if ($[3] !== destroySignal || $[4] !== enabled) {
|
|
24
|
+
if ($[3] !== destroySignal || $[4] !== enabled || $[5] !== hostDestroySignal) {
|
|
25
25
|
t1 = () => {
|
|
26
|
-
if (!enabled || !destroySignal) return;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (!enabled || !destroySignal && !hostDestroySignal) return;
|
|
27
|
+
const current = registrationRef.current;
|
|
28
|
+
if (current !== null && current.destroySignal === destroySignal && current.hostDestroySignal === hostDestroySignal) return;
|
|
29
|
+
current?.controller.abort();
|
|
30
|
+
const registration = new AbortController();
|
|
31
|
+
registrationRef.current = {
|
|
32
|
+
destroySignal,
|
|
33
|
+
hostDestroySignal,
|
|
34
|
+
controller: registration
|
|
35
|
+
};
|
|
36
|
+
const run = () => {
|
|
37
|
+
if (registration.signal.aborted) return;
|
|
38
|
+
registration.abort();
|
|
30
39
|
if (enabledRef.current) cleanupRef.current();
|
|
31
|
-
}
|
|
40
|
+
};
|
|
41
|
+
if (destroySignal?.aborted || hostDestroySignal?.aborted) {
|
|
42
|
+
run();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const options = {
|
|
46
|
+
once: true,
|
|
47
|
+
signal: registration.signal
|
|
48
|
+
};
|
|
49
|
+
destroySignal?.addEventListener("abort", run, options);
|
|
50
|
+
hostDestroySignal?.addEventListener("abort", run, options);
|
|
32
51
|
};
|
|
33
|
-
t2 = [
|
|
52
|
+
t2 = [
|
|
53
|
+
destroySignal,
|
|
54
|
+
enabled,
|
|
55
|
+
hostDestroySignal
|
|
56
|
+
];
|
|
34
57
|
$[3] = destroySignal;
|
|
35
58
|
$[4] = enabled;
|
|
36
|
-
$[5] =
|
|
37
|
-
$[6] =
|
|
59
|
+
$[5] = hostDestroySignal;
|
|
60
|
+
$[6] = t1;
|
|
61
|
+
$[7] = t2;
|
|
38
62
|
} else {
|
|
39
|
-
t1 = $[
|
|
40
|
-
t2 = $[
|
|
63
|
+
t1 = $[6];
|
|
64
|
+
t2 = $[7];
|
|
41
65
|
}
|
|
42
66
|
useEffect(t1, t2);
|
|
43
67
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useResourceCleanup.js","names":["useEffect","useRef","useAssistantClientDestroySignal","useResourceCleanup","enabled","cleanup","$","_c","destroySignal","cleanupRef","enabledRef","
|
|
1
|
+
{"version":3,"file":"useResourceCleanup.js","names":["useEffect","useRef","useAssistantClientDestroySignal","useResourceCleanup","enabled","cleanup","hostDestroySignal","$","_c","destroySignal","cleanupRef","enabledRef","registrationRef","t0","current","t1","t2","controller","abort","registration","AbortController","run","signal","aborted","options","once","addEventListener"],"sources":["../../src/runtime/useResourceCleanup.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { useAssistantClientDestroySignal } from \"@assistant-ui/store/internal\";\n\nexport const useResourceCleanup = (\n enabled: boolean,\n cleanup: () => void,\n hostDestroySignal?: AbortSignal,\n) => {\n const destroySignal = useAssistantClientDestroySignal();\n const cleanupRef = useRef(cleanup);\n const enabledRef = useRef(enabled);\n const registrationRef = useRef<{\n destroySignal: AbortSignal | undefined;\n hostDestroySignal: AbortSignal | undefined;\n controller: AbortController;\n } | null>(null);\n\n useEffect(() => {\n cleanupRef.current = cleanup;\n enabledRef.current = enabled;\n });\n\n useEffect(() => {\n if (!enabled || (!destroySignal && !hostDestroySignal)) return undefined;\n const current = registrationRef.current;\n if (\n current !== null &&\n current.destroySignal === destroySignal &&\n current.hostDestroySignal === hostDestroySignal\n ) {\n return undefined;\n }\n current?.controller.abort();\n\n const registration = new AbortController();\n registrationRef.current = {\n destroySignal,\n hostDestroySignal,\n controller: registration,\n };\n const run = () => {\n if (registration.signal.aborted) return;\n registration.abort();\n if (enabledRef.current) cleanupRef.current();\n };\n if (destroySignal?.aborted || hostDestroySignal?.aborted) {\n run();\n return undefined;\n }\n const options = { once: true, signal: registration.signal };\n destroySignal?.addEventListener(\"abort\", run, options);\n hostDestroySignal?.addEventListener(\"abort\", run, options);\n\n // The listeners must survive standalone soft unmounts so a later\n // permanent destroy still cleans up the retained resource state.\n return undefined;\n }, [destroySignal, enabled, hostDestroySignal]);\n};\n"],"mappings":";;;;AAGA,MAAaG,sBAAqBC,SAAAC,SAAAC,sBAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAKhC,MAAAC,gBAAsBP,gCAAgC;CACtD,MAAAQ,aAAmBT,OAAOI,OAAO;CACjC,MAAAM,aAAmBV,OAAOG,OAAO;CACjC,MAAAQ,kBAAwBX,OAId,IAAI;CAAE,IAAAY;CAAA,IAAAN,EAAA,OAAAF,WAAAE,EAAA,OAAAH,SAAA;EAENS,WAAA;GACRH,WAAUI,UAAWT;GACrBM,WAAUG,UAAWV;EAAH;EACnBG,EAAA,KAAAF;EAAAE,EAAA,KAAAH;EAAAG,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAHDP,UAAUa,EAGT;CAAC,IAAAE;CAAA,IAAAC;CAAA,IAAAT,EAAA,OAAAE,iBAAAF,EAAA,OAAAH,WAAAG,EAAA,OAAAD,mBAAA;EAEQS,WAAA;GACR,IAAI,CAACX,WAAY,CAACK,iBAAD,CAAmBH,mBAAkB;GACtD,MAAAQ,UAAgBF,gBAAeE;GAC/B,IACEA,YAAY,QACZA,QAAOL,kBAAmBA,iBAC1BK,QAAOR,sBAAuBA,mBAAiB;GAIjDQ,SAAOG,WAAkBC,MAAC;GAE1B,MAAAC,eAAqB,IAAIC,gBAAgB;GACzCR,gBAAeE,UAAW;IAAAL;IAAAH;IAAAW,YAGZE;GACd;GACA,MAAAE,YAAY;IACV,IAAIF,aAAYG,OAAOC,SAAQ;IAC/BJ,aAAYD,MAAO;IACnB,IAAIP,WAAUG,SAAUJ,WAAUI,QAAS;GAAE;GAE/C,IAAIL,eAAac,WAAajB,mBAAiBiB,SAAS;IACtDF,IAAI;IAAC;GAAA;GAGP,MAAAG,UAAgB;IAAAC,MAAQ;IAAIH,QAAUH,aAAYG;GAAQ;GAC1Db,eAAaiB,iBAAmB,SAASL,KAAKG,OAAO;GACrDlB,mBAAiBoB,iBAAmB,SAASL,KAAKG,OAAO;EAAC;EAKzDR,KAAA;GAACP;GAAeL;GAASE;EAAiB;EAACC,EAAA,KAAAE;EAAAF,EAAA,KAAAH;EAAAG,EAAA,KAAAD;EAAAC,EAAA,KAAAQ;EAAAR,EAAA,KAAAS;CAAA,OAAA;EAAAD,KAAAR,EAAA;EAAAS,KAAAT,EAAA;CAAA;CAlC9CP,UAAUe,IAkCPC,EAA2C;AAAC"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { MessageTiming } from "@assistant-ui/core";
|
|
3
|
-
import {
|
|
4
|
-
//#region src/runtime/useStreamingTiming.d.ts
|
|
1
|
+
import type { UIMessage } from "@ai-sdk/react";
|
|
2
|
+
import type { MessageTiming } from "@assistant-ui/core";
|
|
3
|
+
import { type StreamingTimingAccessors } from "@assistant-ui/core/react";
|
|
5
4
|
export declare const aiSdkStreamingTimingAccessors: StreamingTimingAccessors<UIMessage>;
|
|
6
5
|
/**
|
|
7
6
|
* Tracks streaming timing for AI SDK messages client-side. Delegates to the
|
|
@@ -10,5 +9,4 @@ export declare const aiSdkStreamingTimingAccessors: StreamingTimingAccessors<UIM
|
|
|
10
9
|
* and stored per message id.
|
|
11
10
|
*/
|
|
12
11
|
export declare const useStreamingTiming: (messages: UIMessage[], isRunning: boolean) => Record<string, MessageTiming>;
|
|
13
|
-
//#endregion
|
|
14
12
|
//# sourceMappingURL=useStreamingTiming.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStreamingTiming.d.ts","
|
|
1
|
+
{"version":3,"file":"useStreamingTiming.d.ts","sourceRoot":"","sources":["../../src/runtime/useStreamingTiming.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAC;AAsClC,eAAO,MAAM,6BAA6B,EAAE,wBAAwB,CAAC,SAAS,CAK3E,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,SAAS,EAAE,EACrB,WAAW,OAAO,KACjB,MAAM,CAAC,MAAM,EAAE,aAAa,CAK5B,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useStreamingTiming as useStreamingTiming$1 } from "@assistant-ui/core/react";
|
|
3
2
|
import { isToolUIPart } from "ai";
|
|
3
|
+
import { useStreamingTiming as useStreamingTiming$1 } from "@assistant-ui/core/react";
|
|
4
4
|
//#region src/runtime/useStreamingTiming.ts
|
|
5
5
|
const findAssistant = (messages, messageId) => messages.find((m) => m.role === "assistant" && m.id === messageId);
|
|
6
6
|
const getTextLength = (messages, messageId) => {
|
|
@@ -1,32 +1,30 @@
|
|
|
1
|
-
import { ToolSet } from "ai";
|
|
2
|
-
import { ToolJSONSchema } from "assistant-stream";
|
|
3
|
-
//#region src/tools/frontendTools.d.ts
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import type { ToolJSONSchema } from "assistant-stream";
|
|
4
3
|
/** Frontend tool definitions uploaded by AssistantChatTransport. */
|
|
5
4
|
export type FrontendTools = Record<string, ToolJSONSchema>;
|
|
6
5
|
export declare const defaultToModelOutput: ({ output }: {
|
|
7
|
-
|
|
6
|
+
output: unknown;
|
|
8
7
|
}) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
type: "content";
|
|
9
|
+
value: ({
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
} | {
|
|
13
|
+
filename?: string;
|
|
14
|
+
type: "file";
|
|
15
|
+
data: {
|
|
16
|
+
type: "data";
|
|
17
|
+
data: string;
|
|
18
|
+
};
|
|
19
|
+
mediaType: string;
|
|
20
|
+
text?: never;
|
|
21
|
+
})[];
|
|
23
22
|
} | {
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
type: "text";
|
|
24
|
+
value: string;
|
|
26
25
|
} | {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
type: "json";
|
|
27
|
+
value: import("ai").JSONValue;
|
|
29
28
|
};
|
|
30
29
|
export declare const frontendTools: (tools: FrontendTools) => ToolSet;
|
|
31
|
-
//#endregion
|
|
32
30
|
//# sourceMappingURL=frontendTools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontendTools.d.ts","
|
|
1
|
+
{"version":3,"file":"frontendTools.d.ts","sourceRoot":"","sources":["../../src/tools/frontendTools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOvD,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAE3D,eAAO,MAAM,oBAAoB,GAAI,YAAY;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;CAMnE,CAAC;AAiDF,eAAO,MAAM,aAAa,GAAI,OAAO,aAAa,KAAG,OAgBpD,CAAC"}
|
|
@@ -1,34 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Toolkit } from "@assistant-ui/core/react";
|
|
3
|
-
import {
|
|
4
|
-
//#region src/tools/generativeTools.d.ts
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import type { Toolkit } from "@assistant-ui/core/react";
|
|
3
|
+
import { type FrontendTools } from "./frontendTools.js";
|
|
5
4
|
/**
|
|
6
5
|
* @deprecated Options for the deprecated {@link generativeTools}. Use
|
|
7
6
|
* {@link AISDKToolkit} with {@link AISDKToolkitOptions} /
|
|
8
7
|
* {@link AISDKToolkitToolsOptions} instead.
|
|
9
8
|
*/
|
|
10
9
|
export interface GenerativeToolsOptions {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The server build of a generative toolkit (schema + server `execute`). Typed
|
|
12
|
+
* as the canonical {@link Toolkit} so callers don't need to cast; the server
|
|
13
|
+
* build carries `execute`, recovered internally as {@link ToolkitDefinition}.
|
|
14
|
+
*/
|
|
15
|
+
toolkit: Toolkit;
|
|
16
|
+
/**
|
|
17
|
+
* Tools uploaded by the frontend (the request body's `tools`). Merged in
|
|
18
|
+
* alongside the `toolkit`; a server `execute` from `toolkit` takes precedence
|
|
19
|
+
* over an uploaded entry of the same name.
|
|
20
|
+
*/
|
|
21
|
+
frontendTools?: FrontendTools;
|
|
23
22
|
}
|
|
24
23
|
export type AISDKToolkitOptions = {
|
|
25
|
-
|
|
24
|
+
toolkit: Toolkit;
|
|
26
25
|
};
|
|
27
26
|
export type AISDKToolkitToolsOptions = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Tools uploaded by the frontend request body.
|
|
29
|
+
*/
|
|
30
|
+
frontend?: FrontendTools;
|
|
32
31
|
};
|
|
33
32
|
/**
|
|
34
33
|
* Builds an AI SDK `ToolSet` for server-side use with `streamText` /
|
|
@@ -63,10 +62,9 @@ export type AISDKToolkitToolsOptions = {
|
|
|
63
62
|
*/
|
|
64
63
|
export declare const generativeTools: (options: GenerativeToolsOptions) => ToolSet;
|
|
65
64
|
export declare class AISDKToolkit {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
#private;
|
|
66
|
+
constructor(options: AISDKToolkitOptions);
|
|
67
|
+
tools(options?: AISDKToolkitToolsOptions): Promise<ToolSet>;
|
|
68
|
+
close(): Promise<void>;
|
|
70
69
|
}
|
|
71
|
-
//#endregion
|
|
72
70
|
//# sourceMappingURL=generativeTools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generativeTools.d.ts","
|
|
1
|
+
{"version":3,"file":"generativeTools.d.ts","sourceRoot":"","sources":["../../src/tools/generativeTools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAU9C,OAAO,KAAK,EAEV,OAAO,EAER,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAiB,KAAK,aAAa,EAAE,2BAAwB;AAkEpE;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,sBAAsB,KAAG,OAUjE,CAAC;AAEF,qBAAa,YAAY;;gBAIX,OAAO,EAAE,mBAAmB;IAIlC,KAAK,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAmH7B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { Experimental_StdioMCPTransport } from "@ai-sdk/mcp/mcp-stdio";
|
|
2
|
+
//# sourceMappingURL=mcp-stdio.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-stdio.node.d.ts","sourceRoot":"","sources":["../../src/tools/mcp-stdio.node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Experimental_StdioMCPTransport as
|
|
2
|
-
|
|
3
|
-
export declare const Experimental_StdioMCPTransport: typeof Experimental_StdioMCPTransport$1;
|
|
4
|
-
//#endregion
|
|
1
|
+
import type { Experimental_StdioMCPTransport as NodeStdioMCPTransport } from "@ai-sdk/mcp/mcp-stdio";
|
|
2
|
+
export declare const Experimental_StdioMCPTransport: typeof NodeStdioMCPTransport;
|
|
5
3
|
//# sourceMappingURL=mcp-stdio.unsupported.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-stdio.unsupported.d.ts","
|
|
1
|
+
{"version":3,"file":"mcp-stdio.unsupported.d.ts","sourceRoot":"","sources":["../../src/tools/mcp-stdio.unsupported.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,IAAI,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAUrG,eAAO,MAAM,8BAA8B,EACE,OAAO,qBAAqB,CAAC"}
|
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DefaultChatTransport, HttpChatTransportInitOptions, UIMessage } from "ai";
|
|
3
|
-
import {
|
|
4
|
-
//#region src/transport/AssistantChatTransport.d.ts
|
|
1
|
+
import type { AssistantRuntime, ThreadListItemRuntime } from "@assistant-ui/core";
|
|
2
|
+
import { DefaultChatTransport, type HttpChatTransportInitOptions, type UIMessage } from "ai";
|
|
3
|
+
import { type AssistantChatResumableOptions } from "./resumable.js";
|
|
5
4
|
export type InitializableThreadListItem = Pick<ThreadListItemRuntime, "initialize">;
|
|
6
5
|
export type AssistantChatTransportInitOptions<UI_MESSAGE extends UIMessage> = HttpChatTransportInitOptions<UI_MESSAGE> & {
|
|
7
|
-
|
|
6
|
+
resumable?: AssistantChatResumableOptions;
|
|
8
7
|
};
|
|
9
8
|
export declare class AssistantChatTransport<UI_MESSAGE extends UIMessage> extends DefaultChatTransport<UI_MESSAGE> {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
private runtime;
|
|
10
|
+
private getThreadListItem;
|
|
11
|
+
private readonly resumable;
|
|
12
|
+
private readonly __internal_initOptions;
|
|
13
|
+
/** Constructs an unwired copy with the same init options. */
|
|
14
|
+
__internal_clone(): AssistantChatTransport<UI_MESSAGE>;
|
|
15
|
+
constructor(initOptions?: AssistantChatTransportInitOptions<UI_MESSAGE>);
|
|
16
|
+
setRuntime(runtime: AssistantRuntime): void;
|
|
17
|
+
getResumableAdapter(): AssistantChatResumableOptions | undefined;
|
|
18
|
+
__internal_setGetThreadListItem(getter: () => InitializableThreadListItem | undefined): void;
|
|
20
19
|
}
|
|
21
|
-
//#endregion
|
|
22
20
|
//# sourceMappingURL=AssistantChatTransport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantChatTransport.d.ts","
|
|
1
|
+
{"version":3,"file":"AssistantChatTransport.d.ts","sourceRoot":"","sources":["../../src/transport/AssistantChatTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,KAAK,4BAA4B,EACjC,KAAK,SAAS,EACf,MAAM,IAAI,CAAC;AAEZ,OAAO,EAEL,KAAK,6BAA6B,EACnC,uBAAoB;AAErB,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAC5C,qBAAqB,EACrB,YAAY,CACb,CAAC;AAYF,MAAM,MAAM,iCAAiC,CAAC,UAAU,SAAS,SAAS,IACxE,4BAA4B,CAAC,UAAU,CAAC,GAAG;IACzC,SAAS,CAAC,EAAE,6BAA6B,CAAC;CAC3C,CAAC;AAEJ,qBAAa,sBAAsB,CACjC,UAAU,SAAS,SAAS,CAC5B,SAAQ,oBAAoB,CAAC,UAAU,CAAC;IACxC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,iBAAiB,CAEX;IACd,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4C;IAEtE,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAEzB;IAEd,6DAA6D;IACtD,gBAAgB,IAAI,sBAAsB,CAAC,UAAU,CAAC;gBAOjD,WAAW,CAAC,EAAE,iCAAiC,CAAC,UAAU,CAAC;IA0DvE,UAAU,CAAC,OAAO,EAAE,gBAAgB;IAIpC,mBAAmB,IAAI,6BAA6B,GAAG,SAAS;IAIhE,+BAA+B,CAC7B,MAAM,EAAE,MAAM,2BAA2B,GAAG,SAAS;CAIxD"}
|
|
@@ -5,6 +5,7 @@ import { toToolsJSONSchema } from "assistant-stream";
|
|
|
5
5
|
const FINISH_MARKER = "\"type\":\"finish\"";
|
|
6
6
|
const FINISH_BUFFER_LIMIT = 4096;
|
|
7
7
|
const RESUMABLE_THREAD_ID_HEADER = "x-assistant-ui-resumable-thread-id";
|
|
8
|
+
const RESUMABLE_RECONNECT_ID_HEADER = "x-assistant-ui-resumable-reconnect-id";
|
|
8
9
|
const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([
|
|
9
10
|
101,
|
|
10
11
|
204,
|
|
@@ -81,13 +82,18 @@ function wrapFetchWithResumable(resumable, userFetch) {
|
|
|
81
82
|
return async (input, init) => {
|
|
82
83
|
const headers = new Headers(init?.headers);
|
|
83
84
|
const threadId = headers.get(RESUMABLE_THREAD_ID_HEADER) ?? void 0;
|
|
85
|
+
const reconnectingStreamId = headers.get(RESUMABLE_RECONNECT_ID_HEADER);
|
|
86
|
+
const checkpointAtRequest = reconnectingStreamId ?? resumable.storage.getStreamId(threadId);
|
|
84
87
|
headers.delete(RESUMABLE_THREAD_ID_HEADER);
|
|
88
|
+
headers.delete(RESUMABLE_RECONNECT_ID_HEADER);
|
|
85
89
|
const res = await baseFetch(input, {
|
|
86
90
|
...init,
|
|
87
91
|
headers
|
|
88
92
|
});
|
|
89
93
|
const id = res.headers.get(RESUMABLE_STREAM_ID_HEADER);
|
|
90
|
-
|
|
94
|
+
const ownsCheckpoint = !reconnectingStreamId || resumable.storage.getStreamId(threadId) === reconnectingStreamId;
|
|
95
|
+
if (id && ownsCheckpoint) resumable.storage.setStreamId(id, threadId);
|
|
96
|
+
if ((res.status === 204 || res.status === 404) && reconnectingStreamId && resumable.storage.getStreamId(threadId) === reconnectingStreamId) resumable.storage.clear(threadId);
|
|
91
97
|
if (!res.body || NULL_BODY_STATUSES.has(res.status)) return res;
|
|
92
98
|
const detectFinish = resumable.isFinishEvent ?? defaultIsFinishEvent;
|
|
93
99
|
const decoder = new TextDecoder();
|
|
@@ -96,7 +102,7 @@ function wrapFetchWithResumable(resumable, userFetch) {
|
|
|
96
102
|
controller.enqueue(chunk);
|
|
97
103
|
accumulator += decoder.decode(chunk, { stream: true });
|
|
98
104
|
if (detectFinish(chunk, accumulator)) {
|
|
99
|
-
if (
|
|
105
|
+
if (ownsCheckpoint && resumable.storage.getStreamId(threadId) === (id ?? checkpointAtRequest)) resumable.storage.clear(threadId);
|
|
100
106
|
accumulator = "";
|
|
101
107
|
} else if (accumulator.length > FINISH_BUFFER_LIMIT) accumulator = accumulator.slice(-1024);
|
|
102
108
|
} });
|
|
@@ -121,6 +127,7 @@ function wrapPrepareReconnect(resumable, userPrepareReconnect) {
|
|
|
121
127
|
});
|
|
122
128
|
const headers = new Headers(userPrepared?.headers ?? options.headers);
|
|
123
129
|
headers.set(RESUMABLE_THREAD_ID_HEADER, options.id);
|
|
130
|
+
headers.set(RESUMABLE_RECONNECT_ID_HEADER, streamId);
|
|
124
131
|
return {
|
|
125
132
|
...userPrepared,
|
|
126
133
|
headers,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantChatTransport.js","names":["AssistantRuntime","ThreadListItemRuntime","DefaultChatTransport","HttpChatTransportInitOptions","UIMessage","toToolsJSONSchema","RESUMABLE_STREAM_ID_HEADER","AssistantChatResumableOptions","InitializableThreadListItem","Pick","FINISH_MARKER","FINISH_BUFFER_LIMIT","FINISH_BUFFER_TAIL","RESUMABLE_THREAD_ID_HEADER","NULL_BODY_STATUSES","Set","AssistantChatTransportInitOptions","UI_MESSAGE","resumable","AssistantChatTransport","runtime","getThreadListItem","__internal_initOptions","__internal_clone","Constructor","constructor","initOptions","rest","userFetch","fetch","userPrepareReconnect","prepareReconnectToStreamRequest","wrapFetchWithResumable","wrapPrepareReconnect","prepareSendMessagesRequest","options","threadId","id","context","thread","getModelContext","threadListItem","threads","mainItem","initialize","remoteId","optionsEx","body","callSettings","system","config","tools","preparedRequest","headers","Headers","undefined","set","messages","trigger","messageId","metadata","requestMetadata","setRuntime","getResumableAdapter","__internal_setGetThreadListItem","getter","NonNullable","baseFetch","globalThis","input","init","RequestInfo","URL","bind","get","delete","res","storage","setStreamId","has","status","detectFinish","isFinishEvent","defaultIsFinishEvent","decoder","TextDecoder","accumulator","tap","TransformStream","Uint8Array","transform","chunk","controller","enqueue","decode","stream","getStreamId","clear","length","slice","Response","pipeThrough","statusText","_chunk","includes","streamId","Error","api","resumeApi","userPrepared"],"sources":["../../src/transport/AssistantChatTransport.ts"],"sourcesContent":["import type {\n AssistantRuntime,\n ThreadListItemRuntime,\n} from \"@assistant-ui/core\";\nimport {\n DefaultChatTransport,\n type HttpChatTransportInitOptions,\n type UIMessage,\n} from \"ai\";\nimport { toToolsJSONSchema } from \"assistant-stream\";\nimport {\n RESUMABLE_STREAM_ID_HEADER,\n type AssistantChatResumableOptions,\n} from \"./resumable\";\n\nexport type InitializableThreadListItem = Pick<\n ThreadListItemRuntime,\n \"initialize\"\n>;\n\nconst FINISH_MARKER = '\"type\":\"finish\"';\nconst FINISH_BUFFER_LIMIT = 4096;\nconst FINISH_BUFFER_TAIL = 1024;\nconst RESUMABLE_THREAD_ID_HEADER = \"x-assistant-ui-resumable-thread-id\";\n\n// 101/204/205/304 are null-body statuses per the fetch spec: `new Response(body, { status })`\n// throws for them, and WebKit returns a non-null empty body, so the body check alone does not guard it.\nconst NULL_BODY_STATUSES = new Set([101, 204, 205, 304]);\n\nexport type AssistantChatTransportInitOptions<UI_MESSAGE extends UIMessage> =\n HttpChatTransportInitOptions<UI_MESSAGE> & {\n resumable?: AssistantChatResumableOptions;\n };\n\nexport class AssistantChatTransport<\n UI_MESSAGE extends UIMessage,\n> extends DefaultChatTransport<UI_MESSAGE> {\n private runtime: AssistantRuntime | undefined;\n private getThreadListItem:\n | (() => InitializableThreadListItem | undefined)\n | undefined;\n private readonly resumable: AssistantChatResumableOptions | undefined;\n\n private readonly __internal_initOptions:\n | AssistantChatTransportInitOptions<UI_MESSAGE>\n | undefined;\n\n /** Constructs an unwired copy with the same init options. */\n public __internal_clone(): AssistantChatTransport<UI_MESSAGE> {\n const Constructor = this.constructor as new (\n initOptions?: AssistantChatTransportInitOptions<UI_MESSAGE>,\n ) => AssistantChatTransport<UI_MESSAGE>;\n return new Constructor(this.__internal_initOptions);\n }\n\n constructor(initOptions?: AssistantChatTransportInitOptions<UI_MESSAGE>) {\n const { resumable, ...rest } = initOptions ?? {};\n const userFetch = rest.fetch;\n const userPrepareReconnect = rest.prepareReconnectToStreamRequest;\n\n super({\n ...rest,\n ...(resumable && {\n fetch: wrapFetchWithResumable(resumable, userFetch),\n prepareReconnectToStreamRequest: wrapPrepareReconnect(\n resumable,\n userPrepareReconnect,\n ),\n }),\n prepareSendMessagesRequest: async (options) => {\n const threadId = options.id;\n const context = this.runtime?.thread.getModelContext();\n const threadListItem =\n this.getThreadListItem?.() ?? this.runtime?.threads.mainItem;\n const id = (await threadListItem?.initialize())?.remoteId ?? options.id;\n\n const optionsEx = {\n ...options,\n id,\n body: {\n callSettings: context?.callSettings,\n system: context?.system,\n config: context?.config,\n tools: toToolsJSONSchema(context?.tools ?? {}),\n ...options?.body,\n },\n };\n const preparedRequest =\n await rest.prepareSendMessagesRequest?.(optionsEx);\n const headers = resumable\n ? new Headers(preparedRequest?.headers ?? options.headers)\n : undefined;\n headers?.set(RESUMABLE_THREAD_ID_HEADER, threadId);\n\n return {\n ...preparedRequest,\n ...(headers && { headers }),\n body: preparedRequest?.body ?? {\n ...optionsEx.body,\n id,\n messages: options.messages,\n trigger: options.trigger,\n messageId: options.messageId,\n metadata: options.requestMetadata,\n },\n };\n },\n });\n\n this.resumable = resumable;\n this.__internal_initOptions = initOptions;\n }\n\n setRuntime(runtime: AssistantRuntime) {\n this.runtime = runtime;\n }\n\n getResumableAdapter(): AssistantChatResumableOptions | undefined {\n return this.resumable;\n }\n\n __internal_setGetThreadListItem(\n getter: () => InitializableThreadListItem | undefined,\n ) {\n this.getThreadListItem = getter;\n }\n}\n\nfunction wrapFetchWithResumable(\n resumable: AssistantChatResumableOptions,\n userFetch: HttpChatTransportInitOptions<UIMessage>[\"fetch\"],\n): NonNullable<HttpChatTransportInitOptions<UIMessage>[\"fetch\"]> {\n const baseFetch: typeof globalThis.fetch = userFetch\n ? (input, init) => userFetch(input as RequestInfo | URL, init)\n : globalThis.fetch.bind(globalThis);\n\n return async (input, init) => {\n const headers = new Headers(init?.headers);\n const threadId = headers.get(RESUMABLE_THREAD_ID_HEADER) ?? undefined;\n headers.delete(RESUMABLE_THREAD_ID_HEADER);\n const res = await baseFetch(input, { ...init, headers });\n const id = res.headers.get(RESUMABLE_STREAM_ID_HEADER);\n if (id) resumable.storage.setStreamId(id, threadId);\n if (!res.body || NULL_BODY_STATUSES.has(res.status)) return res;\n\n const detectFinish = resumable.isFinishEvent ?? defaultIsFinishEvent;\n // a single decoder is required so multi-byte sequences split across\n // chunks buffer via stream: true rather than getting dropped.\n const decoder = new TextDecoder();\n let accumulator = \"\";\n const tap = new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n controller.enqueue(chunk);\n accumulator += decoder.decode(chunk, { stream: true });\n if (detectFinish(chunk, accumulator)) {\n if (!id || resumable.storage.getStreamId(threadId) === id) {\n resumable.storage.clear(threadId);\n }\n accumulator = \"\";\n } else if (accumulator.length > FINISH_BUFFER_LIMIT) {\n accumulator = accumulator.slice(-FINISH_BUFFER_TAIL);\n }\n },\n });\n\n return new Response(res.body.pipeThrough(tap), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n };\n}\n\nfunction defaultIsFinishEvent(_chunk: Uint8Array, accumulator: string) {\n return accumulator.includes(FINISH_MARKER);\n}\n\nfunction wrapPrepareReconnect(\n resumable: AssistantChatResumableOptions,\n userPrepareReconnect: HttpChatTransportInitOptions<UIMessage>[\"prepareReconnectToStreamRequest\"],\n): NonNullable<\n HttpChatTransportInitOptions<UIMessage>[\"prepareReconnectToStreamRequest\"]\n> {\n return async (options) => {\n const streamId = resumable.storage.getStreamId(options.id);\n if (!streamId) {\n throw new Error(\n \"AssistantChatTransport: no resumable stream id available; nothing to resume\",\n );\n }\n const api =\n typeof resumable.resumeApi === \"function\"\n ? resumable.resumeApi(streamId)\n : resumable.resumeApi;\n const userPrepared = await userPrepareReconnect?.({ ...options, api });\n const headers = new Headers(userPrepared?.headers ?? options.headers);\n headers.set(RESUMABLE_THREAD_ID_HEADER, options.id);\n return {\n ...userPrepared,\n headers,\n api: userPrepared?.api ?? api,\n };\n };\n}\n"],"mappings":";;;;AAoBA,MAAMU,gBAAgB;AACtB,MAAMC,sBAAsB;AAE5B,MAAME,6BAA6B;AAInC,MAAMC,qCAAqB,IAAIC,IAAI;CAAC;CAAK;CAAK;CAAK;AAAG,CAAC;AAOvD,IAAaI,yBAAb,cAEUjB,qBAAiC;CACzC;CACA;CAGA;CAEA;;CAKA,mBAA8D;EAC5D,MAAMsB,cAAc,KAAKC;EAGzB,OAAO,IAAID,YAAY,KAAKF,sBAAsB;CACpD;CAEAG,YAAYC,aAA6D;EACvE,MAAM,EAAER,WAAW,GAAGS,SAASD,eAAe,CAAC;EAC/C,MAAME,YAAYD,KAAKE;EACvB,MAAMC,uBAAuBH,KAAKI;EAElC,MAAM;GACJ,GAAGJ;GACH,GAAIT,aAAa;IACfW,OAAOG,uBAAuBd,WAAWU,SAAS;IAClDG,iCAAiCE,qBAC/Bf,WACAY,oBACF;GACF;GACAI,4BAA4B,OAAOC,YAAY;IAC7C,MAAMC,WAAWD,QAAQE;IACzB,MAAMC,UAAU,KAAKlB,SAASmB,OAAOC,gBAAgB;IAGrD,MAAMH,MAAM,OADV,KAAKhB,oBAAoB,KAAK,KAAKD,SAASsB,QAAQC,SAAAA,EACpBC,WAAW,EAAA,EAAIC,YAAYV,QAAQE;IAErE,MAAMS,YAAY;KAChB,GAAGX;KACHE;KACAU,MAAM;MACJC,cAAcV,SAASU;MACvBC,QAAQX,SAASW;MACjBC,QAAQZ,SAASY;MACjBC,OAAO9C,kBAAkBiC,SAASa,SAAS,CAAC,CAAC;MAC7C,GAAGhB,SAASY;KACd;IACF;IACA,MAAMK,kBACJ,MAAMzB,KAAKO,6BAA6BY,SAAS;IACnD,MAAMO,UAAUnC,YACZ,IAAIoC,QAAQF,iBAAiBC,WAAWlB,QAAQkB,OAAO,IACvDE,KAAAA;IACJF,SAASG,IAAI3C,4BAA4BuB,QAAQ;IAEjD,OAAO;KACL,GAAGgB;KACH,GAAIC,WAAW,EAAEA,QAAQ;KACzBN,MAAMK,iBAAiBL,QAAQ;MAC7B,GAAGD,UAAUC;MACbV;MACAoB,UAAUtB,QAAQsB;MAClBC,SAASvB,QAAQuB;MACjBC,WAAWxB,QAAQwB;MACnBC,UAAUzB,QAAQ0B;KACpB;IACF;GACF;EACF,CAAC;EAED,KAAK3C,YAAYA;EACjB,KAAKI,yBAAyBI;CAChC;CAEAoC,WAAW1C,SAA2B;EACpC,KAAKA,UAAUA;CACjB;CAEA2C,sBAAiE;EAC/D,OAAO,KAAK7C;CACd;CAEA8C,gCACEC,QACA;EACA,KAAK5C,oBAAoB4C;CAC3B;AACF;AAEA,SAASjC,uBACPd,WACAU,WAC+D;CAC/D,MAAMuC,YAAqCvC,aACtCyC,OAAOC,SAAS1C,UAAUyC,OAA4BC,IAAI,IAC3DF,WAAWvC,MAAM4C,KAAKL,UAAU;CAEpC,OAAO,OAAOC,OAAOC,SAAS;EAC5B,MAAMjB,UAAU,IAAIC,QAAQgB,MAAMjB,OAAO;EACzC,MAAMjB,WAAWiB,QAAQqB,IAAI7D,0BAA0B,KAAK0C,KAAAA;EAC5DF,QAAQsB,OAAO9D,0BAA0B;EACzC,MAAM+D,MAAM,MAAMT,UAAUE,OAAO;GAAE,GAAGC;GAAMjB;EAAQ,CAAC;EACvD,MAAMhB,KAAKuC,IAAIvB,QAAQqB,IAAIpE,0BAA0B;EACrD,IAAI+B,IAAInB,UAAU2D,QAAQC,YAAYzC,IAAID,QAAQ;EAClD,IAAI,CAACwC,IAAI7B,QAAQjC,mBAAmBiE,IAAIH,IAAII,MAAM,GAAG,OAAOJ;EAE5D,MAAMK,eAAe/D,UAAUgE,iBAAiBC;EAGhD,MAAMC,UAAU,IAAIC,YAAY;EAChC,IAAIC,cAAc;EAClB,MAAMC,MAAM,IAAIC,gBAAwC,EACtDE,UAAUC,OAAOC,YAAY;GAC3BA,WAAWC,QAAQF,KAAK;GACxBL,eAAeF,QAAQU,OAAOH,OAAO,EAAEI,QAAQ,KAAK,CAAC;GACrD,IAAId,aAAaU,OAAOL,WAAW,GAAG;IACpC,IAAI,CAACjD,MAAMnB,UAAU2D,QAAQmB,YAAY5D,QAAQ,MAAMC,IACrDnB,UAAU2D,QAAQoB,MAAM7D,QAAQ;IAElCkD,cAAc;GAChB,OAAO,IAAIA,YAAYY,SAASvF,qBAC9B2E,cAAcA,YAAYa,MAAM,KAAmB;EAEvD,EACF,CAAC;EAED,OAAO,IAAIC,SAASxB,IAAI7B,KAAKsD,YAAYd,GAAG,GAAG;GAC7CP,QAAQJ,IAAII;GACZsB,YAAY1B,IAAI0B;GAChBjD,SAASuB,IAAIvB;EACf,CAAC;CACH;AACF;AAEA,SAAS8B,qBAAqBoB,QAAoBjB,aAAqB;CACrE,OAAOA,YAAYkB,SAAS9F,aAAa;AAC3C;AAEA,SAASuB,qBACPf,WACAY,sBAGA;CACA,OAAO,OAAOK,YAAY;EACxB,MAAMsE,WAAWvF,UAAU2D,QAAQmB,YAAY7D,QAAQE,EAAE;EACzD,IAAI,CAACoE,UACH,MAAM,IAAIC,MACR,6EACF;EAEF,MAAMC,MACJ,OAAOzF,UAAU0F,cAAc,aAC3B1F,UAAU0F,UAAUH,QAAQ,IAC5BvF,UAAU0F;EAChB,MAAMC,eAAe,MAAM/E,uBAAuB;GAAE,GAAGK;GAASwE;EAAI,CAAC;EACrE,MAAMtD,UAAU,IAAIC,QAAQuD,cAAcxD,WAAWlB,QAAQkB,OAAO;EACpEA,QAAQG,IAAI3C,4BAA4BsB,QAAQE,EAAE;EAClD,OAAO;GACL,GAAGwE;GACHxD;GACAsD,KAAKE,cAAcF,OAAOA;EAC5B;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"AssistantChatTransport.js","names":["AssistantRuntime","ThreadListItemRuntime","DefaultChatTransport","HttpChatTransportInitOptions","UIMessage","toToolsJSONSchema","RESUMABLE_STREAM_ID_HEADER","AssistantChatResumableOptions","InitializableThreadListItem","Pick","FINISH_MARKER","FINISH_BUFFER_LIMIT","FINISH_BUFFER_TAIL","RESUMABLE_THREAD_ID_HEADER","RESUMABLE_RECONNECT_ID_HEADER","NULL_BODY_STATUSES","Set","AssistantChatTransportInitOptions","UI_MESSAGE","resumable","AssistantChatTransport","runtime","getThreadListItem","__internal_initOptions","__internal_clone","Constructor","constructor","initOptions","rest","userFetch","fetch","userPrepareReconnect","prepareReconnectToStreamRequest","wrapFetchWithResumable","wrapPrepareReconnect","prepareSendMessagesRequest","options","threadId","id","context","thread","getModelContext","threadListItem","threads","mainItem","initialize","remoteId","optionsEx","body","callSettings","system","config","tools","preparedRequest","headers","Headers","undefined","set","messages","trigger","messageId","metadata","requestMetadata","setRuntime","getResumableAdapter","__internal_setGetThreadListItem","getter","NonNullable","baseFetch","globalThis","input","init","RequestInfo","URL","bind","get","reconnectingStreamId","checkpointAtRequest","storage","getStreamId","delete","res","ownsCheckpoint","setStreamId","status","clear","has","detectFinish","isFinishEvent","defaultIsFinishEvent","decoder","TextDecoder","accumulator","tap","TransformStream","Uint8Array","transform","chunk","controller","enqueue","decode","stream","length","slice","Response","pipeThrough","statusText","_chunk","includes","streamId","Error","api","resumeApi","userPrepared"],"sources":["../../src/transport/AssistantChatTransport.ts"],"sourcesContent":["import type {\n AssistantRuntime,\n ThreadListItemRuntime,\n} from \"@assistant-ui/core\";\nimport {\n DefaultChatTransport,\n type HttpChatTransportInitOptions,\n type UIMessage,\n} from \"ai\";\nimport { toToolsJSONSchema } from \"assistant-stream\";\nimport {\n RESUMABLE_STREAM_ID_HEADER,\n type AssistantChatResumableOptions,\n} from \"./resumable\";\n\nexport type InitializableThreadListItem = Pick<\n ThreadListItemRuntime,\n \"initialize\"\n>;\n\nconst FINISH_MARKER = '\"type\":\"finish\"';\nconst FINISH_BUFFER_LIMIT = 4096;\nconst FINISH_BUFFER_TAIL = 1024;\nconst RESUMABLE_THREAD_ID_HEADER = \"x-assistant-ui-resumable-thread-id\";\nconst RESUMABLE_RECONNECT_ID_HEADER = \"x-assistant-ui-resumable-reconnect-id\";\n\n// 101/204/205/304 are null-body statuses per the fetch spec: `new Response(body, { status })`\n// throws for them, and WebKit returns a non-null empty body, so the body check alone does not guard it.\nconst NULL_BODY_STATUSES = new Set([101, 204, 205, 304]);\n\nexport type AssistantChatTransportInitOptions<UI_MESSAGE extends UIMessage> =\n HttpChatTransportInitOptions<UI_MESSAGE> & {\n resumable?: AssistantChatResumableOptions;\n };\n\nexport class AssistantChatTransport<\n UI_MESSAGE extends UIMessage,\n> extends DefaultChatTransport<UI_MESSAGE> {\n private runtime: AssistantRuntime | undefined;\n private getThreadListItem:\n | (() => InitializableThreadListItem | undefined)\n | undefined;\n private readonly resumable: AssistantChatResumableOptions | undefined;\n\n private readonly __internal_initOptions:\n | AssistantChatTransportInitOptions<UI_MESSAGE>\n | undefined;\n\n /** Constructs an unwired copy with the same init options. */\n public __internal_clone(): AssistantChatTransport<UI_MESSAGE> {\n const Constructor = this.constructor as new (\n initOptions?: AssistantChatTransportInitOptions<UI_MESSAGE>,\n ) => AssistantChatTransport<UI_MESSAGE>;\n return new Constructor(this.__internal_initOptions);\n }\n\n constructor(initOptions?: AssistantChatTransportInitOptions<UI_MESSAGE>) {\n const { resumable, ...rest } = initOptions ?? {};\n const userFetch = rest.fetch;\n const userPrepareReconnect = rest.prepareReconnectToStreamRequest;\n\n super({\n ...rest,\n ...(resumable && {\n fetch: wrapFetchWithResumable(resumable, userFetch),\n prepareReconnectToStreamRequest: wrapPrepareReconnect(\n resumable,\n userPrepareReconnect,\n ),\n }),\n prepareSendMessagesRequest: async (options) => {\n const threadId = options.id;\n const context = this.runtime?.thread.getModelContext();\n const threadListItem =\n this.getThreadListItem?.() ?? this.runtime?.threads.mainItem;\n const id = (await threadListItem?.initialize())?.remoteId ?? options.id;\n\n const optionsEx = {\n ...options,\n id,\n body: {\n callSettings: context?.callSettings,\n system: context?.system,\n config: context?.config,\n tools: toToolsJSONSchema(context?.tools ?? {}),\n ...options?.body,\n },\n };\n const preparedRequest =\n await rest.prepareSendMessagesRequest?.(optionsEx);\n const headers = resumable\n ? new Headers(preparedRequest?.headers ?? options.headers)\n : undefined;\n headers?.set(RESUMABLE_THREAD_ID_HEADER, threadId);\n\n return {\n ...preparedRequest,\n ...(headers && { headers }),\n body: preparedRequest?.body ?? {\n ...optionsEx.body,\n id,\n messages: options.messages,\n trigger: options.trigger,\n messageId: options.messageId,\n metadata: options.requestMetadata,\n },\n };\n },\n });\n\n this.resumable = resumable;\n this.__internal_initOptions = initOptions;\n }\n\n setRuntime(runtime: AssistantRuntime) {\n this.runtime = runtime;\n }\n\n getResumableAdapter(): AssistantChatResumableOptions | undefined {\n return this.resumable;\n }\n\n __internal_setGetThreadListItem(\n getter: () => InitializableThreadListItem | undefined,\n ) {\n this.getThreadListItem = getter;\n }\n}\n\nfunction wrapFetchWithResumable(\n resumable: AssistantChatResumableOptions,\n userFetch: HttpChatTransportInitOptions<UIMessage>[\"fetch\"],\n): NonNullable<HttpChatTransportInitOptions<UIMessage>[\"fetch\"]> {\n const baseFetch: typeof globalThis.fetch = userFetch\n ? (input, init) => userFetch(input as RequestInfo | URL, init)\n : globalThis.fetch.bind(globalThis);\n\n return async (input, init) => {\n const headers = new Headers(init?.headers);\n const threadId = headers.get(RESUMABLE_THREAD_ID_HEADER) ?? undefined;\n const reconnectingStreamId = headers.get(RESUMABLE_RECONNECT_ID_HEADER);\n const checkpointAtRequest =\n reconnectingStreamId ?? resumable.storage.getStreamId(threadId);\n headers.delete(RESUMABLE_THREAD_ID_HEADER);\n headers.delete(RESUMABLE_RECONNECT_ID_HEADER);\n const res = await baseFetch(input, { ...init, headers });\n const id = res.headers.get(RESUMABLE_STREAM_ID_HEADER);\n const ownsCheckpoint =\n !reconnectingStreamId ||\n resumable.storage.getStreamId(threadId) === reconnectingStreamId;\n if (id && ownsCheckpoint) resumable.storage.setStreamId(id, threadId);\n if (\n (res.status === 204 || res.status === 404) &&\n reconnectingStreamId &&\n resumable.storage.getStreamId(threadId) === reconnectingStreamId\n ) {\n resumable.storage.clear(threadId);\n }\n if (!res.body || NULL_BODY_STATUSES.has(res.status)) return res;\n\n const detectFinish = resumable.isFinishEvent ?? defaultIsFinishEvent;\n // a single decoder is required so multi-byte sequences split across\n // chunks buffer via stream: true rather than getting dropped.\n const decoder = new TextDecoder();\n let accumulator = \"\";\n const tap = new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n controller.enqueue(chunk);\n accumulator += decoder.decode(chunk, { stream: true });\n if (detectFinish(chunk, accumulator)) {\n if (\n ownsCheckpoint &&\n resumable.storage.getStreamId(threadId) ===\n (id ?? checkpointAtRequest)\n ) {\n resumable.storage.clear(threadId);\n }\n accumulator = \"\";\n } else if (accumulator.length > FINISH_BUFFER_LIMIT) {\n accumulator = accumulator.slice(-FINISH_BUFFER_TAIL);\n }\n },\n });\n\n return new Response(res.body.pipeThrough(tap), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n };\n}\n\nfunction defaultIsFinishEvent(_chunk: Uint8Array, accumulator: string) {\n return accumulator.includes(FINISH_MARKER);\n}\n\nfunction wrapPrepareReconnect(\n resumable: AssistantChatResumableOptions,\n userPrepareReconnect: HttpChatTransportInitOptions<UIMessage>[\"prepareReconnectToStreamRequest\"],\n): NonNullable<\n HttpChatTransportInitOptions<UIMessage>[\"prepareReconnectToStreamRequest\"]\n> {\n return async (options) => {\n const streamId = resumable.storage.getStreamId(options.id);\n if (!streamId) {\n throw new Error(\n \"AssistantChatTransport: no resumable stream id available; nothing to resume\",\n );\n }\n const api =\n typeof resumable.resumeApi === \"function\"\n ? resumable.resumeApi(streamId)\n : resumable.resumeApi;\n const userPrepared = await userPrepareReconnect?.({ ...options, api });\n const headers = new Headers(userPrepared?.headers ?? options.headers);\n headers.set(RESUMABLE_THREAD_ID_HEADER, options.id);\n headers.set(RESUMABLE_RECONNECT_ID_HEADER, streamId);\n return {\n ...userPrepared,\n headers,\n api: userPrepared?.api ?? api,\n };\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,37 +1,35 @@
|
|
|
1
|
-
//#region src/transport/resumable.d.ts
|
|
2
1
|
/** Response header used by the [Resumable Streams](/docs/guides/resumable-streams) server and client wiring. */
|
|
3
2
|
export declare const RESUMABLE_STREAM_ID_HEADER = "x-resumable-stream-id";
|
|
4
3
|
export type ResumableClientStorage = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
getStreamId(threadId?: string): string | null;
|
|
5
|
+
setStreamId(id: string, threadId?: string): void;
|
|
6
|
+
clear(threadId?: string): void;
|
|
7
|
+
/** Subscribes to stream id changes so automatic resume can react after mount. */
|
|
8
|
+
subscribe?(listener: () => void, threadId?: string): () => void;
|
|
10
9
|
};
|
|
11
10
|
/** `sessionStorage`-backed storage for the pending resumable stream id. See the [Resumable Streams](/docs/guides/resumable-streams) guide for end-to-end wiring. */
|
|
12
11
|
export declare function createResumableSessionStorage(options?: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Storage key for the pending stream id. A static string namespaces per route
|
|
14
|
+
* or chat surface. A getter is read lazily on every access, so the key can be
|
|
15
|
+
* derived from the active thread's identity; while the getter returns
|
|
16
|
+
* `undefined`, reads report no pending stream and writes are dropped, so a
|
|
17
|
+
* thread whose identity is not known yet never touches another thread's key.
|
|
18
|
+
*
|
|
19
|
+
* Under a remote thread list with more than one thread, scope the key per
|
|
20
|
+
* thread and create one storage instance per thread runtime rather than a
|
|
21
|
+
* single shared one. A shared key is written and cleared by whichever thread
|
|
22
|
+
* acts last, so one conversation's stream can resume inside another.
|
|
23
|
+
*/
|
|
24
|
+
key?: string | (() => string | undefined);
|
|
26
25
|
}): ResumableClientStorage;
|
|
27
26
|
export type AssistantChatResumableOptions = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
storage: ResumableClientStorage;
|
|
28
|
+
resumeApi: string | ((streamId: string) => string);
|
|
29
|
+
/**
|
|
30
|
+
* Defaults to scanning for the AI SDK UIMessageStream `finish` marker.
|
|
31
|
+
* Cancellation never invokes this callback, only natural completion does.
|
|
32
|
+
*/
|
|
33
|
+
isFinishEvent?: (chunk: Uint8Array, accumulator: string) => boolean;
|
|
35
34
|
};
|
|
36
|
-
//#endregion
|
|
37
35
|
//# sourceMappingURL=resumable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resumable.d.ts","
|
|
1
|
+
{"version":3,"file":"resumable.d.ts","sourceRoot":"","sources":["../../src/transport/resumable.ts"],"names":[],"mappings":"AAIA,gHAAgH;AAChH,eAAO,MAAM,0BAA0B,0BAAmC,CAAC;AAI3E,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iFAAiF;IACjF,SAAS,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;CACjE,CAAC;AAgBF,oKAAoK;AACpK,wBAAgB,6BAA6B,CAAC,OAAO,CAAC,EAAE;IACtD;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;CAC3C,GAAG,sBAAsB,CAwGzB;AAED,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,sBAAsB,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IACnD;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;CACrE,CAAC"}
|
package/dist/usage.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
/// <reference types="@assistant-ui/core/react" />
|
|
2
|
-
//#region src/usage.d.ts
|
|
1
|
+
/// <reference types="@assistant-ui/core/react" preserve="true" />
|
|
3
2
|
export type ThreadTokenUsage = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
totalTokens?: number;
|
|
4
|
+
inputTokens?: number;
|
|
5
|
+
outputTokens?: number;
|
|
6
|
+
reasoningTokens?: number;
|
|
7
|
+
cachedInputTokens?: number;
|
|
9
8
|
};
|
|
10
9
|
export interface TokenUsageExtractableMessage {
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
role?: string;
|
|
11
|
+
metadata?: unknown;
|
|
13
12
|
}
|
|
14
13
|
export declare function getThreadMessageTokenUsage(message: TokenUsageExtractableMessage | undefined): ThreadTokenUsage | undefined;
|
|
15
14
|
/**
|
|
@@ -21,5 +20,4 @@ export declare function getThreadMessageTokenUsage(message: TokenUsageExtractabl
|
|
|
21
20
|
* looks.
|
|
22
21
|
*/
|
|
23
22
|
export declare function useThreadTokenUsage(): ThreadTokenUsage | undefined;
|
|
24
|
-
//#endregion
|
|
25
23
|
//# sourceMappingURL=usage.d.ts.map
|
package/dist/usage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":";AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,4BAA4B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsHD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,4BAA4B,GAAG,SAAS,GAChD,gBAAgB,GAAG,SAAS,CAa9B;AAiBD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,GAAG,SAAS,CAGlE"}
|
package/dist/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","names":["useMemo","useAuiState","ThreadTokenUsage","totalTokens","inputTokens","outputTokens","reasoningTokens","cachedInputTokens","TokenUsageExtractableMessage","role","metadata","UsageRecord","Record","USAGE_KEYS","const","asRecord","value","Array","isArray","undefined","asPositiveTokenCount","Number","isFinite","computeTotalTokens","usage","normalizeUsage","record","result","hasFields","key","count","outputTokenDetails","inputTokenDetails","cacheReadTokens","withComputedTotal","usageFromSteps","steps","sums","present","stepsWithUsage","stepsWithComputableTotal","step","stepTotal","getThreadMessageTokenUsage","message","topLevelUsage","customUsage","custom","findLatestMessageWithUsage","messages","idx","length","useThreadTokenUsage","$","_c","msg","_temp","t0","s","thread"],"sources":["../src/usage.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/react\" />\nimport { useMemo } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport type ThreadTokenUsage = {\n totalTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n};\n\nexport interface TokenUsageExtractableMessage {\n role?: string;\n metadata?: unknown;\n}\n\ntype UsageRecord = Record<string, unknown>;\n\nconst USAGE_KEYS = [\n \"inputTokens\",\n \"outputTokens\",\n \"reasoningTokens\",\n \"cachedInputTokens\",\n \"totalTokens\",\n] as const satisfies (keyof ThreadTokenUsage)[];\n\nfunction asRecord(value: unknown): UsageRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UsageRecord;\n}\n\nfunction asPositiveTokenCount(value: unknown): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n return undefined;\n }\n return value;\n}\n\nfunction computeTotalTokens(usage: ThreadTokenUsage): number | undefined {\n if (usage.totalTokens !== undefined) return usage.totalTokens;\n if (usage.inputTokens !== undefined && usage.outputTokens !== undefined) {\n return usage.inputTokens + usage.outputTokens;\n }\n return undefined;\n}\n\nfunction normalizeUsage(value: unknown): ThreadTokenUsage | undefined {\n const record = asRecord(value);\n if (!record) return undefined;\n\n const result: ThreadTokenUsage = {};\n let hasFields = false;\n for (const key of USAGE_KEYS) {\n const count = asPositiveTokenCount(record[key]);\n if (count !== undefined) {\n result[key] = count;\n hasFields = true;\n }\n }\n // AI SDK v7 moved these under token detail objects; v6 kept them top-level.\n if (result.reasoningTokens === undefined) {\n const count = asPositiveTokenCount(\n asRecord(record.outputTokenDetails)?.reasoningTokens,\n );\n if (count !== undefined) {\n result.reasoningTokens = count;\n hasFields = true;\n }\n }\n if (result.cachedInputTokens === undefined) {\n const count = asPositiveTokenCount(\n asRecord(record.inputTokenDetails)?.cacheReadTokens,\n );\n if (count !== undefined) {\n result.cachedInputTokens = count;\n hasFields = true;\n }\n }\n return hasFields ? result : undefined;\n}\n\nfunction withComputedTotal(\n usage: ThreadTokenUsage,\n): ThreadTokenUsage | undefined {\n const totalTokens = computeTotalTokens(usage);\n return { ...usage, ...(totalTokens !== undefined && { totalTokens }) };\n}\n\nfunction usageFromSteps(value: unknown): ThreadTokenUsage | undefined {\n const steps = Array.isArray(value) ? value : [];\n\n const sums: Record<string, number> = {};\n const present: Record<string, boolean> = {};\n let stepsWithUsage = 0;\n let stepsWithComputableTotal = 0;\n\n for (const step of steps) {\n const usage = normalizeUsage(asRecord(step)?.usage);\n if (!usage) continue;\n stepsWithUsage++;\n\n const stepTotal = computeTotalTokens(usage);\n if (stepTotal !== undefined) {\n sums.totalTokens = (sums.totalTokens ?? 0) + stepTotal;\n stepsWithComputableTotal++;\n }\n\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (usage[key] !== undefined) {\n sums[key] = (sums[key] ?? 0) + usage[key];\n present[key] = true;\n }\n }\n }\n\n if (stepsWithUsage === 0) return undefined;\n\n const result: ThreadTokenUsage = {};\n if (stepsWithComputableTotal === stepsWithUsage) {\n result.totalTokens = sums.totalTokens!;\n }\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (present[key]) {\n result[key] = sums[key]!;\n }\n }\n return result;\n}\n\nexport function getThreadMessageTokenUsage(\n message: TokenUsageExtractableMessage | undefined,\n): ThreadTokenUsage | undefined {\n if (!message || message.role !== \"assistant\") return undefined;\n\n const metadata = asRecord(message.metadata);\n if (!metadata) return undefined;\n\n const topLevelUsage = normalizeUsage(metadata.usage);\n if (topLevelUsage) return withComputedTotal(topLevelUsage);\n\n const customUsage = normalizeUsage(asRecord(metadata.custom)?.usage);\n if (customUsage) return withComputedTotal(customUsage);\n\n return usageFromSteps(metadata.steps);\n}\n\nfunction findLatestMessageWithUsage(\n messages: readonly TokenUsageExtractableMessage[] | undefined,\n): TokenUsageExtractableMessage | undefined {\n if (!messages) return undefined;\n\n for (let idx = messages.length - 1; idx >= 0; idx -= 1) {\n const message = messages[idx];\n if (getThreadMessageTokenUsage(message)) {\n return message;\n }\n }\n\n return undefined;\n}\n\n/**\n * Reads token usage from the newest assistant message that reports any.\n *\n * A route attaches usage through the AI SDK's `messageMetadata` option. Because\n * a thread message carries a fixed metadata shape, the converter moves every\n * other key the route returns into `metadata.custom`, which is where this hook\n * looks.\n */\nexport function useThreadTokenUsage(): ThreadTokenUsage | undefined {\n const msg = useAuiState((s) => findLatestMessageWithUsage(s.thread.messages));\n return useMemo(() => getThreadMessageTokenUsage(msg), [msg]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usage.js","names":["useMemo","useAuiState","ThreadTokenUsage","totalTokens","inputTokens","outputTokens","reasoningTokens","cachedInputTokens","TokenUsageExtractableMessage","role","metadata","UsageRecord","Record","USAGE_KEYS","const","asRecord","value","Array","isArray","undefined","asPositiveTokenCount","Number","isFinite","computeTotalTokens","usage","normalizeUsage","record","result","hasFields","key","count","outputTokenDetails","inputTokenDetails","cacheReadTokens","withComputedTotal","usageFromSteps","steps","sums","present","stepsWithUsage","stepsWithComputableTotal","step","stepTotal","getThreadMessageTokenUsage","message","topLevelUsage","customUsage","custom","findLatestMessageWithUsage","messages","idx","length","useThreadTokenUsage","$","_c","msg","_temp","t0","s","thread"],"sources":["../src/usage.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/react\" preserve=\"true\" />\nimport { useMemo } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport type ThreadTokenUsage = {\n totalTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n};\n\nexport interface TokenUsageExtractableMessage {\n role?: string;\n metadata?: unknown;\n}\n\ntype UsageRecord = Record<string, unknown>;\n\nconst USAGE_KEYS = [\n \"inputTokens\",\n \"outputTokens\",\n \"reasoningTokens\",\n \"cachedInputTokens\",\n \"totalTokens\",\n] as const satisfies (keyof ThreadTokenUsage)[];\n\nfunction asRecord(value: unknown): UsageRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UsageRecord;\n}\n\nfunction asPositiveTokenCount(value: unknown): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n return undefined;\n }\n return value;\n}\n\nfunction computeTotalTokens(usage: ThreadTokenUsage): number | undefined {\n if (usage.totalTokens !== undefined) return usage.totalTokens;\n if (usage.inputTokens !== undefined && usage.outputTokens !== undefined) {\n return usage.inputTokens + usage.outputTokens;\n }\n return undefined;\n}\n\nfunction normalizeUsage(value: unknown): ThreadTokenUsage | undefined {\n const record = asRecord(value);\n if (!record) return undefined;\n\n const result: ThreadTokenUsage = {};\n let hasFields = false;\n for (const key of USAGE_KEYS) {\n const count = asPositiveTokenCount(record[key]);\n if (count !== undefined) {\n result[key] = count;\n hasFields = true;\n }\n }\n // AI SDK v7 moved these under token detail objects; v6 kept them top-level.\n if (result.reasoningTokens === undefined) {\n const count = asPositiveTokenCount(\n asRecord(record.outputTokenDetails)?.reasoningTokens,\n );\n if (count !== undefined) {\n result.reasoningTokens = count;\n hasFields = true;\n }\n }\n if (result.cachedInputTokens === undefined) {\n const count = asPositiveTokenCount(\n asRecord(record.inputTokenDetails)?.cacheReadTokens,\n );\n if (count !== undefined) {\n result.cachedInputTokens = count;\n hasFields = true;\n }\n }\n return hasFields ? result : undefined;\n}\n\nfunction withComputedTotal(\n usage: ThreadTokenUsage,\n): ThreadTokenUsage | undefined {\n const totalTokens = computeTotalTokens(usage);\n return { ...usage, ...(totalTokens !== undefined && { totalTokens }) };\n}\n\nfunction usageFromSteps(value: unknown): ThreadTokenUsage | undefined {\n const steps = Array.isArray(value) ? value : [];\n\n const sums: Record<string, number> = {};\n const present: Record<string, boolean> = {};\n let stepsWithUsage = 0;\n let stepsWithComputableTotal = 0;\n\n for (const step of steps) {\n const usage = normalizeUsage(asRecord(step)?.usage);\n if (!usage) continue;\n stepsWithUsage++;\n\n const stepTotal = computeTotalTokens(usage);\n if (stepTotal !== undefined) {\n sums.totalTokens = (sums.totalTokens ?? 0) + stepTotal;\n stepsWithComputableTotal++;\n }\n\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (usage[key] !== undefined) {\n sums[key] = (sums[key] ?? 0) + usage[key];\n present[key] = true;\n }\n }\n }\n\n if (stepsWithUsage === 0) return undefined;\n\n const result: ThreadTokenUsage = {};\n if (stepsWithComputableTotal === stepsWithUsage) {\n result.totalTokens = sums.totalTokens!;\n }\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (present[key]) {\n result[key] = sums[key]!;\n }\n }\n return result;\n}\n\nexport function getThreadMessageTokenUsage(\n message: TokenUsageExtractableMessage | undefined,\n): ThreadTokenUsage | undefined {\n if (!message || message.role !== \"assistant\") return undefined;\n\n const metadata = asRecord(message.metadata);\n if (!metadata) return undefined;\n\n const topLevelUsage = normalizeUsage(metadata.usage);\n if (topLevelUsage) return withComputedTotal(topLevelUsage);\n\n const customUsage = normalizeUsage(asRecord(metadata.custom)?.usage);\n if (customUsage) return withComputedTotal(customUsage);\n\n return usageFromSteps(metadata.steps);\n}\n\nfunction findLatestMessageWithUsage(\n messages: readonly TokenUsageExtractableMessage[] | undefined,\n): TokenUsageExtractableMessage | undefined {\n if (!messages) return undefined;\n\n for (let idx = messages.length - 1; idx >= 0; idx -= 1) {\n const message = messages[idx];\n if (getThreadMessageTokenUsage(message)) {\n return message;\n }\n }\n\n return undefined;\n}\n\n/**\n * Reads token usage from the newest assistant message that reports any.\n *\n * A route attaches usage through the AI SDK's `messageMetadata` option. Because\n * a thread message carries a fixed metadata shape, the converter moves every\n * other key the route returns into `metadata.custom`, which is where this hook\n * looks.\n */\nexport function useThreadTokenUsage(): ThreadTokenUsage | undefined {\n const msg = useAuiState((s) => findLatestMessageWithUsage(s.thread.messages));\n return useMemo(() => getThreadMessageTokenUsage(msg), [msg]);\n}\n"],"mappings":"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"}
|