@assistant-ui/react-ai-sdk 1.3.9 → 1.3.10

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/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export * from "./ui/index.js";
2
2
  export { frontendTools } from "./frontendTools.js";
3
+ export type { ThreadTokenUsage, TokenUsageExtractableMessage } from "./usage.js";
4
+ export { getThreadMessageTokenUsage, useThreadTokenUsage } from "./usage.js";
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,2BAAwB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,2BAAwB;AAChD,YAAY,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,mBAAgB;AAC9E,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,mBAAgB"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./ui/index.js";
2
2
  export { frontendTools } from "./frontendTools.js";
3
+ export { getThreadMessageTokenUsage, useThreadTokenUsage } from "./usage.js";
3
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,2BAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,2BAAwB;AAEhD,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,mBAAgB"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzE,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAQrB,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAgB7B,MAAM,MAAM,6BAA6B,GAAG,CAC1C,UAAU,SAAS,SAAS,GAAG,SAAS,EAExC,OAAO,EAAE,aAAa,KACnB,eAAe,CAAC,UAAU,CAAC,CAAC;AAEjC,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EACL,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,GAAG;QAC/C,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;KAC5C,CAAC,GACF,SAAS,CAAC;IACd,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD;;;;;;;OAOG;IACH,4BAA4B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,aAAa,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,EACnD,sFAIG,mBAAwB,qBAkO5B,CAAC"}
1
+ {"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzE,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAQrB,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAgB7B,MAAM,MAAM,6BAA6B,GAAG,CAC1C,UAAU,SAAS,SAAS,GAAG,SAAS,EAExC,OAAO,EAAE,aAAa,KACnB,eAAe,CAAC,UAAU,CAAC,CAAC;AAEjC,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EACL,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,GAAG;QAC/C,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;KAC5C,CAAC,GACF,SAAS,CAAC;IACd,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD;;;;;;;OAOG;IACH,4BAA4B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,aAAa,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,EACnD,sFAIG,mBAAwB,qBAsO5B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useState, useMemo } from "react";
2
+ import { useState, useMemo, useRef } from "react";
3
3
  import { isToolUIPart } from "ai";
4
4
  import { useExternalStoreRuntime, useRuntimeAdapters, INTERNAL, getExternalStoreMessages, } from "@assistant-ui/react";
5
5
  import { sliceMessagesUntil } from "../utils/sliceMessagesUntil.js";
@@ -13,6 +13,7 @@ import { useStreamingTiming } from "./useStreamingTiming.js";
13
13
  export const useAISDKRuntime = (chatHelpers, { adapters, toCreateMessage: customToCreateMessage, cancelPendingToolCallsOnSend = true, } = {}) => {
14
14
  const contextAdapters = useRuntimeAdapters();
15
15
  const [toolStatuses, setToolStatuses] = useState({});
16
+ const toolArgsKeyOrderCacheRef = useRef(new Map());
16
17
  const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
17
18
  const isRunning = chatHelpers.status === "submitted" ||
18
19
  chatHelpers.status === "streaming" ||
@@ -24,6 +25,7 @@ export const useAISDKRuntime = (chatHelpers, { adapters, toCreateMessage: custom
24
25
  metadata: useMemo(() => ({
25
26
  toolStatuses,
26
27
  messageTiming,
28
+ toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,
27
29
  ...(chatHelpers.error && { error: chatHelpers.error.message }),
28
30
  }), [toolStatuses, messageTiming, chatHelpers.error]),
29
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"useAISDKRuntime.js","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAISDKRuntime.js","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import { type UIMessage } from "ai";
2
2
  import { type useExternalMessageConverter } from "@assistant-ui/react";
3
+ export type AISDKMessageConverterMetadata = useExternalMessageConverter.Metadata & {
4
+ toolArgsKeyOrderCache?: Map<string, Map<string, string[]>>;
5
+ };
3
6
  export declare const AISDKMessageConverter: {
4
7
  useThreadMessages: ({ messages, isRunning, joinStrategy, metadata, }: {
5
8
  messages: UIMessage<unknown, import("ai").UIDataTypes, import("ai").UITools>[];
@@ -1 +1 @@
1
- {"version":3,"file":"convertMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/D,OAAO,EAOL,KAAK,2BAA2B,EAEjC,MAAM,qBAAqB,CAAC;AA2J7B,eAAO,MAAM,qBAAqB;;;;;;;;wHA7IL,qDAAyB;uHAGb,qDACtB;;;CAmMlB,CAAC"}
1
+ {"version":3,"file":"convertMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/D,OAAO,EAOL,KAAK,2BAA2B,EAEjC,MAAM,qBAAqB,CAAC;AAI7B,MAAM,MAAM,6BAA6B,GACvC,2BAA2B,CAAC,QAAQ,GAAG;IACrC,qBAAqB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;CAC5D,CAAC;AAmNJ,eAAO,MAAM,qBAAqB;;;;;;;;wHA5MhB,qDAAyB;uHAKpC,qDAAyB;;;CAiQ/B,CAAC"}
@@ -3,6 +3,34 @@ import { unstable_createMessageConverter, } from "@assistant-ui/react";
3
3
  function stripClosingDelimiters(json) {
4
4
  return json.replace(/[}\]"]+$/, "");
5
5
  }
6
+ const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
7
+ const stabilizeToolArgsValue = (value, path, keyOrderByPath) => {
8
+ if (Array.isArray(value)) {
9
+ return value.map((item, idx) => stabilizeToolArgsValue(item, `${path}[${idx}]`, keyOrderByPath));
10
+ }
11
+ if (value && typeof value === "object") {
12
+ const record = value;
13
+ const currentKeys = Object.keys(record);
14
+ const previousOrder = keyOrderByPath.get(path) ?? [];
15
+ const previousOrderSet = new Set(previousOrder);
16
+ const nextOrder = [
17
+ ...previousOrder.filter((key) => hasOwn(record, key)),
18
+ ...currentKeys.filter((key) => !previousOrderSet.has(key)),
19
+ ];
20
+ keyOrderByPath.set(path, nextOrder);
21
+ return Object.fromEntries(nextOrder.map((key) => [
22
+ key,
23
+ stabilizeToolArgsValue(record[key], `${path}.${key}`, keyOrderByPath),
24
+ ]));
25
+ }
26
+ return value;
27
+ };
28
+ function stableStringifyToolArgs(keyOrderCache, cacheKey, args) {
29
+ const keyOrderByPath = keyOrderCache?.get(cacheKey) ?? new Map();
30
+ keyOrderCache?.set(cacheKey, keyOrderByPath);
31
+ const stableArgs = stabilizeToolArgsValue(args, "$", keyOrderByPath);
32
+ return JSON.stringify(stableArgs);
33
+ }
6
34
  /**
7
35
  * Resolves the interrupt fields for a tool call part.
8
36
  *
@@ -56,6 +84,7 @@ function convertParts(message, metadata) {
56
84
  if (isToolUIPart(part)) {
57
85
  const toolName = getToolName(part);
58
86
  const toolCallId = part.toolCallId;
87
+ const argsKeyOrderCacheKey = `${message.id}:${toolCallId}`;
59
88
  const args = part.input || {};
60
89
  let result;
61
90
  let isError = false;
@@ -73,11 +102,14 @@ function convertParts(message, metadata) {
73
102
  "Tool approval denied",
74
103
  };
75
104
  }
76
- let argsText = JSON.stringify(args);
105
+ let argsText = stableStringifyToolArgs(metadata.toolArgsKeyOrderCache, argsKeyOrderCacheKey, args);
77
106
  if (part.state === "input-streaming") {
78
107
  // strip closing delimiters added by the AI SDK's fix-json
79
108
  argsText = stripClosingDelimiters(argsText);
80
109
  }
110
+ else {
111
+ metadata.toolArgsKeyOrderCache?.delete(argsKeyOrderCacheKey);
112
+ }
81
113
  const toolStatus = metadata.toolStatuses?.[toolCallId];
82
114
  return {
83
115
  type: "tool-call",
@@ -1 +1 @@
1
- {"version":3,"file":"convertMessage.js","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"convertMessage.js","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export type ThreadTokenUsage = {
2
+ totalTokens?: number;
3
+ inputTokens?: number;
4
+ outputTokens?: number;
5
+ reasoningTokens?: number;
6
+ cachedInputTokens?: number;
7
+ };
8
+ export interface TokenUsageExtractableMessage {
9
+ role?: string;
10
+ metadata?: unknown;
11
+ }
12
+ export declare function getThreadMessageTokenUsage(message: TokenUsageExtractableMessage | undefined): ThreadTokenUsage | undefined;
13
+ export declare function useThreadTokenUsage(): ThreadTokenUsage | undefined;
14
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AACA,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;AACF,MAAM,WAAW,4BAA4B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA8ID,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,4BAA4B,GAAG,SAAS,GAChD,gBAAgB,GAAG,SAAS,CAa9B;AACD,wBAAgB,mBAAmB,IAAI,gBAAgB,GAAG,SAAS,CAKlE"}
package/dist/usage.js ADDED
@@ -0,0 +1,158 @@
1
+ import { useAuiState } from "@assistant-ui/react";
2
+ function asRecord(value) {
3
+ if (!value || typeof value !== "object" || Array.isArray(value))
4
+ return undefined;
5
+ return value;
6
+ }
7
+ function asPositiveTokenCount(value) {
8
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
9
+ return undefined;
10
+ }
11
+ return value;
12
+ }
13
+ function hasAnyUsageField(parsed) {
14
+ return (parsed.inputTokens !== undefined ||
15
+ parsed.outputTokens !== undefined ||
16
+ parsed.reasoningTokens !== undefined ||
17
+ parsed.cachedInputTokens !== undefined ||
18
+ parsed.totalTokens !== undefined);
19
+ }
20
+ function normalizeUsage(value) {
21
+ const usage = asRecord(value);
22
+ if (!usage)
23
+ return undefined;
24
+ const inputTokens = asPositiveTokenCount(usage.inputTokens);
25
+ const outputTokens = asPositiveTokenCount(usage.outputTokens);
26
+ const reasoningTokens = asPositiveTokenCount(usage.reasoningTokens);
27
+ const cachedInputTokens = asPositiveTokenCount(usage.cachedInputTokens);
28
+ const totalTokens = asPositiveTokenCount(usage.totalTokens);
29
+ const result = {};
30
+ if (inputTokens !== undefined)
31
+ result.inputTokens = inputTokens;
32
+ if (outputTokens !== undefined)
33
+ result.outputTokens = outputTokens;
34
+ if (reasoningTokens !== undefined)
35
+ result.reasoningTokens = reasoningTokens;
36
+ if (cachedInputTokens !== undefined)
37
+ result.cachedInputTokens = cachedInputTokens;
38
+ if (totalTokens !== undefined)
39
+ result.totalTokens = totalTokens;
40
+ if (!hasAnyUsageField(result)) {
41
+ return undefined;
42
+ }
43
+ return result;
44
+ }
45
+ function buildUsageResult(parsed) {
46
+ if (!hasAnyUsageField(parsed)) {
47
+ return undefined;
48
+ }
49
+ const hasBothInputAndOutput = parsed.inputTokens !== undefined && parsed.outputTokens !== undefined;
50
+ const totalTokens = parsed.totalTokens ??
51
+ (hasBothInputAndOutput
52
+ ? (parsed.inputTokens ?? 0) + (parsed.outputTokens ?? 0)
53
+ : undefined);
54
+ const result = {};
55
+ if (totalTokens !== undefined)
56
+ result.totalTokens = totalTokens;
57
+ if (parsed.inputTokens !== undefined)
58
+ result.inputTokens = parsed.inputTokens;
59
+ if (parsed.outputTokens !== undefined)
60
+ result.outputTokens = parsed.outputTokens;
61
+ if (parsed.reasoningTokens !== undefined)
62
+ result.reasoningTokens = parsed.reasoningTokens;
63
+ if (parsed.cachedInputTokens !== undefined)
64
+ result.cachedInputTokens = parsed.cachedInputTokens;
65
+ return result;
66
+ }
67
+ function usageFromSteps(value) {
68
+ const steps = Array.isArray(value) ? value : [];
69
+ let inputTokens = 0;
70
+ let outputTokens = 0;
71
+ let reasoningTokens = 0;
72
+ let cachedInputTokens = 0;
73
+ let totalTokens = 0;
74
+ let hasInput = false;
75
+ let hasOutput = false;
76
+ let hasReasoning = false;
77
+ let hasCachedInput = false;
78
+ let stepsWithUsage = 0;
79
+ let stepsWithComputableTotal = 0;
80
+ for (const step of steps) {
81
+ const usage = normalizeUsage(asRecord(step)?.usage);
82
+ if (!usage)
83
+ continue;
84
+ stepsWithUsage++;
85
+ const stepHasBothInputAndOutput = usage.inputTokens !== undefined && usage.outputTokens !== undefined;
86
+ const stepTotal = usage.totalTokens ??
87
+ (stepHasBothInputAndOutput
88
+ ? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)
89
+ : undefined);
90
+ if (stepTotal !== undefined) {
91
+ totalTokens += stepTotal;
92
+ stepsWithComputableTotal++;
93
+ }
94
+ if (usage.inputTokens !== undefined) {
95
+ inputTokens += usage.inputTokens;
96
+ hasInput = true;
97
+ }
98
+ if (usage.outputTokens !== undefined) {
99
+ outputTokens += usage.outputTokens;
100
+ hasOutput = true;
101
+ }
102
+ if (usage.reasoningTokens !== undefined) {
103
+ reasoningTokens += usage.reasoningTokens;
104
+ hasReasoning = true;
105
+ }
106
+ if (usage.cachedInputTokens !== undefined) {
107
+ cachedInputTokens += usage.cachedInputTokens;
108
+ hasCachedInput = true;
109
+ }
110
+ }
111
+ if (stepsWithUsage === 0)
112
+ return undefined;
113
+ const parsed = {};
114
+ if (hasInput)
115
+ parsed.inputTokens = inputTokens;
116
+ if (hasOutput)
117
+ parsed.outputTokens = outputTokens;
118
+ if (hasReasoning)
119
+ parsed.reasoningTokens = reasoningTokens;
120
+ if (hasCachedInput)
121
+ parsed.cachedInputTokens = cachedInputTokens;
122
+ if (stepsWithComputableTotal === stepsWithUsage) {
123
+ parsed.totalTokens = totalTokens;
124
+ }
125
+ const result = {};
126
+ if (parsed.totalTokens !== undefined)
127
+ result.totalTokens = parsed.totalTokens;
128
+ if (parsed.inputTokens !== undefined)
129
+ result.inputTokens = parsed.inputTokens;
130
+ if (parsed.outputTokens !== undefined)
131
+ result.outputTokens = parsed.outputTokens;
132
+ if (parsed.reasoningTokens !== undefined)
133
+ result.reasoningTokens = parsed.reasoningTokens;
134
+ if (parsed.cachedInputTokens !== undefined)
135
+ result.cachedInputTokens = parsed.cachedInputTokens;
136
+ return result;
137
+ }
138
+ export function getThreadMessageTokenUsage(message) {
139
+ if (!message || message.role !== "assistant")
140
+ return undefined;
141
+ const metadata = asRecord(message.metadata);
142
+ if (!metadata)
143
+ return undefined;
144
+ const topLevelUsage = normalizeUsage(metadata.usage);
145
+ if (topLevelUsage) {
146
+ return buildUsageResult(topLevelUsage);
147
+ }
148
+ const legacyUsage = normalizeUsage(asRecord(metadata.custom)?.usage);
149
+ if (legacyUsage) {
150
+ return buildUsageResult(legacyUsage);
151
+ }
152
+ return usageFromSteps(metadata.steps);
153
+ }
154
+ export function useThreadTokenUsage() {
155
+ const lastAssistant = useAuiState((s) => s.thread.messages.findLast((m) => m.role === "assistant"));
156
+ return getThreadMessageTokenUsage(lastAssistant);
157
+ }
158
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-ai-sdk",
3
- "version": "1.3.9",
3
+ "version": "1.3.10",
4
4
  "description": "Vercel AI SDK adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "ai-sdk",
@@ -36,7 +36,7 @@
36
36
  "zod": "^4.3.6"
37
37
  },
38
38
  "peerDependencies": {
39
- "@assistant-ui/react": "^0.12.12",
39
+ "@assistant-ui/react": "^0.12.14",
40
40
  "@types/react": "*",
41
41
  "assistant-cloud": "*",
42
42
  "react": "^18 || ^19"
@@ -57,7 +57,7 @@
57
57
  "jsdom": "^28.1.0",
58
58
  "react": "^19.2.4",
59
59
  "vitest": "^4.0.18",
60
- "@assistant-ui/react": "0.12.12",
60
+ "@assistant-ui/react": "0.12.14",
61
61
  "@assistant-ui/x-buildutils": "0.0.1",
62
62
  "assistant-stream": "0.3.4"
63
63
  },
package/src/index.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from "./ui";
2
2
  export { frontendTools } from "./frontendTools";
3
+ export type { ThreadTokenUsage, TokenUsageExtractableMessage } from "./usage";
4
+ export { getThreadMessageTokenUsage, useThreadTokenUsage } from "./usage";
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useState, useMemo } from "react";
3
+ import { useState, useMemo, useRef } from "react";
4
4
  import type { UIMessage, useChat, CreateUIMessage } from "@ai-sdk/react";
5
5
  import { isToolUIPart } from "ai";
6
6
  import {
@@ -69,6 +69,9 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
69
69
  const [toolStatuses, setToolStatuses] = useState<
70
70
  Record<string, ToolExecutionStatus>
71
71
  >({});
72
+ const toolArgsKeyOrderCacheRef = useRef<Map<string, Map<string, string[]>>>(
73
+ new Map(),
74
+ );
72
75
 
73
76
  const hasExecutingTools = Object.values(toolStatuses).some(
74
77
  (s) => s?.type === "executing",
@@ -87,6 +90,7 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
87
90
  () => ({
88
91
  toolStatuses,
89
92
  messageTiming,
93
+ toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,
90
94
  ...(chatHelpers.error && { error: chatHelpers.error.message }),
91
95
  }),
92
96
  [toolStatuses, messageTiming, chatHelpers.error],
@@ -122,4 +122,76 @@ describe("AISDKMessageConverter", () => {
122
122
  );
123
123
  expect(toolCall?.argsText).toBe('{"city":"NYC');
124
124
  });
125
+
126
+ it("keeps observed key order from streaming snapshots for final tool args", () => {
127
+ const metadata = {
128
+ toolArgsKeyOrderCache: new Map<string, Map<string, string[]>>(),
129
+ };
130
+
131
+ const streaming = AISDKMessageConverter.toThreadMessages(
132
+ [
133
+ {
134
+ id: "a1",
135
+ role: "assistant",
136
+ parts: [
137
+ {
138
+ type: "tool-stocks",
139
+ toolCallId: "tc-order-1",
140
+ state: "input-streaming",
141
+ input: {
142
+ type: "high_stock_model",
143
+ limit: 5,
144
+ filters: {
145
+ region: "us",
146
+ sector: "tech",
147
+ },
148
+ },
149
+ },
150
+ ],
151
+ } as any,
152
+ ],
153
+ false,
154
+ metadata,
155
+ );
156
+
157
+ const streamingToolCall = streaming[0]?.content.find(
158
+ (part): part is any => part.type === "tool-call",
159
+ );
160
+ expect(streamingToolCall?.argsText).toBe(
161
+ '{"type":"high_stock_model","limit":5,"filters":{"region":"us","sector":"tech',
162
+ );
163
+
164
+ const final = AISDKMessageConverter.toThreadMessages(
165
+ [
166
+ {
167
+ id: "a1",
168
+ role: "assistant",
169
+ parts: [
170
+ {
171
+ type: "tool-stocks",
172
+ toolCallId: "tc-order-1",
173
+ state: "input-available",
174
+ input: {
175
+ filters: {
176
+ sector: "tech",
177
+ region: "us",
178
+ },
179
+ limit: 5,
180
+ type: "high_stock_model",
181
+ },
182
+ },
183
+ ],
184
+ } as any,
185
+ ],
186
+ false,
187
+ metadata,
188
+ );
189
+
190
+ const finalToolCall = final[0]?.content.find(
191
+ (part): part is any => part.type === "tool-call",
192
+ );
193
+ expect(finalToolCall?.argsText).toBe(
194
+ '{"type":"high_stock_model","limit":5,"filters":{"region":"us","sector":"tech"}}',
195
+ );
196
+ });
125
197
  });
@@ -12,11 +12,67 @@ import {
12
12
  import type { ReadonlyJSONObject } from "assistant-stream/utils";
13
13
 
14
14
  type MessageMetadata = ThreadMessageLike["metadata"];
15
+ export type AISDKMessageConverterMetadata =
16
+ useExternalMessageConverter.Metadata & {
17
+ toolArgsKeyOrderCache?: Map<string, Map<string, string[]>>;
18
+ };
15
19
 
16
20
  function stripClosingDelimiters(json: string): string {
17
21
  return json.replace(/[}\]"]+$/, "");
18
22
  }
19
23
 
24
+ const hasOwn = (value: object, key: string) =>
25
+ Object.prototype.hasOwnProperty.call(value, key);
26
+
27
+ const stabilizeToolArgsValue = (
28
+ value: unknown,
29
+ path: string,
30
+ keyOrderByPath: Map<string, string[]>,
31
+ ): unknown => {
32
+ if (Array.isArray(value)) {
33
+ return value.map((item, idx) =>
34
+ stabilizeToolArgsValue(item, `${path}[${idx}]`, keyOrderByPath),
35
+ );
36
+ }
37
+
38
+ if (value && typeof value === "object") {
39
+ const record = value as Record<string, unknown>;
40
+ const currentKeys = Object.keys(record);
41
+ const previousOrder = keyOrderByPath.get(path) ?? [];
42
+ const previousOrderSet = new Set(previousOrder);
43
+ const nextOrder = [
44
+ ...previousOrder.filter((key) => hasOwn(record, key)),
45
+ ...currentKeys.filter((key) => !previousOrderSet.has(key)),
46
+ ];
47
+ keyOrderByPath.set(path, nextOrder);
48
+
49
+ return Object.fromEntries(
50
+ nextOrder.map((key) => [
51
+ key,
52
+ stabilizeToolArgsValue(record[key], `${path}.${key}`, keyOrderByPath),
53
+ ]),
54
+ );
55
+ }
56
+
57
+ return value;
58
+ };
59
+
60
+ function stableStringifyToolArgs(
61
+ keyOrderCache: Map<string, Map<string, string[]>> | undefined,
62
+ cacheKey: string,
63
+ args: ReadonlyJSONObject,
64
+ ): string {
65
+ const keyOrderByPath = keyOrderCache?.get(cacheKey) ?? new Map();
66
+ keyOrderCache?.set(cacheKey, keyOrderByPath);
67
+
68
+ const stableArgs = stabilizeToolArgsValue(
69
+ args,
70
+ "$",
71
+ keyOrderByPath,
72
+ ) as ReadonlyJSONObject;
73
+ return JSON.stringify(stableArgs);
74
+ }
75
+
20
76
  /**
21
77
  * Resolves the interrupt fields for a tool call part.
22
78
  *
@@ -58,7 +114,7 @@ type MessageContent = Exclude<ThreadMessageLike["content"], string>;
58
114
 
59
115
  function convertParts(
60
116
  message: UIMessage,
61
- metadata: useExternalMessageConverter.Metadata,
117
+ metadata: AISDKMessageConverterMetadata,
62
118
  ): MessageContent {
63
119
  if (!message.parts || message.parts.length === 0) {
64
120
  return [];
@@ -84,6 +140,7 @@ function convertParts(
84
140
  if (isToolUIPart(part)) {
85
141
  const toolName = getToolName(part);
86
142
  const toolCallId = part.toolCallId;
143
+ const argsKeyOrderCacheKey = `${message.id}:${toolCallId}`;
87
144
  const args: ReadonlyJSONObject =
88
145
  (part.input as ReadonlyJSONObject) || {};
89
146
 
@@ -104,10 +161,16 @@ function convertParts(
104
161
  };
105
162
  }
106
163
 
107
- let argsText = JSON.stringify(args);
164
+ let argsText = stableStringifyToolArgs(
165
+ metadata.toolArgsKeyOrderCache,
166
+ argsKeyOrderCacheKey,
167
+ args,
168
+ );
108
169
  if (part.state === "input-streaming") {
109
170
  // strip closing delimiters added by the AI SDK's fix-json
110
171
  argsText = stripClosingDelimiters(argsText);
172
+ } else {
173
+ metadata.toolArgsKeyOrderCache?.delete(argsKeyOrderCacheKey);
111
174
  }
112
175
 
113
176
  const toolStatus = metadata.toolStatuses?.[toolCallId];
@@ -164,7 +227,7 @@ function convertParts(
164
227
  }
165
228
 
166
229
  export const AISDKMessageConverter = unstable_createMessageConverter(
167
- (message: UIMessage, metadata: useExternalMessageConverter.Metadata) => {
230
+ (message: UIMessage, metadata: AISDKMessageConverterMetadata) => {
168
231
  const createdAt = new Date();
169
232
  const content = convertParts(message, metadata);
170
233
 
@@ -0,0 +1,137 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getThreadMessageTokenUsage } from "./usage";
3
+
4
+ function msg(metadata: unknown): { role: "assistant"; metadata: unknown } {
5
+ return {
6
+ role: "assistant",
7
+ metadata,
8
+ };
9
+ }
10
+
11
+ describe("getThreadMessageTokenUsage", () => {
12
+ it("does not double-count reasoning/cached in fallback totalTokens", () => {
13
+ const usage = getThreadMessageTokenUsage(
14
+ msg({
15
+ usage: {
16
+ inputTokens: 4,
17
+ outputTokens: 6,
18
+ reasoningTokens: 9,
19
+ cachedInputTokens: 3,
20
+ },
21
+ }),
22
+ );
23
+
24
+ // totalTokens = input + output only; reasoning/cached are detail fields
25
+ expect(usage).toEqual({
26
+ totalTokens: 10,
27
+ inputTokens: 4,
28
+ outputTokens: 6,
29
+ reasoningTokens: 9,
30
+ cachedInputTokens: 3,
31
+ });
32
+ });
33
+
34
+ it("does not fabricate zero splits when only totalTokens is present", () => {
35
+ const usage = getThreadMessageTokenUsage(
36
+ msg({ usage: { totalTokens: 12 } }),
37
+ );
38
+
39
+ expect(usage).toEqual({ totalTokens: 12 });
40
+ expect(usage).not.toHaveProperty("inputTokens");
41
+ expect(usage).not.toHaveProperty("outputTokens");
42
+ });
43
+
44
+ it("retains partial usage when only inputTokens is present", () => {
45
+ const usage = getThreadMessageTokenUsage(
46
+ msg({ usage: { inputTokens: 10 } }),
47
+ );
48
+
49
+ expect(usage).toEqual({ inputTokens: 10 });
50
+ expect(usage).not.toHaveProperty("totalTokens");
51
+ });
52
+
53
+ it("retains partial usage when only outputTokens is present", () => {
54
+ const usage = getThreadMessageTokenUsage(
55
+ msg({ usage: { outputTokens: 4 } }),
56
+ );
57
+
58
+ expect(usage).toEqual({ outputTokens: 4 });
59
+ expect(usage).not.toHaveProperty("totalTokens");
60
+ });
61
+
62
+ it("retains detail-only usage when only reasoning/cached tokens are present", () => {
63
+ const usage = getThreadMessageTokenUsage(
64
+ msg({ usage: { reasoningTokens: 7, cachedInputTokens: 2 } }),
65
+ );
66
+
67
+ expect(usage).toEqual({ reasoningTokens: 7, cachedInputTokens: 2 });
68
+ expect(usage).not.toHaveProperty("totalTokens");
69
+ });
70
+
71
+ it("aggregates multi-step usage without inflating totals", () => {
72
+ const usage = getThreadMessageTokenUsage(
73
+ msg({
74
+ steps: [
75
+ { usage: { inputTokens: 3, outputTokens: 2, reasoningTokens: 11 } },
76
+ { usage: { inputTokens: 4, outputTokens: 1, reasoningTokens: 13 } },
77
+ ],
78
+ }),
79
+ );
80
+
81
+ expect(usage).toEqual({
82
+ totalTokens: 10,
83
+ inputTokens: 7,
84
+ outputTokens: 3,
85
+ reasoningTokens: 24,
86
+ });
87
+ });
88
+
89
+ it("omits totalTokens if any step lacks a computable total", () => {
90
+ const usage = getThreadMessageTokenUsage(
91
+ msg({
92
+ steps: [
93
+ { usage: { inputTokens: 5, outputTokens: 5 } }, // total = 10
94
+ { usage: { reasoningTokens: 10 } }, // total = undefined
95
+ ],
96
+ }),
97
+ );
98
+
99
+ // Sums known partials but omits the invalid total
100
+ expect(usage).toEqual({
101
+ inputTokens: 5,
102
+ outputTokens: 5,
103
+ reasoningTokens: 10,
104
+ });
105
+ expect(usage).not.toHaveProperty("totalTokens");
106
+ });
107
+
108
+ it("aggregates totalTokens if all steps have a computable total", () => {
109
+ const usage = getThreadMessageTokenUsage(
110
+ msg({
111
+ steps: [
112
+ { usage: { inputTokens: 5, outputTokens: 5 } }, // implicit total = 10
113
+ { usage: { totalTokens: 15 } }, // explicit total = 15
114
+ ],
115
+ }),
116
+ );
117
+
118
+ expect(usage).toEqual({
119
+ totalTokens: 25,
120
+ inputTokens: 5,
121
+ outputTokens: 5,
122
+ });
123
+ });
124
+
125
+ it("omits totalTokens when one step has only total and another has only input", () => {
126
+ const usage = getThreadMessageTokenUsage(
127
+ msg({
128
+ steps: [{ usage: { totalTokens: 10 } }, { usage: { inputTokens: 3 } }],
129
+ }),
130
+ );
131
+
132
+ expect(usage).toEqual({
133
+ inputTokens: 3,
134
+ });
135
+ expect(usage).not.toHaveProperty("totalTokens");
136
+ });
137
+ });
package/src/usage.ts ADDED
@@ -0,0 +1,175 @@
1
+ import { useAuiState } from "@assistant-ui/react";
2
+ export type ThreadTokenUsage = {
3
+ totalTokens?: number;
4
+ inputTokens?: number;
5
+ outputTokens?: number;
6
+ reasoningTokens?: number;
7
+ cachedInputTokens?: number;
8
+ };
9
+ export interface TokenUsageExtractableMessage {
10
+ role?: string;
11
+ metadata?: unknown;
12
+ }
13
+ // Internal types for parsing
14
+ type UsageRecord = Record<string, unknown>;
15
+ function asRecord(value: unknown): UsageRecord | undefined {
16
+ if (!value || typeof value !== "object" || Array.isArray(value))
17
+ return undefined;
18
+ return value as UsageRecord;
19
+ }
20
+ function asPositiveTokenCount(value: unknown): number | undefined {
21
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
22
+ return undefined;
23
+ }
24
+ return value;
25
+ }
26
+ // Internal type that makes everything optional for the intermediate parsing steps
27
+ type ParsedUsage = {
28
+ inputTokens?: number;
29
+ outputTokens?: number;
30
+ reasoningTokens?: number;
31
+ cachedInputTokens?: number;
32
+ totalTokens?: number;
33
+ };
34
+
35
+ function hasAnyUsageField(parsed: ParsedUsage): boolean {
36
+ return (
37
+ parsed.inputTokens !== undefined ||
38
+ parsed.outputTokens !== undefined ||
39
+ parsed.reasoningTokens !== undefined ||
40
+ parsed.cachedInputTokens !== undefined ||
41
+ parsed.totalTokens !== undefined
42
+ );
43
+ }
44
+
45
+ function normalizeUsage(value: unknown): ParsedUsage | undefined {
46
+ const usage = asRecord(value);
47
+ if (!usage) return undefined;
48
+ const inputTokens = asPositiveTokenCount(usage.inputTokens);
49
+ const outputTokens = asPositiveTokenCount(usage.outputTokens);
50
+ const reasoningTokens = asPositiveTokenCount(usage.reasoningTokens);
51
+ const cachedInputTokens = asPositiveTokenCount(usage.cachedInputTokens);
52
+ const totalTokens = asPositiveTokenCount(usage.totalTokens);
53
+ const result: ParsedUsage = {};
54
+ if (inputTokens !== undefined) result.inputTokens = inputTokens;
55
+ if (outputTokens !== undefined) result.outputTokens = outputTokens;
56
+ if (reasoningTokens !== undefined) result.reasoningTokens = reasoningTokens;
57
+ if (cachedInputTokens !== undefined)
58
+ result.cachedInputTokens = cachedInputTokens;
59
+ if (totalTokens !== undefined) result.totalTokens = totalTokens;
60
+
61
+ if (!hasAnyUsageField(result)) {
62
+ return undefined;
63
+ }
64
+
65
+ return result;
66
+ }
67
+ function buildUsageResult(parsed: ParsedUsage): ThreadTokenUsage | undefined {
68
+ if (!hasAnyUsageField(parsed)) {
69
+ return undefined;
70
+ }
71
+ const hasBothInputAndOutput =
72
+ parsed.inputTokens !== undefined && parsed.outputTokens !== undefined;
73
+ const totalTokens =
74
+ parsed.totalTokens ??
75
+ (hasBothInputAndOutput
76
+ ? (parsed.inputTokens ?? 0) + (parsed.outputTokens ?? 0)
77
+ : undefined);
78
+ const result: ThreadTokenUsage = {};
79
+ if (totalTokens !== undefined) result.totalTokens = totalTokens;
80
+ if (parsed.inputTokens !== undefined) result.inputTokens = parsed.inputTokens;
81
+ if (parsed.outputTokens !== undefined)
82
+ result.outputTokens = parsed.outputTokens;
83
+ if (parsed.reasoningTokens !== undefined)
84
+ result.reasoningTokens = parsed.reasoningTokens;
85
+ if (parsed.cachedInputTokens !== undefined)
86
+ result.cachedInputTokens = parsed.cachedInputTokens;
87
+ return result;
88
+ }
89
+ function usageFromSteps(value: unknown): ThreadTokenUsage | undefined {
90
+ const steps = Array.isArray(value) ? value : [];
91
+ let inputTokens = 0;
92
+ let outputTokens = 0;
93
+ let reasoningTokens = 0;
94
+ let cachedInputTokens = 0;
95
+ let totalTokens = 0;
96
+ let hasInput = false;
97
+ let hasOutput = false;
98
+ let hasReasoning = false;
99
+ let hasCachedInput = false;
100
+ let stepsWithUsage = 0;
101
+ let stepsWithComputableTotal = 0;
102
+ for (const step of steps) {
103
+ const usage = normalizeUsage(asRecord(step)?.usage);
104
+ if (!usage) continue;
105
+ stepsWithUsage++;
106
+ const stepHasBothInputAndOutput =
107
+ usage.inputTokens !== undefined && usage.outputTokens !== undefined;
108
+ const stepTotal =
109
+ usage.totalTokens ??
110
+ (stepHasBothInputAndOutput
111
+ ? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)
112
+ : undefined);
113
+ if (stepTotal !== undefined) {
114
+ totalTokens += stepTotal;
115
+ stepsWithComputableTotal++;
116
+ }
117
+ if (usage.inputTokens !== undefined) {
118
+ inputTokens += usage.inputTokens;
119
+ hasInput = true;
120
+ }
121
+ if (usage.outputTokens !== undefined) {
122
+ outputTokens += usage.outputTokens;
123
+ hasOutput = true;
124
+ }
125
+ if (usage.reasoningTokens !== undefined) {
126
+ reasoningTokens += usage.reasoningTokens;
127
+ hasReasoning = true;
128
+ }
129
+ if (usage.cachedInputTokens !== undefined) {
130
+ cachedInputTokens += usage.cachedInputTokens;
131
+ hasCachedInput = true;
132
+ }
133
+ }
134
+ if (stepsWithUsage === 0) return undefined;
135
+ const parsed: ParsedUsage = {};
136
+ if (hasInput) parsed.inputTokens = inputTokens;
137
+ if (hasOutput) parsed.outputTokens = outputTokens;
138
+ if (hasReasoning) parsed.reasoningTokens = reasoningTokens;
139
+ if (hasCachedInput) parsed.cachedInputTokens = cachedInputTokens;
140
+ if (stepsWithComputableTotal === stepsWithUsage) {
141
+ parsed.totalTokens = totalTokens;
142
+ }
143
+ const result: ThreadTokenUsage = {};
144
+ if (parsed.totalTokens !== undefined) result.totalTokens = parsed.totalTokens;
145
+ if (parsed.inputTokens !== undefined) result.inputTokens = parsed.inputTokens;
146
+ if (parsed.outputTokens !== undefined)
147
+ result.outputTokens = parsed.outputTokens;
148
+ if (parsed.reasoningTokens !== undefined)
149
+ result.reasoningTokens = parsed.reasoningTokens;
150
+ if (parsed.cachedInputTokens !== undefined)
151
+ result.cachedInputTokens = parsed.cachedInputTokens;
152
+ return result;
153
+ }
154
+ export function getThreadMessageTokenUsage(
155
+ message: TokenUsageExtractableMessage | undefined,
156
+ ): ThreadTokenUsage | undefined {
157
+ if (!message || message.role !== "assistant") return undefined;
158
+ const metadata = asRecord(message.metadata);
159
+ if (!metadata) return undefined;
160
+ const topLevelUsage = normalizeUsage(metadata.usage);
161
+ if (topLevelUsage) {
162
+ return buildUsageResult(topLevelUsage);
163
+ }
164
+ const legacyUsage = normalizeUsage(asRecord(metadata.custom)?.usage);
165
+ if (legacyUsage) {
166
+ return buildUsageResult(legacyUsage);
167
+ }
168
+ return usageFromSteps(metadata.steps);
169
+ }
170
+ export function useThreadTokenUsage(): ThreadTokenUsage | undefined {
171
+ const lastAssistant = useAuiState((s) =>
172
+ s.thread.messages.findLast((m) => m.role === "assistant"),
173
+ );
174
+ return getThreadMessageTokenUsage(lastAssistant);
175
+ }