agent-inspect 2.3.0 → 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/CHANGELOG.md +16 -0
- package/README.md +33 -4
- package/docs/ADAPTERS.md +47 -0
- package/docs/CLI.md +54 -1
- package/docs/SCHEMA.md +1 -0
- package/package.json +2 -2
- package/packages/cli/dist/index.cjs +757 -14
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +757 -14
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +581 -3
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +172 -8
- package/packages/core/dist/advanced.d.ts +172 -8
- package/packages/core/dist/advanced.mjs +572 -4
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.d.cts +2 -2
- package/packages/core/dist/checks.d.ts +2 -2
- package/packages/core/dist/{context-yv2VSDQF.d.ts → context-BDZmi53V.d.ts} +3 -3
- package/packages/core/dist/{context-CSKnzpXR.d.cts → context-DjY-jvQk.d.cts} +3 -3
- package/packages/core/dist/diff.d.cts +3 -3
- package/packages/core/dist/diff.d.ts +3 -3
- package/packages/core/dist/exporters.d.cts +3 -3
- package/packages/core/dist/exporters.d.ts +3 -3
- package/packages/core/dist/index.d.cts +6 -6
- package/packages/core/dist/index.d.ts +6 -6
- package/packages/core/dist/{inspect-event-CevRYp58.d.cts → inspect-event-CYAV7Hxm.d.cts} +1 -1
- package/packages/core/dist/{inspect-event-CevRYp58.d.ts → inspect-event-CYAV7Hxm.d.ts} +1 -1
- package/packages/core/dist/{log-config-8aE5Kxtr.d.cts → log-config-BNQ9UTmP.d.cts} +1 -1
- package/packages/core/dist/{log-config-DVimQJho.d.ts → log-config-D3Yp1SZN.d.ts} +1 -1
- package/packages/core/dist/logs.d.cts +3 -3
- package/packages/core/dist/logs.d.ts +3 -3
- package/packages/core/dist/{persisted-inspect-event-D-WpXeZX.d.ts → persisted-inspect-event-BLvb0jSX.d.ts} +1 -1
- package/packages/core/dist/{persisted-inspect-event-DHcHPUKv.d.cts → persisted-inspect-event-D5SjBz9b.d.cts} +1 -1
- package/packages/core/dist/persisted.d.cts +5 -5
- package/packages/core/dist/persisted.d.ts +5 -5
- package/packages/core/dist/readers.d.cts +2 -2
- package/packages/core/dist/readers.d.ts +2 -2
- package/packages/core/dist/{types-DgMN3qow.d.cts → types-C-llnPH0.d.cts} +1 -1
- package/packages/core/dist/{types-D-Y1kOU-.d.ts → types-CQun9LW6.d.ts} +1 -1
- package/packages/core/dist/writers.d.cts +2 -2
- package/packages/core/dist/writers.d.ts +2 -2
|
@@ -23,7 +23,7 @@ var process2__default = /*#__PURE__*/_interopDefault(process2);
|
|
|
23
23
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
24
24
|
|
|
25
25
|
// package.json
|
|
26
|
-
var version = "2.
|
|
26
|
+
var version = "2.4.0";
|
|
27
27
|
|
|
28
28
|
// packages/core/src/correlation-metadata.ts
|
|
29
29
|
var TRACE_CORRELATION_KEYS = [
|
|
@@ -2540,10 +2540,12 @@ async function searchTraces(metas, options) {
|
|
|
2540
2540
|
durationFilter = parseDurationFilter(options.duration);
|
|
2541
2541
|
}
|
|
2542
2542
|
const limit = options.limit ?? 50;
|
|
2543
|
+
const sessionId = options.session?.trim();
|
|
2543
2544
|
const hasContentFilter = Boolean(
|
|
2544
2545
|
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
|
|
2545
2546
|
);
|
|
2546
2547
|
const results = [];
|
|
2548
|
+
const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
|
|
2547
2549
|
if (!hasContentFilter) {
|
|
2548
2550
|
for (const m of filtered) {
|
|
2549
2551
|
results.push({
|
|
@@ -2552,9 +2554,10 @@ async function searchTraces(metas, options) {
|
|
|
2552
2554
|
runStatus: m.status,
|
|
2553
2555
|
timestamp: m.startedAt,
|
|
2554
2556
|
durationMs: m.durationMs,
|
|
2555
|
-
matchReason: "trace in directory",
|
|
2556
|
-
matchedFields: ["run"],
|
|
2557
|
-
filePath: m.filePath
|
|
2557
|
+
matchReason: sessionLabel ? `trace in session ${sessionLabel}` : "trace in directory",
|
|
2558
|
+
matchedFields: sessionLabel ? ["run", "session"] : ["run"],
|
|
2559
|
+
filePath: m.filePath,
|
|
2560
|
+
...sessionLabel ? { sessionId: sessionLabel } : {}
|
|
2558
2561
|
});
|
|
2559
2562
|
}
|
|
2560
2563
|
return results.slice(0, limit);
|
|
@@ -2693,6 +2696,478 @@ async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
|
|
|
2693
2696
|
}
|
|
2694
2697
|
return metas;
|
|
2695
2698
|
}
|
|
2699
|
+
|
|
2700
|
+
// packages/core/src/sessions/metadata.ts
|
|
2701
|
+
function isNonEmptyString3(value) {
|
|
2702
|
+
return typeof value === "string" && value.trim() !== "";
|
|
2703
|
+
}
|
|
2704
|
+
function finitePositiveInt(value) {
|
|
2705
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
|
|
2706
|
+
return void 0;
|
|
2707
|
+
}
|
|
2708
|
+
return Math.trunc(value);
|
|
2709
|
+
}
|
|
2710
|
+
function extractSessionWorkflowMetadata(record) {
|
|
2711
|
+
if (!record) return void 0;
|
|
2712
|
+
const out = {};
|
|
2713
|
+
let found = false;
|
|
2714
|
+
const assignString = (key, value) => {
|
|
2715
|
+
if (isNonEmptyString3(value)) {
|
|
2716
|
+
out[key] = value.trim();
|
|
2717
|
+
found = true;
|
|
2718
|
+
}
|
|
2719
|
+
};
|
|
2720
|
+
assignString("sessionId", record.sessionId);
|
|
2721
|
+
assignString("conversationId", record.conversationId);
|
|
2722
|
+
assignString("groupId", record.groupId);
|
|
2723
|
+
assignString("parentGroupId", record.parentGroupId);
|
|
2724
|
+
assignString("retryOf", record.retryOf);
|
|
2725
|
+
assignString("retryReason", record.retryReason);
|
|
2726
|
+
assignString("handoffFrom", record.handoffFrom);
|
|
2727
|
+
assignString("handoffTo", record.handoffTo);
|
|
2728
|
+
assignString("subAgentId", record.subAgentId);
|
|
2729
|
+
assignString("subAgentName", record.subAgentName);
|
|
2730
|
+
assignString("jobId", record.jobId);
|
|
2731
|
+
assignString("queueName", record.queueName);
|
|
2732
|
+
assignString("workflowName", record.workflowName);
|
|
2733
|
+
assignString("workflowStep", record.workflowStep);
|
|
2734
|
+
assignString("toolCallId", record.toolCallId);
|
|
2735
|
+
assignString("mcpToolCallId", record.mcpToolCallId);
|
|
2736
|
+
assignString("linkedStepId", record.linkedStepId);
|
|
2737
|
+
assignString("correlationId", record.correlationId);
|
|
2738
|
+
assignString("requestId", record.requestId);
|
|
2739
|
+
assignString("decisionId", record.decisionId);
|
|
2740
|
+
const attempt = finitePositiveInt(record.attempt);
|
|
2741
|
+
if (attempt !== void 0) {
|
|
2742
|
+
out.attempt = attempt;
|
|
2743
|
+
found = true;
|
|
2744
|
+
}
|
|
2745
|
+
return found ? out : void 0;
|
|
2746
|
+
}
|
|
2747
|
+
function sessionKeyForRun(meta, options) {
|
|
2748
|
+
if (meta?.sessionId) return meta.sessionId;
|
|
2749
|
+
if (options?.correlateByGroupId && meta?.groupId) {
|
|
2750
|
+
return `group:${meta.groupId}`;
|
|
2751
|
+
}
|
|
2752
|
+
return void 0;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// packages/core/src/sessions/load.ts
|
|
2756
|
+
async function enrichSessionRunRecord(meta) {
|
|
2757
|
+
let metadata;
|
|
2758
|
+
try {
|
|
2759
|
+
const events = await readTraceEventsFromFile(meta.filePath);
|
|
2760
|
+
for (const event of events) {
|
|
2761
|
+
if (event.event !== "run_started") continue;
|
|
2762
|
+
if (event.metadata && typeof event.metadata === "object") {
|
|
2763
|
+
metadata = event.metadata;
|
|
2764
|
+
}
|
|
2765
|
+
break;
|
|
2766
|
+
}
|
|
2767
|
+
} catch {
|
|
2768
|
+
}
|
|
2769
|
+
return {
|
|
2770
|
+
runId: meta.runId,
|
|
2771
|
+
name: meta.name,
|
|
2772
|
+
status: meta.status,
|
|
2773
|
+
startedAt: meta.startedAt,
|
|
2774
|
+
endedAt: meta.endedAt,
|
|
2775
|
+
durationMs: meta.durationMs,
|
|
2776
|
+
filePath: meta.filePath,
|
|
2777
|
+
metadata
|
|
2778
|
+
};
|
|
2779
|
+
}
|
|
2780
|
+
async function loadSessionRunRecords(metas) {
|
|
2781
|
+
const out = [];
|
|
2782
|
+
for (const meta of metas) {
|
|
2783
|
+
out.push(await enrichSessionRunRecord(meta));
|
|
2784
|
+
}
|
|
2785
|
+
return out;
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
// packages/core/src/sessions/scope.ts
|
|
2789
|
+
function filterMetasBySessionScope(metas, records, options) {
|
|
2790
|
+
const sessionId = options.sessionId?.trim();
|
|
2791
|
+
const groupId = options.groupId?.trim();
|
|
2792
|
+
const warnings = [];
|
|
2793
|
+
if (sessionId) {
|
|
2794
|
+
const index = buildSessionIndex(records, {
|
|
2795
|
+
correlateByGroupId: options.correlateByGroupId === true
|
|
2796
|
+
});
|
|
2797
|
+
warnings.push(...index.warnings);
|
|
2798
|
+
const session = index.sessions.find((item) => item.sessionId === sessionId);
|
|
2799
|
+
if (!session) {
|
|
2800
|
+
return {
|
|
2801
|
+
metas: [],
|
|
2802
|
+
scopeLabel: sessionId,
|
|
2803
|
+
scopeKind: "session",
|
|
2804
|
+
runIds: [],
|
|
2805
|
+
warnings,
|
|
2806
|
+
notFound: true
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
const runIdSet = new Set(session.runIds);
|
|
2810
|
+
const filtered = metas.filter((meta) => runIdSet.has(meta.runId));
|
|
2811
|
+
return {
|
|
2812
|
+
metas: filtered,
|
|
2813
|
+
scopeLabel: sessionId,
|
|
2814
|
+
scopeKind: "session",
|
|
2815
|
+
runIds: session.runIds,
|
|
2816
|
+
warnings,
|
|
2817
|
+
notFound: false
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
if (groupId) {
|
|
2821
|
+
const runIds = records.filter((run) => extractSessionWorkflowMetadata(run.metadata)?.groupId === groupId).map((run) => run.runId).sort();
|
|
2822
|
+
if (runIds.length === 0) {
|
|
2823
|
+
return {
|
|
2824
|
+
metas: [],
|
|
2825
|
+
scopeLabel: groupId,
|
|
2826
|
+
scopeKind: "group",
|
|
2827
|
+
runIds: [],
|
|
2828
|
+
warnings,
|
|
2829
|
+
notFound: true
|
|
2830
|
+
};
|
|
2831
|
+
}
|
|
2832
|
+
const runIdSet = new Set(runIds);
|
|
2833
|
+
return {
|
|
2834
|
+
metas: metas.filter((meta) => runIdSet.has(meta.runId)),
|
|
2835
|
+
scopeLabel: groupId,
|
|
2836
|
+
scopeKind: "group",
|
|
2837
|
+
runIds,
|
|
2838
|
+
warnings,
|
|
2839
|
+
notFound: false
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2842
|
+
return {
|
|
2843
|
+
metas: [...metas],
|
|
2844
|
+
scopeLabel: "",
|
|
2845
|
+
scopeKind: "session",
|
|
2846
|
+
runIds: [],
|
|
2847
|
+
warnings,
|
|
2848
|
+
notFound: false
|
|
2849
|
+
};
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
// packages/core/src/sessions/checks.ts
|
|
2853
|
+
function emptySummary() {
|
|
2854
|
+
return { passed: 0, failed: 0, warnings: 0, errors: 0 };
|
|
2855
|
+
}
|
|
2856
|
+
function mergeSummary(target, source) {
|
|
2857
|
+
return {
|
|
2858
|
+
passed: target.passed + source.passed,
|
|
2859
|
+
failed: target.failed + source.failed,
|
|
2860
|
+
warnings: target.warnings + source.warnings,
|
|
2861
|
+
errors: target.errors + source.errors
|
|
2862
|
+
};
|
|
2863
|
+
}
|
|
2864
|
+
function sessionDiagnostic(code, message) {
|
|
2865
|
+
return { code, message, severity: "error" };
|
|
2866
|
+
}
|
|
2867
|
+
function aggregateSessionCheckResults(perRun, scope) {
|
|
2868
|
+
if (scope.notFound) {
|
|
2869
|
+
return {
|
|
2870
|
+
ok: false,
|
|
2871
|
+
status: "error",
|
|
2872
|
+
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
2873
|
+
scopeKind: scope.scopeKind,
|
|
2874
|
+
scopeLabel: scope.scopeLabel,
|
|
2875
|
+
runIds: [],
|
|
2876
|
+
runResults: [],
|
|
2877
|
+
summary: { ...emptySummary(), errors: 1 },
|
|
2878
|
+
findings: [],
|
|
2879
|
+
diagnostics: [
|
|
2880
|
+
sessionDiagnostic(
|
|
2881
|
+
"AI_CHECK_INVALID_ARGUMENTS",
|
|
2882
|
+
`${scope.scopeKind} not found: ${scope.scopeLabel}`
|
|
2883
|
+
)
|
|
2884
|
+
],
|
|
2885
|
+
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
if (scope.empty || perRun.length === 0) {
|
|
2889
|
+
return {
|
|
2890
|
+
ok: false,
|
|
2891
|
+
status: "error",
|
|
2892
|
+
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
2893
|
+
scopeKind: scope.scopeKind,
|
|
2894
|
+
scopeLabel: scope.scopeLabel,
|
|
2895
|
+
runIds: scope.runIds,
|
|
2896
|
+
runResults: [],
|
|
2897
|
+
summary: { ...emptySummary(), errors: 1 },
|
|
2898
|
+
findings: [],
|
|
2899
|
+
diagnostics: [
|
|
2900
|
+
sessionDiagnostic(
|
|
2901
|
+
"AI_CHECK_TRACE_UNREADABLE",
|
|
2902
|
+
`No readable traces in ${scope.scopeKind}: ${scope.scopeLabel}`
|
|
2903
|
+
)
|
|
2904
|
+
],
|
|
2905
|
+
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
2906
|
+
};
|
|
2907
|
+
}
|
|
2908
|
+
let summary = emptySummary();
|
|
2909
|
+
const findings = [];
|
|
2910
|
+
const diagnostics = [];
|
|
2911
|
+
const runResults = [];
|
|
2912
|
+
for (const result of perRun) {
|
|
2913
|
+
summary = mergeSummary(summary, result.summary);
|
|
2914
|
+
findings.push(...result.findings);
|
|
2915
|
+
diagnostics.push(...result.diagnostics);
|
|
2916
|
+
if (result.runId) {
|
|
2917
|
+
runResults.push({ runId: result.runId, status: result.status });
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
runResults.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
2921
|
+
findings.sort((a, b) => {
|
|
2922
|
+
const runCmp = (a.evidence[0]?.runId ?? "").localeCompare(
|
|
2923
|
+
b.evidence[0]?.runId ?? ""
|
|
2924
|
+
);
|
|
2925
|
+
if (runCmp !== 0) return runCmp;
|
|
2926
|
+
return a.ruleId.localeCompare(b.ruleId);
|
|
2927
|
+
});
|
|
2928
|
+
const hasErrors = diagnostics.some((item) => item.severity === "error");
|
|
2929
|
+
const status = hasErrors ? "error" : summary.failed > 0 ? "fail" : "pass";
|
|
2930
|
+
return {
|
|
2931
|
+
ok: status === "pass",
|
|
2932
|
+
status,
|
|
2933
|
+
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
2934
|
+
scopeKind: scope.scopeKind,
|
|
2935
|
+
scopeLabel: scope.scopeLabel,
|
|
2936
|
+
runIds: scope.runIds,
|
|
2937
|
+
runResults,
|
|
2938
|
+
summary,
|
|
2939
|
+
findings,
|
|
2940
|
+
diagnostics,
|
|
2941
|
+
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
2942
|
+
};
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
// packages/core/src/sessions/index.ts
|
|
2946
|
+
function compareRuns(a, b) {
|
|
2947
|
+
const aStart = a.startedAt ?? 0;
|
|
2948
|
+
const bStart = b.startedAt ?? 0;
|
|
2949
|
+
if (aStart !== bStart) return aStart - bStart;
|
|
2950
|
+
return a.runId.localeCompare(b.runId);
|
|
2951
|
+
}
|
|
2952
|
+
function buildGroups(runIds, metaByRunId) {
|
|
2953
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
2954
|
+
for (const runId of runIds) {
|
|
2955
|
+
const groupId = metaByRunId.get(runId)?.groupId;
|
|
2956
|
+
if (!groupId) continue;
|
|
2957
|
+
const existing = byGroup.get(groupId);
|
|
2958
|
+
if (existing) {
|
|
2959
|
+
existing.runIds.push(runId);
|
|
2960
|
+
} else {
|
|
2961
|
+
byGroup.set(groupId, {
|
|
2962
|
+
groupId,
|
|
2963
|
+
parentGroupId: metaByRunId.get(runId)?.parentGroupId,
|
|
2964
|
+
runIds: [runId]
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
return [...byGroup.values()].map((group) => ({
|
|
2969
|
+
...group,
|
|
2970
|
+
runIds: [...group.runIds].sort((a, b) => a.localeCompare(b))
|
|
2971
|
+
}));
|
|
2972
|
+
}
|
|
2973
|
+
function buildHandoffs(runIds, metaByRunId, warnings, sessionId) {
|
|
2974
|
+
const edges = [];
|
|
2975
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2976
|
+
const pushEdge = (edge) => {
|
|
2977
|
+
const key = `${edge.from}->${edge.to}:${edge.confidence}`;
|
|
2978
|
+
if (seen.has(key)) return;
|
|
2979
|
+
seen.add(key);
|
|
2980
|
+
edges.push(edge);
|
|
2981
|
+
};
|
|
2982
|
+
for (const runId of runIds) {
|
|
2983
|
+
const meta = metaByRunId.get(runId);
|
|
2984
|
+
if (!meta) continue;
|
|
2985
|
+
if (meta.handoffFrom && meta.handoffTo) {
|
|
2986
|
+
pushEdge({
|
|
2987
|
+
from: meta.handoffFrom,
|
|
2988
|
+
to: meta.handoffTo,
|
|
2989
|
+
source: "manual",
|
|
2990
|
+
confidence: "explicit"
|
|
2991
|
+
});
|
|
2992
|
+
continue;
|
|
2993
|
+
}
|
|
2994
|
+
if (meta.handoffFrom) {
|
|
2995
|
+
pushEdge({
|
|
2996
|
+
from: meta.handoffFrom,
|
|
2997
|
+
to: runId,
|
|
2998
|
+
source: "manual",
|
|
2999
|
+
confidence: "explicit"
|
|
3000
|
+
});
|
|
3001
|
+
}
|
|
3002
|
+
if (meta.handoffTo) {
|
|
3003
|
+
pushEdge({
|
|
3004
|
+
from: runId,
|
|
3005
|
+
to: meta.handoffTo,
|
|
3006
|
+
source: "manual",
|
|
3007
|
+
confidence: "explicit"
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
if (meta.subAgentId && meta.parentGroupId && !meta.handoffFrom && !meta.handoffTo) {
|
|
3011
|
+
pushEdge({
|
|
3012
|
+
from: meta.parentGroupId,
|
|
3013
|
+
to: meta.subAgentId,
|
|
3014
|
+
source: "inferred",
|
|
3015
|
+
confidence: "correlated"
|
|
3016
|
+
});
|
|
3017
|
+
warnings.push({
|
|
3018
|
+
code: "ambiguous-handoff-endpoints",
|
|
3019
|
+
message: "Handoff inferred from parentGroupId and subAgentId without explicit handoffFrom/handoffTo.",
|
|
3020
|
+
runId,
|
|
3021
|
+
sessionId
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
return edges.sort((a, b) => {
|
|
3026
|
+
const from = a.from.localeCompare(b.from);
|
|
3027
|
+
if (from !== 0) return from;
|
|
3028
|
+
return a.to.localeCompare(b.to);
|
|
3029
|
+
});
|
|
3030
|
+
}
|
|
3031
|
+
function buildRetries(runIds, metaByRunId, warnings, sessionId) {
|
|
3032
|
+
const retries = [];
|
|
3033
|
+
for (const runId of runIds) {
|
|
3034
|
+
const meta = metaByRunId.get(runId);
|
|
3035
|
+
if (!meta) continue;
|
|
3036
|
+
if (meta.retryOf) {
|
|
3037
|
+
retries.push({
|
|
3038
|
+
runId,
|
|
3039
|
+
retryOf: meta.retryOf,
|
|
3040
|
+
attempt: meta.attempt,
|
|
3041
|
+
source: "manual",
|
|
3042
|
+
confidence: "explicit"
|
|
3043
|
+
});
|
|
3044
|
+
continue;
|
|
3045
|
+
}
|
|
3046
|
+
if (meta.attempt !== void 0 && meta.attempt > 1) {
|
|
3047
|
+
retries.push({
|
|
3048
|
+
runId,
|
|
3049
|
+
attempt: meta.attempt,
|
|
3050
|
+
source: "inferred",
|
|
3051
|
+
confidence: "correlated"
|
|
3052
|
+
});
|
|
3053
|
+
warnings.push({
|
|
3054
|
+
code: "ambiguous-retry-link",
|
|
3055
|
+
message: "attempt > 1 without retryOf; retry link is correlated only.",
|
|
3056
|
+
runId,
|
|
3057
|
+
sessionId
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
return retries.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
3062
|
+
}
|
|
3063
|
+
function buildCriticalPath(runs, handoffs) {
|
|
3064
|
+
const runById = new Map(runs.map((run) => [run.runId, run]));
|
|
3065
|
+
const explicitTargets = new Set(
|
|
3066
|
+
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.to)
|
|
3067
|
+
);
|
|
3068
|
+
const explicitSources = new Set(
|
|
3069
|
+
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3070
|
+
);
|
|
3071
|
+
const ordered = [...runs].sort(compareRuns);
|
|
3072
|
+
const path15 = [];
|
|
3073
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3074
|
+
const pushRun = (run, confidence, source) => {
|
|
3075
|
+
if (visited.has(run.runId)) return;
|
|
3076
|
+
visited.add(run.runId);
|
|
3077
|
+
path15.push({
|
|
3078
|
+
runId: run.runId,
|
|
3079
|
+
name: run.name,
|
|
3080
|
+
startedAt: run.startedAt,
|
|
3081
|
+
durationMs: run.durationMs,
|
|
3082
|
+
confidence,
|
|
3083
|
+
source
|
|
3084
|
+
});
|
|
3085
|
+
};
|
|
3086
|
+
for (const edge of handoffs) {
|
|
3087
|
+
if (edge.confidence !== "explicit") continue;
|
|
3088
|
+
const fromRun = [...runById.values()].find(
|
|
3089
|
+
(run) => run.runId === edge.from || metaRunIdMatches(run, edge.from, runById)
|
|
3090
|
+
);
|
|
3091
|
+
const toRun = [...runById.values()].find(
|
|
3092
|
+
(run) => run.runId === edge.to || metaRunIdMatches(run, edge.to, runById)
|
|
3093
|
+
);
|
|
3094
|
+
if (fromRun) pushRun(fromRun, "explicit", "manual");
|
|
3095
|
+
if (toRun) pushRun(toRun, "explicit", "manual");
|
|
3096
|
+
}
|
|
3097
|
+
for (const run of ordered) {
|
|
3098
|
+
if (visited.has(run.runId)) continue;
|
|
3099
|
+
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3100
|
+
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3101
|
+
}
|
|
3102
|
+
return path15;
|
|
3103
|
+
}
|
|
3104
|
+
function metaRunIdMatches(run, token, runById) {
|
|
3105
|
+
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
3106
|
+
return meta?.subAgentId === token || meta?.groupId === token || runById.has(token);
|
|
3107
|
+
}
|
|
3108
|
+
function buildSessionIndex(inputRuns, options = {}) {
|
|
3109
|
+
const warnings = [];
|
|
3110
|
+
const runs = [...inputRuns].sort(compareRuns);
|
|
3111
|
+
const metaByRunId = /* @__PURE__ */ new Map();
|
|
3112
|
+
for (const run of runs) {
|
|
3113
|
+
metaByRunId.set(run.runId, extractSessionWorkflowMetadata(run.metadata));
|
|
3114
|
+
}
|
|
3115
|
+
const sessionsByKey = /* @__PURE__ */ new Map();
|
|
3116
|
+
const unscopedRunIds = [];
|
|
3117
|
+
for (const run of runs) {
|
|
3118
|
+
const meta = metaByRunId.get(run.runId);
|
|
3119
|
+
const key = sessionKeyForRun(meta, {
|
|
3120
|
+
correlateByGroupId: options.correlateByGroupId === true
|
|
3121
|
+
});
|
|
3122
|
+
if (!key) {
|
|
3123
|
+
unscopedRunIds.push(run.runId);
|
|
3124
|
+
continue;
|
|
3125
|
+
}
|
|
3126
|
+
const bucket = sessionsByKey.get(key) ?? [];
|
|
3127
|
+
bucket.push(run);
|
|
3128
|
+
sessionsByKey.set(key, bucket);
|
|
3129
|
+
}
|
|
3130
|
+
const sessions = [...sessionsByKey.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([sessionId, sessionRuns]) => {
|
|
3131
|
+
const runIds = sessionRuns.map((run) => run.runId).sort();
|
|
3132
|
+
const handoffs = buildHandoffs(runIds, metaByRunId, warnings, sessionId);
|
|
3133
|
+
const retries = buildRetries(runIds, metaByRunId, warnings, sessionId);
|
|
3134
|
+
const groups = buildGroups(runIds, metaByRunId);
|
|
3135
|
+
const criticalPath = buildCriticalPath(sessionRuns, handoffs);
|
|
3136
|
+
const confidences = new Set(handoffs.map((edge) => edge.confidence));
|
|
3137
|
+
if (confidences.has("explicit") && confidences.has("correlated")) {
|
|
3138
|
+
warnings.push({
|
|
3139
|
+
code: "mixed-confidence-group",
|
|
3140
|
+
message: "Session aggregates explicit and correlated handoff edges.",
|
|
3141
|
+
sessionId
|
|
3142
|
+
});
|
|
3143
|
+
}
|
|
3144
|
+
return {
|
|
3145
|
+
sessionId,
|
|
3146
|
+
runIds,
|
|
3147
|
+
groups,
|
|
3148
|
+
handoffs,
|
|
3149
|
+
retries,
|
|
3150
|
+
criticalPath
|
|
3151
|
+
};
|
|
3152
|
+
});
|
|
3153
|
+
if (sessions.length === 0 && runs.length > 0) {
|
|
3154
|
+
warnings.push({
|
|
3155
|
+
code: "missing-session-id",
|
|
3156
|
+
message: "No sessionId (or correlated groupId) found on input runs."
|
|
3157
|
+
});
|
|
3158
|
+
}
|
|
3159
|
+
warnings.sort((a, b) => {
|
|
3160
|
+
const code = a.code.localeCompare(b.code);
|
|
3161
|
+
if (code !== 0) return code;
|
|
3162
|
+
return (a.runId ?? "").localeCompare(b.runId ?? "");
|
|
3163
|
+
});
|
|
3164
|
+
return {
|
|
3165
|
+
runs,
|
|
3166
|
+
sessions,
|
|
3167
|
+
unscopedRunIds: unscopedRunIds.sort(),
|
|
3168
|
+
warnings
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
2696
3171
|
var KNOWN_EVENTS = /* @__PURE__ */ new Set([
|
|
2697
3172
|
"run_started",
|
|
2698
3173
|
"run_completed",
|
|
@@ -3714,13 +4189,13 @@ function persistedEventsForParsedTrace(parsed) {
|
|
|
3714
4189
|
function isRecord8(value) {
|
|
3715
4190
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3716
4191
|
}
|
|
3717
|
-
function
|
|
4192
|
+
function isNonEmptyString4(value) {
|
|
3718
4193
|
return typeof value === "string" && value.trim() !== "";
|
|
3719
4194
|
}
|
|
3720
4195
|
function readStringField(record, keys) {
|
|
3721
4196
|
for (const key of keys) {
|
|
3722
4197
|
const value = record[key];
|
|
3723
|
-
if (
|
|
4198
|
+
if (isNonEmptyString4(value)) return value;
|
|
3724
4199
|
}
|
|
3725
4200
|
return void 0;
|
|
3726
4201
|
}
|
|
@@ -3854,7 +4329,7 @@ function parseUnixNanoToIso(value) {
|
|
|
3854
4329
|
return void 0;
|
|
3855
4330
|
}
|
|
3856
4331
|
function parseIsoTime(value) {
|
|
3857
|
-
if (!
|
|
4332
|
+
if (!isNonEmptyString4(value)) return void 0;
|
|
3858
4333
|
const ms = Date.parse(value);
|
|
3859
4334
|
if (!Number.isFinite(ms)) return void 0;
|
|
3860
4335
|
return new Date(ms).toISOString();
|
|
@@ -8408,11 +8883,29 @@ async function searchCommand(options = {}) {
|
|
|
8408
8883
|
parseDurationFilter(options.duration);
|
|
8409
8884
|
}
|
|
8410
8885
|
const files = await td.list();
|
|
8411
|
-
|
|
8886
|
+
let metas = await loadTraceMetadataList(
|
|
8412
8887
|
traceDir,
|
|
8413
8888
|
files,
|
|
8414
8889
|
(f) => td.getPath(f)
|
|
8415
8890
|
);
|
|
8891
|
+
const sessionId = options.session?.trim();
|
|
8892
|
+
if (sessionId) {
|
|
8893
|
+
const records = await loadSessionRunRecords(metas);
|
|
8894
|
+
const scoped = filterMetasBySessionScope(metas, records, {
|
|
8895
|
+
sessionId,
|
|
8896
|
+
correlateByGroupId: options.correlateGroup === true
|
|
8897
|
+
});
|
|
8898
|
+
if (scoped.notFound) {
|
|
8899
|
+
if (options.json) {
|
|
8900
|
+
console.log(JSON.stringify([], null, 2));
|
|
8901
|
+
} else {
|
|
8902
|
+
console.log(`Session not found: ${sessionId}`);
|
|
8903
|
+
console.log(`Trace directory: ${traceDir}`);
|
|
8904
|
+
}
|
|
8905
|
+
return;
|
|
8906
|
+
}
|
|
8907
|
+
metas = scoped.metas;
|
|
8908
|
+
}
|
|
8416
8909
|
const status = options.status === "success" || options.status === "error" || options.status === "running" || options.status === "unknown" ? options.status : void 0;
|
|
8417
8910
|
const results = await searchTraces(metas, {
|
|
8418
8911
|
traceDir,
|
|
@@ -8423,7 +8916,9 @@ async function searchCommand(options = {}) {
|
|
|
8423
8916
|
name: options.name,
|
|
8424
8917
|
tool: options.tool,
|
|
8425
8918
|
duration: options.duration,
|
|
8426
|
-
limit: parseLimit2(options.limit)
|
|
8919
|
+
limit: parseLimit2(options.limit),
|
|
8920
|
+
...sessionId ? { session: sessionId } : {},
|
|
8921
|
+
...options.correlateGroup ? { correlateGroup: true } : {}
|
|
8427
8922
|
});
|
|
8428
8923
|
if (options.json) {
|
|
8429
8924
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -8451,6 +8946,184 @@ async function searchCommand(options = {}) {
|
|
|
8451
8946
|
}
|
|
8452
8947
|
}
|
|
8453
8948
|
|
|
8949
|
+
// packages/cli/src/sessions.ts
|
|
8950
|
+
async function loadSessionIndex(traceDir, correlateGroup) {
|
|
8951
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
8952
|
+
const files = await td.list();
|
|
8953
|
+
const metas = await loadTraceMetadataList(
|
|
8954
|
+
traceDir,
|
|
8955
|
+
files,
|
|
8956
|
+
(fileName) => td.getPath(fileName)
|
|
8957
|
+
);
|
|
8958
|
+
const runs = await loadSessionRunRecords(metas);
|
|
8959
|
+
return buildSessionIndex(runs, { correlateByGroupId: correlateGroup === true });
|
|
8960
|
+
}
|
|
8961
|
+
function findSession(index, sessionId) {
|
|
8962
|
+
return index.sessions.find((session) => session.sessionId === sessionId);
|
|
8963
|
+
}
|
|
8964
|
+
function renderSessionsHuman(index, traceDir) {
|
|
8965
|
+
if (index.sessions.length === 0) {
|
|
8966
|
+
console.log("No sessions found");
|
|
8967
|
+
console.log(`Trace directory: ${traceDir}`);
|
|
8968
|
+
if (index.unscopedRunIds.length > 0) {
|
|
8969
|
+
console.log(
|
|
8970
|
+
`Unscoped runs (no sessionId): ${index.unscopedRunIds.join(", ")}`
|
|
8971
|
+
);
|
|
8972
|
+
}
|
|
8973
|
+
return;
|
|
8974
|
+
}
|
|
8975
|
+
console.log("Sessions:");
|
|
8976
|
+
for (const session of index.sessions) {
|
|
8977
|
+
const firstRun = index.runs.find(
|
|
8978
|
+
(run) => session.runIds.includes(run.runId)
|
|
8979
|
+
);
|
|
8980
|
+
const workflowName = firstRun?.metadata && typeof firstRun.metadata.workflowName === "string" ? firstRun.metadata.workflowName : void 0;
|
|
8981
|
+
const suffix = workflowName ? ` workflow=${workflowName}` : "";
|
|
8982
|
+
console.log(
|
|
8983
|
+
` ${session.sessionId} (${session.runIds.length} run${session.runIds.length === 1 ? "" : "s"})${suffix}`
|
|
8984
|
+
);
|
|
8985
|
+
}
|
|
8986
|
+
if (index.unscopedRunIds.length > 0) {
|
|
8987
|
+
console.log("");
|
|
8988
|
+
console.log(
|
|
8989
|
+
`Unscoped runs (no sessionId): ${index.unscopedRunIds.join(", ")}`
|
|
8990
|
+
);
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
function renderSessionHuman(session, index, options) {
|
|
8994
|
+
console.log(`Session: ${session.sessionId}`);
|
|
8995
|
+
console.log(`Runs: ${session.runIds.join(", ")}`);
|
|
8996
|
+
if (session.handoffs.length > 0) {
|
|
8997
|
+
console.log("");
|
|
8998
|
+
console.log("Handoffs:");
|
|
8999
|
+
for (const edge of session.handoffs) {
|
|
9000
|
+
console.log(
|
|
9001
|
+
` ${edge.from} -> ${edge.to} (${edge.confidence}, ${edge.source})`
|
|
9002
|
+
);
|
|
9003
|
+
}
|
|
9004
|
+
}
|
|
9005
|
+
if (session.retries.length > 0) {
|
|
9006
|
+
console.log("");
|
|
9007
|
+
console.log("Retries:");
|
|
9008
|
+
for (const retry of session.retries) {
|
|
9009
|
+
const attempt = retry.attempt !== void 0 ? ` attempt=${retry.attempt}` : "";
|
|
9010
|
+
const of = retry.retryOf !== void 0 ? ` retryOf=${retry.retryOf}` : "";
|
|
9011
|
+
console.log(
|
|
9012
|
+
` ${retry.runId}${attempt}${of} (${retry.confidence})`
|
|
9013
|
+
);
|
|
9014
|
+
}
|
|
9015
|
+
}
|
|
9016
|
+
if (options.criticalPath && session.criticalPath.length > 0) {
|
|
9017
|
+
console.log("");
|
|
9018
|
+
console.log("Critical path:");
|
|
9019
|
+
for (const step of session.criticalPath) {
|
|
9020
|
+
const duration = step.durationMs !== void 0 ? ` ${step.durationMs}ms` : "";
|
|
9021
|
+
console.log(
|
|
9022
|
+
` ${step.runId}${step.name ? ` (${step.name})` : ""}${duration} [${step.confidence}]`
|
|
9023
|
+
);
|
|
9024
|
+
}
|
|
9025
|
+
}
|
|
9026
|
+
if (options.diagnostics && index.warnings.length > 0) {
|
|
9027
|
+
const scoped = index.warnings.filter(
|
|
9028
|
+
(warning) => warning.sessionId === session.sessionId || !warning.sessionId
|
|
9029
|
+
);
|
|
9030
|
+
if (scoped.length > 0) {
|
|
9031
|
+
console.log("");
|
|
9032
|
+
console.log("Diagnostics:");
|
|
9033
|
+
for (const warning of scoped) {
|
|
9034
|
+
const run = warning.runId ? ` run=${warning.runId}` : "";
|
|
9035
|
+
console.log(` [${warning.code}]${run} ${warning.message}`);
|
|
9036
|
+
}
|
|
9037
|
+
}
|
|
9038
|
+
}
|
|
9039
|
+
}
|
|
9040
|
+
async function sessionsCommand(options = {}) {
|
|
9041
|
+
try {
|
|
9042
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
9043
|
+
const index = await loadSessionIndex(traceDir, options.correlateGroup);
|
|
9044
|
+
if (options.json) {
|
|
9045
|
+
console.log(
|
|
9046
|
+
JSON.stringify(
|
|
9047
|
+
{
|
|
9048
|
+
traceDir,
|
|
9049
|
+
sessions: index.sessions,
|
|
9050
|
+
unscopedRunIds: index.unscopedRunIds,
|
|
9051
|
+
warnings: index.warnings
|
|
9052
|
+
},
|
|
9053
|
+
null,
|
|
9054
|
+
2
|
|
9055
|
+
)
|
|
9056
|
+
);
|
|
9057
|
+
return;
|
|
9058
|
+
}
|
|
9059
|
+
renderSessionsHuman(index, traceDir);
|
|
9060
|
+
} catch (e) {
|
|
9061
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
9062
|
+
console.error(`[AgentInspect] sessions failed: ${msg}`);
|
|
9063
|
+
process.exitCode = 1;
|
|
9064
|
+
}
|
|
9065
|
+
}
|
|
9066
|
+
async function sessionCommand(sessionId, options = {}) {
|
|
9067
|
+
const id = typeof sessionId === "string" && sessionId.trim() !== "" ? sessionId.trim() : "";
|
|
9068
|
+
if (id === "") {
|
|
9069
|
+
console.error("Session id is required");
|
|
9070
|
+
process.exitCode = 1;
|
|
9071
|
+
return;
|
|
9072
|
+
}
|
|
9073
|
+
try {
|
|
9074
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
9075
|
+
const index = await loadSessionIndex(traceDir);
|
|
9076
|
+
const session = findSession(index, id);
|
|
9077
|
+
if (!session) {
|
|
9078
|
+
console.log(`Session not found: ${id}`);
|
|
9079
|
+
console.log(`Trace directory: ${traceDir}`);
|
|
9080
|
+
process.exitCode = 1;
|
|
9081
|
+
return;
|
|
9082
|
+
}
|
|
9083
|
+
if (options.json) {
|
|
9084
|
+
const timelines = {};
|
|
9085
|
+
if (options.timeline) {
|
|
9086
|
+
for (const runId of session.runIds) {
|
|
9087
|
+
const result = await readRunTraceEvents(runId, traceDir);
|
|
9088
|
+
if (result && result.events.length > 0) {
|
|
9089
|
+
timelines[runId] = buildRunTimeline(result.events);
|
|
9090
|
+
}
|
|
9091
|
+
}
|
|
9092
|
+
}
|
|
9093
|
+
console.log(
|
|
9094
|
+
JSON.stringify(
|
|
9095
|
+
{
|
|
9096
|
+
traceDir,
|
|
9097
|
+
session,
|
|
9098
|
+
warnings: index.warnings.filter(
|
|
9099
|
+
(warning) => warning.sessionId === id || warning.sessionId === void 0
|
|
9100
|
+
),
|
|
9101
|
+
...options.timeline ? { timelines } : {}
|
|
9102
|
+
},
|
|
9103
|
+
null,
|
|
9104
|
+
2
|
|
9105
|
+
)
|
|
9106
|
+
);
|
|
9107
|
+
return;
|
|
9108
|
+
}
|
|
9109
|
+
renderSessionHuman(session, index, options);
|
|
9110
|
+
if (options.timeline) {
|
|
9111
|
+
for (const runId of session.runIds) {
|
|
9112
|
+
const result = await readRunTraceEvents(runId, traceDir);
|
|
9113
|
+
if (!result || result.events.length === 0) continue;
|
|
9114
|
+
const timeline = buildRunTimeline(result.events);
|
|
9115
|
+
console.log("");
|
|
9116
|
+
console.log(`Timeline: ${runId}`);
|
|
9117
|
+
console.log(renderTimeline(timeline));
|
|
9118
|
+
}
|
|
9119
|
+
}
|
|
9120
|
+
} catch (e) {
|
|
9121
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
9122
|
+
console.error(`[AgentInspect] session failed: ${msg}`);
|
|
9123
|
+
process.exitCode = 1;
|
|
9124
|
+
}
|
|
9125
|
+
}
|
|
9126
|
+
|
|
8454
9127
|
// packages/cli/src/what.ts
|
|
8455
9128
|
async function whatCommand(runId, options = {}) {
|
|
8456
9129
|
const id = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "";
|
|
@@ -9597,7 +10270,7 @@ function diagnostic(code, message, ruleId) {
|
|
|
9597
10270
|
...ruleId ? { ruleId } : {}
|
|
9598
10271
|
};
|
|
9599
10272
|
}
|
|
9600
|
-
function
|
|
10273
|
+
function emptySummary2() {
|
|
9601
10274
|
return {
|
|
9602
10275
|
passed: 0,
|
|
9603
10276
|
failed: 0,
|
|
@@ -9612,7 +10285,7 @@ function errorResult(input3, diagnostics, selectedRun) {
|
|
|
9612
10285
|
format: input3.read.format,
|
|
9613
10286
|
...selectedRun ? { runId: selectedRun.runId } : {},
|
|
9614
10287
|
summary: {
|
|
9615
|
-
...
|
|
10288
|
+
...emptySummary2(),
|
|
9616
10289
|
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
9617
10290
|
},
|
|
9618
10291
|
findings: [],
|
|
@@ -10953,6 +11626,13 @@ function printJson(result) {
|
|
|
10953
11626
|
console.log(JSON.stringify(stable2(result), null, 2));
|
|
10954
11627
|
}
|
|
10955
11628
|
function printHuman(result) {
|
|
11629
|
+
const scoped = result;
|
|
11630
|
+
if (scoped.scopeLabel) {
|
|
11631
|
+
console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
|
|
11632
|
+
if (scoped.runIds?.length) {
|
|
11633
|
+
console.log(`Runs: ${scoped.runIds.join(", ")}`);
|
|
11634
|
+
}
|
|
11635
|
+
}
|
|
10956
11636
|
console.log(`Check status: ${result.status}`);
|
|
10957
11637
|
console.log(`Format: ${result.format}`);
|
|
10958
11638
|
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
@@ -10964,7 +11644,9 @@ function printHuman(result) {
|
|
|
10964
11644
|
}
|
|
10965
11645
|
for (const finding of result.findings) {
|
|
10966
11646
|
const path15 = finding.evidence[0]?.path;
|
|
10967
|
-
|
|
11647
|
+
const run = finding.evidence[0]?.runId;
|
|
11648
|
+
const runPrefix = run ? `[${run}] ` : "";
|
|
11649
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
|
|
10968
11650
|
}
|
|
10969
11651
|
}
|
|
10970
11652
|
function readErrorResult(error) {
|
|
@@ -10980,12 +11662,58 @@ function readErrorResult(error) {
|
|
|
10980
11662
|
async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
10981
11663
|
let result;
|
|
10982
11664
|
let phase = "config";
|
|
11665
|
+
const sessionId = options.session?.trim();
|
|
11666
|
+
const groupId = options.group?.trim();
|
|
11667
|
+
const useSessionScope = Boolean(sessionId || groupId);
|
|
10983
11668
|
try {
|
|
10984
11669
|
const config = await loadConfig(options.config);
|
|
10985
11670
|
const built = buildRules(config, options);
|
|
10986
11671
|
if (built.diagnostics.some((item) => item.severity === "error")) {
|
|
10987
11672
|
result = errorResult2("AI_CHECK_INVALID_CONFIG", "Invalid check configuration.");
|
|
10988
11673
|
result.diagnostics = [...built.diagnostics];
|
|
11674
|
+
} else if (useSessionScope) {
|
|
11675
|
+
phase = "read";
|
|
11676
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
11677
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
11678
|
+
const files = await td.list();
|
|
11679
|
+
const metas = await loadTraceMetadataList(
|
|
11680
|
+
traceDir,
|
|
11681
|
+
files,
|
|
11682
|
+
(fileName) => td.getPath(fileName)
|
|
11683
|
+
);
|
|
11684
|
+
const records = await loadSessionRunRecords(metas);
|
|
11685
|
+
const scoped = filterMetasBySessionScope(metas, records, {
|
|
11686
|
+
...sessionId ? { sessionId } : {},
|
|
11687
|
+
...groupId ? { groupId } : {},
|
|
11688
|
+
correlateByGroupId: options.correlateGroup === true
|
|
11689
|
+
});
|
|
11690
|
+
const perRun = [];
|
|
11691
|
+
for (const meta of scoped.metas) {
|
|
11692
|
+
const read = await openTrace(
|
|
11693
|
+
{ type: "file", path: meta.filePath },
|
|
11694
|
+
{
|
|
11695
|
+
...options.format !== void 0 ? { format: options.format } : {}
|
|
11696
|
+
}
|
|
11697
|
+
);
|
|
11698
|
+
perRun.push(
|
|
11699
|
+
runTraceChecks(
|
|
11700
|
+
{ read },
|
|
11701
|
+
{
|
|
11702
|
+
rules: built.rules,
|
|
11703
|
+
select: built.select,
|
|
11704
|
+
runId: meta.runId
|
|
11705
|
+
}
|
|
11706
|
+
)
|
|
11707
|
+
);
|
|
11708
|
+
}
|
|
11709
|
+
result = aggregateSessionCheckResults(perRun, {
|
|
11710
|
+
scopeKind: scoped.scopeKind,
|
|
11711
|
+
scopeLabel: scoped.scopeLabel,
|
|
11712
|
+
runIds: scoped.runIds,
|
|
11713
|
+
sessionWarnings: scoped.warnings,
|
|
11714
|
+
notFound: scoped.notFound,
|
|
11715
|
+
empty: scoped.metas.length === 0
|
|
11716
|
+
});
|
|
10989
11717
|
} else {
|
|
10990
11718
|
phase = "read";
|
|
10991
11719
|
const input3 = await inputFromTarget(target, options, stdin);
|
|
@@ -12973,7 +13701,10 @@ function createCliProgram() {
|
|
|
12973
13701
|
]).option("--allowed-model <model>", "allow an LLM model (repeatable)", (value, previous = []) => [
|
|
12974
13702
|
...previous,
|
|
12975
13703
|
value
|
|
12976
|
-
]).option("--max-total-tokens <number>", "add llm.usage with a max total-token budget").
|
|
13704
|
+
]).option("--max-total-tokens <number>", "add llm.usage with a max total-token budget").option("--session <id>", "check all runs in a workflow session (requires --dir)").option("--group <id>", "check all runs sharing a groupId (requires --dir)").option(
|
|
13705
|
+
"--correlate-group",
|
|
13706
|
+
"when using --session, also match synthetic group: session keys"
|
|
13707
|
+
).action((target, opts) => {
|
|
12977
13708
|
runCommand(() => checkCommand(target, opts));
|
|
12978
13709
|
});
|
|
12979
13710
|
program.command("eval").description("Run deterministic local evals against a trace").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
|
|
@@ -13077,9 +13808,21 @@ function createCliProgram() {
|
|
|
13077
13808
|
).option("--kind <kind>", "filter by step kind/type (llm, tool, logic, \u2026)").option("--type <type>", "alias for --kind on manual trace step type").option("--name <query>", "substring match on run or step name").option("--tool <query>", "substring match on tool step name or metadata.toolName").option(
|
|
13078
13809
|
"--duration <expr>",
|
|
13079
13810
|
"duration filter on run or step (e.g. >5s, >=500ms)"
|
|
13080
|
-
).option("--limit <number>", "max results (default 50)").option("--
|
|
13811
|
+
).option("--limit <number>", "max results (default 50)").option("--session <id>", "limit search to one workflow session").option(
|
|
13812
|
+
"--correlate-group",
|
|
13813
|
+
"when using --session, also match synthetic group: keys"
|
|
13814
|
+
).option("--json", "print results as JSON").action((opts) => {
|
|
13081
13815
|
runCommand(() => searchCommand(opts));
|
|
13082
13816
|
});
|
|
13817
|
+
program.command("sessions").description("List workflow sessions grouped from local trace metadata (read-only)").option("--dir <path>", "trace directory").option(
|
|
13818
|
+
"--correlate-group",
|
|
13819
|
+
"treat shared groupId as a synthetic session when sessionId is absent"
|
|
13820
|
+
).option("--json", "print sessions index as JSON").action((opts) => {
|
|
13821
|
+
runCommand(() => sessionsCommand(opts));
|
|
13822
|
+
});
|
|
13823
|
+
program.command("session").description("Inspect one workflow session: runs, handoffs, retries (read-only)").argument("<session-id>", "session id (from sessions output)").option("--dir <path>", "trace directory").option("--timeline", "include per-run timelines").option("--critical-path", "include critical path section").option("--diagnostics", "include ambiguity warnings").option("--json", "print session view as JSON").action((sessionId, opts) => {
|
|
13824
|
+
runCommand(() => sessionCommand(sessionId, opts));
|
|
13825
|
+
});
|
|
13083
13826
|
program.command("what").description("Concise human-readable summary of a single run (local JSONL)").argument("<run-id>", "run id (e.g. from list output)").option("--dir <path>", "trace directory").option("--json", "print structured summary as JSON").option("--no-correlation", "omit correlation metadata from human output").action((runId, opts) => {
|
|
13084
13827
|
runCommand(() => whatCommand(runId, opts));
|
|
13085
13828
|
});
|