@ai-sdk/devtools 1.0.0-beta.9 → 1.0.0-canary.20
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/client/assets/index-B1quREL_.css +1 -0
- package/dist/client/assets/index-DYruJ8X0.js +181 -0
- package/dist/client/index.html +2 -2
- package/dist/index.d.ts +19 -1
- package/dist/index.js +342 -3
- package/dist/viewer/server.js +42 -5
- package/package.json +28 -4
- package/src/db.ts +32 -5
- package/src/index.ts +1 -0
- package/src/integration.ts +509 -0
- package/src/middleware.ts +5 -5
- package/src/viewer/client/app.tsx +97 -1878
- package/src/viewer/client/components/message-components.tsx +342 -0
- package/src/viewer/client/components/output-components.tsx +145 -0
- package/src/viewer/client/components/shared-components.tsx +691 -0
- package/src/viewer/client/components/step-card.tsx +472 -0
- package/src/viewer/client/components/trace-timeline.tsx +529 -0
- package/src/viewer/client/components/ui/badge.tsx +0 -1
- package/src/viewer/client/components/ui/button.tsx +0 -1
- package/src/viewer/client/types.ts +183 -0
- package/src/viewer/client/utils.ts +708 -0
- package/src/viewer/server.ts +49 -5
- package/dist/client/assets/index-BkyOIjbt.css +0 -1
- package/dist/client/assets/index-BwqXGbSV.js +0 -176
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GenerateTextStartEvent,
|
|
3
|
+
GenerateTextStepStartEvent,
|
|
4
|
+
GenerateTextStepEndEvent,
|
|
5
|
+
StreamTextChunkEvent,
|
|
6
|
+
GenerateObjectStartEvent,
|
|
7
|
+
GenerateObjectStepStartEvent,
|
|
8
|
+
GenerateObjectStepEndEvent,
|
|
9
|
+
Telemetry,
|
|
10
|
+
ToolSet,
|
|
11
|
+
} from 'ai';
|
|
12
|
+
import {
|
|
13
|
+
createRun,
|
|
14
|
+
createStep,
|
|
15
|
+
updateStepResult,
|
|
16
|
+
notifyServerAsync,
|
|
17
|
+
} from './db.js';
|
|
18
|
+
|
|
19
|
+
type OperationType = 'generate' | 'stream';
|
|
20
|
+
|
|
21
|
+
interface StepState {
|
|
22
|
+
stepId: string;
|
|
23
|
+
startTime: number;
|
|
24
|
+
streamChunks: unknown[];
|
|
25
|
+
rawStreamChunks: unknown[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface CallState {
|
|
29
|
+
runId: string;
|
|
30
|
+
operationType: OperationType;
|
|
31
|
+
functionId: string | undefined;
|
|
32
|
+
settings: Record<string, unknown>;
|
|
33
|
+
stepStates: Map<number, StepState>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const activeSteps = new Map<string, StepState>();
|
|
37
|
+
|
|
38
|
+
let signalHandlersRegistered = false;
|
|
39
|
+
const registerSignalHandlers = () => {
|
|
40
|
+
if (signalHandlersRegistered) return;
|
|
41
|
+
signalHandlersRegistered = true;
|
|
42
|
+
|
|
43
|
+
const cleanup = async () => {
|
|
44
|
+
if (activeSteps.size === 0) return;
|
|
45
|
+
|
|
46
|
+
const promises = Array.from(activeSteps.entries()).map(
|
|
47
|
+
async ([stepId, data]) => {
|
|
48
|
+
const durationMs = Date.now() - data.startTime;
|
|
49
|
+
await updateStepResult(stepId, {
|
|
50
|
+
duration_ms: durationMs,
|
|
51
|
+
output: null,
|
|
52
|
+
usage: null,
|
|
53
|
+
error: 'Request aborted',
|
|
54
|
+
raw_request: null,
|
|
55
|
+
raw_response: null,
|
|
56
|
+
raw_chunks: null,
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
await Promise.all(promises);
|
|
61
|
+
await notifyServerAsync('step-update');
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
process.on('SIGINT', () => {
|
|
65
|
+
cleanup().then(() => process.exit(130));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
process.on('SIGTERM', () => {
|
|
69
|
+
cleanup().then(() => process.exit(143));
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const generateRunId = (): string => {
|
|
74
|
+
const now = new Date();
|
|
75
|
+
const timestamp = now
|
|
76
|
+
.toISOString()
|
|
77
|
+
.replace(/[-:T.Z]/g, '')
|
|
78
|
+
.slice(0, 17);
|
|
79
|
+
const uniqueId = crypto.randomUUID().slice(0, 8);
|
|
80
|
+
return `${timestamp}-${uniqueId}`;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
function getOperationType(operationId: string): OperationType {
|
|
84
|
+
if (operationId === 'ai.streamText' || operationId === 'ai.streamObject') {
|
|
85
|
+
return 'stream';
|
|
86
|
+
}
|
|
87
|
+
return 'generate';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Creates a devtools telemetry integration that logs all AI SDK operations
|
|
92
|
+
* to the devtools viewer.
|
|
93
|
+
*
|
|
94
|
+
* Usage:
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { registerTelemetry } from 'ai';
|
|
97
|
+
* import { DevToolsTelemetry } from '@ai-sdk/devtools';
|
|
98
|
+
*
|
|
99
|
+
* registerTelemetry(DevToolsTelemetry());
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* Telemetry is enabled by default — no need to set `telemetry`
|
|
103
|
+
* unless you want to configure `functionId`, `recordInputs`, or `recordOutputs`.
|
|
104
|
+
*/
|
|
105
|
+
export function DevToolsTelemetry(): Telemetry {
|
|
106
|
+
if (process.env.NODE_ENV === 'production') {
|
|
107
|
+
throw new Error(
|
|
108
|
+
'@ai-sdk/devtools should not be used in production. ' +
|
|
109
|
+
'Remove DevToolsTelemetry from your telemetry configuration for production builds.',
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
registerSignalHandlers();
|
|
114
|
+
|
|
115
|
+
const callStates = new Map<string, CallState>();
|
|
116
|
+
|
|
117
|
+
// When executeTool runs a tool's execute function, any nested generateText/
|
|
118
|
+
// streamText call inside that tool gets its own callId. We track the nesting
|
|
119
|
+
// so that the inner call's run can be linked to the parent.
|
|
120
|
+
//
|
|
121
|
+
// We use a per-toolCallId Map instead of a single variable so that parallel
|
|
122
|
+
// tool calls
|
|
123
|
+
const toolContextMap = new Map<
|
|
124
|
+
string,
|
|
125
|
+
{ parentCallId: string; parentToolCallId: string }
|
|
126
|
+
>();
|
|
127
|
+
let currentToolCallId: string | null = null;
|
|
128
|
+
|
|
129
|
+
function resolveParentInfo(): { runId: string; stepId: string } | undefined {
|
|
130
|
+
if (!currentToolCallId) return undefined;
|
|
131
|
+
|
|
132
|
+
const ctx = toolContextMap.get(currentToolCallId);
|
|
133
|
+
if (!ctx) return undefined;
|
|
134
|
+
|
|
135
|
+
const parentState = callStates.get(ctx.parentCallId);
|
|
136
|
+
if (!parentState) return undefined;
|
|
137
|
+
|
|
138
|
+
// Find the step that is currently executing the tool call.
|
|
139
|
+
// This is the most recent (highest step number) step in the parent call.
|
|
140
|
+
let latestStepId: string | undefined;
|
|
141
|
+
let latestStepNumber = -1;
|
|
142
|
+
for (const [stepNumber, stepState] of parentState.stepStates) {
|
|
143
|
+
if (stepNumber > latestStepNumber) {
|
|
144
|
+
latestStepNumber = stepNumber;
|
|
145
|
+
latestStepId = stepState.stepId;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!latestStepId) return undefined;
|
|
150
|
+
|
|
151
|
+
return { runId: parentState.runId, stepId: latestStepId };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function getOrCreateCallState(
|
|
155
|
+
callId: string,
|
|
156
|
+
operationId: string,
|
|
157
|
+
event: {
|
|
158
|
+
functionId?: string | undefined;
|
|
159
|
+
maxOutputTokens?: number | undefined;
|
|
160
|
+
temperature?: number | undefined;
|
|
161
|
+
topP?: number | undefined;
|
|
162
|
+
topK?: number | undefined;
|
|
163
|
+
presencePenalty?: number | undefined;
|
|
164
|
+
frequencyPenalty?: number | undefined;
|
|
165
|
+
seed?: number | undefined;
|
|
166
|
+
},
|
|
167
|
+
): CallState {
|
|
168
|
+
let state = callStates.get(callId);
|
|
169
|
+
if (state) return state;
|
|
170
|
+
|
|
171
|
+
state = {
|
|
172
|
+
runId: generateRunId(),
|
|
173
|
+
operationType: getOperationType(operationId),
|
|
174
|
+
functionId: event.functionId,
|
|
175
|
+
settings: {
|
|
176
|
+
maxOutputTokens: event.maxOutputTokens,
|
|
177
|
+
temperature: event.temperature,
|
|
178
|
+
topP: event.topP,
|
|
179
|
+
topK: event.topK,
|
|
180
|
+
presencePenalty: event.presencePenalty,
|
|
181
|
+
frequencyPenalty: event.frequencyPenalty,
|
|
182
|
+
seed: event.seed,
|
|
183
|
+
},
|
|
184
|
+
stepStates: new Map(),
|
|
185
|
+
};
|
|
186
|
+
callStates.set(callId, state);
|
|
187
|
+
return state;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const integration: Telemetry = {
|
|
191
|
+
onStart: async event => {
|
|
192
|
+
const operationId = (event as { operationId: string }).operationId;
|
|
193
|
+
|
|
194
|
+
if (
|
|
195
|
+
operationId === 'ai.embed' ||
|
|
196
|
+
operationId === 'ai.embedMany' ||
|
|
197
|
+
operationId === 'ai.rerank'
|
|
198
|
+
) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const startEvent = event as (
|
|
203
|
+
| GenerateTextStartEvent<ToolSet>
|
|
204
|
+
| GenerateObjectStartEvent
|
|
205
|
+
) & {
|
|
206
|
+
functionId?: string | undefined;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const parentInfo = resolveParentInfo();
|
|
210
|
+
|
|
211
|
+
const state = getOrCreateCallState(
|
|
212
|
+
startEvent.callId,
|
|
213
|
+
operationId,
|
|
214
|
+
startEvent,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
await createRun(state.runId, parentInfo, state.functionId);
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
onStepStart: async event => {
|
|
221
|
+
const stepStartEvent = event as GenerateTextStepStartEvent<ToolSet> & {
|
|
222
|
+
promptMessages?: unknown[];
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const state = callStates.get(stepStartEvent.callId);
|
|
226
|
+
if (!state) return;
|
|
227
|
+
|
|
228
|
+
const stepId = crypto.randomUUID();
|
|
229
|
+
const startTime = Date.now();
|
|
230
|
+
|
|
231
|
+
const stepState: StepState = {
|
|
232
|
+
stepId,
|
|
233
|
+
startTime,
|
|
234
|
+
streamChunks: [],
|
|
235
|
+
rawStreamChunks: [],
|
|
236
|
+
};
|
|
237
|
+
const stepNumber = stepStartEvent.steps.length;
|
|
238
|
+
state.stepStates.set(stepNumber, stepState);
|
|
239
|
+
activeSteps.set(stepId, stepState);
|
|
240
|
+
|
|
241
|
+
const prompt = stepStartEvent.promptMessages ?? stepStartEvent.messages;
|
|
242
|
+
|
|
243
|
+
await createStep({
|
|
244
|
+
id: stepId,
|
|
245
|
+
run_id: state.runId,
|
|
246
|
+
step_number: stepNumber + 1,
|
|
247
|
+
type: state.operationType,
|
|
248
|
+
model_id: stepStartEvent.modelId,
|
|
249
|
+
provider: stepStartEvent.provider ?? null,
|
|
250
|
+
started_at: new Date().toISOString(),
|
|
251
|
+
input: JSON.stringify({
|
|
252
|
+
prompt,
|
|
253
|
+
tools: stepStartEvent.tools
|
|
254
|
+
? Object.entries(stepStartEvent.tools).map(([name, tool]) => ({
|
|
255
|
+
name,
|
|
256
|
+
description: (tool as { description?: string }).description,
|
|
257
|
+
parameters: (tool as { parameters?: unknown }).parameters,
|
|
258
|
+
}))
|
|
259
|
+
: undefined,
|
|
260
|
+
toolChoice: stepStartEvent.toolChoice,
|
|
261
|
+
maxOutputTokens: state.settings.maxOutputTokens,
|
|
262
|
+
temperature: state.settings.temperature,
|
|
263
|
+
topP: state.settings.topP,
|
|
264
|
+
topK: state.settings.topK,
|
|
265
|
+
presencePenalty: state.settings.presencePenalty,
|
|
266
|
+
frequencyPenalty: state.settings.frequencyPenalty,
|
|
267
|
+
seed: state.settings.seed,
|
|
268
|
+
}),
|
|
269
|
+
provider_options: stepStartEvent.providerOptions
|
|
270
|
+
? JSON.stringify(stepStartEvent.providerOptions)
|
|
271
|
+
: null,
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
onObjectStepStart: async event => {
|
|
276
|
+
const stepStartEvent = event as GenerateObjectStepStartEvent & {
|
|
277
|
+
promptMessages?: unknown[];
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const state = callStates.get(stepStartEvent.callId);
|
|
281
|
+
if (!state) return;
|
|
282
|
+
|
|
283
|
+
const stepId = crypto.randomUUID();
|
|
284
|
+
const startTime = Date.now();
|
|
285
|
+
|
|
286
|
+
const stepState: StepState = {
|
|
287
|
+
stepId,
|
|
288
|
+
startTime,
|
|
289
|
+
streamChunks: [],
|
|
290
|
+
rawStreamChunks: [],
|
|
291
|
+
};
|
|
292
|
+
state.stepStates.set(stepStartEvent.stepNumber, stepState);
|
|
293
|
+
activeSteps.set(stepId, stepState);
|
|
294
|
+
|
|
295
|
+
await createStep({
|
|
296
|
+
id: stepId,
|
|
297
|
+
run_id: state.runId,
|
|
298
|
+
step_number: stepStartEvent.stepNumber + 1,
|
|
299
|
+
type: state.operationType,
|
|
300
|
+
model_id: stepStartEvent.modelId,
|
|
301
|
+
provider: stepStartEvent.provider ?? null,
|
|
302
|
+
started_at: new Date().toISOString(),
|
|
303
|
+
input: JSON.stringify({
|
|
304
|
+
prompt: stepStartEvent.promptMessages,
|
|
305
|
+
maxOutputTokens: state.settings.maxOutputTokens,
|
|
306
|
+
temperature: state.settings.temperature,
|
|
307
|
+
topP: state.settings.topP,
|
|
308
|
+
topK: state.settings.topK,
|
|
309
|
+
presencePenalty: state.settings.presencePenalty,
|
|
310
|
+
frequencyPenalty: state.settings.frequencyPenalty,
|
|
311
|
+
seed: state.settings.seed,
|
|
312
|
+
}),
|
|
313
|
+
provider_options: stepStartEvent.providerOptions
|
|
314
|
+
? JSON.stringify(stepStartEvent.providerOptions)
|
|
315
|
+
: null,
|
|
316
|
+
});
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
onChunk: async event => {
|
|
320
|
+
const { chunk } = event as StreamTextChunkEvent;
|
|
321
|
+
|
|
322
|
+
if (chunk.type === 'raw') {
|
|
323
|
+
const rawValue = (chunk as { rawValue: unknown }).rawValue;
|
|
324
|
+
for (const [, state] of callStates) {
|
|
325
|
+
let latestStepState: StepState | undefined;
|
|
326
|
+
let latestStepNumber = -1;
|
|
327
|
+
for (const [stepNumber, ss] of state.stepStates) {
|
|
328
|
+
if (stepNumber > latestStepNumber) {
|
|
329
|
+
latestStepNumber = stepNumber;
|
|
330
|
+
latestStepState = ss;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (latestStepState) {
|
|
334
|
+
latestStepState.rawStreamChunks.push(rawValue);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if ('callId' in chunk && 'stepNumber' in chunk) {
|
|
342
|
+
const typed = chunk as { callId: string; stepNumber: number };
|
|
343
|
+
const state = callStates.get(typed.callId);
|
|
344
|
+
if (!state) return;
|
|
345
|
+
const stepState = state.stepStates.get(typed.stepNumber);
|
|
346
|
+
if (!stepState) return;
|
|
347
|
+
stepState.streamChunks.push(chunk);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
for (const [, state] of callStates) {
|
|
352
|
+
let latestStepState: StepState | undefined;
|
|
353
|
+
let latestStepNumber = -1;
|
|
354
|
+
for (const [stepNumber, ss] of state.stepStates) {
|
|
355
|
+
if (stepNumber > latestStepNumber) {
|
|
356
|
+
latestStepNumber = stepNumber;
|
|
357
|
+
latestStepState = ss;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (latestStepState) {
|
|
361
|
+
latestStepState.streamChunks.push(chunk);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
onStepFinish: async event => {
|
|
368
|
+
const stepResult = event as GenerateTextStepEndEvent<ToolSet>;
|
|
369
|
+
|
|
370
|
+
const state = callStates.get(stepResult.callId);
|
|
371
|
+
if (!state) return;
|
|
372
|
+
|
|
373
|
+
const stepState = state.stepStates.get(stepResult.stepNumber);
|
|
374
|
+
if (!stepState) return;
|
|
375
|
+
|
|
376
|
+
activeSteps.delete(stepState.stepId);
|
|
377
|
+
|
|
378
|
+
const durationMs = Date.now() - stepState.startTime;
|
|
379
|
+
|
|
380
|
+
const output = {
|
|
381
|
+
content: stepResult.content,
|
|
382
|
+
finishReason: stepResult.finishReason,
|
|
383
|
+
response: {
|
|
384
|
+
id: stepResult.response.id,
|
|
385
|
+
modelId: stepResult.response.modelId,
|
|
386
|
+
timestamp: stepResult.response.timestamp,
|
|
387
|
+
messages: stepResult.response.messages,
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const hasStreamChunks = stepState.streamChunks.length > 0;
|
|
392
|
+
const hasRawStreamChunks = stepState.rawStreamChunks.length > 0;
|
|
393
|
+
|
|
394
|
+
await updateStepResult(stepState.stepId, {
|
|
395
|
+
duration_ms: durationMs,
|
|
396
|
+
output: JSON.stringify(output),
|
|
397
|
+
usage: stepResult.usage ? JSON.stringify(stepResult.usage) : null,
|
|
398
|
+
error: null,
|
|
399
|
+
raw_request: stepResult.request?.body
|
|
400
|
+
? JSON.stringify(stepResult.request.body)
|
|
401
|
+
: null,
|
|
402
|
+
raw_response: stepResult.response?.body
|
|
403
|
+
? JSON.stringify(stepResult.response.body)
|
|
404
|
+
: hasStreamChunks
|
|
405
|
+
? JSON.stringify(stepState.streamChunks)
|
|
406
|
+
: null,
|
|
407
|
+
raw_chunks: hasRawStreamChunks
|
|
408
|
+
? JSON.stringify(stepState.rawStreamChunks)
|
|
409
|
+
: null,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
state.stepStates.delete(stepResult.stepNumber);
|
|
413
|
+
},
|
|
414
|
+
|
|
415
|
+
onObjectStepFinish: async event => {
|
|
416
|
+
const stepResult = event as GenerateObjectStepEndEvent;
|
|
417
|
+
|
|
418
|
+
const state = callStates.get(stepResult.callId);
|
|
419
|
+
if (!state) return;
|
|
420
|
+
|
|
421
|
+
const stepState = state.stepStates.get(stepResult.stepNumber);
|
|
422
|
+
if (!stepState) return;
|
|
423
|
+
|
|
424
|
+
activeSteps.delete(stepState.stepId);
|
|
425
|
+
|
|
426
|
+
const durationMs = Date.now() - stepState.startTime;
|
|
427
|
+
|
|
428
|
+
const output = {
|
|
429
|
+
finishReason: stepResult.finishReason,
|
|
430
|
+
objectText: stepResult.objectText,
|
|
431
|
+
response: {
|
|
432
|
+
id: stepResult.response.id,
|
|
433
|
+
modelId: stepResult.response.modelId,
|
|
434
|
+
timestamp: stepResult.response.timestamp,
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
await updateStepResult(stepState.stepId, {
|
|
439
|
+
duration_ms: durationMs,
|
|
440
|
+
output: JSON.stringify(output),
|
|
441
|
+
usage: stepResult.usage ? JSON.stringify(stepResult.usage) : null,
|
|
442
|
+
error: null,
|
|
443
|
+
raw_request: stepResult.request?.body
|
|
444
|
+
? JSON.stringify(stepResult.request.body)
|
|
445
|
+
: null,
|
|
446
|
+
raw_response: stepResult.response?.body
|
|
447
|
+
? JSON.stringify(stepResult.response.body)
|
|
448
|
+
: null,
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
state.stepStates.delete(stepResult.stepNumber);
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
onFinish: async event => {
|
|
455
|
+
const finishEvent = event as { callId: string };
|
|
456
|
+
callStates.delete(finishEvent.callId);
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
onError: async error => {
|
|
460
|
+
const errorObj = error as
|
|
461
|
+
| { callId?: string; error?: unknown }
|
|
462
|
+
| undefined;
|
|
463
|
+
const callId = errorObj?.callId;
|
|
464
|
+
if (!callId) return;
|
|
465
|
+
|
|
466
|
+
const state = callStates.get(callId);
|
|
467
|
+
if (!state) return;
|
|
468
|
+
|
|
469
|
+
const cause = errorObj?.error ?? error;
|
|
470
|
+
const errorMessage =
|
|
471
|
+
cause instanceof Error ? cause.message : String(cause);
|
|
472
|
+
|
|
473
|
+
for (const [, stepState] of state.stepStates) {
|
|
474
|
+
activeSteps.delete(stepState.stepId);
|
|
475
|
+
const durationMs = Date.now() - stepState.startTime;
|
|
476
|
+
await updateStepResult(stepState.stepId, {
|
|
477
|
+
duration_ms: durationMs,
|
|
478
|
+
output: null,
|
|
479
|
+
usage: null,
|
|
480
|
+
error: errorMessage,
|
|
481
|
+
raw_request: null,
|
|
482
|
+
raw_response: null,
|
|
483
|
+
raw_chunks: null,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
callStates.delete(callId);
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
executeTool: async ({ callId, toolCallId, execute }) => {
|
|
491
|
+
toolContextMap.set(toolCallId, {
|
|
492
|
+
parentCallId: callId,
|
|
493
|
+
parentToolCallId: toolCallId,
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
const previousToolCallId = currentToolCallId;
|
|
497
|
+
currentToolCallId = toolCallId;
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
return await execute();
|
|
501
|
+
} finally {
|
|
502
|
+
currentToolCallId = previousToolCallId;
|
|
503
|
+
toolContextMap.delete(toolCallId);
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
return integration;
|
|
509
|
+
}
|
package/src/middleware.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type {
|
|
2
|
+
LanguageModelV4FinishReason,
|
|
3
|
+
LanguageModelV4Usage,
|
|
4
|
+
LanguageModelV4Middleware,
|
|
5
|
+
LanguageModelV4StreamPart,
|
|
6
6
|
} from '@ai-sdk/provider';
|
|
7
7
|
import {
|
|
8
8
|
createRun,
|