@ai-sdk/devtools 1.0.24 → 1.0.26
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/index.d.ts +15 -13
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +717 -739
- package/dist/index.js.map +1 -0
- package/dist/viewer/server.js +297 -352
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -1,767 +1,745 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
//#region src/db.ts
|
|
4
|
+
const DEVTOOLS_DB_DIR = ".devtools";
|
|
5
|
+
const DEVTOOLS_DB_FILE = "generations.json";
|
|
6
|
+
const DB_DIR = path.join(process.cwd(), DEVTOOLS_DB_DIR);
|
|
7
|
+
const DB_PATH = path.join(DB_DIR, DEVTOOLS_DB_FILE);
|
|
8
|
+
const DEVTOOLS_PORT = process.env.AI_SDK_DEVTOOLS_PORT ? parseInt(process.env.AI_SDK_DEVTOOLS_PORT) : 4983;
|
|
9
|
+
/**
|
|
10
|
+
* Notify the devtools server that data has changed.
|
|
11
|
+
* Fire-and-forget: doesn't block, ignores errors if server isn't running.
|
|
12
|
+
*/
|
|
13
|
+
const notifyServer = (event) => {
|
|
14
|
+
notifyServerAsync(event);
|
|
12
15
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Notify the devtools server and wait for the request to complete.
|
|
18
|
+
* Used during process cleanup to ensure notifications are sent before exit.
|
|
19
|
+
*/
|
|
20
|
+
const notifyServerAsync = async (event) => {
|
|
21
|
+
try {
|
|
22
|
+
await fetch(`http://localhost:${DEVTOOLS_PORT}/api/notify`, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
event,
|
|
27
|
+
timestamp: Date.now(),
|
|
28
|
+
dbPath: DB_PATH
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
} catch {}
|
|
22
32
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
` : `${content}
|
|
36
|
-
.devtools
|
|
37
|
-
`;
|
|
38
|
-
fs.writeFileSync(gitignorePath, newContent);
|
|
39
|
-
}
|
|
33
|
+
/**
|
|
34
|
+
* Ensure .devtools is in .gitignore.
|
|
35
|
+
* Only writes if .gitignore exists and doesn't already contain .devtools.
|
|
36
|
+
*/
|
|
37
|
+
const ensureGitignore = () => {
|
|
38
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
39
|
+
if (!fs.existsSync(gitignorePath)) return;
|
|
40
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
41
|
+
if (!content.split("\n").some((line) => line.trim() === ".devtools" || line.trim() === ".devtools/")) {
|
|
42
|
+
const newContent = content.endsWith("\n") ? `${content}.devtools\n` : `${content}\n.devtools\n`;
|
|
43
|
+
fs.writeFileSync(gitignorePath, newContent);
|
|
44
|
+
}
|
|
40
45
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
const readDb = () => {
|
|
47
|
+
try {
|
|
48
|
+
if (fs.existsSync(DB_PATH)) {
|
|
49
|
+
const content = fs.readFileSync(DB_PATH, "utf-8");
|
|
50
|
+
return JSON.parse(content);
|
|
51
|
+
}
|
|
52
|
+
} catch {}
|
|
53
|
+
return {
|
|
54
|
+
runs: [],
|
|
55
|
+
steps: []
|
|
56
|
+
};
|
|
50
57
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
fs.writeFileSync(DB_PATH, JSON.stringify(db, null, 2));
|
|
58
|
+
const writeDb = (db) => {
|
|
59
|
+
if (!fs.existsSync(DB_DIR)) {
|
|
60
|
+
fs.mkdirSync(DB_DIR, { recursive: true });
|
|
61
|
+
ensureGitignore();
|
|
62
|
+
}
|
|
63
|
+
fs.writeFileSync(DB_PATH, JSON.stringify(db, null, 2));
|
|
58
64
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
return dbCache;
|
|
65
|
+
let dbCache = null;
|
|
66
|
+
const getDb = () => {
|
|
67
|
+
if (!dbCache) dbCache = readDb();
|
|
68
|
+
return dbCache;
|
|
65
69
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
const saveDb = (db) => {
|
|
71
|
+
dbCache = db;
|
|
72
|
+
writeDb(db);
|
|
69
73
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
notifyServer("run");
|
|
87
|
-
return run;
|
|
74
|
+
const createRun = async (id, parent, functionId) => {
|
|
75
|
+
const db = getDb();
|
|
76
|
+
const started_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
77
|
+
const existing = db.runs.find((r) => r.id === id);
|
|
78
|
+
if (existing) return existing;
|
|
79
|
+
const run = {
|
|
80
|
+
id,
|
|
81
|
+
started_at,
|
|
82
|
+
parent_run_id: parent?.runId ?? null,
|
|
83
|
+
parent_step_id: parent?.stepId ?? null,
|
|
84
|
+
function_id: functionId ?? null
|
|
85
|
+
};
|
|
86
|
+
db.runs.push(run);
|
|
87
|
+
saveDb(db);
|
|
88
|
+
notifyServer("run");
|
|
89
|
+
return run;
|
|
88
90
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
const createStep = async (step) => {
|
|
92
|
+
const db = getDb();
|
|
93
|
+
const newStep = {
|
|
94
|
+
...step,
|
|
95
|
+
duration_ms: null,
|
|
96
|
+
output: null,
|
|
97
|
+
usage: null,
|
|
98
|
+
error: null,
|
|
99
|
+
raw_request: null,
|
|
100
|
+
raw_response: null,
|
|
101
|
+
raw_chunks: null
|
|
102
|
+
};
|
|
103
|
+
db.steps.push(newStep);
|
|
104
|
+
saveDb(db);
|
|
105
|
+
notifyServer("step");
|
|
104
106
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
const updateStepResult = async (stepId, result) => {
|
|
108
|
+
const db = getDb();
|
|
109
|
+
const step = db.steps.find((s) => s.id === stepId);
|
|
110
|
+
if (step) {
|
|
111
|
+
step.duration_ms = result.duration_ms;
|
|
112
|
+
step.output = result.output;
|
|
113
|
+
step.usage = result.usage;
|
|
114
|
+
step.error = result.error;
|
|
115
|
+
step.raw_request = result.raw_request ?? null;
|
|
116
|
+
step.raw_response = result.raw_response ?? null;
|
|
117
|
+
step.raw_chunks = result.raw_chunks ?? null;
|
|
118
|
+
saveDb(db);
|
|
119
|
+
notifyServer("step-update");
|
|
120
|
+
}
|
|
119
121
|
};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return db.steps.filter((s) => s.run_id === runId).sort((a, b) => a.step_number - b.step_number);
|
|
122
|
+
const getStepsForRun = async (runId) => {
|
|
123
|
+
return getDb().steps.filter((s) => s.run_id === runId).sort((a, b) => a.step_number - b.step_number);
|
|
123
124
|
};
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/serialize.ts
|
|
126
127
|
function normalizeBinaryData(value) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (ArrayBuffer.isView(value)) {
|
|
131
|
-
return Buffer.from(
|
|
132
|
-
value.buffer,
|
|
133
|
-
value.byteOffset,
|
|
134
|
-
value.byteLength
|
|
135
|
-
).toString("base64");
|
|
136
|
-
}
|
|
137
|
-
return value;
|
|
128
|
+
if (value instanceof ArrayBuffer) return Buffer.from(value).toString("base64");
|
|
129
|
+
if (ArrayBuffer.isView(value)) return Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString("base64");
|
|
130
|
+
return value;
|
|
138
131
|
}
|
|
139
132
|
function isRecord(value) {
|
|
140
|
-
|
|
133
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
141
134
|
}
|
|
142
135
|
function collectMediaBinaryValues(value) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
break;
|
|
180
|
-
case "media":
|
|
181
|
-
case "file-data":
|
|
182
|
-
case "image-data":
|
|
183
|
-
markBinary(candidate.data);
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
for (const child of Array.isArray(candidate) ? candidate : Object.values(candidate)) {
|
|
188
|
-
visit(child);
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
visit(value);
|
|
192
|
-
return mediaBinaryValues;
|
|
136
|
+
const mediaBinaryValues = /* @__PURE__ */ new WeakSet();
|
|
137
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
138
|
+
const markBinary = (candidate) => {
|
|
139
|
+
if (candidate instanceof ArrayBuffer || ArrayBuffer.isView(candidate)) mediaBinaryValues.add(candidate);
|
|
140
|
+
};
|
|
141
|
+
const markGeneratedFile = (candidate) => {
|
|
142
|
+
if (!isRecord(candidate)) return;
|
|
143
|
+
if (Object.hasOwn(candidate, "uint8Array")) markBinary(candidate.uint8Array);
|
|
144
|
+
markBinary(candidate.uint8ArrayData);
|
|
145
|
+
};
|
|
146
|
+
const markDataContent = (candidate) => {
|
|
147
|
+
markBinary(candidate);
|
|
148
|
+
if (!isRecord(candidate)) return;
|
|
149
|
+
if (candidate.type === "data") markBinary(candidate.data);
|
|
150
|
+
};
|
|
151
|
+
const visit = (candidate) => {
|
|
152
|
+
if (candidate == null || typeof candidate !== "object" || candidate instanceof ArrayBuffer || ArrayBuffer.isView(candidate) || visited.has(candidate)) return;
|
|
153
|
+
visited.add(candidate);
|
|
154
|
+
if (isRecord(candidate) && typeof candidate.type === "string") switch (candidate.type) {
|
|
155
|
+
case "file":
|
|
156
|
+
case "reasoning-file":
|
|
157
|
+
markDataContent(candidate.data);
|
|
158
|
+
markGeneratedFile(candidate);
|
|
159
|
+
markGeneratedFile(candidate.file);
|
|
160
|
+
break;
|
|
161
|
+
case "image":
|
|
162
|
+
markDataContent(candidate.image);
|
|
163
|
+
break;
|
|
164
|
+
case "media":
|
|
165
|
+
case "file-data":
|
|
166
|
+
case "image-data": markBinary(candidate.data);
|
|
167
|
+
}
|
|
168
|
+
for (const child of Array.isArray(candidate) ? candidate : Object.values(candidate)) visit(child);
|
|
169
|
+
};
|
|
170
|
+
visit(value);
|
|
171
|
+
return mediaBinaryValues;
|
|
193
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Serializes captured DevTools values while preserving binary values in
|
|
175
|
+
* recognized media-bearing fields as base64. Unrelated binary values retain
|
|
176
|
+
* their normal JSON.stringify representation.
|
|
177
|
+
*/
|
|
194
178
|
function serializeForDevTools(value) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
179
|
+
const mediaBinaryValues = collectMediaBinaryValues(value);
|
|
180
|
+
return JSON.stringify(value, function(key, serializedValue) {
|
|
181
|
+
const originalValue = this[key];
|
|
182
|
+
return originalValue != null && typeof originalValue === "object" && mediaBinaryValues.has(originalValue) ? normalizeBinaryData(originalValue) : serializedValue;
|
|
183
|
+
});
|
|
200
184
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
cleanup().then(() => process.exit(143));
|
|
233
|
-
});
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/middleware.ts
|
|
187
|
+
const generateId = () => crypto.randomUUID();
|
|
188
|
+
const activeSteps$1 = /* @__PURE__ */ new Map();
|
|
189
|
+
let signalHandlersRegistered$1 = false;
|
|
190
|
+
const registerSignalHandlers$1 = () => {
|
|
191
|
+
if (signalHandlersRegistered$1) return;
|
|
192
|
+
signalHandlersRegistered$1 = true;
|
|
193
|
+
const cleanup = async () => {
|
|
194
|
+
if (activeSteps$1.size === 0) return;
|
|
195
|
+
const promises = Array.from(activeSteps$1.entries()).map(async ([stepId, data]) => {
|
|
196
|
+
const durationMs = Date.now() - data.startTime;
|
|
197
|
+
await updateStepResult(stepId, {
|
|
198
|
+
duration_ms: durationMs,
|
|
199
|
+
output: serializeForDevTools(data.collectedOutput),
|
|
200
|
+
usage: null,
|
|
201
|
+
error: "Request aborted",
|
|
202
|
+
raw_request: data.request && typeof data.request === "object" && "body" in data.request ? JSON.stringify(data.request.body) : null,
|
|
203
|
+
raw_response: JSON.stringify(data.fullStreamChunks),
|
|
204
|
+
raw_chunks: JSON.stringify(data.rawChunks)
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
await Promise.all(promises);
|
|
208
|
+
await notifyServerAsync("step-update");
|
|
209
|
+
};
|
|
210
|
+
process.on("SIGINT", () => {
|
|
211
|
+
cleanup().then(() => process.exit(130));
|
|
212
|
+
});
|
|
213
|
+
process.on("SIGTERM", () => {
|
|
214
|
+
cleanup().then(() => process.exit(143));
|
|
215
|
+
});
|
|
234
216
|
};
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Generate a unique run ID with timestamp prefix for sorting.
|
|
219
|
+
*/
|
|
220
|
+
const generateRunId$1 = () => {
|
|
221
|
+
return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:T.Z]/g, "").slice(0, 17)}-${crypto.randomUUID().slice(0, 8)}`;
|
|
240
222
|
};
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Factory function that creates a devtools middleware instance.
|
|
225
|
+
* Each call generates a unique run ID, so all steps within a single
|
|
226
|
+
* streamText/generateText call share the same run.
|
|
227
|
+
*
|
|
228
|
+
* Usage:
|
|
229
|
+
* ```ts
|
|
230
|
+
* const result = streamText({
|
|
231
|
+
* model: wrapLanguageModel({
|
|
232
|
+
* middleware: devToolsMiddleware(),
|
|
233
|
+
* model: yourModel,
|
|
234
|
+
* }),
|
|
235
|
+
* prompt: "...",
|
|
236
|
+
* });
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
const devToolsMiddleware = () => {
|
|
240
|
+
if (process.env.NODE_ENV === "production") throw new Error("@ai-sdk/devtools should not be used in production. Remove devToolsMiddleware from your model configuration for production builds.");
|
|
241
|
+
registerSignalHandlers$1();
|
|
242
|
+
const runId = generateRunId$1();
|
|
243
|
+
let runCreated = false;
|
|
244
|
+
let stepCounter = 0;
|
|
245
|
+
const ensureRunCreated = async () => {
|
|
246
|
+
if (!runCreated) {
|
|
247
|
+
await createRun(runId);
|
|
248
|
+
runCreated = true;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const getNextStepNumber = () => {
|
|
252
|
+
stepCounter++;
|
|
253
|
+
return stepCounter;
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
specificationVersion: "v4",
|
|
257
|
+
wrapGenerate: async ({ doGenerate, params, model }) => {
|
|
258
|
+
const startTime = Date.now();
|
|
259
|
+
const stepId = generateId();
|
|
260
|
+
const stepNumber = getNextStepNumber();
|
|
261
|
+
await ensureRunCreated();
|
|
262
|
+
await createStep({
|
|
263
|
+
id: stepId,
|
|
264
|
+
run_id: runId,
|
|
265
|
+
step_number: stepNumber,
|
|
266
|
+
type: "generate",
|
|
267
|
+
model_id: model.modelId,
|
|
268
|
+
provider: model.config?.provider,
|
|
269
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
270
|
+
input: serializeForDevTools({
|
|
271
|
+
prompt: params.prompt,
|
|
272
|
+
tools: params.tools,
|
|
273
|
+
toolChoice: params.toolChoice,
|
|
274
|
+
maxOutputTokens: params.maxOutputTokens,
|
|
275
|
+
temperature: params.temperature,
|
|
276
|
+
topP: params.topP,
|
|
277
|
+
topK: params.topK,
|
|
278
|
+
presencePenalty: params.presencePenalty,
|
|
279
|
+
frequencyPenalty: params.frequencyPenalty,
|
|
280
|
+
seed: params.seed,
|
|
281
|
+
responseFormat: params.responseFormat
|
|
282
|
+
}),
|
|
283
|
+
provider_options: params.providerOptions ? JSON.stringify(params.providerOptions) : null
|
|
284
|
+
});
|
|
285
|
+
try {
|
|
286
|
+
const result = await doGenerate();
|
|
287
|
+
const durationMs = Date.now() - startTime;
|
|
288
|
+
await updateStepResult(stepId, {
|
|
289
|
+
duration_ms: durationMs,
|
|
290
|
+
output: serializeForDevTools({
|
|
291
|
+
content: result.content,
|
|
292
|
+
finishReason: result.finishReason,
|
|
293
|
+
response: result.response
|
|
294
|
+
}),
|
|
295
|
+
usage: result.usage ? JSON.stringify(result.usage) : null,
|
|
296
|
+
error: null,
|
|
297
|
+
raw_request: result.request?.body ? JSON.stringify(result.request.body) : null,
|
|
298
|
+
raw_response: result.response?.body ? JSON.stringify(result.response.body) : null
|
|
299
|
+
});
|
|
300
|
+
return result;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
const durationMs = Date.now() - startTime;
|
|
303
|
+
await updateStepResult(stepId, {
|
|
304
|
+
duration_ms: durationMs,
|
|
305
|
+
output: null,
|
|
306
|
+
usage: null,
|
|
307
|
+
error: error instanceof Error ? error.message : String(error),
|
|
308
|
+
raw_request: null,
|
|
309
|
+
raw_response: null
|
|
310
|
+
});
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
wrapStream: async ({ doStream, params, model }) => {
|
|
315
|
+
const startTime = Date.now();
|
|
316
|
+
const stepId = generateId();
|
|
317
|
+
const stepNumber = getNextStepNumber();
|
|
318
|
+
await ensureRunCreated();
|
|
319
|
+
const userRequestedRawChunks = params.includeRawChunks === true;
|
|
320
|
+
params.includeRawChunks = true;
|
|
321
|
+
await createStep({
|
|
322
|
+
id: stepId,
|
|
323
|
+
run_id: runId,
|
|
324
|
+
step_number: stepNumber,
|
|
325
|
+
type: "stream",
|
|
326
|
+
model_id: model.modelId,
|
|
327
|
+
provider: model.config?.provider,
|
|
328
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
329
|
+
input: serializeForDevTools({
|
|
330
|
+
prompt: params.prompt,
|
|
331
|
+
tools: params.tools,
|
|
332
|
+
toolChoice: params.toolChoice,
|
|
333
|
+
maxOutputTokens: params.maxOutputTokens,
|
|
334
|
+
temperature: params.temperature,
|
|
335
|
+
topP: params.topP,
|
|
336
|
+
topK: params.topK,
|
|
337
|
+
presencePenalty: params.presencePenalty,
|
|
338
|
+
frequencyPenalty: params.frequencyPenalty,
|
|
339
|
+
seed: params.seed,
|
|
340
|
+
responseFormat: params.responseFormat
|
|
341
|
+
}),
|
|
342
|
+
provider_options: params.providerOptions ? JSON.stringify(params.providerOptions) : null
|
|
343
|
+
});
|
|
344
|
+
try {
|
|
345
|
+
const { stream, request, response, ...rest } = await doStream();
|
|
346
|
+
const collectedOutput = {
|
|
347
|
+
textParts: [],
|
|
348
|
+
reasoningParts: [],
|
|
349
|
+
toolCalls: []
|
|
350
|
+
};
|
|
351
|
+
const currentText = /* @__PURE__ */ new Map();
|
|
352
|
+
const currentReasoning = /* @__PURE__ */ new Map();
|
|
353
|
+
const fullStreamChunks = [];
|
|
354
|
+
const rawChunks = [];
|
|
355
|
+
activeSteps$1.set(stepId, {
|
|
356
|
+
startTime,
|
|
357
|
+
collectedOutput,
|
|
358
|
+
request,
|
|
359
|
+
fullStreamChunks,
|
|
360
|
+
rawChunks
|
|
361
|
+
});
|
|
362
|
+
const transformStream = new TransformStream({
|
|
363
|
+
transform(chunk, controller) {
|
|
364
|
+
if (chunk.type === "raw") {
|
|
365
|
+
rawChunks.push(chunk.rawValue);
|
|
366
|
+
if (userRequestedRawChunks) controller.enqueue(chunk);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
fullStreamChunks.push(chunk);
|
|
370
|
+
switch (chunk.type) {
|
|
371
|
+
case "text-start":
|
|
372
|
+
currentText.set(chunk.id, "");
|
|
373
|
+
break;
|
|
374
|
+
case "text-delta":
|
|
375
|
+
currentText.set(chunk.id, (currentText.get(chunk.id) ?? "") + chunk.delta);
|
|
376
|
+
break;
|
|
377
|
+
case "text-end":
|
|
378
|
+
collectedOutput.textParts.push({
|
|
379
|
+
id: chunk.id,
|
|
380
|
+
text: currentText.get(chunk.id) ?? ""
|
|
381
|
+
});
|
|
382
|
+
break;
|
|
383
|
+
case "reasoning-start":
|
|
384
|
+
currentReasoning.set(chunk.id, "");
|
|
385
|
+
break;
|
|
386
|
+
case "reasoning-delta":
|
|
387
|
+
currentReasoning.set(chunk.id, (currentReasoning.get(chunk.id) ?? "") + chunk.delta);
|
|
388
|
+
break;
|
|
389
|
+
case "reasoning-end":
|
|
390
|
+
collectedOutput.reasoningParts.push({
|
|
391
|
+
id: chunk.id,
|
|
392
|
+
text: currentReasoning.get(chunk.id) ?? ""
|
|
393
|
+
});
|
|
394
|
+
break;
|
|
395
|
+
case "tool-call":
|
|
396
|
+
collectedOutput.toolCalls.push(chunk);
|
|
397
|
+
break;
|
|
398
|
+
case "file":
|
|
399
|
+
case "reasoning-file":
|
|
400
|
+
case "tool-result":
|
|
401
|
+
(collectedOutput.content ??= []).push(chunk);
|
|
402
|
+
break;
|
|
403
|
+
case "finish":
|
|
404
|
+
collectedOutput.finishReason = chunk.finishReason;
|
|
405
|
+
collectedOutput.usage = chunk.usage;
|
|
406
|
+
}
|
|
407
|
+
controller.enqueue(chunk);
|
|
408
|
+
},
|
|
409
|
+
async flush() {
|
|
410
|
+
activeSteps$1.delete(stepId);
|
|
411
|
+
const durationMs = Date.now() - startTime;
|
|
412
|
+
await updateStepResult(stepId, {
|
|
413
|
+
duration_ms: durationMs,
|
|
414
|
+
output: serializeForDevTools(collectedOutput),
|
|
415
|
+
usage: collectedOutput.usage ? JSON.stringify(collectedOutput.usage) : null,
|
|
416
|
+
error: null,
|
|
417
|
+
raw_request: request?.body ? JSON.stringify(request.body) : null,
|
|
418
|
+
raw_response: JSON.stringify(fullStreamChunks),
|
|
419
|
+
raw_chunks: JSON.stringify(rawChunks)
|
|
420
|
+
});
|
|
421
|
+
},
|
|
422
|
+
async cancel() {
|
|
423
|
+
activeSteps$1.delete(stepId);
|
|
424
|
+
const durationMs = Date.now() - startTime;
|
|
425
|
+
await updateStepResult(stepId, {
|
|
426
|
+
duration_ms: durationMs,
|
|
427
|
+
output: serializeForDevTools(collectedOutput),
|
|
428
|
+
usage: collectedOutput.usage ? JSON.stringify(collectedOutput.usage) : null,
|
|
429
|
+
error: "Request aborted",
|
|
430
|
+
raw_request: request?.body ? JSON.stringify(request.body) : null,
|
|
431
|
+
raw_response: JSON.stringify(fullStreamChunks),
|
|
432
|
+
raw_chunks: JSON.stringify(rawChunks)
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
return {
|
|
437
|
+
stream: stream.pipeThrough(transformStream),
|
|
438
|
+
request,
|
|
439
|
+
response,
|
|
440
|
+
...rest
|
|
441
|
+
};
|
|
442
|
+
} catch (error) {
|
|
443
|
+
activeSteps$1.delete(stepId);
|
|
444
|
+
const durationMs = Date.now() - startTime;
|
|
445
|
+
await updateStepResult(stepId, {
|
|
446
|
+
duration_ms: durationMs,
|
|
447
|
+
output: null,
|
|
448
|
+
usage: null,
|
|
449
|
+
error: error instanceof Error ? error.message : String(error),
|
|
450
|
+
raw_request: null,
|
|
451
|
+
raw_response: null,
|
|
452
|
+
raw_chunks: null
|
|
453
|
+
});
|
|
454
|
+
throw error;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
};
|
|
476
458
|
};
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
cleanup().then(() => process.exit(143));
|
|
508
|
-
});
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region src/integration.ts
|
|
461
|
+
const activeSteps = /* @__PURE__ */ new Map();
|
|
462
|
+
let signalHandlersRegistered = false;
|
|
463
|
+
const registerSignalHandlers = () => {
|
|
464
|
+
if (signalHandlersRegistered) return;
|
|
465
|
+
signalHandlersRegistered = true;
|
|
466
|
+
const cleanup = async () => {
|
|
467
|
+
if (activeSteps.size === 0) return;
|
|
468
|
+
const promises = Array.from(activeSteps.entries()).map(async ([stepId, data]) => {
|
|
469
|
+
const durationMs = Date.now() - data.startTime;
|
|
470
|
+
await updateStepResult(stepId, {
|
|
471
|
+
duration_ms: durationMs,
|
|
472
|
+
output: null,
|
|
473
|
+
usage: null,
|
|
474
|
+
error: "Request aborted",
|
|
475
|
+
raw_request: null,
|
|
476
|
+
raw_response: null,
|
|
477
|
+
raw_chunks: null
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
await Promise.all(promises);
|
|
481
|
+
await notifyServerAsync("step-update");
|
|
482
|
+
};
|
|
483
|
+
process.on("SIGINT", () => {
|
|
484
|
+
cleanup().then(() => process.exit(130));
|
|
485
|
+
});
|
|
486
|
+
process.on("SIGTERM", () => {
|
|
487
|
+
cleanup().then(() => process.exit(143));
|
|
488
|
+
});
|
|
509
489
|
};
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const timestamp = now.toISOString().replace(/[-:T.Z]/g, "").slice(0, 17);
|
|
513
|
-
const uniqueId = crypto.randomUUID().slice(0, 8);
|
|
514
|
-
return `${timestamp}-${uniqueId}`;
|
|
490
|
+
const generateRunId = () => {
|
|
491
|
+
return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:T.Z]/g, "").slice(0, 17)}-${crypto.randomUUID().slice(0, 8)}`;
|
|
515
492
|
};
|
|
516
493
|
function getOperationType(operationId) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
return "generate";
|
|
494
|
+
if (operationId === "ai.streamText" || operationId === "ai.streamObject") return "stream";
|
|
495
|
+
return "generate";
|
|
521
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* Creates a devtools telemetry integration that logs all AI SDK operations
|
|
499
|
+
* to the devtools viewer.
|
|
500
|
+
*
|
|
501
|
+
* Usage:
|
|
502
|
+
* ```ts
|
|
503
|
+
* import { registerTelemetry } from 'ai';
|
|
504
|
+
* import { DevToolsTelemetry } from '@ai-sdk/devtools';
|
|
505
|
+
*
|
|
506
|
+
* registerTelemetry(DevToolsTelemetry());
|
|
507
|
+
* ```
|
|
508
|
+
*
|
|
509
|
+
* Telemetry is enabled by default — no need to set `telemetry`
|
|
510
|
+
* unless you want to configure `functionId`, `recordInputs`, or `recordOutputs`.
|
|
511
|
+
*/
|
|
522
512
|
function DevToolsTelemetry(options = {}) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
});
|
|
752
|
-
const previousToolCallId = currentToolCallId;
|
|
753
|
-
currentToolCallId = toolCallId;
|
|
754
|
-
try {
|
|
755
|
-
return await execute();
|
|
756
|
-
} finally {
|
|
757
|
-
currentToolCallId = previousToolCallId;
|
|
758
|
-
toolContextMap.delete(toolCallId);
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
};
|
|
762
|
-
return integration;
|
|
513
|
+
if (process.env.NODE_ENV === "production") throw new Error("@ai-sdk/devtools should not be used in production. Remove DevToolsTelemetry from your telemetry configuration for production builds.");
|
|
514
|
+
registerSignalHandlers();
|
|
515
|
+
const callStates = /* @__PURE__ */ new Map();
|
|
516
|
+
const toolContextMap = /* @__PURE__ */ new Map();
|
|
517
|
+
let currentToolCallId = null;
|
|
518
|
+
function resolveParentInfo() {
|
|
519
|
+
if (!currentToolCallId) return void 0;
|
|
520
|
+
const toolCallContext = toolContextMap.get(currentToolCallId);
|
|
521
|
+
if (!toolCallContext) return void 0;
|
|
522
|
+
const parentState = callStates.get(toolCallContext.parentCallId);
|
|
523
|
+
if (!parentState) return void 0;
|
|
524
|
+
let latestStepId;
|
|
525
|
+
let latestStepNumber = -1;
|
|
526
|
+
for (const [stepNumber, stepState] of parentState.stepStates) if (stepNumber > latestStepNumber) {
|
|
527
|
+
latestStepNumber = stepNumber;
|
|
528
|
+
latestStepId = stepState.stepId;
|
|
529
|
+
}
|
|
530
|
+
if (!latestStepId) return void 0;
|
|
531
|
+
return {
|
|
532
|
+
runId: parentState.runId,
|
|
533
|
+
stepId: latestStepId
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function getOrCreateCallState(callId, operationId, event) {
|
|
537
|
+
let state = callStates.get(callId);
|
|
538
|
+
if (state) return state;
|
|
539
|
+
state = {
|
|
540
|
+
runId: generateRunId(),
|
|
541
|
+
operationType: getOperationType(operationId),
|
|
542
|
+
functionId: event.functionId,
|
|
543
|
+
settings: {
|
|
544
|
+
maxOutputTokens: event.maxOutputTokens,
|
|
545
|
+
temperature: event.temperature,
|
|
546
|
+
topP: event.topP,
|
|
547
|
+
topK: event.topK,
|
|
548
|
+
presencePenalty: event.presencePenalty,
|
|
549
|
+
frequencyPenalty: event.frequencyPenalty,
|
|
550
|
+
seed: event.seed
|
|
551
|
+
},
|
|
552
|
+
stepStates: /* @__PURE__ */ new Map(),
|
|
553
|
+
stepNumberOffset: 0
|
|
554
|
+
};
|
|
555
|
+
callStates.set(callId, state);
|
|
556
|
+
return state;
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
onStart: async (event) => {
|
|
560
|
+
const operationId = event.operationId;
|
|
561
|
+
if (operationId === "ai.embed" || operationId === "ai.embedMany" || operationId === "ai.rerank") return;
|
|
562
|
+
const startEvent = event;
|
|
563
|
+
const parentInfo = resolveParentInfo();
|
|
564
|
+
const state = getOrCreateCallState(startEvent.callId, operationId, startEvent);
|
|
565
|
+
if (options.runId != null) {
|
|
566
|
+
state.runId = options.runId;
|
|
567
|
+
state.stepNumberOffset = (await getStepsForRun(options.runId)).length;
|
|
568
|
+
}
|
|
569
|
+
await createRun(state.runId, parentInfo, state.functionId);
|
|
570
|
+
},
|
|
571
|
+
onStepStart: async (event) => {
|
|
572
|
+
const stepStartEvent = event;
|
|
573
|
+
const state = callStates.get(stepStartEvent.callId);
|
|
574
|
+
if (!state) return;
|
|
575
|
+
const stepId = crypto.randomUUID();
|
|
576
|
+
const stepState = {
|
|
577
|
+
stepId,
|
|
578
|
+
startTime: Date.now()
|
|
579
|
+
};
|
|
580
|
+
const stepNumber = stepStartEvent.steps.length;
|
|
581
|
+
state.stepStates.set(stepNumber, stepState);
|
|
582
|
+
activeSteps.set(stepId, stepState);
|
|
583
|
+
const prompt = stepStartEvent.promptMessages ?? stepStartEvent.messages;
|
|
584
|
+
await createStep({
|
|
585
|
+
id: stepId,
|
|
586
|
+
run_id: state.runId,
|
|
587
|
+
step_number: state.stepNumberOffset + stepNumber + 1,
|
|
588
|
+
type: state.operationType,
|
|
589
|
+
model_id: stepStartEvent.modelId,
|
|
590
|
+
provider: stepStartEvent.provider ?? null,
|
|
591
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
592
|
+
input: serializeForDevTools({
|
|
593
|
+
prompt,
|
|
594
|
+
tools: stepStartEvent.tools ? Object.entries(stepStartEvent.tools).map(([name, tool]) => ({
|
|
595
|
+
name,
|
|
596
|
+
description: tool.description,
|
|
597
|
+
parameters: tool.parameters
|
|
598
|
+
})) : void 0,
|
|
599
|
+
toolChoice: stepStartEvent.toolChoice,
|
|
600
|
+
maxOutputTokens: state.settings.maxOutputTokens,
|
|
601
|
+
temperature: state.settings.temperature,
|
|
602
|
+
topP: state.settings.topP,
|
|
603
|
+
topK: state.settings.topK,
|
|
604
|
+
presencePenalty: state.settings.presencePenalty,
|
|
605
|
+
frequencyPenalty: state.settings.frequencyPenalty,
|
|
606
|
+
seed: state.settings.seed
|
|
607
|
+
}),
|
|
608
|
+
provider_options: stepStartEvent.providerOptions ? JSON.stringify(stepStartEvent.providerOptions) : null
|
|
609
|
+
});
|
|
610
|
+
},
|
|
611
|
+
onObjectStepStart: async (event) => {
|
|
612
|
+
const stepStartEvent = event;
|
|
613
|
+
const state = callStates.get(stepStartEvent.callId);
|
|
614
|
+
if (!state) return;
|
|
615
|
+
const stepId = crypto.randomUUID();
|
|
616
|
+
const stepState = {
|
|
617
|
+
stepId,
|
|
618
|
+
startTime: Date.now()
|
|
619
|
+
};
|
|
620
|
+
state.stepStates.set(stepStartEvent.stepNumber, stepState);
|
|
621
|
+
activeSteps.set(stepId, stepState);
|
|
622
|
+
await createStep({
|
|
623
|
+
id: stepId,
|
|
624
|
+
run_id: state.runId,
|
|
625
|
+
step_number: state.stepNumberOffset + stepStartEvent.stepNumber + 1,
|
|
626
|
+
type: state.operationType,
|
|
627
|
+
model_id: stepStartEvent.modelId,
|
|
628
|
+
provider: stepStartEvent.provider ?? null,
|
|
629
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
630
|
+
input: serializeForDevTools({
|
|
631
|
+
prompt: stepStartEvent.promptMessages,
|
|
632
|
+
maxOutputTokens: state.settings.maxOutputTokens,
|
|
633
|
+
temperature: state.settings.temperature,
|
|
634
|
+
topP: state.settings.topP,
|
|
635
|
+
topK: state.settings.topK,
|
|
636
|
+
presencePenalty: state.settings.presencePenalty,
|
|
637
|
+
frequencyPenalty: state.settings.frequencyPenalty,
|
|
638
|
+
seed: state.settings.seed
|
|
639
|
+
}),
|
|
640
|
+
provider_options: stepStartEvent.providerOptions ? JSON.stringify(stepStartEvent.providerOptions) : null
|
|
641
|
+
});
|
|
642
|
+
},
|
|
643
|
+
onStepEnd: async (event) => {
|
|
644
|
+
const stepResult = event;
|
|
645
|
+
const state = callStates.get(stepResult.callId);
|
|
646
|
+
if (!state) return;
|
|
647
|
+
const stepState = state.stepStates.get(stepResult.stepNumber);
|
|
648
|
+
if (!stepState) return;
|
|
649
|
+
activeSteps.delete(stepState.stepId);
|
|
650
|
+
const durationMs = Date.now() - stepState.startTime;
|
|
651
|
+
const output = {
|
|
652
|
+
content: stepResult.content,
|
|
653
|
+
finishReason: stepResult.finishReason,
|
|
654
|
+
response: {
|
|
655
|
+
id: stepResult.response.id,
|
|
656
|
+
modelId: stepResult.response.modelId,
|
|
657
|
+
timestamp: stepResult.response.timestamp,
|
|
658
|
+
messages: stepResult.response.messages
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
await updateStepResult(stepState.stepId, {
|
|
662
|
+
duration_ms: durationMs,
|
|
663
|
+
output: serializeForDevTools(output),
|
|
664
|
+
usage: stepResult.usage ? JSON.stringify(stepResult.usage) : null,
|
|
665
|
+
error: null,
|
|
666
|
+
raw_request: stepResult.request?.body ? JSON.stringify(stepResult.request.body) : null,
|
|
667
|
+
raw_response: stepResult.response?.body ? JSON.stringify(stepResult.response.body) : null,
|
|
668
|
+
raw_chunks: null
|
|
669
|
+
});
|
|
670
|
+
state.stepStates.delete(stepResult.stepNumber);
|
|
671
|
+
},
|
|
672
|
+
onObjectStepEnd: async (event) => {
|
|
673
|
+
const stepResult = event;
|
|
674
|
+
const state = callStates.get(stepResult.callId);
|
|
675
|
+
if (!state) return;
|
|
676
|
+
const stepState = state.stepStates.get(stepResult.stepNumber);
|
|
677
|
+
if (!stepState) return;
|
|
678
|
+
activeSteps.delete(stepState.stepId);
|
|
679
|
+
const durationMs = Date.now() - stepState.startTime;
|
|
680
|
+
const output = {
|
|
681
|
+
finishReason: stepResult.finishReason,
|
|
682
|
+
objectText: stepResult.objectText,
|
|
683
|
+
response: {
|
|
684
|
+
id: stepResult.response.id,
|
|
685
|
+
modelId: stepResult.response.modelId,
|
|
686
|
+
timestamp: stepResult.response.timestamp
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
await updateStepResult(stepState.stepId, {
|
|
690
|
+
duration_ms: durationMs,
|
|
691
|
+
output: JSON.stringify(output),
|
|
692
|
+
usage: stepResult.usage ? JSON.stringify(stepResult.usage) : null,
|
|
693
|
+
error: null,
|
|
694
|
+
raw_request: stepResult.request?.body ? JSON.stringify(stepResult.request.body) : null,
|
|
695
|
+
raw_response: stepResult.response?.body ? JSON.stringify(stepResult.response.body) : null
|
|
696
|
+
});
|
|
697
|
+
state.stepStates.delete(stepResult.stepNumber);
|
|
698
|
+
},
|
|
699
|
+
onEnd: async (event) => {
|
|
700
|
+
const endEvent = event;
|
|
701
|
+
callStates.delete(endEvent.callId);
|
|
702
|
+
},
|
|
703
|
+
onError: async (error) => {
|
|
704
|
+
const errorObj = error;
|
|
705
|
+
const callId = errorObj?.callId;
|
|
706
|
+
if (!callId) return;
|
|
707
|
+
const state = callStates.get(callId);
|
|
708
|
+
if (!state) return;
|
|
709
|
+
const cause = errorObj?.error ?? error;
|
|
710
|
+
const errorMessage = cause instanceof Error ? cause.message : String(cause);
|
|
711
|
+
for (const [, stepState] of state.stepStates) {
|
|
712
|
+
activeSteps.delete(stepState.stepId);
|
|
713
|
+
const durationMs = Date.now() - stepState.startTime;
|
|
714
|
+
await updateStepResult(stepState.stepId, {
|
|
715
|
+
duration_ms: durationMs,
|
|
716
|
+
output: null,
|
|
717
|
+
usage: null,
|
|
718
|
+
error: errorMessage,
|
|
719
|
+
raw_request: null,
|
|
720
|
+
raw_response: null,
|
|
721
|
+
raw_chunks: null
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
callStates.delete(callId);
|
|
725
|
+
},
|
|
726
|
+
executeTool: async ({ callId, toolCallId, execute }) => {
|
|
727
|
+
toolContextMap.set(toolCallId, {
|
|
728
|
+
parentCallId: callId,
|
|
729
|
+
parentToolCallId: toolCallId
|
|
730
|
+
});
|
|
731
|
+
const previousToolCallId = currentToolCallId;
|
|
732
|
+
currentToolCallId = toolCallId;
|
|
733
|
+
try {
|
|
734
|
+
return await execute();
|
|
735
|
+
} finally {
|
|
736
|
+
currentToolCallId = previousToolCallId;
|
|
737
|
+
toolContextMap.delete(toolCallId);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
};
|
|
763
741
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
742
|
+
//#endregion
|
|
743
|
+
export { DevToolsTelemetry, devToolsMiddleware };
|
|
744
|
+
|
|
745
|
+
//# sourceMappingURL=index.js.map
|