@assistant-ui/ai-sdk 0.0.11 → 0.0.12
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/converters/convertMessage.d.ts +8 -6
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +48 -22
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.native.d.ts +1 -1
- package/dist/index.native.d.ts.map +1 -1
- package/dist/index.native.js +1 -1
- package/dist/model-context/injectInteractableContext.d.ts +3 -0
- package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
- package/dist/model-context/injectInteractableContext.js +3 -0
- package/dist/model-context/injectInteractableContext.js.map +1 -1
- package/dist/model-context/injectQuoteContext.d.ts +1 -0
- package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
- package/dist/model-context/injectQuoteContext.js +1 -0
- package/dist/model-context/injectQuoteContext.js.map +1 -1
- package/dist/runtime/AISDKChat.js +1 -1
- package/dist/runtime/AISDKThreads.d.ts +5 -0
- package/dist/runtime/AISDKThreads.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.js +37 -4
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/DynamicChatTransport.d.ts +49 -0
- package/dist/runtime/DynamicChatTransport.d.ts.map +1 -0
- package/dist/runtime/DynamicChatTransport.js +147 -0
- package/dist/runtime/DynamicChatTransport.js.map +1 -0
- package/dist/runtime/getResumableAdapter.d.ts +5 -0
- package/dist/runtime/getResumableAdapter.d.ts.map +1 -0
- package/dist/runtime/getResumableAdapter.js +12 -0
- package/dist/runtime/getResumableAdapter.js.map +1 -0
- package/dist/runtime/sdkIdentity.js +1 -1
- package/dist/runtime/toolHistoryCodec.d.ts +20 -0
- package/dist/runtime/toolHistoryCodec.d.ts.map +1 -0
- package/dist/runtime/toolHistoryCodec.js +107 -0
- package/dist/runtime/toolHistoryCodec.js.map +1 -0
- package/dist/runtime/useAISDKRuntime.d.ts +4 -1
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +154 -155
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.d.ts +14 -2
- package/dist/runtime/useChatRuntime.d.ts.map +1 -1
- package/dist/runtime/useChatRuntime.js +12 -3
- package/dist/runtime/useChatRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.d.ts +3 -2
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +56 -36
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useDynamicChatTransport.d.ts +4 -0
- package/dist/runtime/useDynamicChatTransport.d.ts.map +1 -0
- package/dist/runtime/useDynamicChatTransport.js +64 -0
- package/dist/runtime/useDynamicChatTransport.js.map +1 -0
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +11 -109
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/dist/runtime/useResourceCleanup.js +1 -1
- package/dist/runtime/useStreamingTiming.js +2 -2
- package/dist/runtime/useStreamingTiming.js.map +1 -1
- package/dist/tools/generativeTools.d.ts +2 -1
- package/dist/tools/generativeTools.d.ts.map +1 -1
- package/dist/tools/generativeTools.js +5 -5
- package/dist/tools/generativeTools.js.map +1 -1
- package/dist/usage.js +1 -1
- package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
- package/dist/utils/sliceMessagesUntil.js +1 -2
- package/dist/utils/sliceMessagesUntil.js.map +1 -1
- package/package.json +11 -10
- package/src/converters/convertMessage.test.ts +120 -2
- package/src/converters/convertMessage.tool-args-status.test.tsx +185 -0
- package/src/converters/convertMessage.ts +60 -19
- package/src/converters/toCreateMessage.test.ts +27 -0
- package/src/index.native.ts +1 -1
- package/src/index.ts +1 -1
- package/src/model-context/injectInteractableContext.ts +3 -0
- package/src/model-context/injectQuoteContext.ts +1 -0
- package/src/runtime/AISDKChat.integration.test.tsx +57 -2
- package/src/runtime/AISDKThreads.cloud.test.ts +3 -0
- package/src/runtime/AISDKThreads.test.ts +181 -0
- package/src/runtime/AISDKThreads.ts +31 -4
- package/src/runtime/DynamicChatTransport.test.ts +203 -0
- package/src/runtime/DynamicChatTransport.ts +273 -0
- package/src/runtime/__tests__/controlled-transport.ts +3 -0
- package/src/runtime/getResumableAdapter.ts +16 -0
- package/src/runtime/toolHistoryCodec.test.ts +161 -0
- package/src/runtime/toolHistoryCodec.ts +207 -0
- package/src/runtime/useAISDKRuntime.approval.test.tsx +12 -0
- package/src/runtime/useAISDKRuntime.reload.test.tsx +219 -0
- package/src/runtime/useAISDKRuntime.test.ts +538 -5
- package/src/runtime/useAISDKRuntime.ts +161 -51
- package/src/runtime/useChatRuntime.integration.test.tsx +319 -4
- package/src/runtime/useChatRuntime.local-storage.test.tsx +123 -0
- package/src/runtime/useChatRuntime.test.ts +107 -1
- package/src/runtime/useChatRuntime.ts +26 -4
- package/src/runtime/useChatThread.binding.test.tsx +143 -0
- package/src/runtime/useChatThread.ts +98 -81
- package/src/runtime/useDynamicChatTransport.ts +26 -0
- package/src/runtime/useExternalHistory.test.ts +111 -0
- package/src/runtime/useExternalHistory.ts +14 -210
- package/src/runtime/useStreamingTiming.ts +2 -2
- package/src/tools/generativeTools.test.ts +1 -1
- package/src/tools/generativeTools.ts +5 -6
- package/src/utils/sliceMessagesUntil.test.ts +2 -6
- package/src/utils/sliceMessagesUntil.ts +1 -5
- package/dist/converters/modelContentEnvelope.d.ts +0 -14
- package/dist/converters/modelContentEnvelope.d.ts.map +0 -1
- package/dist/converters/modelContentEnvelope.js +0 -22
- package/dist/converters/modelContentEnvelope.js.map +0 -1
- package/dist/converters/toolOutputConversion.d.ts +0 -26
- package/dist/converters/toolOutputConversion.d.ts.map +0 -1
- package/dist/converters/toolOutputConversion.js +0 -31
- package/dist/converters/toolOutputConversion.js.map +0 -1
- package/dist/tools/frontendTools.d.ts +0 -30
- package/dist/tools/frontendTools.d.ts.map +0 -1
- package/dist/tools/frontendTools.js +0 -33
- package/dist/tools/frontendTools.js.map +0 -1
- package/src/converters/modelContentEnvelope.ts +0 -41
- package/src/converters/toolOutputConversion.ts +0 -26
- package/src/tools/frontendTools.test.ts +0 -205
- package/src/tools/frontendTools.ts +0 -83
|
@@ -12,10 +12,7 @@ import type {
|
|
|
12
12
|
Unstable_ToolInteractionLog,
|
|
13
13
|
} from "@assistant-ui/core";
|
|
14
14
|
import { getExternalStoreMessages } from "@assistant-ui/core";
|
|
15
|
-
import {
|
|
16
|
-
MessageRepository,
|
|
17
|
-
readToolInteractionLog,
|
|
18
|
-
} from "@assistant-ui/core/internal";
|
|
15
|
+
import { MessageRepository } from "@assistant-ui/core/internal";
|
|
19
16
|
import { useAui } from "@assistant-ui/store";
|
|
20
17
|
import {
|
|
21
18
|
useRef,
|
|
@@ -25,7 +22,14 @@ import {
|
|
|
25
22
|
useCallback,
|
|
26
23
|
useMemo,
|
|
27
24
|
} from "react";
|
|
28
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
addToolData,
|
|
27
|
+
collectToolApprovalResponses,
|
|
28
|
+
collectToolArtifacts,
|
|
29
|
+
collectToolInteractions,
|
|
30
|
+
restoreToolData,
|
|
31
|
+
type StoredToolApprovalResponse,
|
|
32
|
+
} from "./toolHistoryCodec";
|
|
29
33
|
|
|
30
34
|
export const toExportedMessageRepository = <TMessage>(
|
|
31
35
|
toThreadMessages: (messages: TMessage[]) => ThreadMessage[],
|
|
@@ -72,209 +76,6 @@ const isTerminalMessage = (message: ThreadMessage) =>
|
|
|
72
76
|
message.status.type === "complete" ||
|
|
73
77
|
message.status.type === "incomplete";
|
|
74
78
|
|
|
75
|
-
const TOOL_ARTIFACTS_METADATA_KEY = "__aui_toolArtifacts";
|
|
76
|
-
const TOOL_INTERACTIONS_METADATA_KEY = "__aui_toolInteractions";
|
|
77
|
-
const TOOL_APPROVAL_RESPONSES_METADATA_KEY = "__aui_toolApprovalResponses";
|
|
78
|
-
|
|
79
|
-
type StoredToolApprovalResponse = Omit<
|
|
80
|
-
RespondToToolApprovalOptions,
|
|
81
|
-
"approvalId"
|
|
82
|
-
>;
|
|
83
|
-
|
|
84
|
-
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
85
|
-
value !== null && typeof value === "object" && !Array.isArray(value);
|
|
86
|
-
|
|
87
|
-
const collectToolArtifacts = (
|
|
88
|
-
message: ThreadMessage,
|
|
89
|
-
toolArtifacts: ReadonlyMap<string, unknown> | undefined,
|
|
90
|
-
) => {
|
|
91
|
-
if (!toolArtifacts) return undefined;
|
|
92
|
-
const entries = message.content.flatMap((part) => {
|
|
93
|
-
if (part.type !== "tool-call") return [];
|
|
94
|
-
const artifact = toolArtifacts.get(part.toolCallId);
|
|
95
|
-
return artifact === undefined ? [] : [[part.toolCallId, artifact] as const];
|
|
96
|
-
});
|
|
97
|
-
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const collectToolInteractions = (
|
|
101
|
-
message: ThreadMessage,
|
|
102
|
-
toolInteractions:
|
|
103
|
-
| ReadonlyMap<string, Unstable_ToolInteractionLog>
|
|
104
|
-
| undefined,
|
|
105
|
-
) => {
|
|
106
|
-
if (!toolInteractions) return undefined;
|
|
107
|
-
const entries = message.content.flatMap((part) => {
|
|
108
|
-
if (part.type !== "tool-call") return [];
|
|
109
|
-
const interactions = toolInteractions.get(part.toolCallId);
|
|
110
|
-
return interactions === undefined
|
|
111
|
-
? []
|
|
112
|
-
: [[part.toolCallId, interactions] as const];
|
|
113
|
-
});
|
|
114
|
-
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const collectToolApprovalResponses = (
|
|
118
|
-
message: ThreadMessage,
|
|
119
|
-
toolApprovalResponses:
|
|
120
|
-
| ReadonlyMap<string, RespondToToolApprovalOptions>
|
|
121
|
-
| undefined,
|
|
122
|
-
) => {
|
|
123
|
-
if (!toolApprovalResponses) return undefined;
|
|
124
|
-
const entries = message.content.flatMap((part) => {
|
|
125
|
-
if (part.type !== "tool-call" || !part.approval) return [];
|
|
126
|
-
const response = toolApprovalResponses.get(part.approval.id);
|
|
127
|
-
if (!response) return [];
|
|
128
|
-
return [
|
|
129
|
-
[
|
|
130
|
-
part.approval.id,
|
|
131
|
-
{
|
|
132
|
-
approved: response.approved,
|
|
133
|
-
...(response.optionId != null && { optionId: response.optionId }),
|
|
134
|
-
...(response.text != null && { text: response.text }),
|
|
135
|
-
...(response.answers != null && { answers: response.answers }),
|
|
136
|
-
...(response.reason != null && { reason: response.reason }),
|
|
137
|
-
},
|
|
138
|
-
] as const,
|
|
139
|
-
];
|
|
140
|
-
});
|
|
141
|
-
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const addToolData = <TMessage>(
|
|
145
|
-
message: TMessage,
|
|
146
|
-
toolArtifacts: Record<string, unknown> | undefined,
|
|
147
|
-
toolInteractions: Record<string, Unstable_ToolInteractionLog> | undefined,
|
|
148
|
-
toolApprovalResponses: Record<string, StoredToolApprovalResponse> | undefined,
|
|
149
|
-
): TMessage => {
|
|
150
|
-
if (
|
|
151
|
-
(!toolArtifacts && !toolInteractions && !toolApprovalResponses) ||
|
|
152
|
-
!isRecord(message) ||
|
|
153
|
-
!Array.isArray(message.parts)
|
|
154
|
-
)
|
|
155
|
-
return message;
|
|
156
|
-
const toolCallIds = message.parts.flatMap((part) => {
|
|
157
|
-
if (!isRecord(part) || typeof part.toolCallId !== "string") return [];
|
|
158
|
-
return [part.toolCallId];
|
|
159
|
-
});
|
|
160
|
-
const artifacts = toolArtifacts
|
|
161
|
-
? Object.fromEntries(
|
|
162
|
-
toolCallIds.flatMap((toolCallId) =>
|
|
163
|
-
Object.hasOwn(toolArtifacts, toolCallId)
|
|
164
|
-
? [[toolCallId, toolArtifacts[toolCallId]] as const]
|
|
165
|
-
: [],
|
|
166
|
-
),
|
|
167
|
-
)
|
|
168
|
-
: undefined;
|
|
169
|
-
const interactions = toolInteractions
|
|
170
|
-
? Object.fromEntries(
|
|
171
|
-
toolCallIds.flatMap((toolCallId) =>
|
|
172
|
-
Object.hasOwn(toolInteractions, toolCallId)
|
|
173
|
-
? [[toolCallId, toolInteractions[toolCallId]] as const]
|
|
174
|
-
: [],
|
|
175
|
-
),
|
|
176
|
-
)
|
|
177
|
-
: undefined;
|
|
178
|
-
const approvalIds = message.parts.flatMap((part) => {
|
|
179
|
-
if (!isRecord(part) || !isRecord(part.approval)) return [];
|
|
180
|
-
const approvalId = part.approval.id;
|
|
181
|
-
return typeof approvalId === "string" ? [approvalId] : [];
|
|
182
|
-
});
|
|
183
|
-
const approvalResponses = toolApprovalResponses
|
|
184
|
-
? Object.fromEntries(
|
|
185
|
-
approvalIds.flatMap((approvalId) =>
|
|
186
|
-
Object.hasOwn(toolApprovalResponses, approvalId)
|
|
187
|
-
? [[approvalId, toolApprovalResponses[approvalId]] as const]
|
|
188
|
-
: [],
|
|
189
|
-
),
|
|
190
|
-
)
|
|
191
|
-
: undefined;
|
|
192
|
-
const hasArtifacts = !!artifacts && Object.keys(artifacts).length > 0;
|
|
193
|
-
const hasInteractions =
|
|
194
|
-
!!interactions && Object.keys(interactions).length > 0;
|
|
195
|
-
const hasApprovalResponses =
|
|
196
|
-
!!approvalResponses && Object.keys(approvalResponses).length > 0;
|
|
197
|
-
if (!hasArtifacts && !hasInteractions && !hasApprovalResponses)
|
|
198
|
-
return message;
|
|
199
|
-
const metadata = isRecord(message.metadata) ? message.metadata : {};
|
|
200
|
-
return {
|
|
201
|
-
...message,
|
|
202
|
-
metadata: {
|
|
203
|
-
...metadata,
|
|
204
|
-
...(hasArtifacts && { [TOOL_ARTIFACTS_METADATA_KEY]: artifacts }),
|
|
205
|
-
...(hasInteractions && {
|
|
206
|
-
[TOOL_INTERACTIONS_METADATA_KEY]: interactions,
|
|
207
|
-
}),
|
|
208
|
-
...(hasApprovalResponses && {
|
|
209
|
-
[TOOL_APPROVAL_RESPONSES_METADATA_KEY]: approvalResponses,
|
|
210
|
-
}),
|
|
211
|
-
},
|
|
212
|
-
} as TMessage;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
const restoreToolData = <TMessage>(
|
|
216
|
-
message: TMessage,
|
|
217
|
-
toolArtifacts: Map<string, unknown> | undefined,
|
|
218
|
-
toolInteractions: Map<string, Unstable_ToolInteractionLog> | undefined,
|
|
219
|
-
toolApprovalResponses: Map<string, RespondToToolApprovalOptions> | undefined,
|
|
220
|
-
): TMessage => {
|
|
221
|
-
if (!isRecord(message) || !isRecord(message.metadata)) return message;
|
|
222
|
-
const metadata = message.metadata;
|
|
223
|
-
const hasArtifacts = Object.hasOwn(metadata, TOOL_ARTIFACTS_METADATA_KEY);
|
|
224
|
-
const hasInteractions = Object.hasOwn(
|
|
225
|
-
metadata,
|
|
226
|
-
TOOL_INTERACTIONS_METADATA_KEY,
|
|
227
|
-
);
|
|
228
|
-
const hasApprovalResponses = Object.hasOwn(
|
|
229
|
-
metadata,
|
|
230
|
-
TOOL_APPROVAL_RESPONSES_METADATA_KEY,
|
|
231
|
-
);
|
|
232
|
-
if (!hasArtifacts && !hasInteractions && !hasApprovalResponses)
|
|
233
|
-
return message;
|
|
234
|
-
const artifacts = metadata[TOOL_ARTIFACTS_METADATA_KEY];
|
|
235
|
-
if (toolArtifacts && isRecord(artifacts)) {
|
|
236
|
-
for (const [toolCallId, artifact] of Object.entries(artifacts)) {
|
|
237
|
-
toolArtifacts.set(toolCallId, artifact);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const interactions = metadata[TOOL_INTERACTIONS_METADATA_KEY];
|
|
241
|
-
if (toolInteractions && isRecord(interactions)) {
|
|
242
|
-
for (const [toolCallId, value] of Object.entries(interactions)) {
|
|
243
|
-
const log = readToolInteractionLog(value);
|
|
244
|
-
if (log) toolInteractions.set(toolCallId, log);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
const approvalResponses = metadata[TOOL_APPROVAL_RESPONSES_METADATA_KEY];
|
|
248
|
-
if (toolApprovalResponses && isRecord(approvalResponses)) {
|
|
249
|
-
for (const [approvalId, value] of Object.entries(approvalResponses)) {
|
|
250
|
-
if (!isRecord(value) || typeof value.approved !== "boolean") continue;
|
|
251
|
-
const answers = normalizeToolApprovalAnswers(value.answers);
|
|
252
|
-
toolApprovalResponses.set(approvalId, {
|
|
253
|
-
approvalId,
|
|
254
|
-
approved: value.approved,
|
|
255
|
-
...(typeof value.optionId === "string" && {
|
|
256
|
-
optionId: value.optionId,
|
|
257
|
-
}),
|
|
258
|
-
...(typeof value.text === "string" && { text: value.text }),
|
|
259
|
-
...(answers && Object.keys(answers).length > 0 && { answers }),
|
|
260
|
-
...(typeof value.reason === "string" && { reason: value.reason }),
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
const {
|
|
265
|
-
[TOOL_ARTIFACTS_METADATA_KEY]: _,
|
|
266
|
-
[TOOL_INTERACTIONS_METADATA_KEY]: __,
|
|
267
|
-
[TOOL_APPROVAL_RESPONSES_METADATA_KEY]: ___,
|
|
268
|
-
...restMetadata
|
|
269
|
-
} = metadata;
|
|
270
|
-
const { metadata: _metadata, ...restMessage } = message;
|
|
271
|
-
return (
|
|
272
|
-
Object.keys(restMetadata).length === 0
|
|
273
|
-
? restMessage
|
|
274
|
-
: { ...restMessage, metadata: restMetadata }
|
|
275
|
-
) as TMessage;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
79
|
const encodeContent = <TMessage>(
|
|
279
80
|
storageFormatAdapter: MessageFormatAdapter<TMessage, any>,
|
|
280
81
|
item: MessageFormatItem<TMessage>,
|
|
@@ -334,6 +135,10 @@ export const useExternalHistory = <TMessage>(
|
|
|
334
135
|
const loadHistory = async () => {
|
|
335
136
|
try {
|
|
336
137
|
const repo = await formatAdapter.load();
|
|
138
|
+
const threadState = runtimeRef.current.thread.getState();
|
|
139
|
+
if (threadState.isRunning || threadState.messages.length > 0) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
337
142
|
toolArtifacts?.clear();
|
|
338
143
|
toolInteractions?.clear();
|
|
339
144
|
toolApprovalResponses?.clear();
|
|
@@ -394,8 +199,6 @@ export const useExternalHistory = <TMessage>(
|
|
|
394
199
|
|
|
395
200
|
const remoteId = optionalThreadListItem()?.getState().remoteId;
|
|
396
201
|
if (!remoteId) {
|
|
397
|
-
// History loads asynchronously against the thread list item; without a
|
|
398
|
-
// remote id there is nothing to await, so the flag settles here.
|
|
399
202
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
400
203
|
setHasLoaded(true);
|
|
401
204
|
return aui.subscribe(() => {
|
|
@@ -413,6 +216,7 @@ export const useExternalHistory = <TMessage>(
|
|
|
413
216
|
}
|
|
414
217
|
|
|
415
218
|
loadedRef.current = true;
|
|
219
|
+
setHasLoaded(false);
|
|
416
220
|
void loadHistory();
|
|
417
221
|
return undefined;
|
|
418
222
|
}, [
|
|
@@ -22,7 +22,7 @@ const getTextLength = (
|
|
|
22
22
|
if (!message?.parts) return 0;
|
|
23
23
|
let len = 0;
|
|
24
24
|
for (const part of message.parts) {
|
|
25
|
-
if (part
|
|
25
|
+
if (part?.type === "text") len += part.text?.length ?? 0;
|
|
26
26
|
}
|
|
27
27
|
return len;
|
|
28
28
|
};
|
|
@@ -35,7 +35,7 @@ const getToolCallCount = (
|
|
|
35
35
|
if (!message?.parts) return 0;
|
|
36
36
|
let count = 0;
|
|
37
37
|
for (const part of message.parts) {
|
|
38
|
-
if (isToolUIPart(part)) count++;
|
|
38
|
+
if (typeof part?.type === "string" && isToolUIPart(part)) count++;
|
|
39
39
|
}
|
|
40
40
|
return count;
|
|
41
41
|
};
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type ToolkitDefinition,
|
|
6
6
|
} from "@assistant-ui/core/react";
|
|
7
7
|
import { AISDKToolkit } from "./generativeTools";
|
|
8
|
-
import { wrapModelContentEnvelope } from "
|
|
8
|
+
import { wrapModelContentEnvelope } from "assistant-stream/internal";
|
|
9
9
|
|
|
10
10
|
const mocks = vi.hoisted(() => ({
|
|
11
11
|
close: vi.fn(),
|
|
@@ -13,15 +13,13 @@ import type {
|
|
|
13
13
|
Toolkit,
|
|
14
14
|
ToolkitDefinition,
|
|
15
15
|
} from "@assistant-ui/core/react";
|
|
16
|
-
import { frontendTools, type FrontendTools } from "
|
|
16
|
+
import { frontendTools, type FrontendTools } from "assistant-stream/ai-sdk";
|
|
17
17
|
import {
|
|
18
18
|
toAISDKContent,
|
|
19
19
|
toAISDKDefaultOutput,
|
|
20
|
-
} from "../converters/toolOutputConversion";
|
|
21
|
-
import {
|
|
22
20
|
unwrapModelContentEnvelope,
|
|
23
21
|
type ModelContentEnvelope,
|
|
24
|
-
} from "
|
|
22
|
+
} from "assistant-stream/internal";
|
|
25
23
|
|
|
26
24
|
const EMPTY_SCHEMA = { type: "object" as const, properties: {} };
|
|
27
25
|
|
|
@@ -156,6 +154,7 @@ export type AISDKToolkitToolsOptions = {
|
|
|
156
154
|
* // In your route handler:
|
|
157
155
|
* const { tools } = await req.json();
|
|
158
156
|
* streamText({
|
|
157
|
+
* abortSignal: req.signal,
|
|
159
158
|
* model,
|
|
160
159
|
* messages,
|
|
161
160
|
* tools: await aiToolkit.tools({ frontend: tools }),
|
|
@@ -415,7 +414,7 @@ const toAISDKToModelOutput =
|
|
|
415
414
|
const { result, modelContent } = unwrapModelContentEnvelope(options.output);
|
|
416
415
|
|
|
417
416
|
if (modelContent !== undefined) {
|
|
418
|
-
return toAISDKContent(modelContent);
|
|
417
|
+
return toAISDKContent(modelContent, { taggedFileData: true });
|
|
419
418
|
}
|
|
420
419
|
|
|
421
420
|
if (!toModelOutput) {
|
|
@@ -426,7 +425,7 @@ const toAISDKToModelOutput =
|
|
|
426
425
|
...options,
|
|
427
426
|
output: result,
|
|
428
427
|
});
|
|
429
|
-
return toAISDKContent(parts);
|
|
428
|
+
return toAISDKContent(parts, { taggedFileData: true });
|
|
430
429
|
};
|
|
431
430
|
|
|
432
431
|
const toServerToolSet = (toolkit: ToolkitDefinition): ToolSet =>
|
|
@@ -31,18 +31,14 @@ describe("sliceMessagesUntil", () => {
|
|
|
31
31
|
]);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it("
|
|
34
|
+
it("stops at the target even when assistant messages follow it", () => {
|
|
35
35
|
const messages = [
|
|
36
36
|
msg("u1", "user"),
|
|
37
37
|
msg("a1", "assistant"),
|
|
38
38
|
msg("a2", "assistant"),
|
|
39
39
|
msg("u2", "user"),
|
|
40
40
|
];
|
|
41
|
-
expect(sliceMessagesUntil(messages, "u1").map((m) => m.id)).toEqual([
|
|
42
|
-
"u1",
|
|
43
|
-
"a1",
|
|
44
|
-
"a2",
|
|
45
|
-
]);
|
|
41
|
+
expect(sliceMessagesUntil(messages, "u1").map((m) => m.id)).toEqual(["u1"]);
|
|
46
42
|
});
|
|
47
43
|
|
|
48
44
|
it("returns the whole array when the target is the last message", () => {
|
|
@@ -6,15 +6,11 @@ export const sliceMessagesUntil = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
6
6
|
) => {
|
|
7
7
|
if (messageId == null) return [];
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const messageIdx = messages.findIndex((m) => m.id === messageId);
|
|
10
10
|
if (messageIdx === -1)
|
|
11
11
|
throw new Error(
|
|
12
12
|
`sliceMessagesUntil: Message "${messageId}" not found in AI SDK messages. This is likely an internal bug in assistant-ui.`,
|
|
13
13
|
);
|
|
14
14
|
|
|
15
|
-
while (messages[messageIdx + 1]?.role === "assistant") {
|
|
16
|
-
messageIdx++;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
15
|
return messages.slice(0, messageIdx + 1);
|
|
20
16
|
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ToolModelContentPart } from "assistant-stream";
|
|
2
|
-
declare const ENVELOPE_KEY = "__aui_modelContent";
|
|
3
|
-
export type ModelContentEnvelope<TResult = unknown> = {
|
|
4
|
-
readonly [ENVELOPE_KEY]: readonly ToolModelContentPart[];
|
|
5
|
-
readonly value: TResult;
|
|
6
|
-
};
|
|
7
|
-
export declare function isModelContentEnvelope<TResult = unknown>(value: TResult | ModelContentEnvelope<TResult>): value is ModelContentEnvelope<TResult>;
|
|
8
|
-
export declare function wrapModelContentEnvelope<TResult>(result: TResult, modelContent: readonly ToolModelContentPart[]): ModelContentEnvelope<TResult>;
|
|
9
|
-
export declare function unwrapModelContentEnvelope<TResult>(output: TResult | ModelContentEnvelope<TResult>): {
|
|
10
|
-
result: TResult;
|
|
11
|
-
modelContent?: readonly ToolModelContentPart[];
|
|
12
|
-
};
|
|
13
|
-
export {};
|
|
14
|
-
//# sourceMappingURL=modelContentEnvelope.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modelContentEnvelope.d.ts","sourceRoot":"","sources":["../../src/converters/modelContentEnvelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,QAAA,MAAM,YAAY,uBAAuB,CAAC;AAE1C,MAAM,MAAM,oBAAoB,CAAC,OAAO,GAAG,OAAO,IAAI;IACpD,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACzD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,OAAO,GAAG,OAAO,EACtD,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAC7C,KAAK,IAAI,oBAAoB,CAAC,OAAO,CAAC,CAOxC;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAC9C,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAC5C,oBAAoB,CAAC,OAAO,CAAC,CAE/B;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAChD,MAAM,EAAE,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAC9C;IACD,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAChD,CAQA"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//#region src/converters/modelContentEnvelope.ts
|
|
2
|
-
const ENVELOPE_KEY = "__aui_modelContent";
|
|
3
|
-
function isModelContentEnvelope(value) {
|
|
4
|
-
return value != null && typeof value === "object" && ENVELOPE_KEY in value && Array.isArray(value[ENVELOPE_KEY]);
|
|
5
|
-
}
|
|
6
|
-
function wrapModelContentEnvelope(result, modelContent) {
|
|
7
|
-
return {
|
|
8
|
-
[ENVELOPE_KEY]: modelContent,
|
|
9
|
-
value: result
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
function unwrapModelContentEnvelope(output) {
|
|
13
|
-
if (isModelContentEnvelope(output)) return {
|
|
14
|
-
result: output.value,
|
|
15
|
-
modelContent: output[ENVELOPE_KEY]
|
|
16
|
-
};
|
|
17
|
-
return { result: output };
|
|
18
|
-
}
|
|
19
|
-
//#endregion
|
|
20
|
-
export { isModelContentEnvelope, unwrapModelContentEnvelope, wrapModelContentEnvelope };
|
|
21
|
-
|
|
22
|
-
//# sourceMappingURL=modelContentEnvelope.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modelContentEnvelope.js","names":["ToolModelContentPart","ENVELOPE_KEY","ModelContentEnvelope","value","TResult","isModelContentEnvelope","Array","isArray","Record","wrapModelContentEnvelope","result","modelContent","unwrapModelContentEnvelope","output"],"sources":["../../src/converters/modelContentEnvelope.ts"],"sourcesContent":["import type { ToolModelContentPart } from \"assistant-stream\";\n\nconst ENVELOPE_KEY = \"__aui_modelContent\";\n\nexport type ModelContentEnvelope<TResult = unknown> = {\n readonly [ENVELOPE_KEY]: readonly ToolModelContentPart[];\n readonly value: TResult;\n};\n\nexport function isModelContentEnvelope<TResult = unknown>(\n value: TResult | ModelContentEnvelope<TResult>,\n): value is ModelContentEnvelope<TResult> {\n return (\n value != null &&\n typeof value === \"object\" &&\n ENVELOPE_KEY in value &&\n Array.isArray((value as Record<string, unknown>)[ENVELOPE_KEY])\n );\n}\n\nexport function wrapModelContentEnvelope<TResult>(\n result: TResult,\n modelContent: readonly ToolModelContentPart[],\n): ModelContentEnvelope<TResult> {\n return { [ENVELOPE_KEY]: modelContent, value: result };\n}\n\nexport function unwrapModelContentEnvelope<TResult>(\n output: TResult | ModelContentEnvelope<TResult>,\n): {\n result: TResult;\n modelContent?: readonly ToolModelContentPart[];\n} {\n if (isModelContentEnvelope(output)) {\n return {\n result: output.value,\n modelContent: output[ENVELOPE_KEY],\n };\n }\n return { result: output };\n}\n"],"mappings":";AAEA,MAAMC,eAAe;AAOrB,SAAgBI,uBACdF,OACwC;CACxC,OACEA,SAAS,QACT,OAAOA,UAAU,YACjBF,gBAAgBE,SAChBG,MAAMC,QAASJ,MAAkCF,aAAa;AAElE;AAEA,SAAgBQ,yBACdC,QACAC,cAC+B;CAC/B,OAAO;GAAGV,eAAeU;EAAcR,OAAOO;CAAO;AACvD;AAEA,SAAgBE,2BACdC,QAIA;CACA,IAAIR,uBAAuBQ,MAAM,GAC/B,OAAO;EACLH,QAAQG,OAAOV;EACfQ,cAAcE,OAAOZ;CACvB;CAEF,OAAO,EAAES,QAAQG,OAAO;AAC1B"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { JSONValue } from "ai";
|
|
2
|
-
import type { ToolModelContentPart } from "assistant-stream";
|
|
3
|
-
export declare const toAISDKContent: (parts: readonly ToolModelContentPart[]) => {
|
|
4
|
-
type: "content";
|
|
5
|
-
value: ({
|
|
6
|
-
type: "text";
|
|
7
|
-
text: string;
|
|
8
|
-
} | {
|
|
9
|
-
filename?: string;
|
|
10
|
-
type: "file";
|
|
11
|
-
data: {
|
|
12
|
-
type: "data";
|
|
13
|
-
data: string;
|
|
14
|
-
};
|
|
15
|
-
mediaType: string;
|
|
16
|
-
text?: never;
|
|
17
|
-
})[];
|
|
18
|
-
};
|
|
19
|
-
export declare const toAISDKDefaultOutput: (output: unknown) => {
|
|
20
|
-
type: "text";
|
|
21
|
-
value: string;
|
|
22
|
-
} | {
|
|
23
|
-
type: "json";
|
|
24
|
-
value: JSONValue;
|
|
25
|
-
};
|
|
26
|
-
//# sourceMappingURL=toolOutputConversion.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"toolOutputConversion.d.ts","sourceRoot":"","sources":["../../src/converters/toolOutputConversion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,eAAO,MAAM,cAAc,GAAI,OAAO,SAAS,oBAAoB,EAAE;;;;;;;;;;;;;;;CAiBnE,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,OAAO;;;;;WAGM,SAAS;CAAE,CAAC"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
//#region src/converters/toolOutputConversion.ts
|
|
2
|
-
const toAISDKContent = (parts) => ({
|
|
3
|
-
type: "content",
|
|
4
|
-
value: parts.map((part) => {
|
|
5
|
-
if (part.type === "text") return {
|
|
6
|
-
type: "text",
|
|
7
|
-
text: part.text
|
|
8
|
-
};
|
|
9
|
-
const mediaType = typeof part.mediaType === "string" ? part.mediaType : "application/octet-stream";
|
|
10
|
-
return {
|
|
11
|
-
type: "file",
|
|
12
|
-
data: {
|
|
13
|
-
type: "data",
|
|
14
|
-
data: part.data
|
|
15
|
-
},
|
|
16
|
-
mediaType,
|
|
17
|
-
...part.filename !== void 0 && { filename: part.filename }
|
|
18
|
-
};
|
|
19
|
-
})
|
|
20
|
-
});
|
|
21
|
-
const toAISDKDefaultOutput = (output) => typeof output === "string" ? {
|
|
22
|
-
type: "text",
|
|
23
|
-
value: output
|
|
24
|
-
} : {
|
|
25
|
-
type: "json",
|
|
26
|
-
value: output ?? null
|
|
27
|
-
};
|
|
28
|
-
//#endregion
|
|
29
|
-
export { toAISDKContent, toAISDKDefaultOutput };
|
|
30
|
-
|
|
31
|
-
//# sourceMappingURL=toolOutputConversion.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"toolOutputConversion.js","names":["JSONValue","ToolModelContentPart","toAISDKContent","parts","type","const","value","map","part","text","mediaType","data","filename","undefined","toAISDKDefaultOutput","output"],"sources":["../../src/converters/toolOutputConversion.ts"],"sourcesContent":["import type { JSONValue } from \"ai\";\nimport type { ToolModelContentPart } from \"assistant-stream\";\n\nexport const toAISDKContent = (parts: readonly ToolModelContentPart[]) => ({\n type: \"content\" as const,\n value: parts.map((part) => {\n if (part.type === \"text\") {\n return { type: \"text\" as const, text: part.text };\n }\n const mediaType =\n typeof part.mediaType === \"string\"\n ? part.mediaType\n : \"application/octet-stream\";\n return {\n type: \"file\" as const,\n data: { type: \"data\" as const, data: part.data },\n mediaType,\n ...(part.filename !== undefined && { filename: part.filename }),\n };\n }),\n});\n\nexport const toAISDKDefaultOutput = (output: unknown) =>\n typeof output === \"string\"\n ? { type: \"text\" as const, value: output }\n : { type: \"json\" as const, value: (output ?? null) as JSONValue };\n"],"mappings":";AAGA,MAAaE,kBAAkBC,WAA4C;CACzEC,MAAM;CACNE,OAAOH,MAAMI,KAAKC,SAAS;EACzB,IAAIA,KAAKJ,SAAS,QAChB,OAAO;GAAEA,MAAM;GAAiBK,MAAMD,KAAKC;EAAK;EAElD,MAAMC,YACJ,OAAOF,KAAKE,cAAc,WACtBF,KAAKE,YACL;EACN,OAAO;GACLN,MAAM;GACNO,MAAM;IAAEP,MAAM;IAAiBO,MAAMH,KAAKG;GAAK;GAC/CD;GACA,GAAIF,KAAKI,aAAaC,KAAAA,KAAa,EAAED,UAAUJ,KAAKI,SAAS;EAC/D;CACF,CAAC;AACH;AAEA,MAAaE,wBAAwBC,WACnC,OAAOA,WAAW,WACd;CAAEX,MAAM;CAAiBE,OAAOS;AAAO,IACvC;CAAEX,MAAM;CAAiBE,OAAQS,UAAU;AAAmB"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { type ToolSet } from "ai";
|
|
2
|
-
import type { ToolJSONSchema } from "assistant-stream";
|
|
3
|
-
/** Frontend tool definitions uploaded by AssistantChatTransport. */
|
|
4
|
-
export type FrontendTools = Record<string, ToolJSONSchema>;
|
|
5
|
-
export declare const defaultToModelOutput: ({ output }: {
|
|
6
|
-
output: unknown;
|
|
7
|
-
}) => {
|
|
8
|
-
type: "content";
|
|
9
|
-
value: ({
|
|
10
|
-
type: "text";
|
|
11
|
-
text: string;
|
|
12
|
-
} | {
|
|
13
|
-
filename?: string;
|
|
14
|
-
type: "file";
|
|
15
|
-
data: {
|
|
16
|
-
type: "data";
|
|
17
|
-
data: string;
|
|
18
|
-
};
|
|
19
|
-
mediaType: string;
|
|
20
|
-
text?: never;
|
|
21
|
-
})[];
|
|
22
|
-
} | {
|
|
23
|
-
type: "text";
|
|
24
|
-
value: string;
|
|
25
|
-
} | {
|
|
26
|
-
type: "json";
|
|
27
|
-
value: import("ai").JSONValue;
|
|
28
|
-
};
|
|
29
|
-
export declare const frontendTools: (tools: FrontendTools) => ToolSet;
|
|
30
|
-
//# sourceMappingURL=frontendTools.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frontendTools.d.ts","sourceRoot":"","sources":["../../src/tools/frontendTools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOvD,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAE3D,eAAO,MAAM,oBAAoB,GAAI,YAAY;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;CAMnE,CAAC;AAiDF,eAAO,MAAM,aAAa,GAAI,OAAO,aAAa,KAAG,OAgBpD,CAAC"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { unwrapModelContentEnvelope } from "../converters/modelContentEnvelope.js";
|
|
2
|
-
import { toAISDKContent, toAISDKDefaultOutput } from "../converters/toolOutputConversion.js";
|
|
3
|
-
import { jsonSchema } from "ai";
|
|
4
|
-
//#region src/tools/frontendTools.ts
|
|
5
|
-
const defaultToModelOutput = ({ output }) => {
|
|
6
|
-
const { result, modelContent } = unwrapModelContentEnvelope(output);
|
|
7
|
-
if (modelContent !== void 0) return toAISDKContent(modelContent);
|
|
8
|
-
return toAISDKDefaultOutput(result);
|
|
9
|
-
};
|
|
10
|
-
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
-
function validateFrontendTool(name, tool) {
|
|
12
|
-
if (!isPlainObject(tool)) throw new Error(`frontendTools() expected tool "${name}" to be an object with a JSON Schema parameters object.`);
|
|
13
|
-
if (!isPlainObject(tool.parameters)) throw new Error(`frontendTools() expected tool "${name}" to include a JSON Schema parameters object.`);
|
|
14
|
-
if (tool.description !== void 0 && typeof tool.description !== "string") throw new Error(`frontendTools() expected tool "${name}" description to be a string.`);
|
|
15
|
-
if (tool.providerOptions !== void 0 && !isPlainObject(tool.providerOptions)) throw new Error(`frontendTools() expected tool "${name}" providerOptions to be an object.`);
|
|
16
|
-
}
|
|
17
|
-
function validateFrontendTools(tools) {
|
|
18
|
-
if (!isPlainObject(tools)) throw new Error("frontendTools() expected tools to be an object keyed by tool name.");
|
|
19
|
-
for (const [name, tool] of Object.entries(tools)) validateFrontendTool(name, tool);
|
|
20
|
-
}
|
|
21
|
-
const frontendTools = (tools) => {
|
|
22
|
-
validateFrontendTools(tools);
|
|
23
|
-
return Object.fromEntries(Object.entries(tools).map(([name, tool]) => [name, {
|
|
24
|
-
...tool.description !== void 0 && { description: tool.description },
|
|
25
|
-
inputSchema: jsonSchema(tool.parameters),
|
|
26
|
-
toModelOutput: defaultToModelOutput,
|
|
27
|
-
...tool.providerOptions && { providerOptions: tool.providerOptions }
|
|
28
|
-
}]));
|
|
29
|
-
};
|
|
30
|
-
//#endregion
|
|
31
|
-
export { defaultToModelOutput, frontendTools };
|
|
32
|
-
|
|
33
|
-
//# sourceMappingURL=frontendTools.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frontendTools.js","names":["jsonSchema","ToolSet","ToolJSONSchema","unwrapModelContentEnvelope","toAISDKContent","toAISDKDefaultOutput","FrontendTools","Record","defaultToModelOutput","output","result","modelContent","undefined","isPlainObject","value","Array","isArray","validateFrontendTool","name","tool","Error","parameters","description","providerOptions","validateFrontendTools","tools","Object","entries","frontendTools","fromEntries","map","inputSchema","toModelOutput"],"sources":["../../src/tools/frontendTools.ts"],"sourcesContent":["import { jsonSchema, type ToolSet } from \"ai\";\nimport type { ToolJSONSchema } from \"assistant-stream\";\nimport { unwrapModelContentEnvelope } from \"../converters/modelContentEnvelope\";\nimport {\n toAISDKContent,\n toAISDKDefaultOutput,\n} from \"../converters/toolOutputConversion\";\n\n/** Frontend tool definitions uploaded by AssistantChatTransport. */\nexport type FrontendTools = Record<string, ToolJSONSchema>;\n\nexport const defaultToModelOutput = ({ output }: { output: unknown }) => {\n const { result, modelContent } = unwrapModelContentEnvelope(output);\n if (modelContent !== undefined) {\n return toAISDKContent(modelContent);\n }\n return toAISDKDefaultOutput(result);\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction validateFrontendTool(\n name: string,\n tool: unknown,\n): asserts tool is ToolJSONSchema {\n if (!isPlainObject(tool)) {\n throw new Error(\n `frontendTools() expected tool \"${name}\" to be an object with a JSON Schema parameters object.`,\n );\n }\n\n if (!isPlainObject(tool.parameters)) {\n throw new Error(\n `frontendTools() expected tool \"${name}\" to include a JSON Schema parameters object.`,\n );\n }\n\n if (tool.description !== undefined && typeof tool.description !== \"string\") {\n throw new Error(\n `frontendTools() expected tool \"${name}\" description to be a string.`,\n );\n }\n\n if (\n tool.providerOptions !== undefined &&\n !isPlainObject(tool.providerOptions)\n ) {\n throw new Error(\n `frontendTools() expected tool \"${name}\" providerOptions to be an object.`,\n );\n }\n}\n\nfunction validateFrontendTools(tools: unknown): asserts tools is FrontendTools {\n if (!isPlainObject(tools)) {\n throw new Error(\n \"frontendTools() expected tools to be an object keyed by tool name.\",\n );\n }\n\n for (const [name, tool] of Object.entries(tools)) {\n validateFrontendTool(name, tool);\n }\n}\n\nexport const frontendTools = (tools: FrontendTools): ToolSet => {\n validateFrontendTools(tools);\n\n return Object.fromEntries(\n Object.entries(tools).map(([name, tool]) => [\n name,\n {\n ...(tool.description !== undefined && {\n description: tool.description,\n }),\n inputSchema: jsonSchema(tool.parameters),\n toModelOutput: defaultToModelOutput,\n ...(tool.providerOptions && { providerOptions: tool.providerOptions }),\n },\n ]),\n ) as ToolSet;\n};\n"],"mappings":";;;;AAWA,MAAaQ,wBAAwB,EAAEC,aAAkC;CACvE,MAAM,EAAEC,QAAQC,iBAAiBR,2BAA2BM,MAAM;CAClE,IAAIE,iBAAiBC,KAAAA,GACnB,OAAOR,eAAeO,YAAY;CAEpC,OAAON,qBAAqBK,MAAM;AACpC;AAEA,MAAMG,iBAAiBC,UACrB,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACC,MAAMC,QAAQF,KAAK;AAErE,SAASG,qBACPC,MACAC,MACgC;CAChC,IAAI,CAACN,cAAcM,IAAI,GACrB,MAAM,IAAIC,MACR,kCAAkCF,KAAI,wDACxC;CAGF,IAAI,CAACL,cAAcM,KAAKE,UAAU,GAChC,MAAM,IAAID,MACR,kCAAkCF,KAAI,8CACxC;CAGF,IAAIC,KAAKG,gBAAgBV,KAAAA,KAAa,OAAOO,KAAKG,gBAAgB,UAChE,MAAM,IAAIF,MACR,kCAAkCF,KAAI,8BACxC;CAGF,IACEC,KAAKI,oBAAoBX,KAAAA,KACzB,CAACC,cAAcM,KAAKI,eAAe,GAEnC,MAAM,IAAIH,MACR,kCAAkCF,KAAI,mCACxC;AAEJ;AAEA,SAASM,sBAAsBC,OAAgD;CAC7E,IAAI,CAACZ,cAAcY,KAAK,GACtB,MAAM,IAAIL,MACR,oEACF;CAGF,KAAK,MAAM,CAACF,MAAMC,SAASO,OAAOC,QAAQF,KAAK,GAC7CR,qBAAqBC,MAAMC,IAAI;AAEnC;AAEA,MAAaS,iBAAiBH,UAAkC;CAC9DD,sBAAsBC,KAAK;CAE3B,OAAOC,OAAOG,YACZH,OAAOC,QAAQF,KAAK,CAAC,CAACK,KAAK,CAACZ,MAAMC,UAAU,CAC1CD,MACA;EACE,GAAIC,KAAKG,gBAAgBV,KAAAA,KAAa,EACpCU,aAAaH,KAAKG,YACpB;EACAS,aAAa/B,WAAWmB,KAAKE,UAAU;EACvCW,eAAexB;EACf,GAAIW,KAAKI,mBAAmB,EAAEA,iBAAiBJ,KAAKI,gBAAgB;CACtE,CAAC,CACF,CACH;AACF"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { ToolModelContentPart } from "assistant-stream";
|
|
2
|
-
|
|
3
|
-
const ENVELOPE_KEY = "__aui_modelContent";
|
|
4
|
-
|
|
5
|
-
export type ModelContentEnvelope<TResult = unknown> = {
|
|
6
|
-
readonly [ENVELOPE_KEY]: readonly ToolModelContentPart[];
|
|
7
|
-
readonly value: TResult;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export function isModelContentEnvelope<TResult = unknown>(
|
|
11
|
-
value: TResult | ModelContentEnvelope<TResult>,
|
|
12
|
-
): value is ModelContentEnvelope<TResult> {
|
|
13
|
-
return (
|
|
14
|
-
value != null &&
|
|
15
|
-
typeof value === "object" &&
|
|
16
|
-
ENVELOPE_KEY in value &&
|
|
17
|
-
Array.isArray((value as Record<string, unknown>)[ENVELOPE_KEY])
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function wrapModelContentEnvelope<TResult>(
|
|
22
|
-
result: TResult,
|
|
23
|
-
modelContent: readonly ToolModelContentPart[],
|
|
24
|
-
): ModelContentEnvelope<TResult> {
|
|
25
|
-
return { [ENVELOPE_KEY]: modelContent, value: result };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function unwrapModelContentEnvelope<TResult>(
|
|
29
|
-
output: TResult | ModelContentEnvelope<TResult>,
|
|
30
|
-
): {
|
|
31
|
-
result: TResult;
|
|
32
|
-
modelContent?: readonly ToolModelContentPart[];
|
|
33
|
-
} {
|
|
34
|
-
if (isModelContentEnvelope(output)) {
|
|
35
|
-
return {
|
|
36
|
-
result: output.value,
|
|
37
|
-
modelContent: output[ENVELOPE_KEY],
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
return { result: output };
|
|
41
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { JSONValue } from "ai";
|
|
2
|
-
import type { ToolModelContentPart } from "assistant-stream";
|
|
3
|
-
|
|
4
|
-
export const toAISDKContent = (parts: readonly ToolModelContentPart[]) => ({
|
|
5
|
-
type: "content" as const,
|
|
6
|
-
value: parts.map((part) => {
|
|
7
|
-
if (part.type === "text") {
|
|
8
|
-
return { type: "text" as const, text: part.text };
|
|
9
|
-
}
|
|
10
|
-
const mediaType =
|
|
11
|
-
typeof part.mediaType === "string"
|
|
12
|
-
? part.mediaType
|
|
13
|
-
: "application/octet-stream";
|
|
14
|
-
return {
|
|
15
|
-
type: "file" as const,
|
|
16
|
-
data: { type: "data" as const, data: part.data },
|
|
17
|
-
mediaType,
|
|
18
|
-
...(part.filename !== undefined && { filename: part.filename }),
|
|
19
|
-
};
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
export const toAISDKDefaultOutput = (output: unknown) =>
|
|
24
|
-
typeof output === "string"
|
|
25
|
-
? { type: "text" as const, value: output }
|
|
26
|
-
: { type: "json" as const, value: (output ?? null) as JSONValue };
|