@assistant-ui/ai-sdk 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/aiSDKFormatAdapter.d.ts +2 -2
  3. package/dist/adapters/aiSDKFormatAdapter.d.ts.map +1 -0
  4. package/dist/adapters/vercelAttachmentAdapter.d.ts +2 -5
  5. package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -1
  6. package/dist/adapters/vercelAttachmentAdapter.js +3 -3
  7. package/dist/adapters/vercelAttachmentAdapter.js.map +1 -1
  8. package/dist/aiSDKExtras.d.ts +6 -9
  9. package/dist/aiSDKExtras.d.ts.map +1 -1
  10. package/dist/converters/convertMessage.d.ts +34 -25
  11. package/dist/converters/convertMessage.d.ts.map +1 -1
  12. package/dist/converters/convertMessage.js +78 -8
  13. package/dist/converters/convertMessage.js.map +1 -1
  14. package/dist/converters/modelContentEnvelope.d.ts +10 -12
  15. package/dist/converters/modelContentEnvelope.d.ts.map +1 -1
  16. package/dist/converters/toCreateMessage.d.ts +3 -6
  17. package/dist/converters/toCreateMessage.d.ts.map +1 -1
  18. package/dist/converters/toolOutputConversion.d.ts +22 -25
  19. package/dist/converters/toolOutputConversion.d.ts.map +1 -1
  20. package/dist/hooks.d.ts +4 -7
  21. package/dist/hooks.d.ts.map +1 -1
  22. package/dist/index.d.ts +17 -14
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.native.d.ts +15 -12
  25. package/dist/index.native.d.ts.map +1 -0
  26. package/dist/model-context/injectInteractableContext.d.ts +3 -6
  27. package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
  28. package/dist/model-context/injectQuoteContext.d.ts +2 -5
  29. package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
  30. package/dist/runtime/AISDKChat.d.ts +4 -7
  31. package/dist/runtime/AISDKChat.d.ts.map +1 -1
  32. package/dist/runtime/AISDKChat.js +1 -1
  33. package/dist/runtime/AISDKThreads.d.ts +29 -32
  34. package/dist/runtime/AISDKThreads.d.ts.map +1 -1
  35. package/dist/runtime/AISDKThreads.js +26 -33
  36. package/dist/runtime/AISDKThreads.js.map +1 -1
  37. package/dist/runtime/sdkIdentity.d.ts +2 -5
  38. package/dist/runtime/sdkIdentity.d.ts.map +1 -1
  39. package/dist/runtime/sdkIdentity.js +1 -1
  40. package/dist/runtime/useAISDKRuntime.d.ts +72 -61
  41. package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
  42. package/dist/runtime/useAISDKRuntime.js +170 -56
  43. package/dist/runtime/useAISDKRuntime.js.map +1 -1
  44. package/dist/runtime/useChatRuntime.d.ts +8 -11
  45. package/dist/runtime/useChatRuntime.d.ts.map +1 -1
  46. package/dist/runtime/useChatRuntime.js +14 -10
  47. package/dist/runtime/useChatRuntime.js.map +1 -1
  48. package/dist/runtime/useChatThread.d.ts +100 -81
  49. package/dist/runtime/useChatThread.d.ts.map +1 -1
  50. package/dist/runtime/useChatThread.js +33 -13
  51. package/dist/runtime/useChatThread.js.map +1 -1
  52. package/dist/runtime/useExternalHistory.d.ts +8 -9
  53. package/dist/runtime/useExternalHistory.d.ts.map +1 -1
  54. package/dist/runtime/useExternalHistory.js +236 -58
  55. package/dist/runtime/useExternalHistory.js.map +1 -1
  56. package/dist/runtime/useResourceCleanup.d.ts +1 -4
  57. package/dist/runtime/useResourceCleanup.d.ts.map +1 -1
  58. package/dist/runtime/useResourceCleanup.js +38 -14
  59. package/dist/runtime/useResourceCleanup.js.map +1 -1
  60. package/dist/runtime/useStreamingTiming.d.ts +5 -8
  61. package/dist/runtime/useStreamingTiming.d.ts.map +1 -1
  62. package/dist/runtime/useStreamingTiming.js +1 -1
  63. package/dist/tools/frontendTools.d.ts +24 -27
  64. package/dist/tools/frontendTools.d.ts.map +1 -1
  65. package/dist/tools/generativeTools.d.ts +29 -32
  66. package/dist/tools/generativeTools.d.ts.map +1 -1
  67. package/dist/tools/mcp-stdio.node.d.ts +2 -2
  68. package/dist/tools/mcp-stdio.node.d.ts.map +1 -0
  69. package/dist/tools/mcp-stdio.unsupported.d.ts +2 -5
  70. package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -1
  71. package/dist/transport/AssistantChatTransport.d.ts +17 -20
  72. package/dist/transport/AssistantChatTransport.d.ts.map +1 -1
  73. package/dist/transport/resumable.d.ts +29 -32
  74. package/dist/transport/resumable.d.ts.map +1 -1
  75. package/dist/usage.d.ts +12 -15
  76. package/dist/usage.d.ts.map +1 -1
  77. package/dist/usage.js.map +1 -1
  78. package/dist/utils/getVercelAIMessages.d.ts +3 -6
  79. package/dist/utils/getVercelAIMessages.d.ts.map +1 -1
  80. package/dist/utils/sliceMessagesUntil.d.ts +2 -5
  81. package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
  82. package/package.json +16 -14
  83. package/src/adapters/vercelAttachmentAdapter.test.ts +23 -0
  84. package/src/adapters/vercelAttachmentAdapter.ts +2 -2
  85. package/src/converters/convertMessage.test.ts +616 -3
  86. package/src/converters/convertMessage.ts +187 -12
  87. package/src/index.native.ts +1 -1
  88. package/src/index.ts +1 -1
  89. package/src/runtime/AISDKChat.test.ts +4 -5
  90. package/src/runtime/AISDKThreads.cloud.test.ts +60 -2
  91. package/src/runtime/AISDKThreads.test.ts +88 -51
  92. package/src/runtime/AISDKThreads.ts +4 -13
  93. package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +338 -0
  94. package/src/runtime/useAISDKRuntime.approval.test.tsx +476 -4
  95. package/src/runtime/useAISDKRuntime.test.ts +282 -8
  96. package/src/runtime/useAISDKRuntime.ts +274 -46
  97. package/src/runtime/useAISDKRuntime.voice.test.tsx +319 -0
  98. package/src/runtime/useChatRuntime.integration.test.tsx +56 -0
  99. package/src/runtime/useChatRuntime.test.ts +77 -5
  100. package/src/runtime/useChatRuntime.ts +6 -2
  101. package/src/runtime/useChatThread.transport.test.tsx +149 -0
  102. package/src/runtime/useChatThread.ts +77 -10
  103. package/src/runtime/useExternalHistory.test.ts +989 -3
  104. package/src/runtime/useExternalHistory.ts +390 -24
  105. package/src/runtime/useResourceCleanup.ts +41 -15
  106. package/src/tools/generativeTools.test.ts +7 -1
  107. package/src/usage.ts +1 -1
@@ -1,38 +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
- declare const RESUMABLE_STREAM_ID_HEADER = "x-resumable-stream-id";
4
- type ResumableClientStorage = {
5
- getStreamId(threadId?: string): string | null;
6
- setStreamId(id: string, threadId?: string): void;
7
- clear(threadId?: string): void;
8
- /** Subscribes to stream id changes so automatic resume can react after mount. */
9
- subscribe?(listener: () => void, threadId?: string): () => void;
2
+ export declare const RESUMABLE_STREAM_ID_HEADER = "x-resumable-stream-id";
3
+ export type ResumableClientStorage = {
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
- declare function createResumableSessionStorage(options?: {
13
- /**
14
- * Storage key for the pending stream id. A static string namespaces per route
15
- * or chat surface. A getter is read lazily on every access, so the key can be
16
- * derived from the active thread's identity; while the getter returns
17
- * `undefined`, reads report no pending stream and writes are dropped, so a
18
- * thread whose identity is not known yet never touches another thread's key.
19
- *
20
- * Under a remote thread list with more than one thread, scope the key per
21
- * thread and create one storage instance per thread runtime rather than a
22
- * single shared one. A shared key is written and cleared by whichever thread
23
- * acts last, so one conversation's stream can resume inside another.
24
- */
25
- key?: string | (() => string | undefined);
11
+ export declare function createResumableSessionStorage(options?: {
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
- type AssistantChatResumableOptions = {
28
- storage: ResumableClientStorage;
29
- resumeApi: string | ((streamId: string) => string);
30
- /**
31
- * Defaults to scanning for the AI SDK UIMessageStream `finish` marker.
32
- * Cancellation never invokes this callback, only natural completion does.
33
- */
34
- isFinishEvent?: (chunk: Uint8Array, accumulator: string) => boolean;
26
+ export type AssistantChatResumableOptions = {
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
- export { AssistantChatResumableOptions, RESUMABLE_STREAM_ID_HEADER, ResumableClientStorage, createResumableSessionStorage };
38
35
  //# sourceMappingURL=resumable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resumable.d.ts","names":[],"sources":["../../src/transport/resumable.ts"],"mappings":";;cAKa;KAID;EACV,YAAY;EACZ,YAAY,YAAY;EACxB,MAAM;;EAEN,WAAW,sBAAsB;;;iBAkBnB,8BAA8B;;;;;;;;;;;;;EAa5C;IACE;KA0GQ;EACV,SAAS;EACT,sBAAsB;;;;;EAKtB,iBAAiB,OAAO,YAAY"}
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,17 +1,16 @@
1
- /// <reference types="@assistant-ui/core/react" />
2
- //#region src/usage.d.ts
3
- type ThreadTokenUsage = {
4
- totalTokens?: number;
5
- inputTokens?: number;
6
- outputTokens?: number;
7
- reasoningTokens?: number;
8
- cachedInputTokens?: number;
1
+ /// <reference types="@assistant-ui/core/react" preserve="true" />
2
+ export type ThreadTokenUsage = {
3
+ totalTokens?: number;
4
+ inputTokens?: number;
5
+ outputTokens?: number;
6
+ reasoningTokens?: number;
7
+ cachedInputTokens?: number;
9
8
  };
10
- interface TokenUsageExtractableMessage {
11
- role?: string;
12
- metadata?: unknown;
9
+ export interface TokenUsageExtractableMessage {
10
+ role?: string;
11
+ metadata?: unknown;
13
12
  }
14
- declare function getThreadMessageTokenUsage(message: TokenUsageExtractableMessage | undefined): ThreadTokenUsage | undefined;
13
+ export declare function getThreadMessageTokenUsage(message: TokenUsageExtractableMessage | undefined): ThreadTokenUsage | undefined;
15
14
  /**
16
15
  * Reads token usage from the newest assistant message that reports any.
17
16
  *
@@ -20,7 +19,5 @@ declare function getThreadMessageTokenUsage(message: TokenUsageExtractableMessag
20
19
  * other key the route returns into `metadata.custom`, which is where this hook
21
20
  * looks.
22
21
  */
23
- declare function useThreadTokenUsage(): ThreadTokenUsage | undefined;
24
- //#endregion
25
- export { ThreadTokenUsage, TokenUsageExtractableMessage, getThreadMessageTokenUsage, useThreadTokenUsage };
22
+ export declare function useThreadTokenUsage(): ThreadTokenUsage | undefined;
26
23
  //# sourceMappingURL=usage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage.d.ts","names":[],"sources":["../src/usage.ts"],"mappings":";KAIY;EACV;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;iBAuHc,2BACd,SAAS,2CACR;;;;;;;;;iBAsCa,uBAAuB"}
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":";;;;AAmBA,MAAMa,aAAa;CACjB;CACA;CACA;CACA;CACA;AAAa;AAGf,SAASE,SAASC,OAAyC;CACzD,IAAI,CAACA,SAAS,OAAOA,UAAU,YAAYC,MAAMC,QAAQF,KAAK,GAC5D,OAAOG,KAAAA;CACT,OAAOH;AACT;AAEA,SAASI,qBAAqBJ,OAAoC;CAChE,IAAI,OAAOA,UAAU,YAAY,CAACK,OAAOC,SAASN,KAAK,KAAKA,QAAQ,GAClE;CAEF,OAAOA;AACT;AAEA,SAASO,mBAAmBC,OAA6C;CACvE,IAAIA,MAAMrB,gBAAgBgB,KAAAA,GAAW,OAAOK,MAAMrB;CAClD,IAAIqB,MAAMpB,gBAAgBe,KAAAA,KAAaK,MAAMnB,iBAAiBc,KAAAA,GAC5D,OAAOK,MAAMpB,cAAcoB,MAAMnB;AAGrC;AAEA,SAASoB,eAAeT,OAA8C;CACpE,MAAMU,SAASX,SAASC,KAAK;CAC7B,IAAI,CAACU,QAAQ,OAAOP,KAAAA;CAEpB,MAAMQ,SAA2B,CAAC;CAClC,IAAIC,YAAY;CAChB,KAAK,MAAMC,OAAOhB,YAAY;EAC5B,MAAMiB,QAAQV,qBAAqBM,OAAOG,IAAI;EAC9C,IAAIC,UAAUX,KAAAA,GAAW;GACvBQ,OAAOE,OAAOC;GACdF,YAAY;EACd;CACF;CAEA,IAAID,OAAOrB,oBAAoBa,KAAAA,GAAW;EACxC,MAAMW,QAAQV,qBACZL,SAASW,OAAOK,kBAAkB,CAAC,EAAEzB,eACvC;EACA,IAAIwB,UAAUX,KAAAA,GAAW;GACvBQ,OAAOrB,kBAAkBwB;GACzBF,YAAY;EACd;CACF;CACA,IAAID,OAAOpB,sBAAsBY,KAAAA,GAAW;EAC1C,MAAMW,QAAQV,qBACZL,SAASW,OAAOM,iBAAiB,CAAC,EAAEC,eACtC;EACA,IAAIH,UAAUX,KAAAA,GAAW;GACvBQ,OAAOpB,oBAAoBuB;GAC3BF,YAAY;EACd;CACF;CACA,OAAOA,YAAYD,SAASR,KAAAA;AAC9B;AAEA,SAASe,kBACPV,OAC8B;CAC9B,MAAMrB,cAAcoB,mBAAmBC,KAAK;CAC5C,OAAO;EAAE,GAAGA;EAAO,GAAIrB,gBAAgBgB,KAAAA,KAAa,EAAEhB,YAAY;CAAG;AACvE;AAEA,SAASgC,eAAenB,OAA8C;CACpE,MAAMoB,QAAQnB,MAAMC,QAAQF,KAAK,IAAIA,QAAQ,CAAA;CAE7C,MAAMqB,OAA+B,CAAC;CACtC,MAAMC,UAAmC,CAAC;CAC1C,IAAIC,iBAAiB;CACrB,IAAIC,2BAA2B;CAE/B,KAAK,MAAMC,QAAQL,OAAO;EACxB,MAAMZ,QAAQC,eAAeV,SAAS0B,IAAI,CAAC,EAAEjB,KAAK;EAClD,IAAI,CAACA,OAAO;EACZe;EAEA,MAAMG,YAAYnB,mBAAmBC,KAAK;EAC1C,IAAIkB,cAAcvB,KAAAA,GAAW;GAC3BkB,KAAKlC,eAAekC,KAAKlC,eAAe,KAAKuC;GAC7CF;EACF;EAEA,KAAK,MAAMX,OAAOhB,YAAY;GAC5B,IAAIgB,QAAQ,eAAe;GAC3B,IAAIL,MAAMK,SAASV,KAAAA,GAAW;IAC5BkB,KAAKR,QAAQQ,KAAKR,QAAQ,KAAKL,MAAMK;IACrCS,QAAQT,OAAO;GACjB;EACF;CACF;CAEA,IAAIU,mBAAmB,GAAG,OAAOpB,KAAAA;CAEjC,MAAMQ,SAA2B,CAAC;CAClC,IAAIa,6BAA6BD,gBAC/BZ,OAAOxB,cAAckC,KAAKlC;CAE5B,KAAK,MAAM0B,OAAOhB,YAAY;EAC5B,IAAIgB,QAAQ,eAAe;EAC3B,IAAIS,QAAQT,MACVF,OAAOE,OAAOQ,KAAKR;CAEvB;CACA,OAAOF;AACT;AAEA,SAAgBgB,2BACdC,SAC8B;CAC9B,IAAI,CAACA,WAAWA,QAAQnC,SAAS,aAAa,OAAOU,KAAAA;CAErD,MAAMT,WAAWK,SAAS6B,QAAQlC,QAAQ;CAC1C,IAAI,CAACA,UAAU,OAAOS,KAAAA;CAEtB,MAAM0B,gBAAgBpB,eAAef,SAASc,KAAK;CACnD,IAAIqB,eAAe,OAAOX,kBAAkBW,aAAa;CAEzD,MAAMC,cAAcrB,eAAeV,SAASL,SAASqC,MAAM,CAAC,EAAEvB,KAAK;CACnE,IAAIsB,aAAa,OAAOZ,kBAAkBY,WAAW;CAErD,OAAOX,eAAezB,SAAS0B,KAAK;AACtC;AAEA,SAASY,2BACPC,UAC0C;CAC1C,IAAI,CAACA,UAAU,OAAO9B,KAAAA;CAEtB,KAAK,IAAI+B,MAAMD,SAASE,SAAS,GAAGD,OAAO,GAAGA,OAAO,GAAG;EACtD,MAAMN,UAAUK,SAASC;EACzB,IAAIP,2BAA2BC,OAAO,GACpC,OAAOA;CAEX;AAGF;;;;;;;;;AAUA,SAAOQ,sBAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CACL,MAAAC,MAAYtD,YAAYuD,KAAoD;CAAE,IAAAC;CAAA,IAAAJ,EAAA,OAAAE,KAAA;EACzDE,KAAAd,2BAA2BY,GAAG;EAACF,EAAA,KAAAE;EAAAF,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CAAA,OAA/BI;AAA+B;AAF/C,SAAAD,MAAAE,GAAA;CAAA,OAC0BV,2BAA2BU,EAACC,OAAOV,QAAS;AAAC"}
@@ -1,7 +1,4 @@
1
- import { UIMessage } from "ai";
2
- import { ThreadMessage } from "@assistant-ui/core";
3
- //#region src/utils/getVercelAIMessages.d.ts
4
- declare const getVercelAIMessages: <UI_MESSAGE extends UIMessage = UIMessage>(message: ThreadMessage) => UI_MESSAGE[];
5
- //#endregion
6
- export { getVercelAIMessages };
1
+ import { type ThreadMessage } from "@assistant-ui/core";
2
+ import type { UIMessage } from "ai";
3
+ export declare const getVercelAIMessages: <UI_MESSAGE extends UIMessage = UIMessage>(message: ThreadMessage) => UI_MESSAGE[];
7
4
  //# sourceMappingURL=getVercelAIMessages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getVercelAIMessages.d.ts","names":[],"sources":["../../src/utils/getVercelAIMessages.ts"],"mappings":";;;cAMa,sBAAuB,mBAAmB,YAAY,WACjE,SAAS,kBAEmC"}
1
+ {"version":3,"file":"getVercelAIMessages.d.ts","sourceRoot":"","sources":["../../src/utils/getVercelAIMessages.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAEpC,eAAO,MAAM,mBAAmB,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EAC1E,SAAS,aAAa,KAEsB,UAAU,EACvD,CAAC"}
@@ -1,6 +1,3 @@
1
- import { UIMessage } from "ai";
2
- //#region src/utils/sliceMessagesUntil.d.ts
3
- declare const sliceMessagesUntil: <UI_MESSAGE extends UIMessage = UIMessage>(messages: UI_MESSAGE[], messageId: string | null) => UI_MESSAGE[];
4
- //#endregion
5
- export { sliceMessagesUntil };
1
+ import type { UIMessage } from "ai";
2
+ export declare const sliceMessagesUntil: <UI_MESSAGE extends UIMessage = UIMessage>(messages: UI_MESSAGE[], messageId: string | null) => UI_MESSAGE[];
6
3
  //# sourceMappingURL=sliceMessagesUntil.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sliceMessagesUntil.d.ts","names":[],"sources":["../../src/utils/sliceMessagesUntil.ts"],"mappings":";;cAEa,qBAAsB,mBAAmB,YAAY,WAChE,UAAU,cACV,6BAAwB"}
1
+ {"version":3,"file":"sliceMessagesUntil.d.ts","sourceRoot":"","sources":["../../src/utils/sliceMessagesUntil.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAEpC,eAAO,MAAM,kBAAkB,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACzE,UAAU,UAAU,EAAE,EACtB,WAAW,MAAM,GAAG,IAAI,iBAezB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/ai-sdk",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Vercel AI SDK adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "ai-sdk",
@@ -46,17 +46,17 @@
46
46
  ],
47
47
  "sideEffects": false,
48
48
  "dependencies": {
49
- "@ai-sdk/mcp": "^2.0.45",
50
- "@ai-sdk/react": "^4.0.96",
51
- "@assistant-ui/core": "^0.3.19",
52
- "@assistant-ui/store": "^0.3.13",
53
- "@assistant-ui/tap": "^0.9.17",
54
- "ai": "^7.0.93",
55
- "assistant-cloud": "^0.2.1",
56
- "assistant-stream": "^0.3.43"
49
+ "@ai-sdk/mcp": "^2.0.49",
50
+ "@ai-sdk/react": "^4.0.104",
51
+ "@assistant-ui/core": "^0.3.21",
52
+ "@assistant-ui/store": "^0.3.15",
53
+ "@assistant-ui/tap": "^0.9.19",
54
+ "assistant-cloud": "^0.2.3",
55
+ "assistant-stream": "^0.3.45"
57
56
  },
58
57
  "peerDependencies": {
59
58
  "@types/react": "*",
59
+ "ai": "^7.0.101",
60
60
  "react": "^18 || ^19"
61
61
  },
62
62
  "peerDependenciesMeta": {
@@ -68,14 +68,15 @@
68
68
  }
69
69
  },
70
70
  "devDependencies": {
71
- "@assistant-ui/x-buildutils": "0.0.27",
71
+ "@assistant-ui/x-buildutils": "0.0.29",
72
72
  "@testing-library/react": "^16.3.3",
73
73
  "@types/json-schema": "^7.0.15",
74
- "@types/react": "^19.2.18",
75
- "@types/react-dom": "^19.2.7",
74
+ "@types/react": "^19.3.0",
75
+ "@types/react-dom": "^19.3.0",
76
+ "ai": "^7.0.101",
76
77
  "jsdom": "^30.0.1",
77
- "react": "^19.2.8",
78
- "vitest": "^5.0.0"
78
+ "react": "^19.3.0",
79
+ "vitest": "^5.0.1"
79
80
  },
80
81
  "publishConfig": {
81
82
  "access": "public",
@@ -93,6 +94,7 @@
93
94
  "scripts": {
94
95
  "build": "aui-build",
95
96
  "test": "vitest run",
97
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
96
98
  "test:react-compiler": "vitest run --config vitest.react-compiler.config.ts",
97
99
  "test:standalone": "vitest run --project standalone",
98
100
  "test:watch": "vitest"
@@ -26,4 +26,27 @@ describe("vercelAttachmentAdapter", () => {
26
26
  if (part?.type !== "file") throw new Error("expected file content part");
27
27
  expect(part.data).toBe("data:text/plain;base64,aGVsbG8=");
28
28
  });
29
+
30
+ it("aborts a file send via the shared core encoder", async () => {
31
+ globalThis.FileReader = undefined as unknown as typeof FileReader;
32
+
33
+ const file = new File(["hello"], "a.txt", { type: "text/plain" });
34
+ const controller = new AbortController();
35
+ controller.abort();
36
+
37
+ await expect(
38
+ vercelAttachmentAdapter.send(
39
+ {
40
+ id: "1",
41
+ type: "file",
42
+ name: file.name,
43
+ file,
44
+ contentType: file.type,
45
+ content: [],
46
+ status: { type: "requires-action", reason: "composer-send" },
47
+ },
48
+ { signal: controller.signal },
49
+ ),
50
+ ).rejects.toBe(controller.signal.reason);
51
+ });
29
52
  });
@@ -15,7 +15,7 @@ export const vercelAttachmentAdapter: AttachmentAdapter = {
15
15
  status: { type: "requires-action", reason: "composer-send" },
16
16
  };
17
17
  },
18
- async send(attachment) {
18
+ async send(attachment, options) {
19
19
  // noop
20
20
  return {
21
21
  ...attachment,
@@ -25,7 +25,7 @@ export const vercelAttachmentAdapter: AttachmentAdapter = {
25
25
  type: "file",
26
26
  mimeType: attachment.contentType ?? "",
27
27
  filename: attachment.name,
28
- data: await getFileDataURL(attachment.file),
28
+ data: await getFileDataURL(attachment.file, options),
29
29
  },
30
30
  ],
31
31
  };