agent-inspect 1.3.0 → 1.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.
@@ -2834,6 +2834,574 @@ function filterTraces(traces, options) {
2834
2834
  }
2835
2835
  return out;
2836
2836
  }
2837
+
2838
+ // packages/core/src/timeline.ts
2839
+ function finite(n) {
2840
+ return typeof n === "number" && Number.isFinite(n);
2841
+ }
2842
+ function pickStreamingMeta(metadata) {
2843
+ if (!metadata || typeof metadata !== "object") return void 0;
2844
+ const chunkCount = metadata.chunkCount;
2845
+ const streamDurationMs = metadata.streamDurationMs;
2846
+ const streamedCharCount = metadata.streamedCharCount;
2847
+ if (!finite(chunkCount) && !finite(streamDurationMs) && !finite(streamedCharCount)) {
2848
+ return void 0;
2849
+ }
2850
+ return {
2851
+ ...finite(chunkCount) ? { chunkCount } : {},
2852
+ ...finite(streamDurationMs) ? { streamDurationMs } : {},
2853
+ ...finite(streamedCharCount) ? { streamedCharCount } : {}
2854
+ };
2855
+ }
2856
+ function pickCorrelation(metadata) {
2857
+ if (!metadata || typeof metadata !== "object") return void 0;
2858
+ const out = {};
2859
+ for (const key of [
2860
+ "correlationId",
2861
+ "requestId",
2862
+ "decisionId",
2863
+ "groupId"
2864
+ ]) {
2865
+ const v = metadata[key];
2866
+ if (typeof v === "string" && v.trim() !== "") {
2867
+ out[key] = v;
2868
+ }
2869
+ }
2870
+ return Object.keys(out).length > 0 ? out : void 0;
2871
+ }
2872
+ function buildRunTimeline(events, options = {}) {
2873
+ const started = events.find(
2874
+ (e) => e.event === "run_started"
2875
+ );
2876
+ const completed = events.filter(
2877
+ (e) => e.event === "run_completed"
2878
+ );
2879
+ const lastCompleted = completed[completed.length - 1];
2880
+ const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
2881
+ const runStart = started && finite(started.startTime) ? started.startTime : started && finite(started.timestamp) ? started.timestamp : void 0;
2882
+ const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
2883
+ const steps = /* @__PURE__ */ new Map();
2884
+ for (const e of events) {
2885
+ if (e.event === "step_started") {
2886
+ const s = e;
2887
+ steps.set(s.stepId, {
2888
+ name: s.name,
2889
+ type: s.type,
2890
+ parentId: s.parentId,
2891
+ startedAt: finite(s.startTime) ? s.startTime : s.timestamp,
2892
+ status: "running",
2893
+ metadata: s.metadata
2894
+ });
2895
+ }
2896
+ }
2897
+ for (const e of events) {
2898
+ if (e.event !== "step_completed") continue;
2899
+ const c = e;
2900
+ const node = steps.get(c.stepId);
2901
+ if (!node) continue;
2902
+ node.status = c.status;
2903
+ if (finite(c.durationMs)) node.durationMs = c.durationMs;
2904
+ }
2905
+ const depthCache = /* @__PURE__ */ new Map();
2906
+ const computeDepth = (stepId) => {
2907
+ const cached = depthCache.get(stepId);
2908
+ if (cached !== void 0) return cached;
2909
+ const node = steps.get(stepId);
2910
+ if (!node) return 0;
2911
+ const parent = node.parentId;
2912
+ if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
2913
+ depthCache.set(stepId, 0);
2914
+ return 0;
2915
+ }
2916
+ const d = Math.min(1e3, computeDepth(parent) + 1);
2917
+ depthCache.set(stepId, d);
2918
+ return d;
2919
+ };
2920
+ const entries = [];
2921
+ for (const [stepId, s] of steps.entries()) {
2922
+ const offsetMs = runStart !== void 0 && finite(s.startedAt) ? Math.max(0, s.startedAt - runStart) : 0;
2923
+ entries.push({
2924
+ stepId,
2925
+ name: s.name,
2926
+ type: s.type,
2927
+ status: s.status,
2928
+ depth: computeDepth(stepId),
2929
+ startedAt: s.startedAt,
2930
+ offsetMs,
2931
+ durationMs: s.durationMs,
2932
+ isError: s.status === "error",
2933
+ streaming: pickStreamingMeta(s.metadata)
2934
+ });
2935
+ }
2936
+ entries.sort((a, b) => a.startedAt - b.startedAt);
2937
+ const slowTopN = options.slowTopN ?? 3;
2938
+ if (options.focus === "slow" && entries.length > 0) {
2939
+ const ranked = [...entries].filter((e) => finite(e.durationMs)).sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
2940
+ const slowIds = new Set(
2941
+ ranked.slice(0, slowTopN).map((e) => e.stepId)
2942
+ );
2943
+ for (const e of entries) {
2944
+ if (slowIds.has(e.stepId)) e.slow = true;
2945
+ }
2946
+ }
2947
+ return {
2948
+ runId,
2949
+ name: typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0,
2950
+ status,
2951
+ startedAt: runStart,
2952
+ endedAt: lastCompleted && finite(lastCompleted.endTime) ? lastCompleted.endTime : void 0,
2953
+ durationMs: lastCompleted && finite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0,
2954
+ correlation: pickCorrelation(
2955
+ started?.metadata
2956
+ ),
2957
+ entries
2958
+ };
2959
+ }
2960
+ function renderTimeline(timeline, options = {}) {
2961
+ const lines = [];
2962
+ lines.push(`Timeline: ${timeline.name ?? timeline.runId}`);
2963
+ lines.push(`Run ID: ${timeline.runId}`);
2964
+ lines.push(`Status: ${timeline.status}`);
2965
+ if (timeline.startedAt !== void 0) {
2966
+ lines.push(`Started: ${formatTimestamp(timeline.startedAt)}`);
2967
+ }
2968
+ if (timeline.durationMs !== void 0) {
2969
+ lines.push(`Duration: ${formatDuration2(timeline.durationMs)}`);
2970
+ }
2971
+ if (timeline.correlation) {
2972
+ const parts = Object.entries(timeline.correlation).filter(([, v]) => typeof v === "string").map(([k, v]) => `${k}=${v}`);
2973
+ if (parts.length > 0) {
2974
+ lines.push(`Correlation: ${parts.join(", ")}`);
2975
+ }
2976
+ }
2977
+ lines.push("");
2978
+ lines.push("Steps (chronological):");
2979
+ const show = timeline.entries.filter((e) => {
2980
+ if (options.focus === "slow") return e.slow === true;
2981
+ return true;
2982
+ });
2983
+ if (show.length === 0) {
2984
+ lines.push(
2985
+ options.focus === "slow" ? "(no steps with duration for slow focus)" : "(no steps)"
2986
+ );
2987
+ return lines.join("\n");
2988
+ }
2989
+ for (const e of show) {
2990
+ const prefix = e.slow ? "[slow] " : "";
2991
+ const typeTag = e.type === "llm" ? "llm" : e.type === "tool" ? "tool" : e.type;
2992
+ const dur = e.durationMs !== void 0 ? formatDuration2(e.durationMs) : "-";
2993
+ const err = e.isError ? " error" : "";
2994
+ const off = formatDuration2(e.offsetMs);
2995
+ let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
2996
+ if (e.streaming?.chunkCount !== void 0) {
2997
+ line += ` chunks=${e.streaming.chunkCount}`;
2998
+ }
2999
+ if (e.streaming?.streamDurationMs !== void 0) {
3000
+ line += ` stream=${formatDuration2(e.streaming.streamDurationMs)}`;
3001
+ }
3002
+ lines.push(line);
3003
+ }
3004
+ return lines.join("\n");
3005
+ }
3006
+ function percentile(sorted, p) {
3007
+ if (sorted.length === 0) return void 0;
3008
+ const idx = Math.min(
3009
+ sorted.length - 1,
3010
+ Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
3011
+ );
3012
+ return sorted[idx];
3013
+ }
3014
+ async function readRunStartedMetadata(filePath) {
3015
+ try {
3016
+ const raw = await promises.readFile(filePath, "utf-8");
3017
+ for (const line of raw.split(/\r?\n/)) {
3018
+ const trimmed = line.trim();
3019
+ if (trimmed === "") continue;
3020
+ let parsed;
3021
+ try {
3022
+ parsed = JSON.parse(trimmed);
3023
+ } catch {
3024
+ continue;
3025
+ }
3026
+ if (!isTraceEvent(parsed)) continue;
3027
+ if (parsed.event !== "run_started") continue;
3028
+ const rs = parsed;
3029
+ if (rs.metadata && typeof rs.metadata === "object") {
3030
+ return rs.metadata;
3031
+ }
3032
+ return void 0;
3033
+ }
3034
+ } catch {
3035
+ }
3036
+ return void 0;
3037
+ }
3038
+ function metaMatchesCorrelation(metadata, correlationId, groupId) {
3039
+ if (correlationId) {
3040
+ const v = metadata?.correlationId;
3041
+ if (typeof v !== "string" || v !== correlationId) return false;
3042
+ }
3043
+ if (groupId) {
3044
+ const v = metadata?.groupId;
3045
+ if (typeof v !== "string" || v !== groupId) return false;
3046
+ }
3047
+ return true;
3048
+ }
3049
+ async function buildTraceStats(metas, options) {
3050
+ let filtered = filterTraces(metas, { since: options.since });
3051
+ if (options.correlationId || options.groupId) {
3052
+ const next = [];
3053
+ for (const m of filtered) {
3054
+ const md = await readRunStartedMetadata(m.filePath);
3055
+ if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
3056
+ next.push(m);
3057
+ }
3058
+ }
3059
+ filtered = next;
3060
+ }
3061
+ let successCount = 0;
3062
+ let errorCount = 0;
3063
+ let runningCount = 0;
3064
+ let unknownCount = 0;
3065
+ const durations = [];
3066
+ let totalSteps = 0;
3067
+ let totalLlmSteps = 0;
3068
+ let totalToolSteps = 0;
3069
+ let totalErrorSteps = 0;
3070
+ const slowestRuns = [];
3071
+ const slowestSteps = [];
3072
+ for (const m of filtered) {
3073
+ if (m.status === "success") successCount += 1;
3074
+ else if (m.status === "error") errorCount += 1;
3075
+ else if (m.status === "running") runningCount += 1;
3076
+ else unknownCount += 1;
3077
+ if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
3078
+ durations.push(m.durationMs);
3079
+ slowestRuns.push({
3080
+ runId: m.runId,
3081
+ name: m.name,
3082
+ durationMs: m.durationMs,
3083
+ status: m.status
3084
+ });
3085
+ }
3086
+ try {
3087
+ const events = await readTraceEvents(m.runId, options.traceDir);
3088
+ if (events.length === 0) continue;
3089
+ const summary = buildRunSummary(events);
3090
+ totalSteps += summary.totalSteps;
3091
+ totalLlmSteps += summary.llmSteps;
3092
+ totalToolSteps += summary.toolSteps;
3093
+ totalErrorSteps += summary.errorSteps;
3094
+ const steps = collectCompletedSteps(events, m.runId);
3095
+ for (const s of steps) {
3096
+ slowestSteps.push(s);
3097
+ }
3098
+ } catch {
3099
+ }
3100
+ }
3101
+ slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
3102
+ slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
3103
+ const runLimit = options.slowRunLimit ?? 5;
3104
+ const stepLimit = options.slowStepLimit ?? 5;
3105
+ const sortedDur = [...durations].sort((a, b) => a - b);
3106
+ const totalRuns = filtered.length;
3107
+ const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
3108
+ const sumDur = durations.reduce((a, b) => a + b, 0);
3109
+ return {
3110
+ traceDir: options.traceDir,
3111
+ ...options.since ? { since: options.since } : {},
3112
+ ...options.correlationId ? { correlationId: options.correlationId } : {},
3113
+ ...options.groupId ? { groupId: options.groupId } : {},
3114
+ totalRuns,
3115
+ successCount,
3116
+ errorCount,
3117
+ runningCount,
3118
+ unknownCount,
3119
+ errorRate,
3120
+ duration: {
3121
+ ...sortedDur.length > 0 ? {
3122
+ minMs: sortedDur[0],
3123
+ maxMs: sortedDur[sortedDur.length - 1],
3124
+ avgMs: sumDur / sortedDur.length,
3125
+ p50Ms: percentile(sortedDur, 50),
3126
+ p95Ms: percentile(sortedDur, 95)
3127
+ } : {}
3128
+ },
3129
+ totalSteps,
3130
+ avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
3131
+ totalLlmSteps,
3132
+ totalToolSteps,
3133
+ totalErrorSteps,
3134
+ slowestRuns: slowestRuns.slice(0, runLimit),
3135
+ slowestSteps: slowestSteps.slice(0, stepLimit)
3136
+ };
3137
+ }
3138
+ function collectCompletedSteps(events, runId) {
3139
+ const started = /* @__PURE__ */ new Map();
3140
+ const out = [];
3141
+ for (const e of events) {
3142
+ if (e.event === "step_started") {
3143
+ const s = e;
3144
+ started.set(s.stepId, { name: s.name, type: s.type });
3145
+ }
3146
+ if (e.event === "step_completed") {
3147
+ const c = e;
3148
+ if (c.status !== "success" && c.status !== "error") continue;
3149
+ if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
3150
+ continue;
3151
+ }
3152
+ const meta = started.get(c.stepId);
3153
+ out.push({
3154
+ runId,
3155
+ stepName: meta?.name ?? c.stepId,
3156
+ stepType: meta?.type ?? "logic",
3157
+ durationMs: c.durationMs
3158
+ });
3159
+ }
3160
+ }
3161
+ return out;
3162
+ }
3163
+ function renderTraceStats(stats) {
3164
+ const lines = [];
3165
+ lines.push("Trace stats (local)");
3166
+ lines.push(`Directory: ${stats.traceDir}`);
3167
+ if (stats.since) lines.push(`Since: ${stats.since}`);
3168
+ if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
3169
+ if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
3170
+ lines.push("");
3171
+ lines.push(`Runs: ${stats.totalRuns}`);
3172
+ lines.push(
3173
+ ` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
3174
+ );
3175
+ lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
3176
+ if (stats.duration.avgMs !== void 0) {
3177
+ lines.push(
3178
+ `Duration: min ${formatDuration2(stats.duration.minMs ?? 0)} | avg ${formatDuration2(stats.duration.avgMs)} | p50 ${formatDuration2(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration2(stats.duration.p95Ms ?? 0)} | max ${formatDuration2(stats.duration.maxMs ?? 0)}`
3179
+ );
3180
+ }
3181
+ lines.push("");
3182
+ lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
3183
+ lines.push(
3184
+ ` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
3185
+ );
3186
+ if (stats.slowestRuns.length > 0) {
3187
+ lines.push("");
3188
+ lines.push("Slowest runs:");
3189
+ for (const r of stats.slowestRuns) {
3190
+ lines.push(
3191
+ ` ${r.runId} | ${r.name ?? "-"} | ${formatDuration2(r.durationMs ?? 0)} | ${r.status}`
3192
+ );
3193
+ }
3194
+ }
3195
+ if (stats.slowestSteps.length > 0) {
3196
+ lines.push("");
3197
+ lines.push("Slowest steps:");
3198
+ for (const s of stats.slowestSteps) {
3199
+ lines.push(
3200
+ ` ${s.runId} | ${s.stepType}:${s.stepName} | ${formatDuration2(s.durationMs)}`
3201
+ );
3202
+ }
3203
+ }
3204
+ return lines.join("\n");
3205
+ }
3206
+
3207
+ // packages/core/src/search.ts
3208
+ function parseDurationFilter(expr) {
3209
+ const raw = expr.trim();
3210
+ const m = raw.match(/^(>=|<=|>|<)\s*(.+)$/);
3211
+ if (!m) {
3212
+ throw new Error(
3213
+ `Invalid --duration "${expr}". Use forms like >5s, >=500ms, <2m.`
3214
+ );
3215
+ }
3216
+ const op = m[1];
3217
+ const ms = parseDuration(m[2].trim());
3218
+ return { op, ms };
3219
+ }
3220
+ function durationMatches(valueMs, filter) {
3221
+ if (valueMs === void 0 || !Number.isFinite(valueMs)) return false;
3222
+ switch (filter.op) {
3223
+ case ">":
3224
+ return valueMs > filter.ms;
3225
+ case ">=":
3226
+ return valueMs >= filter.ms;
3227
+ case "<":
3228
+ return valueMs < filter.ms;
3229
+ case "<=":
3230
+ return valueMs <= filter.ms;
3231
+ default:
3232
+ return false;
3233
+ }
3234
+ }
3235
+ function normalizeStepTypeFilter(kind, type) {
3236
+ const v = (kind ?? type)?.trim().toLowerCase();
3237
+ return v && v !== "" ? v : void 0;
3238
+ }
3239
+ function nameMatches(hay, needle) {
3240
+ return hay.toLowerCase().includes(needle.toLowerCase());
3241
+ }
3242
+ async function searchTraces(metas, options) {
3243
+ let filtered = filterTraces(metas, { since: options.since });
3244
+ const stepTypeFilter = normalizeStepTypeFilter(options.kind, options.type);
3245
+ const nameQuery = options.name?.trim();
3246
+ const toolQuery = options.tool?.trim();
3247
+ let durationFilter;
3248
+ if (options.duration) {
3249
+ durationFilter = parseDurationFilter(options.duration);
3250
+ }
3251
+ const limit = options.limit ?? 50;
3252
+ const hasContentFilter = Boolean(
3253
+ options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
3254
+ );
3255
+ const results = [];
3256
+ if (!hasContentFilter) {
3257
+ for (const m of filtered) {
3258
+ results.push({
3259
+ runId: m.runId,
3260
+ runName: m.name,
3261
+ runStatus: m.status,
3262
+ timestamp: m.startedAt,
3263
+ durationMs: m.durationMs,
3264
+ matchReason: "trace in directory",
3265
+ matchedFields: ["run"],
3266
+ filePath: m.filePath
3267
+ });
3268
+ }
3269
+ return results.slice(0, limit);
3270
+ }
3271
+ for (const m of filtered) {
3272
+ if (options.status && m.status !== options.status) continue;
3273
+ let events = [];
3274
+ try {
3275
+ events = await readTraceEvents(m.runId, options.traceDir);
3276
+ } catch {
3277
+ continue;
3278
+ }
3279
+ if (events.length === 0) continue;
3280
+ const runMatches = matchRunLevel(m, {
3281
+ stepTypeFilter,
3282
+ nameQuery,
3283
+ toolQuery,
3284
+ durationFilter,
3285
+ statusFilter: options.status
3286
+ });
3287
+ results.push(...runMatches);
3288
+ const stepMatches = matchStepLevel(m, events, {
3289
+ stepTypeFilter,
3290
+ nameQuery,
3291
+ toolQuery,
3292
+ durationFilter,
3293
+ statusFilter: options.status
3294
+ });
3295
+ results.push(...stepMatches);
3296
+ }
3297
+ results.sort((a, b) => {
3298
+ const ta = a.timestamp ?? 0;
3299
+ const tb = b.timestamp ?? 0;
3300
+ if (ta !== tb) return ta - tb;
3301
+ const runCmp = a.runId.localeCompare(b.runId);
3302
+ if (runCmp !== 0) return runCmp;
3303
+ return (a.stepName ?? "").localeCompare(b.stepName ?? "");
3304
+ });
3305
+ return results.slice(0, limit);
3306
+ }
3307
+ function matchRunLevel(m, opts) {
3308
+ if (opts.stepTypeFilter || opts.toolQuery) return [];
3309
+ const out = [];
3310
+ const fields = [];
3311
+ if (opts.statusFilter && m.status === opts.statusFilter) {
3312
+ fields.push("run.status");
3313
+ }
3314
+ if (opts.nameQuery && nameMatches(m.name ?? m.runId, opts.nameQuery)) {
3315
+ fields.push("run.name");
3316
+ }
3317
+ if (opts.durationFilter && durationMatches(m.durationMs, opts.durationFilter)) {
3318
+ fields.push("run.durationMs");
3319
+ }
3320
+ if (fields.length === 0) return out;
3321
+ out.push({
3322
+ runId: m.runId,
3323
+ runName: m.name,
3324
+ runStatus: m.status,
3325
+ timestamp: m.startedAt,
3326
+ durationMs: m.durationMs,
3327
+ matchReason: `run match: ${fields.join(", ")}`,
3328
+ matchedFields: fields,
3329
+ filePath: m.filePath
3330
+ });
3331
+ return out;
3332
+ }
3333
+ function matchStepLevel(m, events, opts) {
3334
+ const out = [];
3335
+ const started = /* @__PURE__ */ new Map();
3336
+ for (const e of events) {
3337
+ if (e.event === "step_started") {
3338
+ started.set(e.stepId, e);
3339
+ }
3340
+ }
3341
+ for (const e of events) {
3342
+ if (e.event !== "step_completed") continue;
3343
+ const c = e;
3344
+ const s = started.get(c.stepId);
3345
+ if (!s) continue;
3346
+ const fields = [];
3347
+ const stepType = s.type;
3348
+ if (opts.stepTypeFilter && stepType !== opts.stepTypeFilter) {
3349
+ continue;
3350
+ }
3351
+ const hasStepFilters = opts.stepTypeFilter || opts.nameQuery || opts.toolQuery || opts.durationFilter || opts.statusFilter === "error" || opts.statusFilter === "success";
3352
+ if (!hasStepFilters) continue;
3353
+ if (opts.statusFilter === "error" && c.status === "error") {
3354
+ fields.push("step.status");
3355
+ } else if (opts.statusFilter === "success" && c.status === "success") {
3356
+ fields.push("step.status");
3357
+ } else if (opts.statusFilter === "error" || opts.statusFilter === "success") {
3358
+ continue;
3359
+ }
3360
+ if (opts.nameQuery) {
3361
+ if (!nameMatches(s.name, opts.nameQuery)) continue;
3362
+ fields.push("step.name");
3363
+ }
3364
+ if (opts.toolQuery) {
3365
+ const toolName = typeof s.metadata?.toolName === "string" ? s.metadata.toolName : s.name;
3366
+ if (!nameMatches(toolName, opts.toolQuery)) continue;
3367
+ fields.push("step.tool");
3368
+ }
3369
+ if (opts.durationFilter) {
3370
+ if (!durationMatches(c.durationMs, opts.durationFilter)) continue;
3371
+ fields.push("step.durationMs");
3372
+ }
3373
+ if (opts.stepTypeFilter) {
3374
+ fields.push("step.type");
3375
+ }
3376
+ if (fields.length === 0) continue;
3377
+ out.push({
3378
+ runId: m.runId,
3379
+ runName: m.name,
3380
+ runStatus: m.status,
3381
+ stepId: c.stepId,
3382
+ stepName: s.name,
3383
+ stepType,
3384
+ timestamp: s.startTime ?? s.timestamp,
3385
+ durationMs: c.durationMs,
3386
+ matchReason: `step match: ${fields.join(", ")}`,
3387
+ matchedFields: fields,
3388
+ filePath: m.filePath
3389
+ });
3390
+ }
3391
+ return out;
3392
+ }
3393
+ async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
3394
+ const metas = [];
3395
+ for (const fileName of fileNames) {
3396
+ try {
3397
+ const filePath = getPath(fileName);
3398
+ const meta = await extractMetadata(filePath);
3399
+ metas.push(meta);
3400
+ } catch {
3401
+ }
3402
+ }
3403
+ return metas;
3404
+ }
2837
3405
  var KNOWN_EVENTS = /* @__PURE__ */ new Set([
2838
3406
  "run_started",
2839
3407
  "run_completed",
@@ -5339,6 +5907,8 @@ exports.TERMINAL_INDENT = TERMINAL_INDENT;
5339
5907
  exports.TraceDirectory = TraceDirectory;
5340
5908
  exports.TreeBuilder = TreeBuilder;
5341
5909
  exports.buildRunSummary = buildRunSummary;
5910
+ exports.buildRunTimeline = buildRunTimeline;
5911
+ exports.buildTraceStats = buildTraceStats;
5342
5912
  exports.compactAttributes = compactAttributes4;
5343
5913
  exports.createRunId = createRunId;
5344
5914
  exports.createStepId = createStepId;
@@ -5386,6 +5956,7 @@ exports.isStepType = isStepType;
5386
5956
  exports.isTraceEvent = isTraceEvent;
5387
5957
  exports.listTraceFiles = listTraceFiles;
5388
5958
  exports.loadLogIngestConfig = loadLogIngestConfig;
5959
+ exports.loadTraceMetadataList = loadTraceMetadataList;
5389
5960
  exports.manualTraceEventsToComparableRun = manualTraceEventsToComparableRun;
5390
5961
  exports.manualTraceEventsToRunTree = manualTraceEventsToRunTree;
5391
5962
  exports.matchMapping = matchMapping;
@@ -5394,6 +5965,7 @@ exports.mergeExportDefaults = mergeExportDefaults;
5394
5965
  exports.mergeLogIngestConfig = mergeLogIngestConfig;
5395
5966
  exports.observe = observe;
5396
5967
  exports.parseDuration = parseDuration;
5968
+ exports.parseDurationFilter = parseDurationFilter;
5397
5969
  exports.parseLogLine = parseLogLine;
5398
5970
  exports.parseLogsToTrees = parseLogsToTrees;
5399
5971
  exports.persistedInspectEventToInspectEvent = persistedInspectEventToInspectEvent;
@@ -5416,12 +5988,15 @@ exports.renderRunSummary = renderRunSummary;
5416
5988
  exports.renderRunTree = renderRunTree;
5417
5989
  exports.renderRunTrees = renderRunTrees;
5418
5990
  exports.renderStepLine = renderStepLine;
5991
+ exports.renderTimeline = renderTimeline;
5992
+ exports.renderTraceStats = renderTraceStats;
5419
5993
  exports.resolveRedactionProfile = resolveRedactionProfile;
5420
5994
  exports.resolveTraceDir = resolveTraceDir;
5421
5995
  exports.resolveTraceSafetyOptions = resolveTraceSafetyOptions;
5422
5996
  exports.runWithContext = runWithContext;
5423
5997
  exports.runWithStepContext = runWithStepContext;
5424
5998
  exports.safeString = safeString2;
5999
+ exports.searchTraces = searchTraces;
5425
6000
  exports.serializeEvent = serializeEvent;
5426
6001
  exports.stableJson = stableJson;
5427
6002
  exports.step = step;