@agent-inspect/mcp 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1068 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +61 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.mjs +1056 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1056 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { appendFile, mkdir } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { nanoid } from 'nanoid';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
// packages/mcp/src/summarize.ts
|
|
10
|
+
var DEFAULT_MAX_SUMMARY_LENGTH = 240;
|
|
11
|
+
function summarizeMcpValue(value, maxLength = DEFAULT_MAX_SUMMARY_LENGTH) {
|
|
12
|
+
let text;
|
|
13
|
+
try {
|
|
14
|
+
if (typeof value === "string") {
|
|
15
|
+
text = value;
|
|
16
|
+
} else {
|
|
17
|
+
text = JSON.stringify(value);
|
|
18
|
+
}
|
|
19
|
+
} catch {
|
|
20
|
+
text = String(value);
|
|
21
|
+
}
|
|
22
|
+
if (text.length <= maxLength) return text;
|
|
23
|
+
return `${text.slice(0, Math.max(0, maxLength - 3))}...`;
|
|
24
|
+
}
|
|
25
|
+
function hashServerUrl(url) {
|
|
26
|
+
let hash = 0;
|
|
27
|
+
for (let i = 0; i < url.length; i += 1) {
|
|
28
|
+
hash = hash * 31 + url.charCodeAt(i) >>> 0;
|
|
29
|
+
}
|
|
30
|
+
return hash.toString(16).padStart(8, "0");
|
|
31
|
+
}
|
|
32
|
+
var DEFAULT_REDACT_KEYS = [
|
|
33
|
+
"authorization",
|
|
34
|
+
"cookie",
|
|
35
|
+
"token",
|
|
36
|
+
"apiKey",
|
|
37
|
+
"password",
|
|
38
|
+
"secret",
|
|
39
|
+
"email"
|
|
40
|
+
];
|
|
41
|
+
function isRecord(v) {
|
|
42
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
43
|
+
}
|
|
44
|
+
function toKey(s) {
|
|
45
|
+
return s.toLowerCase();
|
|
46
|
+
}
|
|
47
|
+
function stableHash(value) {
|
|
48
|
+
const h = crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
49
|
+
return h.slice(0, 8);
|
|
50
|
+
}
|
|
51
|
+
function compileRules(rules, extraKeys) {
|
|
52
|
+
const out = /* @__PURE__ */ new Map();
|
|
53
|
+
const set = (r) => {
|
|
54
|
+
const k = toKey(r.key);
|
|
55
|
+
out.set(k, { ...r, key: k });
|
|
56
|
+
};
|
|
57
|
+
for (const k of DEFAULT_REDACT_KEYS) {
|
|
58
|
+
set({ key: k, strategy: "full" });
|
|
59
|
+
}
|
|
60
|
+
for (const k of extraKeys ?? []) {
|
|
61
|
+
if (typeof k === "string" && k.length > 0) {
|
|
62
|
+
set({ key: k, strategy: "full" });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const r of rules ?? []) {
|
|
66
|
+
if (typeof r === "string") {
|
|
67
|
+
set({ key: r, strategy: "full" });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const key = r.key;
|
|
71
|
+
if (r.strategy === "full") set({ key, strategy: "full" });
|
|
72
|
+
if (r.strategy === "hash") set({ key, strategy: "hash" });
|
|
73
|
+
if (r.strategy === "prefix") {
|
|
74
|
+
set({ key, strategy: "prefix", keep: typeof r.keep === "number" ? r.keep : 8 });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return [...out.values()];
|
|
78
|
+
}
|
|
79
|
+
var Redactor = class {
|
|
80
|
+
#rules;
|
|
81
|
+
constructor(options) {
|
|
82
|
+
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
83
|
+
}
|
|
84
|
+
redactValue(key, value) {
|
|
85
|
+
const k = toKey(key);
|
|
86
|
+
const rule = this.#rules.find((r) => r.key === k);
|
|
87
|
+
if (!rule) {
|
|
88
|
+
return this.#redactNested(value);
|
|
89
|
+
}
|
|
90
|
+
if (rule.strategy === "full") return "[REDACTED]";
|
|
91
|
+
const asString = typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" ? String(value) : void 0;
|
|
92
|
+
if (rule.strategy === "prefix") {
|
|
93
|
+
if (asString === void 0) return "[REDACTED]";
|
|
94
|
+
const keep = Math.max(0, Math.floor(rule.keep));
|
|
95
|
+
return asString.length <= keep ? `${asString}\u2026` : `${asString.slice(0, keep)}\u2026`;
|
|
96
|
+
}
|
|
97
|
+
if (rule.strategy === "hash") {
|
|
98
|
+
if (asString === void 0) return "[HASH:unknown]";
|
|
99
|
+
return `[HASH:${stableHash(asString)}]`;
|
|
100
|
+
}
|
|
101
|
+
return this.#redactNested(value);
|
|
102
|
+
}
|
|
103
|
+
redactRecord(record) {
|
|
104
|
+
const out = {};
|
|
105
|
+
for (const [k, v] of Object.entries(record)) {
|
|
106
|
+
out[k] = this.redactValue(k, v);
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
#redactNested(value) {
|
|
111
|
+
if (Array.isArray(value)) {
|
|
112
|
+
return value.map((v) => this.#redactNested(v));
|
|
113
|
+
}
|
|
114
|
+
if (isRecord(value)) {
|
|
115
|
+
const out = {};
|
|
116
|
+
for (const [k, v] of Object.entries(value)) {
|
|
117
|
+
out[k] = this.redactValue(k, v);
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// packages/core/src/redaction-profiles.ts
|
|
126
|
+
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
127
|
+
"userEmail",
|
|
128
|
+
"customerEmail",
|
|
129
|
+
"phone",
|
|
130
|
+
"phoneNumber",
|
|
131
|
+
"address",
|
|
132
|
+
"ip",
|
|
133
|
+
"ipAddress",
|
|
134
|
+
"sessionId",
|
|
135
|
+
"requestId",
|
|
136
|
+
"correlationId",
|
|
137
|
+
"decisionId",
|
|
138
|
+
"groupId",
|
|
139
|
+
"customerId",
|
|
140
|
+
"userId",
|
|
141
|
+
"accountId",
|
|
142
|
+
"tenantId",
|
|
143
|
+
"orgId",
|
|
144
|
+
"organizationId",
|
|
145
|
+
"traceId",
|
|
146
|
+
"spanId",
|
|
147
|
+
"parentSpanId"
|
|
148
|
+
];
|
|
149
|
+
var STRICT_PROFILE_EXTRA_KEYS = [
|
|
150
|
+
"prompt",
|
|
151
|
+
"completion",
|
|
152
|
+
"input",
|
|
153
|
+
"output",
|
|
154
|
+
"inputPreview",
|
|
155
|
+
"outputPreview",
|
|
156
|
+
"message",
|
|
157
|
+
"messages",
|
|
158
|
+
"transcript",
|
|
159
|
+
"context",
|
|
160
|
+
"document",
|
|
161
|
+
"documents",
|
|
162
|
+
"chunk",
|
|
163
|
+
"chunks",
|
|
164
|
+
"retrieval",
|
|
165
|
+
"query"
|
|
166
|
+
];
|
|
167
|
+
function resolveRedactionProfile(profile = "local") {
|
|
168
|
+
switch (profile) {
|
|
169
|
+
case "local":
|
|
170
|
+
return { profile: "local", extraKeys: [] };
|
|
171
|
+
case "share":
|
|
172
|
+
return {
|
|
173
|
+
profile: "share",
|
|
174
|
+
extraKeys: SHARE_PROFILE_EXTRA_KEYS,
|
|
175
|
+
maxMetadataValueLengthCap: 500,
|
|
176
|
+
maxPreviewLengthCap: 200
|
|
177
|
+
};
|
|
178
|
+
case "strict":
|
|
179
|
+
return {
|
|
180
|
+
profile: "strict",
|
|
181
|
+
extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
|
|
182
|
+
maxMetadataValueLengthCap: 200,
|
|
183
|
+
maxPreviewLengthCap: 80
|
|
184
|
+
};
|
|
185
|
+
default:
|
|
186
|
+
return { profile: "local", extraKeys: [] };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, resolved) {
|
|
190
|
+
let meta = maxMetadataValueLength;
|
|
191
|
+
let preview = maxPreviewLength;
|
|
192
|
+
if (resolved.maxMetadataValueLengthCap !== void 0) {
|
|
193
|
+
meta = Math.min(meta, resolved.maxMetadataValueLengthCap);
|
|
194
|
+
}
|
|
195
|
+
if (resolved.maxPreviewLengthCap !== void 0) {
|
|
196
|
+
preview = Math.min(preview, resolved.maxPreviewLengthCap);
|
|
197
|
+
}
|
|
198
|
+
return { maxMetadataValueLength: meta, maxPreviewLength: preview };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// packages/core/src/types.ts
|
|
202
|
+
var STEP_TYPES = [
|
|
203
|
+
"run",
|
|
204
|
+
"llm",
|
|
205
|
+
"tool",
|
|
206
|
+
"decision",
|
|
207
|
+
"logic",
|
|
208
|
+
"state",
|
|
209
|
+
"custom"
|
|
210
|
+
];
|
|
211
|
+
function isStepType(value) {
|
|
212
|
+
return typeof value === "string" && STEP_TYPES.includes(value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// packages/core/src/utils/duration.ts
|
|
216
|
+
function formatDuration(ms) {
|
|
217
|
+
if (!Number.isFinite(ms)) {
|
|
218
|
+
return "0ms";
|
|
219
|
+
}
|
|
220
|
+
if (ms < 0) {
|
|
221
|
+
throw new Error(`formatDuration: ms must be non-negative (got ${ms})`);
|
|
222
|
+
}
|
|
223
|
+
if (ms < 1e3) {
|
|
224
|
+
return `${Math.floor(ms)}ms`;
|
|
225
|
+
}
|
|
226
|
+
if (ms < 6e4) {
|
|
227
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
228
|
+
}
|
|
229
|
+
if (ms < 36e5) {
|
|
230
|
+
return `${(ms / 6e4).toFixed(1)}m`;
|
|
231
|
+
}
|
|
232
|
+
return `${(ms / 36e5).toFixed(1)}h`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// packages/core/src/utils.ts
|
|
236
|
+
var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
237
|
+
var RUNS_DIR_NAME = "runs";
|
|
238
|
+
var FALLBACK_TRACE_DIR = path.join(
|
|
239
|
+
os.tmpdir(),
|
|
240
|
+
"agent-inspect",
|
|
241
|
+
RUNS_DIR_NAME
|
|
242
|
+
);
|
|
243
|
+
var MAX_NAME_LENGTH = 100;
|
|
244
|
+
function createStepId() {
|
|
245
|
+
return `step_${nanoid(10)}`;
|
|
246
|
+
}
|
|
247
|
+
function formatDuration2(ms) {
|
|
248
|
+
return formatDuration(ms);
|
|
249
|
+
}
|
|
250
|
+
function getDefaultTraceDir() {
|
|
251
|
+
const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
|
|
252
|
+
if (typeof envDir === "string" && envDir.trim() !== "") {
|
|
253
|
+
return envDir.trim();
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const home = os.homedir();
|
|
257
|
+
if (typeof home !== "string" || home.trim() === "") {
|
|
258
|
+
return FALLBACK_TRACE_DIR;
|
|
259
|
+
}
|
|
260
|
+
return path.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
261
|
+
} catch {
|
|
262
|
+
return FALLBACK_TRACE_DIR;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function getTraceFilePath(runId, traceDir) {
|
|
266
|
+
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
267
|
+
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
268
|
+
safeId = path.basename(safeId);
|
|
269
|
+
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
270
|
+
safeId = "run_unknown";
|
|
271
|
+
}
|
|
272
|
+
return path.join(baseDir, `${safeId}.jsonl`);
|
|
273
|
+
}
|
|
274
|
+
async function ensureTraceDir(traceDir) {
|
|
275
|
+
const primary = path.resolve(traceDir);
|
|
276
|
+
try {
|
|
277
|
+
await mkdir(primary, { recursive: true });
|
|
278
|
+
return primary;
|
|
279
|
+
} catch {
|
|
280
|
+
warn(`Failed to create trace directory: ${primary}`);
|
|
281
|
+
const fallback = path.resolve(FALLBACK_TRACE_DIR);
|
|
282
|
+
try {
|
|
283
|
+
await mkdir(fallback, { recursive: true });
|
|
284
|
+
return fallback;
|
|
285
|
+
} catch {
|
|
286
|
+
warn(`Failed to create fallback trace directory: ${fallback}`);
|
|
287
|
+
return primary;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function formatError(error) {
|
|
292
|
+
if (error instanceof Error) {
|
|
293
|
+
const out = { message: error.message };
|
|
294
|
+
if (typeof error.stack === "string" && error.stack.length > 0) {
|
|
295
|
+
out.stack = error.stack;
|
|
296
|
+
}
|
|
297
|
+
return out;
|
|
298
|
+
}
|
|
299
|
+
if (typeof error === "string") {
|
|
300
|
+
return { message: error };
|
|
301
|
+
}
|
|
302
|
+
if (error === null) {
|
|
303
|
+
return { message: "Unknown error: null" };
|
|
304
|
+
}
|
|
305
|
+
if (error === void 0) {
|
|
306
|
+
return { message: "Unknown error: undefined" };
|
|
307
|
+
}
|
|
308
|
+
if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") {
|
|
309
|
+
return { message: String(error) };
|
|
310
|
+
}
|
|
311
|
+
if (typeof error === "object") {
|
|
312
|
+
try {
|
|
313
|
+
return { message: JSON.stringify(error) };
|
|
314
|
+
} catch {
|
|
315
|
+
return { message: "Unknown error" };
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { message: "Unknown error" };
|
|
319
|
+
}
|
|
320
|
+
function truncateName(name, maxLength = MAX_NAME_LENGTH) {
|
|
321
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
322
|
+
return "unnamed";
|
|
323
|
+
}
|
|
324
|
+
const trimmed = name.trim();
|
|
325
|
+
if (trimmed.length <= maxLength) {
|
|
326
|
+
return trimmed;
|
|
327
|
+
}
|
|
328
|
+
const ellipsis = "...";
|
|
329
|
+
const head = Math.max(0, maxLength - ellipsis.length);
|
|
330
|
+
return `${trimmed.slice(0, head)}${ellipsis}`;
|
|
331
|
+
}
|
|
332
|
+
function warn(message, error) {
|
|
333
|
+
const base = `[AgentInspect] ${message}`;
|
|
334
|
+
if (error === void 0) {
|
|
335
|
+
console.warn(base);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
console.warn(`${base}: ${formatError(error).message}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// packages/core/src/storage.ts
|
|
342
|
+
function isRecord2(value) {
|
|
343
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
344
|
+
}
|
|
345
|
+
function nonEmptyString(value) {
|
|
346
|
+
return typeof value === "string" && value.trim() !== "";
|
|
347
|
+
}
|
|
348
|
+
function finiteNumber(value) {
|
|
349
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
350
|
+
}
|
|
351
|
+
function optionalErrorInfo(value) {
|
|
352
|
+
if (value === void 0) return true;
|
|
353
|
+
if (!isRecord2(value)) return false;
|
|
354
|
+
if (typeof value.message !== "string") return false;
|
|
355
|
+
if ("stack" in value && value.stack !== void 0) {
|
|
356
|
+
if (typeof value.stack !== "string") return false;
|
|
357
|
+
}
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
function validateEvent(event) {
|
|
361
|
+
if (!isRecord2(event)) return false;
|
|
362
|
+
if (event.schemaVersion !== "0.1") return false;
|
|
363
|
+
if (!finiteNumber(event.timestamp)) return false;
|
|
364
|
+
if (typeof event.event !== "string") return false;
|
|
365
|
+
switch (event.event) {
|
|
366
|
+
case "run_started": {
|
|
367
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
case "run_completed": {
|
|
376
|
+
return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
377
|
+
}
|
|
378
|
+
case "step_started": {
|
|
379
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
if (event.parentId !== void 0 && typeof event.parentId !== "string") {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
case "step_completed": {
|
|
391
|
+
return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
392
|
+
}
|
|
393
|
+
default:
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function serializeEvent(event) {
|
|
398
|
+
try {
|
|
399
|
+
return JSON.stringify(event);
|
|
400
|
+
} catch {
|
|
401
|
+
return "";
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
function ensureEventWithinBounds(event) {
|
|
405
|
+
const line = serializeEvent(event);
|
|
406
|
+
if (line === "") return event;
|
|
407
|
+
const bytes = Buffer.byteLength(line, "utf8");
|
|
408
|
+
if (bytes <= DEFAULT_MAX_EVENT_BYTES) return event;
|
|
409
|
+
return prepareTraceEventForDisk(event, resolveTraceSafetyOptions());
|
|
410
|
+
}
|
|
411
|
+
async function writeTraceEvent(event, traceDir) {
|
|
412
|
+
const bounded = ensureEventWithinBounds(event);
|
|
413
|
+
if (!validateEvent(bounded)) {
|
|
414
|
+
warn("Skipped invalid trace event (validation failed)");
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const line = serializeEvent(bounded);
|
|
418
|
+
if (line === "") {
|
|
419
|
+
warn("Skipped trace event (serialization failed)");
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const payload = `${line}
|
|
423
|
+
`;
|
|
424
|
+
const tryAppend = async (dir) => {
|
|
425
|
+
try {
|
|
426
|
+
const usable = await ensureTraceDir(dir);
|
|
427
|
+
const filePath = getTraceFilePath(event.runId, usable);
|
|
428
|
+
await appendFile(filePath, payload, "utf-8");
|
|
429
|
+
return true;
|
|
430
|
+
} catch {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
if (await tryAppend(traceDir)) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
warn(`Failed to append trace event for run ${event.runId}`);
|
|
438
|
+
if (await tryAppend(FALLBACK_TRACE_DIR)) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
warn("Failed to append trace event to fallback directory");
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// packages/core/src/trace-event-safety.ts
|
|
445
|
+
var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
|
|
446
|
+
var DEFAULT_MAX_PREVIEW_LENGTH = 500;
|
|
447
|
+
var DEFAULT_MAX_EVENT_BYTES = 65536;
|
|
448
|
+
function isRecord3(value) {
|
|
449
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
450
|
+
}
|
|
451
|
+
function isPreviewKey(key) {
|
|
452
|
+
return key.toLowerCase().includes("preview");
|
|
453
|
+
}
|
|
454
|
+
function truncateString(value, maxLen) {
|
|
455
|
+
if (maxLen <= 0) return "\u2026";
|
|
456
|
+
if (value.length <= maxLen) return value;
|
|
457
|
+
return `${value.slice(0, maxLen)}\u2026`;
|
|
458
|
+
}
|
|
459
|
+
function byteLength(text) {
|
|
460
|
+
return Buffer.byteLength(text, "utf8");
|
|
461
|
+
}
|
|
462
|
+
function resolveTraceSafetyOptions(options) {
|
|
463
|
+
let redactEnabled = true;
|
|
464
|
+
let redactionRules;
|
|
465
|
+
{
|
|
466
|
+
redactEnabled = true;
|
|
467
|
+
}
|
|
468
|
+
const profile = options?.redactionProfile ?? "local";
|
|
469
|
+
const resolvedProfile = resolveRedactionProfile(profile);
|
|
470
|
+
const userMaxMetadata = "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : void 0;
|
|
471
|
+
const userMaxPreview = "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : void 0;
|
|
472
|
+
let maxMetadataValueLength = userMaxMetadata ?? DEFAULT_MAX_METADATA_VALUE_LENGTH;
|
|
473
|
+
let maxPreviewLength = userMaxPreview ?? DEFAULT_MAX_PREVIEW_LENGTH;
|
|
474
|
+
if (redactEnabled && profile !== "local") {
|
|
475
|
+
const capped = applyProfileMetadataCaps(
|
|
476
|
+
maxMetadataValueLength,
|
|
477
|
+
maxPreviewLength,
|
|
478
|
+
resolvedProfile
|
|
479
|
+
);
|
|
480
|
+
maxMetadataValueLength = capped.maxMetadataValueLength;
|
|
481
|
+
maxPreviewLength = capped.maxPreviewLength;
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
redactEnabled,
|
|
485
|
+
redactionRules,
|
|
486
|
+
redactionProfile: profile,
|
|
487
|
+
profileExtraKeys: redactEnabled ? resolvedProfile.extraKeys : [],
|
|
488
|
+
maxMetadataValueLength,
|
|
489
|
+
maxPreviewLength,
|
|
490
|
+
maxEventBytes: "undefined" === "number" && Number.isFinite(options.maxEventBytes) && options.maxEventBytes > 0 ? Math.floor(options.maxEventBytes) : DEFAULT_MAX_EVENT_BYTES
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function boundMetadataValue(key, value, opts, seen, depth) {
|
|
494
|
+
if (depth > 32) return "[MaxDepth]";
|
|
495
|
+
if (typeof value === "bigint") {
|
|
496
|
+
return `${value.toString()}n`;
|
|
497
|
+
}
|
|
498
|
+
if (typeof value === "function") {
|
|
499
|
+
return "[Function]";
|
|
500
|
+
}
|
|
501
|
+
if (typeof value === "symbol") {
|
|
502
|
+
return "[Symbol]";
|
|
503
|
+
}
|
|
504
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
505
|
+
return String(value);
|
|
506
|
+
}
|
|
507
|
+
if (value === void 0) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
if (value === null || typeof value !== "object") {
|
|
511
|
+
if (typeof value === "string") {
|
|
512
|
+
const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
|
|
513
|
+
return truncateString(value, max);
|
|
514
|
+
}
|
|
515
|
+
return value;
|
|
516
|
+
}
|
|
517
|
+
if (seen.has(value)) return "[Circular]";
|
|
518
|
+
seen.add(value);
|
|
519
|
+
if (Array.isArray(value)) {
|
|
520
|
+
const maxItems = 50;
|
|
521
|
+
const out2 = value.slice(0, maxItems).map(
|
|
522
|
+
(item, index) => boundMetadataValue(String(index), item, opts, seen, depth + 1)
|
|
523
|
+
);
|
|
524
|
+
if (value.length > maxItems) {
|
|
525
|
+
out2.push(`\u2026(+${value.length - maxItems} more)`);
|
|
526
|
+
}
|
|
527
|
+
return out2;
|
|
528
|
+
}
|
|
529
|
+
const record = value;
|
|
530
|
+
const out = {};
|
|
531
|
+
try {
|
|
532
|
+
for (const [k, v] of Object.entries(record)) {
|
|
533
|
+
out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
|
|
534
|
+
}
|
|
535
|
+
} catch {
|
|
536
|
+
return { truncated: true, reason: "metadataEnumerationFailed" };
|
|
537
|
+
}
|
|
538
|
+
return out;
|
|
539
|
+
}
|
|
540
|
+
function redactMetadata(metadata, opts) {
|
|
541
|
+
if (!opts.redactEnabled) return { ...metadata };
|
|
542
|
+
const redactor = new Redactor({
|
|
543
|
+
rules: opts.redactionRules,
|
|
544
|
+
extraKeys: opts.profileExtraKeys
|
|
545
|
+
});
|
|
546
|
+
return redactor.redactRecord(metadata);
|
|
547
|
+
}
|
|
548
|
+
function prepareMetadataForDisk(metadata, opts) {
|
|
549
|
+
try {
|
|
550
|
+
const preBounded = boundMetadataValue(
|
|
551
|
+
"metadata",
|
|
552
|
+
metadata,
|
|
553
|
+
opts,
|
|
554
|
+
/* @__PURE__ */ new WeakSet(),
|
|
555
|
+
0
|
|
556
|
+
);
|
|
557
|
+
const redacted = redactMetadata(
|
|
558
|
+
isRecord3(preBounded) ? preBounded : {},
|
|
559
|
+
opts
|
|
560
|
+
);
|
|
561
|
+
const bounded = boundMetadataValue(
|
|
562
|
+
"metadata",
|
|
563
|
+
redacted,
|
|
564
|
+
opts,
|
|
565
|
+
/* @__PURE__ */ new WeakSet(),
|
|
566
|
+
0
|
|
567
|
+
);
|
|
568
|
+
return isRecord3(bounded) ? bounded : {};
|
|
569
|
+
} catch {
|
|
570
|
+
return { truncated: true, reason: "metadataPreparationFailed" };
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function truncateErrorStack(event, maxLen) {
|
|
574
|
+
if (event.event !== "run_completed" && event.event !== "step_completed") {
|
|
575
|
+
return event;
|
|
576
|
+
}
|
|
577
|
+
if (!event.error?.stack || typeof event.error.stack !== "string") {
|
|
578
|
+
return event;
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
...event,
|
|
582
|
+
error: {
|
|
583
|
+
...event.error,
|
|
584
|
+
stack: truncateString(event.error.stack, maxLen)
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
function replaceMetadataWithTruncationMarker(event, originalApproxBytes) {
|
|
589
|
+
const marker = {
|
|
590
|
+
truncated: true,
|
|
591
|
+
reason: "maxEventBytes",
|
|
592
|
+
originalApproxBytes
|
|
593
|
+
};
|
|
594
|
+
if (event.event === "run_started") {
|
|
595
|
+
return { ...event, metadata: marker };
|
|
596
|
+
}
|
|
597
|
+
if (event.event === "step_started") {
|
|
598
|
+
return { ...event, metadata: marker };
|
|
599
|
+
}
|
|
600
|
+
return event;
|
|
601
|
+
}
|
|
602
|
+
function shrinkMetadataLimits(opts, factor) {
|
|
603
|
+
return {
|
|
604
|
+
...opts,
|
|
605
|
+
maxMetadataValueLength: Math.max(32, Math.floor(opts.maxMetadataValueLength * factor)),
|
|
606
|
+
maxPreviewLength: Math.max(16, Math.floor(opts.maxPreviewLength * factor))
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function applyMetadataToEvent(event, metadata) {
|
|
610
|
+
if (event.event === "run_started") {
|
|
611
|
+
return { ...event, metadata };
|
|
612
|
+
}
|
|
613
|
+
if (event.event === "step_started") {
|
|
614
|
+
return { ...event, metadata };
|
|
615
|
+
}
|
|
616
|
+
return event;
|
|
617
|
+
}
|
|
618
|
+
function eventHasMetadata(event) {
|
|
619
|
+
return (event.event === "run_started" || event.event === "step_started") && event.metadata !== void 0;
|
|
620
|
+
}
|
|
621
|
+
function getEventMetadata(event) {
|
|
622
|
+
if (event.event === "run_started" || event.event === "step_started") {
|
|
623
|
+
return event.metadata;
|
|
624
|
+
}
|
|
625
|
+
return void 0;
|
|
626
|
+
}
|
|
627
|
+
function prepareTraceEventForDisk(event, opts) {
|
|
628
|
+
try {
|
|
629
|
+
let working = { ...event };
|
|
630
|
+
const rawMetadata = getEventMetadata(working);
|
|
631
|
+
if (rawMetadata !== void 0) {
|
|
632
|
+
const safe = prepareMetadataForDisk(rawMetadata, opts);
|
|
633
|
+
working = applyMetadataToEvent(working, safe);
|
|
634
|
+
}
|
|
635
|
+
let serialized = serializeEvent(working);
|
|
636
|
+
if (serialized === "") {
|
|
637
|
+
return working;
|
|
638
|
+
}
|
|
639
|
+
let bytes = byteLength(serialized);
|
|
640
|
+
if (bytes <= opts.maxEventBytes) {
|
|
641
|
+
return working;
|
|
642
|
+
}
|
|
643
|
+
if (rawMetadata !== void 0) {
|
|
644
|
+
for (const factor of [0.5, 0.25, 0.1]) {
|
|
645
|
+
const tighter = shrinkMetadataLimits(opts, factor);
|
|
646
|
+
const shrunk = prepareMetadataForDisk(rawMetadata, tighter);
|
|
647
|
+
working = applyMetadataToEvent(working, shrunk);
|
|
648
|
+
serialized = serializeEvent(working);
|
|
649
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
650
|
+
return working;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
working = replaceMetadataWithTruncationMarker(working, bytes);
|
|
654
|
+
serialized = serializeEvent(working);
|
|
655
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
656
|
+
return working;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
working = truncateErrorStack(working, Math.min(opts.maxMetadataValueLength, 500));
|
|
660
|
+
serialized = serializeEvent(working);
|
|
661
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
662
|
+
return working;
|
|
663
|
+
}
|
|
664
|
+
if (eventHasMetadata(working)) {
|
|
665
|
+
working = replaceMetadataWithTruncationMarker(working, bytes);
|
|
666
|
+
serialized = serializeEvent(working);
|
|
667
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
668
|
+
return working;
|
|
669
|
+
}
|
|
670
|
+
if (working.event === "run_started") {
|
|
671
|
+
const { metadata: _meta, ...rest } = working;
|
|
672
|
+
working = rest;
|
|
673
|
+
} else if (working.event === "step_started") {
|
|
674
|
+
const { metadata: _meta, ...rest } = working;
|
|
675
|
+
working = rest;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return working;
|
|
679
|
+
} catch {
|
|
680
|
+
if (event.event === "run_started" || event.event === "step_started") {
|
|
681
|
+
return applyMetadataToEvent(event, {
|
|
682
|
+
truncated: true,
|
|
683
|
+
reason: "prepareTraceEventFailed"
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
return event;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
var storage = new AsyncLocalStorage();
|
|
690
|
+
function toPublicContext(ctx) {
|
|
691
|
+
return {
|
|
692
|
+
runId: ctx.runId,
|
|
693
|
+
runName: ctx.runName,
|
|
694
|
+
traceDir: ctx.traceDir,
|
|
695
|
+
silent: ctx.silent,
|
|
696
|
+
metadata: ctx.metadata
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
function invoke(fn) {
|
|
700
|
+
return new Promise((resolve, reject) => {
|
|
701
|
+
try {
|
|
702
|
+
Promise.resolve(fn()).then(resolve, reject);
|
|
703
|
+
} catch (e) {
|
|
704
|
+
reject(e);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
function getCurrentContext() {
|
|
709
|
+
try {
|
|
710
|
+
const s = storage.getStore();
|
|
711
|
+
if (!s) return void 0;
|
|
712
|
+
return toPublicContext(s);
|
|
713
|
+
} catch {
|
|
714
|
+
return void 0;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function getCurrentStepId() {
|
|
718
|
+
try {
|
|
719
|
+
return storage.getStore()?.currentStepId;
|
|
720
|
+
} catch {
|
|
721
|
+
return void 0;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
function getParentStepId() {
|
|
725
|
+
return getCurrentStepId();
|
|
726
|
+
}
|
|
727
|
+
function getCurrentDepth() {
|
|
728
|
+
try {
|
|
729
|
+
const d = storage.getStore()?.currentDepth;
|
|
730
|
+
return typeof d === "number" && Number.isFinite(d) ? d : 0;
|
|
731
|
+
} catch {
|
|
732
|
+
return 0;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
function isSilentContext() {
|
|
736
|
+
try {
|
|
737
|
+
const s = storage.getStore();
|
|
738
|
+
return s ? s.silent : false;
|
|
739
|
+
} catch {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
function getTraceSafetyFromContext() {
|
|
744
|
+
try {
|
|
745
|
+
return storage.getStore()?.traceSafety;
|
|
746
|
+
} catch {
|
|
747
|
+
return void 0;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function runWithStepContext(stepId, fn) {
|
|
751
|
+
let parent;
|
|
752
|
+
try {
|
|
753
|
+
parent = storage.getStore();
|
|
754
|
+
} catch {
|
|
755
|
+
parent = void 0;
|
|
756
|
+
}
|
|
757
|
+
if (!parent) {
|
|
758
|
+
return invoke(fn);
|
|
759
|
+
}
|
|
760
|
+
const derived = {
|
|
761
|
+
runId: parent.runId,
|
|
762
|
+
runName: parent.runName,
|
|
763
|
+
traceDir: parent.traceDir,
|
|
764
|
+
silent: parent.silent,
|
|
765
|
+
metadata: parent.metadata,
|
|
766
|
+
traceSafety: parent.traceSafety,
|
|
767
|
+
currentStepId: stepId,
|
|
768
|
+
currentDepth: parent.currentDepth + 1
|
|
769
|
+
};
|
|
770
|
+
return new Promise((resolve, reject) => {
|
|
771
|
+
storage.run(derived, () => {
|
|
772
|
+
try {
|
|
773
|
+
Promise.resolve(fn()).then(resolve, reject);
|
|
774
|
+
} catch (e) {
|
|
775
|
+
reject(e);
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
var TERMINAL_INDENT = " ";
|
|
781
|
+
var MAX_TERMINAL_NAME_LENGTH = 80;
|
|
782
|
+
var MAX_TERMINAL_DEPTH = 10;
|
|
783
|
+
function normalizeDepth(depth) {
|
|
784
|
+
if (!Number.isFinite(depth) || depth < 0) {
|
|
785
|
+
return 0;
|
|
786
|
+
}
|
|
787
|
+
return Math.min(Math.floor(depth), MAX_TERMINAL_DEPTH);
|
|
788
|
+
}
|
|
789
|
+
function safePrint(line = "") {
|
|
790
|
+
try {
|
|
791
|
+
console.log(line);
|
|
792
|
+
} catch {
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function getIndent(depth) {
|
|
796
|
+
return TERMINAL_INDENT.repeat(normalizeDepth(depth));
|
|
797
|
+
}
|
|
798
|
+
function formatTerminalName(name) {
|
|
799
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
800
|
+
return "unnamed";
|
|
801
|
+
}
|
|
802
|
+
return truncateName(name, MAX_TERMINAL_NAME_LENGTH);
|
|
803
|
+
}
|
|
804
|
+
function getStatusIcon(status) {
|
|
805
|
+
if (status === "success") return chalk.green("\u2714");
|
|
806
|
+
if (status === "error") return chalk.red("\u2716");
|
|
807
|
+
return chalk.yellow("\u23F3");
|
|
808
|
+
}
|
|
809
|
+
function renderStepLine(name, durationMs, status, depth) {
|
|
810
|
+
try {
|
|
811
|
+
const nm = formatTerminalName(name);
|
|
812
|
+
const ind = getIndent(depth ?? 0);
|
|
813
|
+
if (status === "running" && durationMs === void 0) {
|
|
814
|
+
return `${ind}${chalk.yellow("\u23F3")} ${nm}`;
|
|
815
|
+
}
|
|
816
|
+
const hasDur = durationMs !== void 0 && Number.isFinite(durationMs);
|
|
817
|
+
const dur = hasDur ? formatDuration2(durationMs) : void 0;
|
|
818
|
+
if (status === "running") {
|
|
819
|
+
return dur !== void 0 ? `${ind}${chalk.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${chalk.yellow("\u23F3")} ${nm}`;
|
|
820
|
+
}
|
|
821
|
+
if (!hasDur || dur === void 0) {
|
|
822
|
+
return `${ind}${chalk.yellow("\u23F3")} ${nm}`;
|
|
823
|
+
}
|
|
824
|
+
if (status === "success") {
|
|
825
|
+
return `${ind}${getStatusIcon("success")} ${nm} (${dur})`;
|
|
826
|
+
}
|
|
827
|
+
return `${ind}${getStatusIcon("error")} ${nm} (${dur})`;
|
|
828
|
+
} catch {
|
|
829
|
+
return "";
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function renderErrorLine(error, depth) {
|
|
833
|
+
try {
|
|
834
|
+
const msg = typeof error.message === "string" ? error.message : "";
|
|
835
|
+
const ind = getIndent((depth ?? 0) + 1);
|
|
836
|
+
return `${ind}Error: ${msg}`;
|
|
837
|
+
} catch {
|
|
838
|
+
return "";
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function printStepStart(name, depth = 0) {
|
|
842
|
+
if (isSilentContext()) return;
|
|
843
|
+
try {
|
|
844
|
+
safePrint(renderStepLine(name, void 0, "running", depth));
|
|
845
|
+
} catch {
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function printStepComplete(name, durationMs, status, depth = 0) {
|
|
849
|
+
if (isSilentContext()) return;
|
|
850
|
+
try {
|
|
851
|
+
safePrint(renderStepLine(name, durationMs, status, depth));
|
|
852
|
+
} catch {
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
function printError(error, depth = 0) {
|
|
856
|
+
if (isSilentContext()) return;
|
|
857
|
+
try {
|
|
858
|
+
safePrint(renderErrorLine(error, depth));
|
|
859
|
+
} catch {
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
function printFailedAt(stepName) {
|
|
863
|
+
if (isSilentContext()) return;
|
|
864
|
+
try {
|
|
865
|
+
safePrint(`Failed at: ${formatTerminalName(stepName)}`);
|
|
866
|
+
} catch {
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// packages/core/src/step.ts
|
|
871
|
+
function normalizeStepName(name) {
|
|
872
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
873
|
+
return "unnamed-step";
|
|
874
|
+
}
|
|
875
|
+
return truncateName(name.trim(), 100);
|
|
876
|
+
}
|
|
877
|
+
async function safeInstrumentation(label, op) {
|
|
878
|
+
try {
|
|
879
|
+
await Promise.resolve(op());
|
|
880
|
+
} catch (e) {
|
|
881
|
+
warn(`step: ${label}`, e);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
async function stepImpl(name, fn, options) {
|
|
885
|
+
if (typeof fn !== "function") {
|
|
886
|
+
throw new TypeError("step requires `fn` to be a function");
|
|
887
|
+
}
|
|
888
|
+
const stepName = normalizeStepName(name);
|
|
889
|
+
const context = getCurrentContext();
|
|
890
|
+
if (!context) {
|
|
891
|
+
warn("step() called outside inspectRun(); executing without instrumentation");
|
|
892
|
+
return Promise.resolve(fn());
|
|
893
|
+
}
|
|
894
|
+
const stepId = createStepId();
|
|
895
|
+
const renderDepth = getCurrentDepth();
|
|
896
|
+
const parentId = getParentStepId();
|
|
897
|
+
const stepType = options?.type ?? "logic";
|
|
898
|
+
const metadata = options?.metadata;
|
|
899
|
+
const traceSafety = getTraceSafetyFromContext();
|
|
900
|
+
const startTime = Date.now();
|
|
901
|
+
await safeInstrumentation("writeTraceEvent(step_started)", async () => {
|
|
902
|
+
const started = {
|
|
903
|
+
schemaVersion: "0.1",
|
|
904
|
+
event: "step_started",
|
|
905
|
+
timestamp: startTime,
|
|
906
|
+
runId: context.runId,
|
|
907
|
+
stepId,
|
|
908
|
+
...typeof parentId === "string" && parentId.trim() !== "" ? { parentId } : {},
|
|
909
|
+
name: stepName,
|
|
910
|
+
type: stepType,
|
|
911
|
+
startTime,
|
|
912
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
913
|
+
};
|
|
914
|
+
const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(started, traceSafety) : started;
|
|
915
|
+
await writeTraceEvent(safe, context.traceDir);
|
|
916
|
+
});
|
|
917
|
+
await safeInstrumentation("printStepStart", () => {
|
|
918
|
+
printStepStart(stepName, renderDepth);
|
|
919
|
+
});
|
|
920
|
+
let result;
|
|
921
|
+
try {
|
|
922
|
+
result = await runWithStepContext(stepId, async () => {
|
|
923
|
+
return await Promise.resolve(fn());
|
|
924
|
+
});
|
|
925
|
+
} catch (userError) {
|
|
926
|
+
const endTime2 = Date.now();
|
|
927
|
+
const durationMs2 = endTime2 - startTime;
|
|
928
|
+
const formatted = formatError(userError);
|
|
929
|
+
await safeInstrumentation("writeTraceEvent(step_completed error)", async () => {
|
|
930
|
+
const completed = {
|
|
931
|
+
schemaVersion: "0.1",
|
|
932
|
+
event: "step_completed",
|
|
933
|
+
timestamp: endTime2,
|
|
934
|
+
runId: context.runId,
|
|
935
|
+
stepId,
|
|
936
|
+
status: "error",
|
|
937
|
+
endTime: endTime2,
|
|
938
|
+
durationMs: durationMs2,
|
|
939
|
+
error: formatted
|
|
940
|
+
};
|
|
941
|
+
const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
|
|
942
|
+
await writeTraceEvent(safe, context.traceDir);
|
|
943
|
+
});
|
|
944
|
+
await safeInstrumentation("printStepComplete(error)", () => {
|
|
945
|
+
printStepComplete(stepName, durationMs2, "error", renderDepth);
|
|
946
|
+
});
|
|
947
|
+
await safeInstrumentation("printError", () => {
|
|
948
|
+
printError(formatted, renderDepth);
|
|
949
|
+
});
|
|
950
|
+
await safeInstrumentation("printFailedAt", () => {
|
|
951
|
+
printFailedAt(stepName);
|
|
952
|
+
});
|
|
953
|
+
throw userError;
|
|
954
|
+
}
|
|
955
|
+
const endTime = Date.now();
|
|
956
|
+
const durationMs = endTime - startTime;
|
|
957
|
+
await safeInstrumentation("writeTraceEvent(step_completed success)", async () => {
|
|
958
|
+
const completed = {
|
|
959
|
+
schemaVersion: "0.1",
|
|
960
|
+
event: "step_completed",
|
|
961
|
+
timestamp: endTime,
|
|
962
|
+
runId: context.runId,
|
|
963
|
+
stepId,
|
|
964
|
+
status: "success",
|
|
965
|
+
endTime,
|
|
966
|
+
durationMs
|
|
967
|
+
};
|
|
968
|
+
const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
|
|
969
|
+
await writeTraceEvent(safe, context.traceDir);
|
|
970
|
+
});
|
|
971
|
+
await safeInstrumentation("printStepComplete(success)", () => {
|
|
972
|
+
printStepComplete(stepName, durationMs, "success", renderDepth);
|
|
973
|
+
});
|
|
974
|
+
return result;
|
|
975
|
+
}
|
|
976
|
+
async function stepLlm(model, fn) {
|
|
977
|
+
const modelName = typeof model === "string" && model.trim() !== "" ? model.trim() : "unknown-model";
|
|
978
|
+
return stepImpl(`llm:${modelName}`, fn, {
|
|
979
|
+
type: "llm",
|
|
980
|
+
metadata: { model: modelName }
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
async function stepTool(toolName, fn) {
|
|
984
|
+
const normalized = typeof toolName === "string" && toolName.trim() !== "" ? toolName.trim() : "unknown-tool";
|
|
985
|
+
return stepImpl(`tool:${normalized}`, fn, {
|
|
986
|
+
type: "tool",
|
|
987
|
+
metadata: { toolName: normalized }
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
var step = Object.assign(stepImpl, {
|
|
991
|
+
llm: stepLlm,
|
|
992
|
+
tool: stepTool
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
// packages/mcp/src/wrap.ts
|
|
996
|
+
var toolCallCounter = 0;
|
|
997
|
+
function nextToolCallId(prefix) {
|
|
998
|
+
toolCallCounter += 1;
|
|
999
|
+
const base = prefix?.trim() || "mcp";
|
|
1000
|
+
return `${base}-${toolCallCounter}`;
|
|
1001
|
+
}
|
|
1002
|
+
function baseMetadata(options, overrides = {}) {
|
|
1003
|
+
const metadata = {
|
|
1004
|
+
source: { type: "mcp-client" },
|
|
1005
|
+
...options.serverName ? { mcpServerName: options.serverName } : {},
|
|
1006
|
+
...options.serverUrl ? { mcpServerUrlHash: hashServerUrl(options.serverUrl) } : {},
|
|
1007
|
+
...options.sessionId ? { sessionId: options.sessionId } : {},
|
|
1008
|
+
...overrides
|
|
1009
|
+
};
|
|
1010
|
+
return { ...options.metadata ?? {}, ...metadata };
|
|
1011
|
+
}
|
|
1012
|
+
function wrapMcpClient(client, options = {}) {
|
|
1013
|
+
const maxSummaryLength = options.maxSummaryLength ?? 240;
|
|
1014
|
+
const wrapped = { ...client };
|
|
1015
|
+
if (typeof client.listTools === "function") {
|
|
1016
|
+
const listTools = client.listTools.bind(client);
|
|
1017
|
+
wrapped.listTools = async (params) => step(
|
|
1018
|
+
"mcp:tools/list",
|
|
1019
|
+
async () => {
|
|
1020
|
+
const result = await listTools(params);
|
|
1021
|
+
return result;
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
type: "tool",
|
|
1025
|
+
metadata: baseMetadata(options, {
|
|
1026
|
+
toolName: "tools/list",
|
|
1027
|
+
toolCallId: nextToolCallId(options.toolCallIdPrefix)
|
|
1028
|
+
})
|
|
1029
|
+
}
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
const callTool = client.callTool.bind(client);
|
|
1033
|
+
wrapped.callTool = async (params) => step(
|
|
1034
|
+
`mcp:${params.name}`,
|
|
1035
|
+
async () => callTool(params),
|
|
1036
|
+
{
|
|
1037
|
+
type: "tool",
|
|
1038
|
+
metadata: baseMetadata(options, {
|
|
1039
|
+
toolName: params.name,
|
|
1040
|
+
toolCallId: nextToolCallId(options.toolCallIdPrefix),
|
|
1041
|
+
argumentSummary: summarizeMcpValue(
|
|
1042
|
+
params.arguments ?? {},
|
|
1043
|
+
maxSummaryLength
|
|
1044
|
+
)
|
|
1045
|
+
})
|
|
1046
|
+
}
|
|
1047
|
+
);
|
|
1048
|
+
return wrapped;
|
|
1049
|
+
}
|
|
1050
|
+
function resetMcpToolCallIdsForTests() {
|
|
1051
|
+
toolCallCounter = 0;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
export { hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
|
|
1055
|
+
//# sourceMappingURL=index.mjs.map
|
|
1056
|
+
//# sourceMappingURL=index.mjs.map
|