@convex-dev/agent 0.6.4 → 0.7.0
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/MIGRATION.md +60 -116
- package/dist/client/messages.d.ts +1 -398
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/messages.js +3 -47
- package/dist/client/messages.js.map +1 -1
- package/dist/client/types.d.ts +1 -455
- package/dist/client/types.d.ts.map +1 -1
- package/dist/component/_generated/component.d.ts +805 -45
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/messages.d.ts +1252 -201
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +49 -23
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +2593 -332
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/streams.d.ts +7 -1
- package/dist/component/streams.d.ts.map +1 -1
- package/dist/component/streams.js +24 -30
- package/dist/component/streams.js.map +1 -1
- package/dist/component/threads.d.ts.map +1 -1
- package/dist/component/threads.js +1 -2
- package/dist/component/threads.js.map +1 -1
- package/dist/react/index.d.ts +5 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -5
- package/dist/react/index.js.map +1 -1
- package/dist/shared.d.ts +19 -7
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +4 -4
- package/dist/shared.js.map +1 -1
- package/dist/streaming/materializePersistedUIMessageChunks.d.ts +16 -0
- package/dist/streaming/materializePersistedUIMessageChunks.d.ts.map +1 -0
- package/dist/streaming/materializePersistedUIMessageChunks.js +302 -0
- package/dist/streaming/materializePersistedUIMessageChunks.js.map +1 -0
- package/dist/streaming/persistedUIMessageChunks.d.ts +106 -0
- package/dist/streaming/persistedUIMessageChunks.d.ts.map +1 -0
- package/dist/streaming/persistedUIMessageChunks.js +475 -0
- package/dist/streaming/persistedUIMessageChunks.js.map +1 -0
- package/dist/validators.d.ts +10026 -1055
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +71 -9
- package/dist/validators.js.map +1 -1
- package/dist/{UIMessages.d.ts → vercel/UIMessages.d.ts} +1 -1
- package/dist/vercel/UIMessages.d.ts.map +1 -0
- package/dist/{UIMessages.js → vercel/UIMessages.js} +63 -1
- package/dist/vercel/UIMessages.js.map +1 -0
- package/dist/{client → vercel/client}/createTool.d.ts +23 -16
- package/dist/vercel/client/createTool.d.ts.map +1 -0
- package/dist/{client → vercel/client}/createTool.js +2 -0
- package/dist/vercel/client/createTool.js.map +1 -0
- package/dist/{client → vercel/client}/definePlaygroundAPI.d.ts +533 -79
- package/dist/{client → vercel/client}/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/{client → vercel/client}/definePlaygroundAPI.js +8 -7
- package/dist/vercel/client/definePlaygroundAPI.js.map +1 -0
- package/dist/{client → vercel/client}/files.d.ts +2 -2
- package/dist/vercel/client/files.d.ts.map +1 -0
- package/dist/vercel/client/files.js.map +1 -0
- package/dist/vercel/client/messages.d.ts +542 -0
- package/dist/vercel/client/messages.d.ts.map +1 -0
- package/dist/vercel/client/messages.js +66 -0
- package/dist/vercel/client/messages.js.map +1 -0
- package/dist/{client → vercel/client}/mockModel.d.ts +17 -17
- package/dist/vercel/client/mockModel.d.ts.map +1 -0
- package/dist/{client → vercel/client}/mockModel.js +12 -13
- package/dist/vercel/client/mockModel.js.map +1 -0
- package/dist/{client → vercel/client}/saveInputMessages.d.ts +2 -2
- package/dist/vercel/client/saveInputMessages.d.ts.map +1 -0
- package/dist/vercel/client/saveInputMessages.js.map +1 -0
- package/dist/{client → vercel/client}/search.d.ts +119 -22
- package/dist/vercel/client/search.d.ts.map +1 -0
- package/dist/{client → vercel/client}/search.js +2 -2
- package/dist/vercel/client/search.js.map +1 -0
- package/dist/{client → vercel/client}/start.d.ts +26 -11
- package/dist/vercel/client/start.d.ts.map +1 -0
- package/dist/{client → vercel/client}/start.js +64 -22
- package/dist/vercel/client/start.js.map +1 -0
- package/dist/{client → vercel/client}/streamText.d.ts +13 -12
- package/dist/vercel/client/streamText.d.ts.map +1 -0
- package/dist/{client → vercel/client}/streamText.js +43 -9
- package/dist/vercel/client/streamText.js.map +1 -0
- package/dist/{client → vercel/client}/streaming.d.ts +1410 -183
- package/dist/vercel/client/streaming.d.ts.map +1 -0
- package/dist/{client → vercel/client}/streaming.js +120 -52
- package/dist/vercel/client/streaming.js.map +1 -0
- package/dist/vercel/client/types.d.ts +456 -0
- package/dist/vercel/client/types.d.ts.map +1 -0
- package/dist/vercel/client/types.js +3 -0
- package/dist/vercel/client/types.js.map +1 -0
- package/dist/{client → vercel/client}/utils.d.ts +3 -2
- package/dist/vercel/client/utils.d.ts.map +1 -0
- package/dist/{client → vercel/client}/utils.js +2 -2
- package/dist/vercel/client/utils.js.map +1 -0
- package/dist/{deltas.d.ts → vercel/deltas.d.ts} +3 -4
- package/dist/vercel/deltas.d.ts.map +1 -0
- package/dist/{deltas.js → vercel/deltas.js} +195 -99
- package/dist/vercel/deltas.js.map +1 -0
- package/dist/{client → vercel}/index.d.ts +482 -106
- package/dist/vercel/index.d.ts.map +1 -0
- package/dist/{client → vercel}/index.js +64 -46
- package/dist/vercel/index.js.map +1 -0
- package/dist/{mapping.d.ts → vercel/mapping.d.ts} +5 -19
- package/dist/vercel/mapping.d.ts.map +1 -0
- package/dist/{mapping.js → vercel/mapping.js} +411 -114
- package/dist/vercel/mapping.js.map +1 -0
- package/dist/{react → vercel/react}/optimisticallySendMessage.d.ts +2 -2
- package/dist/vercel/react/optimisticallySendMessage.d.ts.map +1 -0
- package/dist/vercel/react/optimisticallySendMessage.js.map +1 -0
- package/dist/{react → vercel/react}/types.d.ts +1 -1
- package/dist/vercel/react/types.d.ts.map +1 -0
- package/dist/{react → vercel/react}/types.js.map +1 -1
- package/dist/{react → vercel/react}/useDeltaStreams.d.ts +1 -1
- package/dist/vercel/react/useDeltaStreams.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useDeltaStreams.js +1 -1
- package/dist/vercel/react/useDeltaStreams.js.map +1 -0
- package/dist/{react → vercel/react}/useStreamingUIMessages.d.ts +1 -1
- package/dist/vercel/react/useStreamingUIMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useStreamingUIMessages.js +7 -3
- package/dist/vercel/react/useStreamingUIMessages.js.map +1 -0
- package/dist/{react → vercel/react}/useThreadMessages.d.ts +1 -1
- package/dist/vercel/react/useThreadMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useThreadMessages.js +1 -1
- package/dist/vercel/react/useThreadMessages.js.map +1 -0
- package/dist/{react → vercel/react}/useUIMessages.d.ts +1 -1
- package/dist/vercel/react/useUIMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useUIMessages.js +1 -1
- package/dist/vercel/react/useUIMessages.js.map +1 -0
- package/package.json +31 -24
- package/src/client/messages.ts +5 -107
- package/src/client/types.ts +0 -608
- package/src/component/_generated/component.ts +1089 -48
- package/src/component/messages.test.ts +273 -1
- package/src/component/messages.ts +62 -32
- package/src/component/streams.ts +47 -47
- package/src/component/threads.ts +5 -2
- package/src/eslintConfig.test.ts +44 -0
- package/src/react/index.ts +8 -5
- package/src/shared.ts +26 -36
- package/src/streaming/materializePersistedUIMessageChunks.test.ts +513 -0
- package/src/streaming/materializePersistedUIMessageChunks.ts +398 -0
- package/src/streaming/persistedUIMessageChunks.test.ts +205 -0
- package/src/streaming/persistedUIMessageChunks.ts +658 -0
- package/src/validators.test.ts +4 -1
- package/src/validators.ts +89 -8
- package/src/{UIMessages.combineUIMessages.test.ts → vercel/UIMessages.combineUIMessages.test.ts} +4 -1
- package/src/{UIMessages.ts → vercel/UIMessages.ts} +95 -3
- package/src/{client → vercel/client}/approval.test.ts +23 -13
- package/src/{client → vercel/client}/createTool.ts +62 -22
- package/src/{client → vercel/client}/definePlaygroundAPI.ts +15 -16
- package/src/{client → vercel/client}/files.ts +2 -2
- package/src/{client → vercel/client}/index.test.ts +99 -31
- package/src/vercel/client/messages.ts +182 -0
- package/src/{client → vercel/client}/mockModel.ts +38 -39
- package/src/{client → vercel/client}/saveInputMessages.test.ts +1 -1
- package/src/{client → vercel/client}/saveInputMessages.ts +3 -3
- package/src/{client → vercel/client}/search.test.ts +3 -3
- package/src/{client → vercel/client}/search.ts +4 -4
- package/src/{client → vercel/client}/setup.test.ts +6 -3
- package/src/vercel/client/start.test.ts +14 -0
- package/src/{client → vercel/client}/start.ts +147 -36
- package/src/vercel/client/streamText.test.ts +223 -0
- package/src/{client → vercel/client}/streamText.ts +102 -31
- package/src/{client → vercel/client}/streaming.integration.test.ts +6 -3
- package/src/{client → vercel/client}/streaming.test.ts +178 -4
- package/src/{client → vercel/client}/streaming.ts +114 -52
- package/src/vercel/client/types.test.ts +13 -0
- package/src/vercel/client/types.ts +679 -0
- package/src/{client → vercel/client}/utils.ts +13 -7
- package/src/{deltas.test.ts → vercel/deltas.test.ts} +384 -93
- package/src/{deltas.ts → vercel/deltas.ts} +218 -115
- package/src/{fromUIMessages.test.ts → vercel/fromUIMessages.test.ts} +17 -1
- package/src/{client → vercel}/index.ts +167 -84
- package/src/{mapping.test.ts → vercel/mapping.test.ts} +377 -92
- package/src/{mapping.ts → vercel/mapping.ts} +501 -137
- package/src/{react → vercel/react}/optimisticallySendMessage.ts +2 -2
- package/src/{react → vercel/react}/types.ts +1 -1
- package/src/{react → vercel/react}/useDeltaStreams.ts +6 -2
- package/src/{react → vercel/react}/useStreamingUIMessages.ts +7 -3
- package/src/{react → vercel/react}/useThreadMessages.ts +2 -2
- package/src/{react → vercel/react}/useUIMessages.ts +2 -2
- package/src/{toUIMessages.test.ts → vercel/toUIMessages.test.ts} +49 -2
- package/dist/UIMessages.d.ts.map +0 -1
- package/dist/UIMessages.js.map +0 -1
- package/dist/client/createTool.d.ts.map +0 -1
- package/dist/client/createTool.js.map +0 -1
- package/dist/client/definePlaygroundAPI.js.map +0 -1
- package/dist/client/files.d.ts.map +0 -1
- package/dist/client/files.js.map +0 -1
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js.map +0 -1
- package/dist/client/mockModel.d.ts.map +0 -1
- package/dist/client/mockModel.js.map +0 -1
- package/dist/client/saveInputMessages.d.ts.map +0 -1
- package/dist/client/saveInputMessages.js.map +0 -1
- package/dist/client/search.d.ts.map +0 -1
- package/dist/client/search.js.map +0 -1
- package/dist/client/start.d.ts.map +0 -1
- package/dist/client/start.js.map +0 -1
- package/dist/client/streamText.d.ts.map +0 -1
- package/dist/client/streamText.js.map +0 -1
- package/dist/client/streaming.d.ts.map +0 -1
- package/dist/client/streaming.js.map +0 -1
- package/dist/client/utils.d.ts.map +0 -1
- package/dist/client/utils.js.map +0 -1
- package/dist/deltas.d.ts.map +0 -1
- package/dist/deltas.js.map +0 -1
- package/dist/mapping.d.ts.map +0 -1
- package/dist/mapping.js.map +0 -1
- package/dist/react/optimisticallySendMessage.d.ts.map +0 -1
- package/dist/react/optimisticallySendMessage.js.map +0 -1
- package/dist/react/types.d.ts.map +0 -1
- package/dist/react/useDeltaStreams.d.ts.map +0 -1
- package/dist/react/useDeltaStreams.js.map +0 -1
- package/dist/react/useStreamingUIMessages.d.ts.map +0 -1
- package/dist/react/useStreamingUIMessages.js.map +0 -1
- package/dist/react/useThreadMessages.d.ts.map +0 -1
- package/dist/react/useThreadMessages.js.map +0 -1
- package/dist/react/useUIMessages.d.ts.map +0 -1
- package/dist/react/useUIMessages.js.map +0 -1
- package/src/client/streamText.test.ts +0 -102
- /package/dist/{client → vercel/client}/files.js +0 -0
- /package/dist/{client → vercel/client}/saveInputMessages.js +0 -0
- /package/dist/{react → vercel/react}/optimisticallySendMessage.js +0 -0
- /package/dist/{react → vercel/react}/types.js +0 -0
- /package/src/{UIMessages.test.ts → vercel/UIMessages.test.ts} +0 -0
- /package/src/{react → vercel/react}/useUIMessages.test.ts +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
type CustomContentUIPart,
|
|
3
3
|
type DynamicToolUIPart,
|
|
4
4
|
type ProviderMetadata,
|
|
5
|
+
type ReasoningFileUIPart,
|
|
5
6
|
type ReasoningUIPart,
|
|
6
7
|
type TextUIPart,
|
|
7
8
|
type ToolUIPart,
|
|
8
9
|
type UIMessageChunk,
|
|
9
10
|
} from "ai";
|
|
10
|
-
import { assert } from "convex-helpers";
|
|
11
11
|
import { type UIMessage } from "./UIMessages.js";
|
|
12
|
-
import { joinText, sorted } from "
|
|
12
|
+
import { joinText, sorted } from "../shared.js";
|
|
13
13
|
import {
|
|
14
14
|
type MessageStatus,
|
|
15
15
|
type StreamDelta,
|
|
16
16
|
type StreamMessage,
|
|
17
|
-
} from "
|
|
17
|
+
} from "../validators.js";
|
|
18
18
|
|
|
19
19
|
export function blankUIMessage<METADATA = unknown>(
|
|
20
20
|
streamMessage: StreamMessage & { metadata?: METADATA },
|
|
@@ -50,58 +50,6 @@ export function statusFromStreamStatus(
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export async function updateFromUIMessageChunks(
|
|
54
|
-
uiMessage: UIMessage,
|
|
55
|
-
parts: UIMessageChunk[],
|
|
56
|
-
) {
|
|
57
|
-
if (parts.length === 0) {
|
|
58
|
-
return uiMessage;
|
|
59
|
-
}
|
|
60
|
-
const partsStream = new ReadableStream<UIMessageChunk>({
|
|
61
|
-
start(controller) {
|
|
62
|
-
for (const part of parts) {
|
|
63
|
-
controller.enqueue(part);
|
|
64
|
-
}
|
|
65
|
-
controller.close();
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
let failed = false;
|
|
69
|
-
let suppressError = false;
|
|
70
|
-
const messageStream = readUIMessageStream({
|
|
71
|
-
message: uiMessage,
|
|
72
|
-
stream: partsStream,
|
|
73
|
-
onError: (e) => {
|
|
74
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
75
|
-
if (errorMessage.toLowerCase().includes("no tool invocation found")) {
|
|
76
|
-
suppressError = true;
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
failed = true;
|
|
80
|
-
console.error("Error in stream", e);
|
|
81
|
-
},
|
|
82
|
-
terminateOnError: true,
|
|
83
|
-
});
|
|
84
|
-
let message = uiMessage;
|
|
85
|
-
try {
|
|
86
|
-
for await (const messagePart of messageStream) {
|
|
87
|
-
assert(
|
|
88
|
-
messagePart.id === message.id,
|
|
89
|
-
`Expecting to only make one UIMessage in a stream`,
|
|
90
|
-
);
|
|
91
|
-
message = messagePart;
|
|
92
|
-
}
|
|
93
|
-
} catch (e) {
|
|
94
|
-
if (!suppressError) {
|
|
95
|
-
throw e;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (failed) {
|
|
99
|
-
message.status = "failed";
|
|
100
|
-
}
|
|
101
|
-
message.text = joinText(message.parts);
|
|
102
|
-
return message;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
53
|
type ToolPart = ToolUIPart | DynamicToolUIPart;
|
|
106
54
|
|
|
107
55
|
function transitionToolPart<S extends ToolPart["state"]>(
|
|
@@ -133,11 +81,18 @@ export function emptyIncrementalStreamState(): IncrementalStreamState {
|
|
|
133
81
|
* indices stay stable across the structuredClone between batches. Behavior
|
|
134
82
|
* mirrors the AI SDK's processUIMessageStream.
|
|
135
83
|
*/
|
|
136
|
-
export function applyUIMessageChunksIncremental
|
|
137
|
-
|
|
84
|
+
export function applyUIMessageChunksIncremental<
|
|
85
|
+
METADATA = unknown,
|
|
86
|
+
DATA_PARTS extends import("ai").UIDataTypes = import("ai").UIDataTypes,
|
|
87
|
+
TOOLS extends import("ai").UITools = import("ai").UITools,
|
|
88
|
+
>(
|
|
89
|
+
uiMessage: UIMessage<METADATA, DATA_PARTS, TOOLS>,
|
|
138
90
|
newParts: UIMessageChunk[],
|
|
139
91
|
prev: IncrementalStreamState,
|
|
140
|
-
): {
|
|
92
|
+
): {
|
|
93
|
+
message: UIMessage<METADATA, DATA_PARTS, TOOLS>;
|
|
94
|
+
streamState: IncrementalStreamState;
|
|
95
|
+
} {
|
|
141
96
|
const message: UIMessage = structuredClone(uiMessage);
|
|
142
97
|
const activeText: Record<string, number> = { ...prev.activeText };
|
|
143
98
|
const activeReasoning: Record<string, number> = { ...prev.activeReasoning };
|
|
@@ -174,7 +129,9 @@ export function applyUIMessageChunksIncremental(
|
|
|
174
129
|
type: "text",
|
|
175
130
|
text: "",
|
|
176
131
|
state: "streaming",
|
|
177
|
-
|
|
132
|
+
...(part.providerMetadata
|
|
133
|
+
? { providerMetadata: part.providerMetadata }
|
|
134
|
+
: {}),
|
|
178
135
|
};
|
|
179
136
|
message.parts.push(newPart);
|
|
180
137
|
activeText[part.id] = message.parts.length - 1;
|
|
@@ -185,10 +142,11 @@ export function applyUIMessageChunksIncremental(
|
|
|
185
142
|
if (idx !== undefined) {
|
|
186
143
|
const textPart = message.parts[idx] as TextUIPart;
|
|
187
144
|
textPart.text += part.delta;
|
|
188
|
-
|
|
145
|
+
const providerMetadata = mergeProviderMetadata(
|
|
189
146
|
textPart.providerMetadata,
|
|
190
147
|
part.providerMetadata,
|
|
191
148
|
);
|
|
149
|
+
if (providerMetadata) textPart.providerMetadata = providerMetadata;
|
|
192
150
|
}
|
|
193
151
|
break;
|
|
194
152
|
}
|
|
@@ -197,10 +155,11 @@ export function applyUIMessageChunksIncremental(
|
|
|
197
155
|
if (idx !== undefined) {
|
|
198
156
|
const textPart = message.parts[idx] as TextUIPart;
|
|
199
157
|
textPart.state = "done";
|
|
200
|
-
|
|
158
|
+
const providerMetadata = mergeProviderMetadata(
|
|
201
159
|
textPart.providerMetadata,
|
|
202
160
|
part.providerMetadata,
|
|
203
161
|
);
|
|
162
|
+
if (providerMetadata) textPart.providerMetadata = providerMetadata;
|
|
204
163
|
delete activeText[part.id];
|
|
205
164
|
}
|
|
206
165
|
break;
|
|
@@ -210,7 +169,9 @@ export function applyUIMessageChunksIncremental(
|
|
|
210
169
|
type: "reasoning",
|
|
211
170
|
text: "",
|
|
212
171
|
state: "streaming",
|
|
213
|
-
|
|
172
|
+
...(part.providerMetadata
|
|
173
|
+
? { providerMetadata: part.providerMetadata }
|
|
174
|
+
: {}),
|
|
214
175
|
};
|
|
215
176
|
message.parts.push(newPart);
|
|
216
177
|
activeReasoning[part.id] = message.parts.length - 1;
|
|
@@ -221,10 +182,12 @@ export function applyUIMessageChunksIncremental(
|
|
|
221
182
|
if (idx !== undefined) {
|
|
222
183
|
const reasoningPart = message.parts[idx] as ReasoningUIPart;
|
|
223
184
|
reasoningPart.text += part.delta;
|
|
224
|
-
|
|
185
|
+
const providerMetadata = mergeProviderMetadata(
|
|
225
186
|
reasoningPart.providerMetadata,
|
|
226
187
|
part.providerMetadata,
|
|
227
188
|
);
|
|
189
|
+
if (providerMetadata)
|
|
190
|
+
reasoningPart.providerMetadata = providerMetadata;
|
|
228
191
|
}
|
|
229
192
|
break;
|
|
230
193
|
}
|
|
@@ -233,14 +196,35 @@ export function applyUIMessageChunksIncremental(
|
|
|
233
196
|
if (idx !== undefined) {
|
|
234
197
|
const reasoningPart = message.parts[idx] as ReasoningUIPart;
|
|
235
198
|
reasoningPart.state = "done";
|
|
236
|
-
|
|
199
|
+
const providerMetadata = mergeProviderMetadata(
|
|
237
200
|
reasoningPart.providerMetadata,
|
|
238
201
|
part.providerMetadata,
|
|
239
202
|
);
|
|
203
|
+
if (providerMetadata)
|
|
204
|
+
reasoningPart.providerMetadata = providerMetadata;
|
|
240
205
|
delete activeReasoning[part.id];
|
|
241
206
|
}
|
|
242
207
|
break;
|
|
243
208
|
}
|
|
209
|
+
case "reasoning-file":
|
|
210
|
+
message.parts.push({
|
|
211
|
+
type: "reasoning-file",
|
|
212
|
+
url: part.url,
|
|
213
|
+
mediaType: part.mediaType,
|
|
214
|
+
...(part.providerMetadata
|
|
215
|
+
? { providerMetadata: part.providerMetadata }
|
|
216
|
+
: {}),
|
|
217
|
+
} satisfies ReasoningFileUIPart);
|
|
218
|
+
break;
|
|
219
|
+
case "custom":
|
|
220
|
+
message.parts.push({
|
|
221
|
+
type: "custom",
|
|
222
|
+
kind: part.kind,
|
|
223
|
+
...(part.providerMetadata
|
|
224
|
+
? { providerMetadata: part.providerMetadata }
|
|
225
|
+
: {}),
|
|
226
|
+
} satisfies CustomContentUIPart);
|
|
227
|
+
break;
|
|
244
228
|
case "tool-input-start": {
|
|
245
229
|
const newToolPart: ToolUIPart | DynamicToolUIPart = part.dynamic
|
|
246
230
|
? ({
|
|
@@ -249,13 +233,32 @@ export function applyUIMessageChunksIncremental(
|
|
|
249
233
|
toolName: part.toolName,
|
|
250
234
|
state: "input-streaming",
|
|
251
235
|
input: undefined,
|
|
236
|
+
...(part.providerExecuted === undefined
|
|
237
|
+
? {}
|
|
238
|
+
: { providerExecuted: part.providerExecuted }),
|
|
239
|
+
...(part.title === undefined ? {} : { title: part.title }),
|
|
240
|
+
...(part.toolMetadata === undefined
|
|
241
|
+
? {}
|
|
242
|
+
: { toolMetadata: part.toolMetadata }),
|
|
243
|
+
...(part.providerMetadata
|
|
244
|
+
? { callProviderMetadata: part.providerMetadata }
|
|
245
|
+
: {}),
|
|
252
246
|
} satisfies DynamicToolUIPart)
|
|
253
247
|
: ({
|
|
254
248
|
type: `tool-${part.toolName}`,
|
|
255
249
|
toolCallId: part.toolCallId,
|
|
256
250
|
state: "input-streaming",
|
|
257
251
|
input: undefined,
|
|
258
|
-
|
|
252
|
+
...(part.providerExecuted === undefined
|
|
253
|
+
? {}
|
|
254
|
+
: { providerExecuted: part.providerExecuted }),
|
|
255
|
+
...(part.title === undefined ? {} : { title: part.title }),
|
|
256
|
+
...(part.toolMetadata === undefined
|
|
257
|
+
? {}
|
|
258
|
+
: { toolMetadata: part.toolMetadata }),
|
|
259
|
+
...(part.providerMetadata
|
|
260
|
+
? { callProviderMetadata: part.providerMetadata }
|
|
261
|
+
: {}),
|
|
259
262
|
} satisfies ToolUIPart);
|
|
260
263
|
message.parts.push(newToolPart);
|
|
261
264
|
toolIndexById.set(part.toolCallId, message.parts.length - 1);
|
|
@@ -275,18 +278,42 @@ export function applyUIMessageChunksIncremental(
|
|
|
275
278
|
break;
|
|
276
279
|
}
|
|
277
280
|
case "tool-input-available": {
|
|
278
|
-
|
|
279
|
-
if (toolPart) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
281
|
+
let toolPart = toolPartAt(part.toolCallId);
|
|
282
|
+
if (!toolPart) {
|
|
283
|
+
toolPart = part.dynamic
|
|
284
|
+
? ({
|
|
285
|
+
type: "dynamic-tool",
|
|
286
|
+
toolCallId: part.toolCallId,
|
|
287
|
+
toolName: part.toolName,
|
|
288
|
+
state: "input-available",
|
|
289
|
+
input: part.input,
|
|
290
|
+
} satisfies DynamicToolUIPart)
|
|
291
|
+
: ({
|
|
292
|
+
type: `tool-${part.toolName}`,
|
|
293
|
+
toolCallId: part.toolCallId,
|
|
294
|
+
state: "input-available",
|
|
295
|
+
input: part.input,
|
|
296
|
+
} satisfies ToolUIPart);
|
|
297
|
+
message.parts.push(toolPart);
|
|
298
|
+
toolIndexById.set(part.toolCallId, message.parts.length - 1);
|
|
289
299
|
}
|
|
300
|
+
const callProviderMetadata = mergeProviderMetadata(
|
|
301
|
+
(toolPart as { callProviderMetadata?: ProviderMetadata })
|
|
302
|
+
.callProviderMetadata,
|
|
303
|
+
part.providerMetadata,
|
|
304
|
+
);
|
|
305
|
+
transitionToolPart(toolPart, {
|
|
306
|
+
state: "input-available",
|
|
307
|
+
input: part.input,
|
|
308
|
+
...(part.providerExecuted === undefined
|
|
309
|
+
? {}
|
|
310
|
+
: { providerExecuted: part.providerExecuted }),
|
|
311
|
+
...(part.title === undefined ? {} : { title: part.title }),
|
|
312
|
+
...(part.toolMetadata === undefined
|
|
313
|
+
? {}
|
|
314
|
+
: { toolMetadata: part.toolMetadata }),
|
|
315
|
+
...(callProviderMetadata ? { callProviderMetadata } : {}),
|
|
316
|
+
});
|
|
290
317
|
touchedTools.delete(part.toolCallId);
|
|
291
318
|
// The raw JSON buffer is no longer needed; drop it so it doesn't get
|
|
292
319
|
// carried through every later batch on the hot path.
|
|
@@ -294,22 +321,53 @@ export function applyUIMessageChunksIncremental(
|
|
|
294
321
|
break;
|
|
295
322
|
}
|
|
296
323
|
case "tool-input-error": {
|
|
297
|
-
|
|
298
|
-
if (toolPart) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
324
|
+
let toolPart = toolPartAt(part.toolCallId);
|
|
325
|
+
if (!toolPart) {
|
|
326
|
+
toolPart = part.dynamic
|
|
327
|
+
? ({
|
|
328
|
+
type: "dynamic-tool",
|
|
329
|
+
toolCallId: part.toolCallId,
|
|
330
|
+
toolName: part.toolName,
|
|
331
|
+
state: "output-error",
|
|
332
|
+
input: part.input,
|
|
333
|
+
errorText: part.errorText,
|
|
334
|
+
} satisfies DynamicToolUIPart)
|
|
335
|
+
: ({
|
|
336
|
+
type: `tool-${part.toolName}`,
|
|
337
|
+
toolCallId: part.toolCallId,
|
|
338
|
+
state: "output-error",
|
|
339
|
+
input: undefined,
|
|
340
|
+
rawInput: part.input,
|
|
341
|
+
errorText: part.errorText,
|
|
342
|
+
} satisfies ToolUIPart);
|
|
343
|
+
message.parts.push(toolPart);
|
|
344
|
+
toolIndexById.set(part.toolCallId, message.parts.length - 1);
|
|
312
345
|
}
|
|
346
|
+
const resultProviderMetadata = mergeProviderMetadata(
|
|
347
|
+
(toolPart as { resultProviderMetadata?: ProviderMetadata })
|
|
348
|
+
.resultProviderMetadata,
|
|
349
|
+
part.providerMetadata,
|
|
350
|
+
);
|
|
351
|
+
transitionToolPart(toolPart, {
|
|
352
|
+
state: "output-error",
|
|
353
|
+
errorText: part.errorText,
|
|
354
|
+
...(part.providerExecuted === undefined
|
|
355
|
+
? {}
|
|
356
|
+
: { providerExecuted: part.providerExecuted }),
|
|
357
|
+
...(toolPart.type === "dynamic-tool"
|
|
358
|
+
? {
|
|
359
|
+
input: part.input,
|
|
360
|
+
}
|
|
361
|
+
: {
|
|
362
|
+
input: undefined,
|
|
363
|
+
rawInput: part.input,
|
|
364
|
+
}),
|
|
365
|
+
...(part.title === undefined ? {} : { title: part.title }),
|
|
366
|
+
...(part.toolMetadata === undefined
|
|
367
|
+
? {}
|
|
368
|
+
: { toolMetadata: part.toolMetadata }),
|
|
369
|
+
...(resultProviderMetadata ? { resultProviderMetadata } : {}),
|
|
370
|
+
});
|
|
313
371
|
touchedTools.delete(part.toolCallId);
|
|
314
372
|
delete toolInputText[part.toolCallId];
|
|
315
373
|
break;
|
|
@@ -321,7 +379,15 @@ export function applyUIMessageChunksIncremental(
|
|
|
321
379
|
state: "output-available",
|
|
322
380
|
output: part.output,
|
|
323
381
|
preliminary: part.preliminary,
|
|
324
|
-
|
|
382
|
+
...(part.providerExecuted === undefined
|
|
383
|
+
? {}
|
|
384
|
+
: { providerExecuted: part.providerExecuted }),
|
|
385
|
+
...(part.providerMetadata
|
|
386
|
+
? { resultProviderMetadata: part.providerMetadata }
|
|
387
|
+
: {}),
|
|
388
|
+
...(part.toolMetadata === undefined
|
|
389
|
+
? {}
|
|
390
|
+
: { toolMetadata: part.toolMetadata }),
|
|
325
391
|
});
|
|
326
392
|
}
|
|
327
393
|
break;
|
|
@@ -332,8 +398,20 @@ export function applyUIMessageChunksIncremental(
|
|
|
332
398
|
transitionToolPart(toolPart, {
|
|
333
399
|
state: "output-error",
|
|
334
400
|
errorText: part.errorText,
|
|
335
|
-
|
|
401
|
+
output: undefined,
|
|
402
|
+
...(part.providerExecuted === undefined
|
|
403
|
+
? {}
|
|
404
|
+
: { providerExecuted: part.providerExecuted }),
|
|
405
|
+
...(part.providerMetadata
|
|
406
|
+
? { resultProviderMetadata: part.providerMetadata }
|
|
407
|
+
: {}),
|
|
408
|
+
...(part.toolMetadata === undefined
|
|
409
|
+
? {}
|
|
410
|
+
: { toolMetadata: part.toolMetadata }),
|
|
336
411
|
});
|
|
412
|
+
// The SDK clears a prior preliminary result when the final outcome
|
|
413
|
+
// is an error. `preliminary` is not part of the error-state type.
|
|
414
|
+
Object.assign(toolPart, { preliminary: undefined });
|
|
337
415
|
}
|
|
338
416
|
break;
|
|
339
417
|
}
|
|
@@ -349,7 +427,43 @@ export function applyUIMessageChunksIncremental(
|
|
|
349
427
|
if (toolPart) {
|
|
350
428
|
transitionToolPart(toolPart, {
|
|
351
429
|
state: "approval-requested",
|
|
352
|
-
approval: {
|
|
430
|
+
approval: {
|
|
431
|
+
id: part.approvalId,
|
|
432
|
+
...(part.isAutomatic === undefined
|
|
433
|
+
? {}
|
|
434
|
+
: { isAutomatic: part.isAutomatic }),
|
|
435
|
+
...(part.signature === undefined
|
|
436
|
+
? {}
|
|
437
|
+
: { signature: part.signature }),
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
case "tool-approval-response": {
|
|
444
|
+
const toolPart = message.parts.find(
|
|
445
|
+
(candidate) =>
|
|
446
|
+
"approval" in candidate &&
|
|
447
|
+
(candidate as ToolPart).approval?.id === part.approvalId,
|
|
448
|
+
) as ToolPart | undefined;
|
|
449
|
+
if (toolPart) {
|
|
450
|
+
const callProviderMetadata = mergeProviderMetadata(
|
|
451
|
+
(toolPart as { callProviderMetadata?: ProviderMetadata })
|
|
452
|
+
.callProviderMetadata,
|
|
453
|
+
part.providerMetadata,
|
|
454
|
+
);
|
|
455
|
+
transitionToolPart(toolPart, {
|
|
456
|
+
state: "approval-responded",
|
|
457
|
+
approval: {
|
|
458
|
+
...toolPart.approval,
|
|
459
|
+
id: part.approvalId,
|
|
460
|
+
approved: part.approved,
|
|
461
|
+
...(part.reason === undefined ? {} : { reason: part.reason }),
|
|
462
|
+
},
|
|
463
|
+
...(part.providerExecuted === undefined
|
|
464
|
+
? {}
|
|
465
|
+
: { providerExecuted: part.providerExecuted }),
|
|
466
|
+
...(callProviderMetadata ? { callProviderMetadata } : {}),
|
|
353
467
|
});
|
|
354
468
|
}
|
|
355
469
|
break;
|
|
@@ -378,6 +492,7 @@ export function applyUIMessageChunksIncremental(
|
|
|
378
492
|
type: "file",
|
|
379
493
|
mediaType: part.mediaType,
|
|
380
494
|
url: part.url,
|
|
495
|
+
providerMetadata: part.providerMetadata,
|
|
381
496
|
});
|
|
382
497
|
break;
|
|
383
498
|
case "start-step":
|
|
@@ -414,6 +529,9 @@ export function applyUIMessageChunksIncremental(
|
|
|
414
529
|
(p as { id?: string }).id === dataPart.id,
|
|
415
530
|
)
|
|
416
531
|
: -1;
|
|
532
|
+
if (dataPart.transient) {
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
417
535
|
if (existingIdx >= 0) {
|
|
418
536
|
(message.parts[existingIdx] as { data?: unknown }).data =
|
|
419
537
|
dataPart.data;
|
|
@@ -445,7 +563,7 @@ export function applyUIMessageChunksIncremental(
|
|
|
445
563
|
|
|
446
564
|
message.text = joinText(message.parts);
|
|
447
565
|
return {
|
|
448
|
-
message,
|
|
566
|
+
message: message as UIMessage<METADATA, DATA_PARTS, TOOLS>,
|
|
449
567
|
streamState: { activeText, activeReasoning, toolInputText },
|
|
450
568
|
};
|
|
451
569
|
}
|
|
@@ -466,10 +584,11 @@ export async function deriveUIMessagesFromDeltas(
|
|
|
466
584
|
allDeltas.filter((d) => d.streamId === streamMessage.streamId),
|
|
467
585
|
0,
|
|
468
586
|
);
|
|
469
|
-
const uiMessage =
|
|
587
|
+
const uiMessage = applyUIMessageChunksIncremental(
|
|
470
588
|
blankUIMessage(streamMessage, threadId),
|
|
471
589
|
parts,
|
|
472
|
-
|
|
590
|
+
emptyIncrementalStreamState(),
|
|
591
|
+
).message;
|
|
473
592
|
messages.push(uiMessage);
|
|
474
593
|
}
|
|
475
594
|
return sorted(messages);
|
|
@@ -510,21 +629,5 @@ function mergeProviderMetadata(
|
|
|
510
629
|
existing: ProviderMetadata | undefined,
|
|
511
630
|
part: ProviderMetadata | undefined,
|
|
512
631
|
): ProviderMetadata | undefined {
|
|
513
|
-
|
|
514
|
-
return undefined;
|
|
515
|
-
}
|
|
516
|
-
if (!existing) {
|
|
517
|
-
return part;
|
|
518
|
-
}
|
|
519
|
-
if (!part) {
|
|
520
|
-
return existing;
|
|
521
|
-
}
|
|
522
|
-
const merged: ProviderMetadata = existing;
|
|
523
|
-
for (const [provider, metadata] of Object.entries(part)) {
|
|
524
|
-
merged[provider] = {
|
|
525
|
-
...merged[provider],
|
|
526
|
-
...metadata,
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
return merged;
|
|
632
|
+
return part ?? existing;
|
|
530
633
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import type { MessageDoc } from "
|
|
2
|
+
import type { MessageDoc } from "../validators.js";
|
|
3
3
|
import type { UIMessage } from "./UIMessages.js";
|
|
4
4
|
import { fromUIMessages, toUIMessages } from "./UIMessages.js";
|
|
5
5
|
|
|
@@ -310,6 +310,7 @@ describe("fromUIMessages round-trip tests", () => {
|
|
|
310
310
|
id: "source2",
|
|
311
311
|
mediaType: "application/pdf",
|
|
312
312
|
title: "Document Source",
|
|
313
|
+
filename: "document.pdf",
|
|
313
314
|
},
|
|
314
315
|
],
|
|
315
316
|
}),
|
|
@@ -327,6 +328,13 @@ describe("fromUIMessages round-trip tests", () => {
|
|
|
327
328
|
(part) => part.type === "source-url" || part.type === "source-document",
|
|
328
329
|
);
|
|
329
330
|
expect(sourceParts).toHaveLength(2);
|
|
331
|
+
expect(sourceParts).toContainEqual({
|
|
332
|
+
type: "source-document",
|
|
333
|
+
sourceId: "source2",
|
|
334
|
+
mediaType: "application/pdf",
|
|
335
|
+
title: "Document Source",
|
|
336
|
+
filename: "document.pdf",
|
|
337
|
+
});
|
|
330
338
|
|
|
331
339
|
expect(backToMessageDocs).toHaveLength(1);
|
|
332
340
|
expect(backToMessageDocs[0].sources).toHaveLength(2);
|
|
@@ -337,6 +345,14 @@ describe("fromUIMessages round-trip tests", () => {
|
|
|
337
345
|
url: "https://example.com",
|
|
338
346
|
title: "Example Source",
|
|
339
347
|
});
|
|
348
|
+
expect(backToMessageDocs[0].sources![1]).toMatchObject({
|
|
349
|
+
type: "source",
|
|
350
|
+
sourceType: "document",
|
|
351
|
+
id: "source2",
|
|
352
|
+
mediaType: "application/pdf",
|
|
353
|
+
title: "Document Source",
|
|
354
|
+
filename: "document.pdf",
|
|
355
|
+
});
|
|
340
356
|
});
|
|
341
357
|
|
|
342
358
|
it("preserves metadata when provided", async () => {
|