@assistant-ui/react-ai-sdk 1.3.30 → 1.3.31
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/assistant-stream/dist/core/tool/schema-utils.d.ts +15 -0
- package/dist/assistant-stream/dist/core/tool/schema-utils.d.ts.map +1 -0
- package/dist/{packages/assistant-stream → assistant-stream}/dist/core/tool/schema-utils.js +9 -3
- package/dist/assistant-stream/dist/core/tool/schema-utils.js.map +1 -0
- package/dist/{packages/assistant-stream → assistant-stream}/dist/core/tool/tool-types.d.ts +27 -1
- package/dist/assistant-stream/dist/core/tool/tool-types.d.ts.map +1 -0
- package/dist/assistant-stream/dist/index.d.ts +2 -0
- package/dist/{node_modules → assistant-stream/dist/node_modules}/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +4 -5
- package/dist/assistant-stream/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +1 -0
- package/dist/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +1 -0
- package/dist/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js.map +1 -0
- package/dist/assistant-stream/dist/utils/json/json-value.d.ts.map +1 -0
- package/dist/frontendTools.d.ts +33 -6
- package/dist/frontendTools.d.ts.map +1 -1
- package/dist/frontendTools.js +3 -2
- package/dist/frontendTools.js.map +1 -1
- package/dist/generativeTools.d.ts +44 -0
- package/dist/generativeTools.d.ts.map +1 -0
- package/dist/generativeTools.js +55 -0
- package/dist/generativeTools.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/modelContentEnvelope.d.ts +1 -1
- package/dist/modelContentEnvelope.d.ts.map +1 -1
- package/dist/ui/resumable.d.ts +1 -1
- package/dist/ui/resumable.js +1 -1
- package/dist/ui/use-chat/AssistantChatTransport.d.ts.map +1 -1
- package/dist/ui/use-chat/AssistantChatTransport.js +2 -2
- package/dist/ui/use-chat/useAISDKRuntime.d.ts +3 -16
- package/dist/ui/use-chat/useAISDKRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useAISDKRuntime.js +8 -3
- package/dist/ui/use-chat/useAISDKRuntime.js.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.d.ts +2 -3
- package/dist/ui/use-chat/useChatRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.js +4 -3
- package/dist/ui/use-chat/useChatRuntime.js.map +1 -1
- package/dist/ui/use-chat/useExternalHistory.d.ts.map +1 -1
- package/dist/ui/use-chat/useExternalHistory.js +16 -8
- package/dist/ui/use-chat/useExternalHistory.js.map +1 -1
- package/dist/ui/utils/convertMessage.d.ts +3 -2
- package/dist/ui/utils/convertMessage.d.ts.map +1 -1
- package/dist/ui/utils/convertMessage.js +3 -1
- package/dist/ui/utils/convertMessage.js.map +1 -1
- package/dist/usage.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/frontendTools.test.ts +24 -0
- package/src/frontendTools.ts +4 -6
- package/src/generativeTools.ts +90 -0
- package/src/index.ts +4 -0
- package/src/ui/use-chat/useAISDKRuntime.test.ts +36 -0
- package/src/ui/use-chat/useAISDKRuntime.ts +19 -16
- package/src/ui/use-chat/useChatRuntime.ts +22 -21
- package/src/ui/use-chat/useExternalHistory.test.ts +60 -1
- package/src/ui/use-chat/useExternalHistory.ts +17 -8
- package/src/ui/utils/convertMessage.test.ts +25 -0
- package/src/ui/utils/convertMessage.ts +6 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +0 -1
- package/dist/packages/assistant-stream/dist/core/tool/schema-utils.d.ts +0 -1
- package/dist/packages/assistant-stream/dist/core/tool/schema-utils.js.map +0 -1
- package/dist/packages/assistant-stream/dist/core/tool/tool-types.d.ts.map +0 -1
- package/dist/packages/assistant-stream/dist/index.d.ts +0 -1
- package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +0 -1
- package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js.map +0 -1
- package/dist/packages/assistant-stream/dist/utils/json/json-value.d.ts.map +0 -1
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/AssistantStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/AssistantStreamChunk.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/accumulators/AssistantMessageStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/accumulators/assistant-message-accumulator.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/modules/assistant-stream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/modules/text.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/modules/tool-call.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/serialization/PlainText.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/serialization/assistant-transport/AssistantTransport.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/serialization/data-stream/DataStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/tool/ToolExecutionStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/tool/toolResultStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/utils/stream/AssistantMetaTransformStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/utils/stream/AssistantTransformStream.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/core/utils/types.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/resumable/createResumableAssistantStreamResponse.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/resumable/createResumableAssistantStreamResponse.js +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/resumable/index.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/utils/json/json-value.d.ts +0 -0
- /package/dist/{packages/assistant-stream → assistant-stream}/dist/utils.d.ts +0 -0
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
import type { ToolExecutionStatus } from "@assistant-ui/core";
|
|
11
11
|
import type {
|
|
12
12
|
ExternalStoreAdapter,
|
|
13
|
+
ExternalStoreSharedOptions,
|
|
13
14
|
ThreadHistoryAdapter,
|
|
14
15
|
AssistantRuntime,
|
|
15
16
|
ThreadMessage,
|
|
16
|
-
ThreadSuggestion,
|
|
17
17
|
MessageFormatAdapter,
|
|
18
18
|
MessageFormatItem,
|
|
19
19
|
MessageFormatRepository,
|
|
@@ -21,7 +21,10 @@ import type {
|
|
|
21
21
|
RunConfig,
|
|
22
22
|
McpAppMetadata,
|
|
23
23
|
} from "@assistant-ui/core";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
getExternalStoreMessages,
|
|
26
|
+
pickExternalStoreSharedOptions,
|
|
27
|
+
} from "@assistant-ui/core";
|
|
25
28
|
import type { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
26
29
|
import { sliceMessagesUntil } from "../utils/sliceMessagesUntil";
|
|
27
30
|
import { toCreateMessage } from "../utils/toCreateMessage";
|
|
@@ -55,7 +58,7 @@ const toUIMessage = <UI_MESSAGE extends UIMessage>(
|
|
|
55
58
|
role: createMessage.role ?? fallbackRole,
|
|
56
59
|
}) as UI_MESSAGE;
|
|
57
60
|
|
|
58
|
-
export type AISDKRuntimeAdapter = {
|
|
61
|
+
export type AISDKRuntimeAdapter = ExternalStoreSharedOptions & {
|
|
59
62
|
adapters?:
|
|
60
63
|
| (NonNullable<ExternalStoreAdapter["adapters"]> & {
|
|
61
64
|
history?: ThreadHistoryAdapter | undefined;
|
|
@@ -79,25 +82,18 @@ export type AISDKRuntimeAdapter = {
|
|
|
79
82
|
* (for example, an SSE reconnect endpoint keyed by turn id).
|
|
80
83
|
*/
|
|
81
84
|
onResume?: ExternalStoreAdapter["onResume"];
|
|
82
|
-
/**
|
|
83
|
-
* Follow up suggestions to surface on the thread. Use this to drive
|
|
84
|
-
* dynamic suggestions from application state, tool results, or backend
|
|
85
|
-
* responses; flows into `thread.suggestions` and is rendered by
|
|
86
|
-
* components that read it (such as the shadcn `ThreadFollowupSuggestions`).
|
|
87
|
-
*/
|
|
88
|
-
suggestions?: readonly ThreadSuggestion[] | undefined;
|
|
89
85
|
};
|
|
90
86
|
|
|
91
87
|
export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
92
88
|
chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,
|
|
93
|
-
{
|
|
89
|
+
adapter: AISDKRuntimeAdapter = {},
|
|
90
|
+
) => {
|
|
91
|
+
const {
|
|
94
92
|
adapters,
|
|
95
93
|
toCreateMessage: customToCreateMessage,
|
|
96
94
|
cancelPendingToolCallsOnSend = true,
|
|
97
95
|
onResume,
|
|
98
|
-
|
|
99
|
-
}: AISDKRuntimeAdapter = {},
|
|
100
|
-
) => {
|
|
96
|
+
} = adapter;
|
|
101
97
|
const contextAdapters = useRuntimeAdapters();
|
|
102
98
|
const [toolStatuses, setToolStatuses] = useState<
|
|
103
99
|
Record<string, ToolExecutionStatus>
|
|
@@ -121,6 +117,12 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
121
117
|
|
|
122
118
|
const messageTiming = useStreamingTiming(chatHelpers.messages, isRunning);
|
|
123
119
|
|
|
120
|
+
// Flag the streaming message optimistic: its id can be swapped for a server
|
|
121
|
+
// id mid-run, and the repository then drops the orphaned pre-swap id (#4037).
|
|
122
|
+
const lastMessage = chatHelpers.messages.at(-1);
|
|
123
|
+
const optimisticMessageId =
|
|
124
|
+
isRunning && lastMessage?.role === "assistant" ? lastMessage.id : undefined;
|
|
125
|
+
|
|
124
126
|
const messages = AISDKMessageConverter.useThreadMessages({
|
|
125
127
|
isRunning,
|
|
126
128
|
messages: chatHelpers.messages,
|
|
@@ -131,9 +133,10 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
131
133
|
toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,
|
|
132
134
|
toolLastInputCache: toolLastInputCacheRef.current,
|
|
133
135
|
mcpAppMetadataCache: mcpAppMetadataCacheRef.current,
|
|
136
|
+
...(optimisticMessageId && { optimisticMessageId }),
|
|
134
137
|
...(chatHelpers.error && { error: chatHelpers.error.message }),
|
|
135
138
|
}),
|
|
136
|
-
[toolStatuses, messageTiming, chatHelpers.error],
|
|
139
|
+
[toolStatuses, messageTiming, optimisticMessageId, chatHelpers.error],
|
|
137
140
|
),
|
|
138
141
|
});
|
|
139
142
|
|
|
@@ -344,8 +347,8 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
344
347
|
options: { metadata: lastRunConfigRef.current },
|
|
345
348
|
});
|
|
346
349
|
},
|
|
350
|
+
...pickExternalStoreSharedOptions(adapter),
|
|
347
351
|
...(onResume && { onResume }),
|
|
348
|
-
...(suggestions && { suggestions }),
|
|
349
352
|
adapters: {
|
|
350
353
|
attachments: vercelAttachmentAdapter,
|
|
351
354
|
...contextAdapters,
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { useChat, type UIMessage } from "@ai-sdk/react";
|
|
4
4
|
import type { AssistantCloud } from "assistant-cloud";
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
pickExternalStoreSharedOptions,
|
|
7
|
+
type AssistantRuntime,
|
|
8
|
+
type ExternalStoreSharedOptions,
|
|
9
|
+
} from "@assistant-ui/core";
|
|
6
10
|
import {
|
|
7
11
|
useCloudThreadListAdapter,
|
|
8
12
|
useRemoteThreadListRuntime,
|
|
@@ -19,24 +23,21 @@ import type { AssistantChatResumableOptions } from "../resumable";
|
|
|
19
23
|
import { useEffect, useMemo, useRef } from "react";
|
|
20
24
|
|
|
21
25
|
export type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =
|
|
22
|
-
ChatInit<UI_MESSAGE> &
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
ChatInit<UI_MESSAGE> &
|
|
27
|
+
ExternalStoreSharedOptions & {
|
|
28
|
+
cloud?: AssistantCloud | undefined;
|
|
29
|
+
adapters?: AISDKRuntimeAdapter["adapters"] | undefined;
|
|
30
|
+
toCreateMessage?: CustomToCreateMessageFunction;
|
|
31
|
+
onResume?: AISDKRuntimeAdapter["onResume"];
|
|
32
|
+
};
|
|
29
33
|
|
|
30
34
|
const useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
31
35
|
transport: ChatTransport<UI_MESSAGE>,
|
|
32
36
|
): ChatTransport<UI_MESSAGE> => {
|
|
33
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
34
37
|
const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);
|
|
35
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
36
38
|
useEffect(() => {
|
|
37
39
|
transportRef.current = transport;
|
|
38
40
|
});
|
|
39
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
40
41
|
const dynamicTransport = useMemo(
|
|
41
42
|
() =>
|
|
42
43
|
new Proxy(transportRef.current, {
|
|
@@ -72,33 +73,36 @@ const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
72
73
|
adapters,
|
|
73
74
|
transport: transportOptions,
|
|
74
75
|
toCreateMessage,
|
|
76
|
+
isDisabled: _isDisabled,
|
|
77
|
+
isSendDisabled: _isSendDisabled,
|
|
78
|
+
unstable_capabilities: _unstable_capabilities,
|
|
79
|
+
suggestions: _suggestions,
|
|
75
80
|
onResume,
|
|
76
|
-
suggestions,
|
|
77
81
|
...chatOptions
|
|
78
82
|
} = options ?? {};
|
|
83
|
+
// peel guard: any shared key left in `chatOptions` collapses this to `never`
|
|
84
|
+
true satisfies keyof typeof chatOptions &
|
|
85
|
+
keyof ExternalStoreSharedOptions extends never
|
|
86
|
+
? true
|
|
87
|
+
: never;
|
|
79
88
|
|
|
80
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
81
89
|
const transport = useDynamicChatTransport(
|
|
82
90
|
transportOptions ?? new AssistantChatTransport(),
|
|
83
91
|
);
|
|
84
92
|
|
|
85
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
86
93
|
const id = useAuiState((s) => s.threadListItem.id);
|
|
87
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
88
94
|
const aui = useAui();
|
|
89
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
90
95
|
const chat = useChat({
|
|
91
96
|
...chatOptions,
|
|
92
97
|
id,
|
|
93
98
|
transport,
|
|
94
99
|
});
|
|
95
100
|
|
|
96
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
97
101
|
const runtime = useAISDKRuntime(chat, {
|
|
98
102
|
adapters,
|
|
103
|
+
...pickExternalStoreSharedOptions(options ?? {}),
|
|
99
104
|
...(toCreateMessage && { toCreateMessage }),
|
|
100
105
|
...(onResume && { onResume }),
|
|
101
|
-
...(suggestions && { suggestions }),
|
|
102
106
|
});
|
|
103
107
|
|
|
104
108
|
if (transport instanceof AssistantChatTransport) {
|
|
@@ -108,9 +112,7 @@ const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
108
112
|
);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
112
115
|
const resumeFiredRef = useRef(false);
|
|
113
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
114
116
|
useEffect(() => {
|
|
115
117
|
if (resumeFiredRef.current) return;
|
|
116
118
|
const adapter = getResumableAdapter(transport);
|
|
@@ -137,7 +139,6 @@ export const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({
|
|
|
137
139
|
const cloudAdapter = useCloudThreadListAdapter({ cloud });
|
|
138
140
|
return useRemoteThreadListRuntime({
|
|
139
141
|
runtimeHook: function RuntimeHook() {
|
|
140
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
|
|
141
142
|
return useChatThreadRuntime(options);
|
|
142
143
|
},
|
|
143
144
|
adapter: cloudAdapter,
|
|
@@ -5,6 +5,7 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
5
5
|
import type {
|
|
6
6
|
AssistantRuntime,
|
|
7
7
|
MessageFormatAdapter,
|
|
8
|
+
MessageFormatRepository,
|
|
8
9
|
ThreadHistoryAdapter,
|
|
9
10
|
ThreadMessage,
|
|
10
11
|
} from "@assistant-ui/core";
|
|
@@ -15,7 +16,11 @@ vi.mock("@assistant-ui/store", () => ({
|
|
|
15
16
|
}),
|
|
16
17
|
}));
|
|
17
18
|
|
|
18
|
-
import {
|
|
19
|
+
import { MessageRepository } from "@assistant-ui/core/internal";
|
|
20
|
+
import {
|
|
21
|
+
toExportedMessageRepository,
|
|
22
|
+
useExternalHistory,
|
|
23
|
+
} from "./useExternalHistory";
|
|
19
24
|
|
|
20
25
|
const noopThread = {
|
|
21
26
|
subscribe: () => () => {},
|
|
@@ -105,3 +110,57 @@ describe("useExternalHistory withFormat contract", () => {
|
|
|
105
110
|
expect(adapter.withFormat).toHaveBeenCalledWith(storageFormat);
|
|
106
111
|
});
|
|
107
112
|
});
|
|
113
|
+
|
|
114
|
+
describe("toExportedMessageRepository", () => {
|
|
115
|
+
const convert = (items: { id: string; ok: boolean }[]): ThreadMessage[] =>
|
|
116
|
+
items[0]!.ok ? [{ id: items[0]!.id } as ThreadMessage] : [];
|
|
117
|
+
|
|
118
|
+
it("drops a malformed row together with its now-orphaned descendants", () => {
|
|
119
|
+
const repo: MessageFormatRepository<{ id: string; ok: boolean }> = {
|
|
120
|
+
headId: "c",
|
|
121
|
+
messages: [
|
|
122
|
+
{ parentId: null, message: { id: "a", ok: true } },
|
|
123
|
+
{ parentId: "a", message: { id: "b", ok: false } },
|
|
124
|
+
{ parentId: "b", message: { id: "c", ok: true } },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const result = toExportedMessageRepository(convert, repo);
|
|
129
|
+
|
|
130
|
+
expect(result.messages.map((m) => m.message.id)).toEqual(["a"]);
|
|
131
|
+
expect(result.headId).toBeNull();
|
|
132
|
+
expect(() => new MessageRepository().import(result)).not.toThrow();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("drops a headId that points at a filtered row", () => {
|
|
136
|
+
const repo: MessageFormatRepository<{ id: string; ok: boolean }> = {
|
|
137
|
+
headId: "b",
|
|
138
|
+
messages: [
|
|
139
|
+
{ parentId: null, message: { id: "a", ok: true } },
|
|
140
|
+
{ parentId: "a", message: { id: "b", ok: false } },
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const result = toExportedMessageRepository(convert, repo);
|
|
145
|
+
|
|
146
|
+
expect(result.messages.map((m) => m.message.id)).toEqual(["a"]);
|
|
147
|
+
expect(result.headId).toBeNull();
|
|
148
|
+
expect(() => new MessageRepository().import(result)).not.toThrow();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("drops a malformed root and its entire subtree", () => {
|
|
152
|
+
const repo: MessageFormatRepository<{ id: string; ok: boolean }> = {
|
|
153
|
+
headId: "b",
|
|
154
|
+
messages: [
|
|
155
|
+
{ parentId: null, message: { id: "a", ok: false } },
|
|
156
|
+
{ parentId: "a", message: { id: "b", ok: true } },
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const result = toExportedMessageRepository(convert, repo);
|
|
161
|
+
|
|
162
|
+
expect(result.messages).toHaveLength(0);
|
|
163
|
+
expect(result.headId).toBeNull();
|
|
164
|
+
expect(() => new MessageRepository().import(result)).not.toThrow();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -24,15 +24,24 @@ export const toExportedMessageRepository = <TMessage>(
|
|
|
24
24
|
toThreadMessages: (messages: TMessage[]) => ThreadMessage[],
|
|
25
25
|
messages: MessageFormatRepository<TMessage>,
|
|
26
26
|
): ExportedMessageRepository => {
|
|
27
|
+
const survivingIds = new Set<string>();
|
|
28
|
+
const survivors = messages.messages.flatMap((m) => {
|
|
29
|
+
const message = toThreadMessages([m.message])[0];
|
|
30
|
+
if (!message) {
|
|
31
|
+
console.warn("Skipping a stored message that could not be loaded.");
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
if (m.parentId && !survivingIds.has(m.parentId)) return [];
|
|
35
|
+
survivingIds.add(message.id);
|
|
36
|
+
return [{ ...m, message }];
|
|
37
|
+
});
|
|
38
|
+
|
|
27
39
|
return {
|
|
28
|
-
headId:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
message,
|
|
34
|
-
};
|
|
35
|
-
}),
|
|
40
|
+
headId:
|
|
41
|
+
messages.headId && survivingIds.has(messages.headId)
|
|
42
|
+
? messages.headId
|
|
43
|
+
: null,
|
|
44
|
+
messages: survivors,
|
|
36
45
|
};
|
|
37
46
|
};
|
|
38
47
|
|
|
@@ -6,6 +6,31 @@ import {
|
|
|
6
6
|
} from "./convertMessage";
|
|
7
7
|
|
|
8
8
|
describe("AISDKMessageConverter", () => {
|
|
9
|
+
it("flags the streaming assistant message as optimistic", () => {
|
|
10
|
+
const metadata: AISDKMessageConverterMetadata = {
|
|
11
|
+
optimisticMessageId: "a1",
|
|
12
|
+
};
|
|
13
|
+
const converted = AISDKMessageConverter.toThreadMessages(
|
|
14
|
+
[
|
|
15
|
+
{ id: "u1", role: "user", parts: [{ type: "text", text: "hi" }] },
|
|
16
|
+
{ id: "a1", role: "assistant", parts: [{ type: "text", text: "yo" }] },
|
|
17
|
+
] as any,
|
|
18
|
+
true,
|
|
19
|
+
metadata,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
expect(converted[0]?.metadata.isOptimistic).toBeFalsy();
|
|
23
|
+
expect(converted[1]?.metadata.isOptimistic).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("does not flag messages when no optimistic id is provided", () => {
|
|
27
|
+
const converted = AISDKMessageConverter.toThreadMessages([
|
|
28
|
+
{ id: "a1", role: "assistant", parts: [{ type: "text", text: "yo" }] },
|
|
29
|
+
] as any);
|
|
30
|
+
|
|
31
|
+
expect(converted[0]?.metadata.isOptimistic).toBeFalsy();
|
|
32
|
+
});
|
|
33
|
+
|
|
9
34
|
it("converts user files into attachments and keeps text content", () => {
|
|
10
35
|
const converted = AISDKMessageConverter.toThreadMessages([
|
|
11
36
|
{
|
|
@@ -24,6 +24,8 @@ export type AISDKMessageConverterMetadata =
|
|
|
24
24
|
toolArgsKeyOrderCache?: Map<string, Map<string, string[]>>;
|
|
25
25
|
toolLastInputCache?: Map<string, ReadonlyJSONObject>;
|
|
26
26
|
mcpAppMetadataCache?: Map<string, McpAppMetadata>;
|
|
27
|
+
/** Id of the currently-streaming message, flagged optimistic (#4037). */
|
|
28
|
+
optimisticMessageId?: string | undefined;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
function stripClosingDelimiters(json: string): string {
|
|
@@ -393,6 +395,9 @@ export const AISDKMessageConverter = unstable_createMessageConverter(
|
|
|
393
395
|
case "system":
|
|
394
396
|
case "assistant": {
|
|
395
397
|
const timing = metadata.messageTiming?.[message.id];
|
|
398
|
+
const isOptimistic =
|
|
399
|
+
message.role === "assistant" &&
|
|
400
|
+
message.id === metadata.optimisticMessageId;
|
|
396
401
|
return {
|
|
397
402
|
role: message.role,
|
|
398
403
|
id: message.id,
|
|
@@ -401,6 +406,7 @@ export const AISDKMessageConverter = unstable_createMessageConverter(
|
|
|
401
406
|
metadata: {
|
|
402
407
|
...(message.metadata as MessageMetadata),
|
|
403
408
|
...(timing && { timing }),
|
|
409
|
+
...(isOptimistic && { isOptimistic: true }),
|
|
404
410
|
},
|
|
405
411
|
};
|
|
406
412
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":["JSONSchema4TypeName","JSONSchema4Type","JSONSchema4Object","JSONSchema4Array","key","Array","JSONSchema4Version","JSONSchema4","id","$ref","$schema","title","description","default","multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","additionalItems","items","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","additionalProperties","definitions","k","properties","patternProperties","dependencies","enum","type","allOf","anyOf","oneOf","not","extends","format","JSONSchema6TypeName","JSONSchema6Type","JSONSchema6Object","JSONSchema6Array","JSONSchema6Version","JSONSchema6Definition","JSONSchema6","$id","contains","propertyNames","const","examples","JSONSchema7TypeName","JSONSchema7Type","JSONSchema7Object","JSONSchema7Array","JSONSchema7Version","JSONSchema7Definition","JSONSchema7","$comment","$defs","if","then","else","contentMediaType","contentEncoding","readOnly","writeOnly","ValidationResult","ValidationError","valid","errors","property","message","validate","instance","schema","checkPropertyChange","value","mustBeValid","result"],"sources":["../../../../../../../../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;KA+iBYwD,mBAAAA;AAAAA;;;;;KAaAC,eAAAA;AAAAA,qBAINC,iBAAAA,GACAC,gBAAgB;AAAA;AAAA,UAILD,iBAAAA;EAAAA,CACZtD,GAAAA,WAAcqD,eAAe;AAAA;AAAA;AAAA;AAAA,UAKjBE,gBAAAA,SAAyBtD,KAAK,CAACoD,eAAAA;;;;;;;;;;;;KAapCG,kBAAAA;;;;;KAMAC,qBAAAA,GAAwBC,WAAW;AAAA,UAC9BA,WAAAA;EACbX,GAAAA;EACA1C,IAAAA;EACAC,OAAAA,GAAUkD,kBAAAA;EACVG,QAAAA;;;;;EAMAC,KAAAA;IAAAA,CACK5D,GAAAA,WAAcyD,qBAAAA;EAAAA;;;;EAMnBxB,IAAAA,GAAOmB,mBAAAA,GAAsBA,mBAAAA;EAC7BpB,IAAAA,GAAOqB,eAAAA;EACPH,KAAAA,GAAQG,eAAAA;;;;EAKR3C,UAAAA;EACAC,OAAAA;EACAC,gBAAAA;EACAC,OAAAA;EACAC,gBAAAA;;;;EAKAC,SAAAA;EACAC,SAAAA;EACAC,OAAAA;;;;EAKAE,KAAAA,GAAQsC,qBAAAA,GAAwBA,qBAAAA;EAChCvC,eAAAA,GAAkBuC,qBAAAA;EAClBrC,QAAAA;EACAC,QAAAA;EACAC,WAAAA;EACA0B,QAAAA,GAAWS,qBAAAA;;;;EAKXlC,aAAAA;EACAC,aAAAA;EACAC,QAAAA;EACAI,UAAAA;IAAAA,CACK7B,GAAAA,WAAcyD,qBAAAA;EAAAA;EAEnB3B,iBAAAA;IAAAA,CACK9B,GAAAA,WAAcyD,qBAAAA;EAAAA;EAEnB/B,oBAAAA,GAAuB+B,qBAAAA;EACvB1B,YAAAA;IAAAA,CACK/B,GAAAA,WAAcyD,qBAAAA;EAAAA;EAEnBR,aAAAA,GAAgBQ,qBAAAA;;;;EAKhBI,EAAAA,GAAKJ,qBAAAA;EACLK,IAAAA,GAAOL,qBAAAA;EACPM,IAAAA,GAAON,qBAAAA;;;;EAKPvB,KAAAA,GAAQuB,qBAAAA;EACRtB,KAAAA,GAAQsB,qBAAAA;EACRrB,KAAAA,GAAQqB,qBAAAA;EACRpB,GAAAA,GAAMoB,qBAAAA;;;;EAKNlB,MAAAA;;;;EAKAyB,gBAAAA;EACAC,eAAAA;;;;EAKAtC,WAAAA;IAAAA,CACK3B,GAAAA,WAAcyD,qBAAAA;EAAAA;;;;EAMnBlD,KAAAA;EACAC,WAAAA;EACAC,OAAAA,GAAU4C,eAAAA;EACVa,QAAAA;EACAC,SAAAA;EACAhB,QAAAA,GAAWE,eAAAA;AAAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-utils.js","names":[],"sources":["../../../../../../../assistant-stream/dist/core/tool/schema-utils.js"],"sourcesContent":["//#region src/core/tool/schema-utils.ts\nfunction isStandardSchema(schema) {\n\treturn typeof schema === \"object\" && schema !== null && \"~standard\" in schema && typeof schema[\"~standard\"] === \"object\";\n}\nfunction hasToJSONSchemaMethod(schema) {\n\treturn typeof schema === \"object\" && schema !== null && \"toJSONSchema\" in schema && typeof schema.toJSONSchema === \"function\";\n}\nfunction hasToJSONMethod(schema) {\n\treturn typeof schema === \"object\" && schema !== null && \"toJSON\" in schema && typeof schema.toJSON === \"function\";\n}\n/**\n* Converts a schema to JSONSchema7.\n* Supports:\n* - StandardSchemaV1 with ~standard.toJSONSchema (e.g., Zod v4)\n* - StandardSchemaV1 with ~standard.jsonSchema.input() (e.g., Zod v4)\n* - Objects with toJSONSchema() method (e.g., Zod v4)\n* - Objects with toJSON() method\n* - Plain JSONSchema7 objects (must have a \"type\" property)\n*/\nfunction toJSONSchema(schema) {\n\tif (isStandardSchema(schema)) {\n\t\tconst toJSONSchemaMethod = schema[\"~standard\"].toJSONSchema;\n\t\tif (typeof toJSONSchemaMethod === \"function\") return toJSONSchemaMethod();\n\t\tconst jsonSchema = schema[\"~standard\"].jsonSchema;\n\t\tif (typeof jsonSchema === \"object\" && jsonSchema !== null && typeof jsonSchema.input === \"function\") return jsonSchema.input();\n\t}\n\tif (hasToJSONSchemaMethod(schema)) return schema.toJSONSchema();\n\tif (hasToJSONMethod(schema)) return schema.toJSON();\n\tif (isStandardSchema(schema)) throw new Error(\"Could not convert schema to JSON Schema. The schema implements Standard Schema but does not support JSON Schema conversion. If you are using Zod, please upgrade to Zod v4 (npm install zod@latest). Alternatively, pass a plain JSON Schema object instead.\");\n\treturn schema;\n}\n/**\n* Returns a copy of the JSON Schema with `required` removed recursively,\n* making every property optional. Array item schemas are left unchanged.\n*/\nfunction toPartialJSONSchema(schema) {\n\tconst { required: _, ...result } = schema;\n\tif (result.properties) result.properties = Object.fromEntries(Object.entries(result.properties).map(([key, prop]) => {\n\t\tif (typeof prop === \"object\" && prop !== null && !Array.isArray(prop)) {\n\t\t\tconst p = prop;\n\t\t\treturn [key, p.properties != null ? toPartialJSONSchema(p) : prop];\n\t\t}\n\t\treturn [key, prop];\n\t}));\n\treturn result;\n}\nfunction defaultToolFilter(_name, tool) {\n\treturn !tool.disabled && tool.type !== \"backend\";\n}\n/**\n* Converts a record of tools to a record of tool definitions with JSON Schema parameters.\n* By default, filters out disabled tools and backend tools.\n*/\nfunction toToolsJSONSchema(tools, options = {}) {\n\tif (!tools) return {};\n\tconst filter = options.filter ?? defaultToolFilter;\n\treturn Object.fromEntries(Object.entries(tools).filter(([name, tool]) => filter(name, tool) && tool.parameters).map(([name, tool]) => [name, {\n\t\t...tool.description && { description: tool.description },\n\t\tparameters: toJSONSchema(tool.parameters)\n\t}]));\n}\n//#endregion\nexport { toJSONSchema, toPartialJSONSchema, toToolsJSONSchema };\n\n//# sourceMappingURL=schema-utils.js.map"],"mappings":";AACA,SAAS,iBAAiB,QAAQ;CACjC,OAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,eAAe,UAAU,OAAO,OAAO,iBAAiB;AACjH;AACA,SAAS,sBAAsB,QAAQ;CACtC,OAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,kBAAkB,UAAU,OAAO,OAAO,iBAAiB;AACpH;AACA,SAAS,gBAAgB,QAAQ;CAChC,OAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,YAAY,UAAU,OAAO,OAAO,WAAW;AACxG;;;;;;;;;;AAUA,SAAS,aAAa,QAAQ;CAC7B,IAAI,iBAAiB,MAAM,GAAG;EAC7B,MAAM,qBAAqB,OAAO,aAAa;EAC/C,IAAI,OAAO,uBAAuB,YAAY,OAAO,mBAAmB;EACxE,MAAM,aAAa,OAAO,aAAa;EACvC,IAAI,OAAO,eAAe,YAAY,eAAe,QAAQ,OAAO,WAAW,UAAU,YAAY,OAAO,WAAW,MAAM;CAC9H;CACA,IAAI,sBAAsB,MAAM,GAAG,OAAO,OAAO,aAAa;CAC9D,IAAI,gBAAgB,MAAM,GAAG,OAAO,OAAO,OAAO;CAClD,IAAI,iBAAiB,MAAM,GAAG,MAAM,IAAI,MAAM,8PAA8P;CAC5S,OAAO;AACR;AAgBA,SAAS,kBAAkB,OAAO,MAAM;CACvC,OAAO,CAAC,KAAK,YAAY,KAAK,SAAS;AACxC;;;;;AAKA,SAAS,kBAAkB,OAAO,UAAU,CAAC,GAAG;CAC/C,IAAI,CAAC,OAAO,OAAO,CAAC;CACpB,MAAM,SAAS,QAAQ,UAAU;CACjC,OAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,QAAQ,CAAC,MAAM,UAAU,OAAO,MAAM,IAAI,KAAK,KAAK,UAAU,EAAE,KAAK,CAAC,MAAM,UAAU,CAAC,MAAM;EAC5I,GAAG,KAAK,eAAe,EAAE,aAAa,KAAK,YAAY;EACvD,YAAY,aAAa,KAAK,UAAU;CACzC,CAAC,CAAC,CAAC;AACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-types.d.ts","names":["AsyncIterableStream","JSONSchema7","DeepPartial","TypeAtPath","TypePath","ToolResponse","StandardSchemaV1","ToolModelContentPart","type","text","data","mediaType","filename","ToolModelOutputFunction","TArgs","TResult","Promise","toolCallId","input","output","options","ToolCallArgsReader","PathT","Record","U","Array","get","fieldPath","streamValues","streamText","forEach","ToolCallResponseReader","ToolCallReader","args","response","result","ToolExecutionContext","AbortSignal","abortSignal","human","payload","ToolExecuteFunction","context","ToolStreamCallFunction","reader","OnSchemaValidationErrorFunction","ToolBase","streamCall","BackendTool","description","parameters","disabled","execute","toModelOutput","experimental_onSchemaValidationError","FrontendTool","HumanTool","Tool","ToolWithoutType","Omit"],"sources":["../../../../../../../assistant-stream/dist/core/tool/tool-types.d.ts"],"mappings":";;KAOKO,oBAAAA;EAEME,4EADmED,IAAAA,UACnEC;EAAAA,SAAAA,IAAAA;AAAAA;EAQAE,4EANmEH,IAAAA;EAOnEI;;AAAQ;;EAARA,SAFAF,IAAAA;WACAC,SAAAA;WACAC,QAAAA;AAAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import { ToolModelContentPart } from "./core/tool/tool-types.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createResumableAssistantStreamResponse.d.ts","names":["AssistantStreamController","AssistantStreamEncoder","ResumableStreamContext","RESUMABLE_STREAM_ID_HEADER","CreateResumableAssistantStreamResponseOptions","PromiseLike","HeadersInit","context","streamId","callback","controller","encoder","headers","createResumableAssistantStreamResponse","Response","Promise","options","CreateResumeAssistantStreamResponseOptions","missingResponse","createResumeAssistantStreamResponse"],"sources":["../../../../../../assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts"],"mappings":";;cAKcG,0BAAAA"}
|
package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createResumableAssistantStreamResponse.js","names":[],"sources":["../../../../../../assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js"],"sourcesContent":["import { DataStreamEncoder } from \"../core/serialization/data-stream/DataStream.js\";\nimport { createAssistantStream } from \"../core/modules/assistant-stream.js\";\n//#region src/resumable/createResumableAssistantStreamResponse.ts\nconst RESUMABLE_STREAM_ID_HEADER = \"x-resumable-stream-id\";\nasync function createResumableAssistantStreamResponse(options) {\n\tconst encoder = (options.encoder ?? (() => new DataStreamEncoder()))();\n\tconst stream = await options.context.run(options.streamId, () => {\n\t\treturn createAssistantStream(options.callback).pipeThrough(encoder);\n\t});\n\treturn new Response(stream, { headers: mergeHeaders(encoder.headers, options.headers, options.streamId) });\n}\nasync function createResumeAssistantStreamResponse(options) {\n\tconst stream = await options.context.resume(options.streamId);\n\tif (!stream) return options.missingResponse?.() ?? defaultMissingResponse();\n\tconst encoder = (options.encoder ?? (() => new DataStreamEncoder()))();\n\treturn new Response(stream, { headers: mergeHeaders(encoder.headers, options.headers, options.streamId) });\n}\nfunction defaultMissingResponse() {\n\treturn new Response(JSON.stringify({ error: \"stream not found\" }), {\n\t\tstatus: 404,\n\t\theaders: { \"Content-Type\": \"application/json\" }\n\t});\n}\nfunction mergeHeaders(encoderHeaders, extra, streamId) {\n\tconst merged = new Headers(encoderHeaders ?? {});\n\tif (extra) for (const [key, value] of new Headers(extra)) merged.set(key, value);\n\tmerged.set(RESUMABLE_STREAM_ID_HEADER, streamId);\n\treturn merged;\n}\n//#endregion\nexport { RESUMABLE_STREAM_ID_HEADER, createResumableAssistantStreamResponse, createResumeAssistantStreamResponse };\n\n//# sourceMappingURL=createResumableAssistantStreamResponse.js.map"],"mappings":";AAGA,MAAM,6BAA6B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"json-value.d.ts","names":["ReadonlyJSONValue","ReadonlyJSONObject","ReadonlyJSONArray","key"],"sources":["../../../../../../../assistant-stream/dist/utils/json/json-value.d.ts"],"mappings":";;KACKA,iBAAAA,sCAAuDC,kBAAAA,GAAqBC,iBAAiB;AAAA,KAC7FD,kBAAAA;EAAAA,UACOE,GAAAA,WAAcH,iBAAiB;AAAA;AAAA,KAEtCE,iBAAAA,YAA6BF,iBAAiB"}
|
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/core/AssistantStreamChunk.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/core/modules/assistant-stream.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/core/modules/tool-call.d.ts
RENAMED
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/core/serialization/PlainText.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/core/tool/ToolExecutionStream.d.ts
RENAMED
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/core/tool/toolResultStream.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{packages/assistant-stream → assistant-stream}/dist/utils/json/json-value.d.ts
RENAMED
|
File without changes
|
|
File without changes
|