agent-inspect 1.8.0 → 1.9.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 +8 -0
- package/README.md +137 -18
- package/docs/ADAPTERS.md +41 -6
- package/docs/API.md +98 -12
- package/docs/CLI.md +35 -1
- package/docs/GETTING-STARTED.md +71 -16
- package/docs/LOG-TO-TREE-QUICKSTART.md +1 -2
- package/docs/MIGRATION.md +67 -0
- package/package.json +2 -2
- package/packages/cli/dist/index.cjs +338 -48
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +338 -48
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/index.cjs +146 -0
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +39 -2
- package/packages/core/dist/index.d.ts +39 -2
- package/packages/core/dist/index.mjs +148 -1
- package/packages/core/dist/index.mjs.map +1 -1
|
@@ -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 = "1.
|
|
26
|
+
var version = "1.9.0";
|
|
27
27
|
|
|
28
28
|
// packages/core/src/types.ts
|
|
29
29
|
var STEP_TYPES = [
|
|
@@ -4069,6 +4069,151 @@ ${attrsSection}
|
|
|
4069
4069
|
};
|
|
4070
4070
|
}
|
|
4071
4071
|
|
|
4072
|
+
// packages/core/src/explain.ts
|
|
4073
|
+
function flatten(nodes, out = []) {
|
|
4074
|
+
for (const node of nodes) {
|
|
4075
|
+
out.push({ node, index: out.length + 1 });
|
|
4076
|
+
flatten(node.children, out);
|
|
4077
|
+
}
|
|
4078
|
+
return out;
|
|
4079
|
+
}
|
|
4080
|
+
function redactValue(redactor, key, value) {
|
|
4081
|
+
return redactor.redactValue(key, value);
|
|
4082
|
+
}
|
|
4083
|
+
function fact(id, label, value, redactor) {
|
|
4084
|
+
return {
|
|
4085
|
+
id,
|
|
4086
|
+
label,
|
|
4087
|
+
value: redactValue(redactor, id.split(".").at(-1) ?? id, value),
|
|
4088
|
+
source: "trace",
|
|
4089
|
+
confidence: "observed"
|
|
4090
|
+
};
|
|
4091
|
+
}
|
|
4092
|
+
function topKinds(run) {
|
|
4093
|
+
return Object.entries(run.metadata.kinds).filter(([, count]) => count > 0).sort((a, b) => {
|
|
4094
|
+
if (b[1] !== a[1]) return b[1] - a[1];
|
|
4095
|
+
return a[0].localeCompare(b[0]);
|
|
4096
|
+
}).slice(0, 5).map(([kind, count]) => `${kind}:${count}`);
|
|
4097
|
+
}
|
|
4098
|
+
function countErrorNodes(nodes) {
|
|
4099
|
+
return nodes.filter((entry) => entry.node.event.status === "error").length;
|
|
4100
|
+
}
|
|
4101
|
+
function slowestNode(nodes) {
|
|
4102
|
+
return nodes.filter((entry) => entry.node.event.durationMs !== void 0).sort((a, b) => {
|
|
4103
|
+
const delta = (b.node.event.durationMs ?? 0) - (a.node.event.durationMs ?? 0);
|
|
4104
|
+
return delta !== 0 ? delta : a.index - b.index;
|
|
4105
|
+
})[0];
|
|
4106
|
+
}
|
|
4107
|
+
function attributeFacts(nodes, redactor) {
|
|
4108
|
+
const facts = [];
|
|
4109
|
+
for (const entry of nodes) {
|
|
4110
|
+
const attrs = entry.node.event.attributes;
|
|
4111
|
+
if (attrs === void 0) continue;
|
|
4112
|
+
for (const key of Object.keys(attrs).sort()) {
|
|
4113
|
+
facts.push({
|
|
4114
|
+
id: `node.${entry.index}.attributes.${key}`,
|
|
4115
|
+
label: `${entry.node.event.name} attribute ${key}`,
|
|
4116
|
+
value: redactValue(redactor, key, attrs[key]),
|
|
4117
|
+
source: "trace",
|
|
4118
|
+
confidence: "observed"
|
|
4119
|
+
});
|
|
4120
|
+
if (facts.length >= 8) return facts;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
return facts;
|
|
4124
|
+
}
|
|
4125
|
+
function buildFacts(run, redactor) {
|
|
4126
|
+
const nodes = flatten(run.children);
|
|
4127
|
+
const facts = [
|
|
4128
|
+
fact("run.id", "Run id", run.runId, redactor),
|
|
4129
|
+
fact("run.name", "Run name", run.name ?? run.runId, redactor),
|
|
4130
|
+
fact("run.status", "Run status", run.status ?? "unknown", redactor),
|
|
4131
|
+
fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
|
|
4132
|
+
fact("run.stepCount", "Top-level step count", run.children.length, redactor),
|
|
4133
|
+
fact("run.nodeCount", "Total node count", nodes.length, redactor),
|
|
4134
|
+
fact("run.errorNodeCount", "Error node count", countErrorNodes(nodes), redactor),
|
|
4135
|
+
fact("run.kinds", "Observed kind mix", topKinds(run), redactor)
|
|
4136
|
+
];
|
|
4137
|
+
if (run.durationMs !== void 0) {
|
|
4138
|
+
facts.push(fact("run.durationMs", "Run duration milliseconds", run.durationMs, redactor));
|
|
4139
|
+
}
|
|
4140
|
+
const slowest = slowestNode(nodes);
|
|
4141
|
+
if (slowest !== void 0) {
|
|
4142
|
+
facts.push(
|
|
4143
|
+
fact("run.slowestNode", "Slowest observed node", {
|
|
4144
|
+
name: slowest.node.event.name,
|
|
4145
|
+
kind: slowest.node.event.kind,
|
|
4146
|
+
durationMs: slowest.node.event.durationMs
|
|
4147
|
+
}, redactor)
|
|
4148
|
+
);
|
|
4149
|
+
}
|
|
4150
|
+
facts.push(...attributeFacts(nodes, redactor));
|
|
4151
|
+
return facts;
|
|
4152
|
+
}
|
|
4153
|
+
function buildInferences(run, facts) {
|
|
4154
|
+
const inferences = [];
|
|
4155
|
+
const errorFact = facts.find((item) => item.id === "run.errorNodeCount");
|
|
4156
|
+
const kindFact = facts.find((item) => item.id === "run.kinds");
|
|
4157
|
+
const durationFact = facts.find((item) => item.id === "run.durationMs");
|
|
4158
|
+
const errorNodeCount = typeof errorFact?.value === "number" ? errorFact.value : 0;
|
|
4159
|
+
if (run.status === "error" || errorNodeCount > 0) {
|
|
4160
|
+
inferences.push({
|
|
4161
|
+
id: "outcome.error",
|
|
4162
|
+
label: "Outcome",
|
|
4163
|
+
text: "The run recorded an error status or at least one error node.",
|
|
4164
|
+
evidence: ["run.status", "run.errorNodeCount"],
|
|
4165
|
+
confidence: "deterministic"
|
|
4166
|
+
});
|
|
4167
|
+
} else if (run.status === "ok") {
|
|
4168
|
+
inferences.push({
|
|
4169
|
+
id: "outcome.success",
|
|
4170
|
+
label: "Outcome",
|
|
4171
|
+
text: "The run completed without observed error nodes.",
|
|
4172
|
+
evidence: ["run.status", "run.errorNodeCount"],
|
|
4173
|
+
confidence: "deterministic"
|
|
4174
|
+
});
|
|
4175
|
+
}
|
|
4176
|
+
if (kindFact !== void 0) {
|
|
4177
|
+
inferences.push({
|
|
4178
|
+
id: "shape.kind-mix",
|
|
4179
|
+
label: "Trace shape",
|
|
4180
|
+
text: "The explanation is based on the observed event kind mix, not generated content.",
|
|
4181
|
+
evidence: [kindFact.id],
|
|
4182
|
+
confidence: "deterministic"
|
|
4183
|
+
});
|
|
4184
|
+
}
|
|
4185
|
+
if (durationFact !== void 0) {
|
|
4186
|
+
inferences.push({
|
|
4187
|
+
id: "timing.duration",
|
|
4188
|
+
label: "Timing",
|
|
4189
|
+
text: "Timing claims are limited to persisted duration fields in the trace.",
|
|
4190
|
+
evidence: [durationFact.id],
|
|
4191
|
+
confidence: "deterministic"
|
|
4192
|
+
});
|
|
4193
|
+
}
|
|
4194
|
+
return inferences;
|
|
4195
|
+
}
|
|
4196
|
+
function buildLocalExplanation(run, options = {}) {
|
|
4197
|
+
const redactionProfile = options.redactionProfile ?? "local";
|
|
4198
|
+
const resolved = resolveRedactionProfile(redactionProfile);
|
|
4199
|
+
const redactor = new Redactor({ extraKeys: resolved.extraKeys });
|
|
4200
|
+
const mode = options.mode ?? "local";
|
|
4201
|
+
const facts = buildFacts(run, redactor);
|
|
4202
|
+
return {
|
|
4203
|
+
mode,
|
|
4204
|
+
runId: String(redactValue(redactor, "runId", run.runId)),
|
|
4205
|
+
...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
|
|
4206
|
+
...run.status !== void 0 ? { status: run.status } : {},
|
|
4207
|
+
redactionProfile,
|
|
4208
|
+
facts,
|
|
4209
|
+
inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
|
|
4210
|
+
notes: [
|
|
4211
|
+
"Generated locally without provider or network calls.",
|
|
4212
|
+
"Facts are observed from normalized trace data; inferences are deterministic labels."
|
|
4213
|
+
]
|
|
4214
|
+
};
|
|
4215
|
+
}
|
|
4216
|
+
|
|
4072
4217
|
// packages/core/src/stats.ts
|
|
4073
4218
|
function percentile(sorted, p) {
|
|
4074
4219
|
if (sorted.length === 0) return void 0;
|
|
@@ -8958,9 +9103,164 @@ async function readStdin(stdin) {
|
|
|
8958
9103
|
}
|
|
8959
9104
|
return content;
|
|
8960
9105
|
}
|
|
9106
|
+
function isMissingFileError2(error) {
|
|
9107
|
+
return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
|
|
9108
|
+
}
|
|
9109
|
+
async function inputFromTarget(target, options, stdin) {
|
|
9110
|
+
if (target === "-") {
|
|
9111
|
+
return { type: "string", content: await readStdin(stdin) };
|
|
9112
|
+
}
|
|
9113
|
+
try {
|
|
9114
|
+
const stats2 = await promises.stat(target);
|
|
9115
|
+
if (stats2.isDirectory()) return { type: "directory", path: target };
|
|
9116
|
+
return { type: "file", path: target };
|
|
9117
|
+
} catch (error) {
|
|
9118
|
+
if (!isMissingFileError2(error)) throw error;
|
|
9119
|
+
}
|
|
9120
|
+
const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
|
|
9121
|
+
const stats = await promises.stat(runPath);
|
|
9122
|
+
if (stats.isDirectory()) return { type: "directory", path: runPath };
|
|
9123
|
+
return { type: "file", path: runPath };
|
|
9124
|
+
}
|
|
9125
|
+
|
|
9126
|
+
// packages/cli/src/explain.ts
|
|
9127
|
+
function parseRedactionProfile3(value) {
|
|
9128
|
+
const profile = (value ?? "local").trim().toLowerCase();
|
|
9129
|
+
if (profile === "local" || profile === "share" || profile === "strict") {
|
|
9130
|
+
return profile;
|
|
9131
|
+
}
|
|
9132
|
+
throw new Error(
|
|
9133
|
+
`Unsupported --redaction-profile "${value ?? ""}". Use local, share, or strict.`
|
|
9134
|
+
);
|
|
9135
|
+
}
|
|
9136
|
+
function selectRun(result, runId) {
|
|
9137
|
+
if (runId !== void 0) {
|
|
9138
|
+
return result.runs.find((run) => run.runId === runId);
|
|
9139
|
+
}
|
|
9140
|
+
return result.runs.length === 1 ? result.runs[0] : void 0;
|
|
9141
|
+
}
|
|
9142
|
+
function printMultipleRuns(result) {
|
|
9143
|
+
console.error(
|
|
9144
|
+
`Trace contains ${result.runs.length} runs. Re-run with --run <run-id>.`
|
|
9145
|
+
);
|
|
9146
|
+
for (const run of result.runs) {
|
|
9147
|
+
console.error(`- ${run.runId}${run.name !== void 0 ? ` name=${run.name}` : ""}`);
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
function renderHuman(result) {
|
|
9151
|
+
const lines = [
|
|
9152
|
+
`Explain: ${result.name ?? result.runId}`,
|
|
9153
|
+
`Mode: ${result.mode}`,
|
|
9154
|
+
`Status: ${result.status ?? "unknown"}`,
|
|
9155
|
+
`Redaction: ${result.redactionProfile}`,
|
|
9156
|
+
"",
|
|
9157
|
+
"Facts:"
|
|
9158
|
+
];
|
|
9159
|
+
for (const fact2 of result.facts) {
|
|
9160
|
+
lines.push(`- ${fact2.id}: ${JSON.stringify(fact2.value)}`);
|
|
9161
|
+
}
|
|
9162
|
+
lines.push("", "Inferences:");
|
|
9163
|
+
if (result.inferences.length === 0) {
|
|
9164
|
+
lines.push("- none");
|
|
9165
|
+
} else {
|
|
9166
|
+
for (const inference of result.inferences) {
|
|
9167
|
+
lines.push(`- ${inference.label}: ${inference.text}`);
|
|
9168
|
+
}
|
|
9169
|
+
}
|
|
9170
|
+
lines.push("", "Notes:");
|
|
9171
|
+
for (const note of result.notes) {
|
|
9172
|
+
lines.push(`- ${note}`);
|
|
9173
|
+
}
|
|
9174
|
+
return lines.join("\n");
|
|
9175
|
+
}
|
|
9176
|
+
function writeJson(result) {
|
|
9177
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9178
|
+
}
|
|
9179
|
+
function rejectProvider(provider, json) {
|
|
9180
|
+
process.exitCode = 1;
|
|
9181
|
+
const message = `Provider explain is not implemented in this build: ${provider}. Use --dry-run to inspect the redacted local payload.`;
|
|
9182
|
+
if (json) {
|
|
9183
|
+
writeJson({
|
|
9184
|
+
ok: false,
|
|
9185
|
+
error: { code: "PROVIDER_NOT_IMPLEMENTED", message }
|
|
9186
|
+
});
|
|
9187
|
+
return;
|
|
9188
|
+
}
|
|
9189
|
+
console.error(message);
|
|
9190
|
+
}
|
|
9191
|
+
async function explainCommand(target, options = {}, stdin = process.stdin) {
|
|
9192
|
+
if (options.provider !== void 0) {
|
|
9193
|
+
rejectProvider(options.provider, options.json);
|
|
9194
|
+
return;
|
|
9195
|
+
}
|
|
9196
|
+
let redactionProfile;
|
|
9197
|
+
try {
|
|
9198
|
+
redactionProfile = parseRedactionProfile3(options.redactionProfile);
|
|
9199
|
+
} catch (error) {
|
|
9200
|
+
process.exitCode = 1;
|
|
9201
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
9202
|
+
return;
|
|
9203
|
+
}
|
|
9204
|
+
try {
|
|
9205
|
+
const input3 = await inputFromTarget(target, options, stdin);
|
|
9206
|
+
const read = await openTrace(input3, {
|
|
9207
|
+
...options.format !== void 0 ? { format: options.format } : {}
|
|
9208
|
+
});
|
|
9209
|
+
const selected = selectRun(read, options.run);
|
|
9210
|
+
if (selected === void 0) {
|
|
9211
|
+
process.exitCode = 1;
|
|
9212
|
+
const message = options.run !== void 0 ? `Run not found: ${options.run}` : `Trace contains ${read.runs.length} runs. Specify --run <run-id>.`;
|
|
9213
|
+
if (options.json) {
|
|
9214
|
+
writeJson({ ok: false, error: { message }, runs: read.runs });
|
|
9215
|
+
} else if (options.run !== void 0) {
|
|
9216
|
+
console.error(message);
|
|
9217
|
+
} else {
|
|
9218
|
+
printMultipleRuns(read);
|
|
9219
|
+
}
|
|
9220
|
+
return;
|
|
9221
|
+
}
|
|
9222
|
+
const mode = options.dryRun ? "dry-run" : "local";
|
|
9223
|
+
const explanation = buildLocalExplanation(selected, {
|
|
9224
|
+
mode,
|
|
9225
|
+
redactionProfile
|
|
9226
|
+
});
|
|
9227
|
+
if (options.json) {
|
|
9228
|
+
writeJson({
|
|
9229
|
+
ok: true,
|
|
9230
|
+
format: read.format,
|
|
9231
|
+
sourceFiles: read.sourceFiles,
|
|
9232
|
+
warnings: read.warnings,
|
|
9233
|
+
unsupportedFields: read.unsupportedFields,
|
|
9234
|
+
explanation
|
|
9235
|
+
});
|
|
9236
|
+
return;
|
|
9237
|
+
}
|
|
9238
|
+
console.log(renderHuman(explanation));
|
|
9239
|
+
} catch (error) {
|
|
9240
|
+
process.exitCode = 1;
|
|
9241
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9242
|
+
const code = error instanceof TraceReadError ? error.code : void 0;
|
|
9243
|
+
if (options.json) {
|
|
9244
|
+
writeJson({
|
|
9245
|
+
ok: false,
|
|
9246
|
+
error: { ...code !== void 0 ? { code } : {}, message }
|
|
9247
|
+
});
|
|
9248
|
+
return;
|
|
9249
|
+
}
|
|
9250
|
+
console.error(message);
|
|
9251
|
+
}
|
|
9252
|
+
}
|
|
9253
|
+
async function readStdin2(stdin) {
|
|
9254
|
+
stdin.setEncoding("utf8");
|
|
9255
|
+
let content = "";
|
|
9256
|
+
for await (const chunk of stdin) {
|
|
9257
|
+
content += typeof chunk === "string" ? chunk : String(chunk);
|
|
9258
|
+
}
|
|
9259
|
+
return content;
|
|
9260
|
+
}
|
|
8961
9261
|
async function inputFromPathOrStdin(input3, stdin) {
|
|
8962
9262
|
if (input3 === void 0 || input3 === "-") {
|
|
8963
|
-
return { type: "string", content: await
|
|
9263
|
+
return { type: "string", content: await readStdin2(stdin) };
|
|
8964
9264
|
}
|
|
8965
9265
|
const stats = await promises.stat(input3);
|
|
8966
9266
|
if (stats.isDirectory()) return { type: "directory", path: input3 };
|
|
@@ -9011,13 +9311,13 @@ function printRun(result, run) {
|
|
|
9011
9311
|
printNode(node, 0);
|
|
9012
9312
|
}
|
|
9013
9313
|
}
|
|
9014
|
-
function
|
|
9314
|
+
function selectRun2(result, runId) {
|
|
9015
9315
|
if (runId !== void 0) {
|
|
9016
9316
|
return result.runs.find((run) => run.runId === runId);
|
|
9017
9317
|
}
|
|
9018
9318
|
return result.runs.length === 1 ? result.runs[0] : void 0;
|
|
9019
9319
|
}
|
|
9020
|
-
function
|
|
9320
|
+
function printMultipleRuns2(result) {
|
|
9021
9321
|
console.error(
|
|
9022
9322
|
`Trace contains ${result.runs.length} runs. Re-run with --run <run-id>.`
|
|
9023
9323
|
);
|
|
@@ -9031,7 +9331,7 @@ function printMultipleRuns(result) {
|
|
|
9031
9331
|
console.error(`- ${bits.join(" ")}`);
|
|
9032
9332
|
}
|
|
9033
9333
|
}
|
|
9034
|
-
function
|
|
9334
|
+
function writeJson2(output2) {
|
|
9035
9335
|
console.log(JSON.stringify(output2, null, 2));
|
|
9036
9336
|
}
|
|
9037
9337
|
async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
@@ -9040,12 +9340,12 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
|
9040
9340
|
const result = await openTrace(traceInput, {
|
|
9041
9341
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
9042
9342
|
});
|
|
9043
|
-
const selected =
|
|
9343
|
+
const selected = selectRun2(result, options.run);
|
|
9044
9344
|
if (selected === void 0) {
|
|
9045
9345
|
process.exitCode = 1;
|
|
9046
9346
|
const message = options.run !== void 0 ? `Run not found: ${options.run}` : `Trace contains ${result.runs.length} runs. Specify --run <run-id>.`;
|
|
9047
9347
|
if (options.json) {
|
|
9048
|
-
|
|
9348
|
+
writeJson2({
|
|
9049
9349
|
format: result.format,
|
|
9050
9350
|
sourceFiles: result.sourceFiles,
|
|
9051
9351
|
warnings: result.warnings,
|
|
@@ -9056,12 +9356,12 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
|
9056
9356
|
} else if (options.run !== void 0) {
|
|
9057
9357
|
console.error(message);
|
|
9058
9358
|
} else {
|
|
9059
|
-
|
|
9359
|
+
printMultipleRuns2(result);
|
|
9060
9360
|
}
|
|
9061
9361
|
return;
|
|
9062
9362
|
}
|
|
9063
9363
|
if (options.json) {
|
|
9064
|
-
|
|
9364
|
+
writeJson2({
|
|
9065
9365
|
format: result.format,
|
|
9066
9366
|
sourceFiles: result.sourceFiles,
|
|
9067
9367
|
warnings: result.warnings,
|
|
@@ -9081,7 +9381,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
|
9081
9381
|
const code = error instanceof TraceReadError ? error.code : void 0;
|
|
9082
9382
|
const warnings = error instanceof TraceReadError ? error.warnings : [];
|
|
9083
9383
|
if (options.json) {
|
|
9084
|
-
|
|
9384
|
+
writeJson2({
|
|
9085
9385
|
warnings,
|
|
9086
9386
|
error: { ...code !== void 0 ? { code } : {}, message }
|
|
9087
9387
|
});
|
|
@@ -9185,7 +9485,7 @@ function errorResult(input3, diagnostics, selectedRun) {
|
|
|
9185
9485
|
function flattenNodes(nodes) {
|
|
9186
9486
|
return nodes.flatMap((node) => [node, ...flattenNodes(node.children)]);
|
|
9187
9487
|
}
|
|
9188
|
-
function
|
|
9488
|
+
function buildFacts2(input3, selectedRun) {
|
|
9189
9489
|
const scopedRuns = selectedRun ? [selectedRun] : input3.read.runs;
|
|
9190
9490
|
const scopedRunIds = new Set(scopedRuns.map((run) => run.runId));
|
|
9191
9491
|
const scopedEvents = selectedRun === void 0 ? input3.read.events : input3.read.events.filter((event) => scopedRunIds.has(event.runId));
|
|
@@ -10193,7 +10493,7 @@ function createBaselineRegressionRule(options) {
|
|
|
10193
10493
|
)
|
|
10194
10494
|
];
|
|
10195
10495
|
}
|
|
10196
|
-
const baselineFacts =
|
|
10496
|
+
const baselineFacts = buildFacts2(options.baseline, baselineSelection.run);
|
|
10197
10497
|
const baselineContext = {
|
|
10198
10498
|
...baselineFacts,
|
|
10199
10499
|
selectedRun: baselineSelection.run,
|
|
@@ -10312,7 +10612,7 @@ function runTraceChecks(input3, options = {}) {
|
|
|
10312
10612
|
if (rules.diagnostics.length > 0) {
|
|
10313
10613
|
return errorResult(input3, rules.diagnostics, selected.run);
|
|
10314
10614
|
}
|
|
10315
|
-
const facts =
|
|
10615
|
+
const facts = buildFacts2(input3, selected.run);
|
|
10316
10616
|
const context = {
|
|
10317
10617
|
...facts,
|
|
10318
10618
|
...selected.run ? { selectedRun: selected.run } : {},
|
|
@@ -10347,33 +10647,6 @@ function runTraceChecks(input3, options = {}) {
|
|
|
10347
10647
|
diagnostics
|
|
10348
10648
|
};
|
|
10349
10649
|
}
|
|
10350
|
-
async function readStdin2(stdin) {
|
|
10351
|
-
stdin.setEncoding("utf8");
|
|
10352
|
-
let content = "";
|
|
10353
|
-
for await (const chunk of stdin) {
|
|
10354
|
-
content += typeof chunk === "string" ? chunk : String(chunk);
|
|
10355
|
-
}
|
|
10356
|
-
return content;
|
|
10357
|
-
}
|
|
10358
|
-
function isMissingFileError2(error) {
|
|
10359
|
-
return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
|
|
10360
|
-
}
|
|
10361
|
-
async function inputFromTarget(target, options, stdin) {
|
|
10362
|
-
if (target === "-") {
|
|
10363
|
-
return { type: "string", content: await readStdin2(stdin) };
|
|
10364
|
-
}
|
|
10365
|
-
try {
|
|
10366
|
-
const stats2 = await promises.stat(target);
|
|
10367
|
-
if (stats2.isDirectory()) return { type: "directory", path: target };
|
|
10368
|
-
return { type: "file", path: target };
|
|
10369
|
-
} catch (error) {
|
|
10370
|
-
if (!isMissingFileError2(error)) throw error;
|
|
10371
|
-
}
|
|
10372
|
-
const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
|
|
10373
|
-
const stats = await promises.stat(runPath);
|
|
10374
|
-
if (stats.isDirectory()) return { type: "directory", path: runPath };
|
|
10375
|
-
return { type: "file", path: runPath };
|
|
10376
|
-
}
|
|
10377
10650
|
|
|
10378
10651
|
// packages/cli/src/check.ts
|
|
10379
10652
|
var DEFAULT_SELECT = ["run.status"];
|
|
@@ -10820,7 +11093,7 @@ function stable3(value) {
|
|
|
10820
11093
|
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
|
|
10821
11094
|
);
|
|
10822
11095
|
}
|
|
10823
|
-
function
|
|
11096
|
+
function writeJson3(value) {
|
|
10824
11097
|
return `${JSON.stringify(stable3(value), null, 2)}
|
|
10825
11098
|
`;
|
|
10826
11099
|
}
|
|
@@ -10838,7 +11111,7 @@ function increment(record, key) {
|
|
|
10838
11111
|
const label = key && key.trim() !== "" ? key : "unknown";
|
|
10839
11112
|
record[label] = (record[label] ?? 0) + 1;
|
|
10840
11113
|
}
|
|
10841
|
-
function
|
|
11114
|
+
function selectRun3(read, runId) {
|
|
10842
11115
|
if (runId !== void 0) {
|
|
10843
11116
|
return read.runs.find((run) => run.runId === runId);
|
|
10844
11117
|
}
|
|
@@ -10986,7 +11259,7 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
10986
11259
|
process.exitCode = 1;
|
|
10987
11260
|
return;
|
|
10988
11261
|
}
|
|
10989
|
-
const selectedRun =
|
|
11262
|
+
const selectedRun = selectRun3(read, options.run);
|
|
10990
11263
|
const check = runTraceChecks(
|
|
10991
11264
|
{ read },
|
|
10992
11265
|
{
|
|
@@ -11023,12 +11296,12 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
11023
11296
|
}
|
|
11024
11297
|
const files = [];
|
|
11025
11298
|
await promises.mkdir(outputDir, { recursive: true });
|
|
11026
|
-
await writeArtifact(outputDir, "trace.json",
|
|
11027
|
-
await writeArtifact(outputDir, "check.json",
|
|
11299
|
+
await writeArtifact(outputDir, "trace.json", writeJson3(trace), files);
|
|
11300
|
+
await writeArtifact(outputDir, "check.json", writeJson3(check), files);
|
|
11028
11301
|
await writeArtifact(
|
|
11029
11302
|
outputDir,
|
|
11030
11303
|
"diff.json",
|
|
11031
|
-
|
|
11304
|
+
writeJson3(diff ?? { status: "not_requested", findings: [], diagnostics: [] }),
|
|
11032
11305
|
files
|
|
11033
11306
|
);
|
|
11034
11307
|
await writeArtifact(outputDir, "summary.md", renderMarkdown(trace, check, diff), files);
|
|
@@ -11058,9 +11331,9 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
11058
11331
|
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path10__default.default.resolve(summaryTarget) } : {},
|
|
11059
11332
|
note: NOTE
|
|
11060
11333
|
};
|
|
11061
|
-
await promises.writeFile(path10__default.default.join(outputDir, "manifest.json"),
|
|
11334
|
+
await promises.writeFile(path10__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
11062
11335
|
if (options.json === true) {
|
|
11063
|
-
console.log(
|
|
11336
|
+
console.log(writeJson3(manifest).trimEnd());
|
|
11064
11337
|
} else {
|
|
11065
11338
|
console.log(`Wrote AgentInspect artifacts to ${outputDir}`);
|
|
11066
11339
|
console.log(`Status: ${manifest.status}`);
|
|
@@ -11279,6 +11552,23 @@ function createCliProgram() {
|
|
|
11279
11552
|
).action((runId, opts) => {
|
|
11280
11553
|
runCommand(() => reportCommand(runId, opts));
|
|
11281
11554
|
});
|
|
11555
|
+
program.command("explain").description("Explain a local trace with deterministic facts (no provider calls)").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
|
|
11556
|
+
new commander.Option("--format <format>", "trace input format").choices([
|
|
11557
|
+
"agent-inspect-jsonl",
|
|
11558
|
+
"openinference-json",
|
|
11559
|
+
"otlp-json"
|
|
11560
|
+
])
|
|
11561
|
+
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--dry-run", "emit only the local facts payload that a provider could receive").option(
|
|
11562
|
+
"--provider <provider>",
|
|
11563
|
+
"reserved for explicit provider explain; currently rejected without network calls"
|
|
11564
|
+
).option("--json", "print deterministic JSON explanation result").addOption(
|
|
11565
|
+
new commander.Option(
|
|
11566
|
+
"--redaction-profile <profile>",
|
|
11567
|
+
"redaction profile for explanation payload: local, share, strict (default: local)"
|
|
11568
|
+
).choices(["local", "share", "strict"])
|
|
11569
|
+
).action((target, opts) => {
|
|
11570
|
+
runCommand(() => explainCommand(target, opts));
|
|
11571
|
+
});
|
|
11282
11572
|
return program;
|
|
11283
11573
|
}
|
|
11284
11574
|
function isPrimaryModule() {
|