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.
@@ -4613,6 +4613,151 @@ ${attrsSection}
4613
4613
  };
4614
4614
  }
4615
4615
 
4616
+ // packages/core/src/explain.ts
4617
+ function flatten(nodes, out = []) {
4618
+ for (const node of nodes) {
4619
+ out.push({ node, index: out.length + 1 });
4620
+ flatten(node.children, out);
4621
+ }
4622
+ return out;
4623
+ }
4624
+ function redactValue(redactor, key, value) {
4625
+ return redactor.redactValue(key, value);
4626
+ }
4627
+ function fact(id, label, value, redactor) {
4628
+ return {
4629
+ id,
4630
+ label,
4631
+ value: redactValue(redactor, id.split(".").at(-1) ?? id, value),
4632
+ source: "trace",
4633
+ confidence: "observed"
4634
+ };
4635
+ }
4636
+ function topKinds(run) {
4637
+ return Object.entries(run.metadata.kinds).filter(([, count]) => count > 0).sort((a, b) => {
4638
+ if (b[1] !== a[1]) return b[1] - a[1];
4639
+ return a[0].localeCompare(b[0]);
4640
+ }).slice(0, 5).map(([kind, count]) => `${kind}:${count}`);
4641
+ }
4642
+ function countErrorNodes(nodes) {
4643
+ return nodes.filter((entry) => entry.node.event.status === "error").length;
4644
+ }
4645
+ function slowestNode(nodes) {
4646
+ return nodes.filter((entry) => entry.node.event.durationMs !== void 0).sort((a, b) => {
4647
+ const delta = (b.node.event.durationMs ?? 0) - (a.node.event.durationMs ?? 0);
4648
+ return delta !== 0 ? delta : a.index - b.index;
4649
+ })[0];
4650
+ }
4651
+ function attributeFacts(nodes, redactor) {
4652
+ const facts = [];
4653
+ for (const entry of nodes) {
4654
+ const attrs = entry.node.event.attributes;
4655
+ if (attrs === void 0) continue;
4656
+ for (const key of Object.keys(attrs).sort()) {
4657
+ facts.push({
4658
+ id: `node.${entry.index}.attributes.${key}`,
4659
+ label: `${entry.node.event.name} attribute ${key}`,
4660
+ value: redactValue(redactor, key, attrs[key]),
4661
+ source: "trace",
4662
+ confidence: "observed"
4663
+ });
4664
+ if (facts.length >= 8) return facts;
4665
+ }
4666
+ }
4667
+ return facts;
4668
+ }
4669
+ function buildFacts(run, redactor) {
4670
+ const nodes = flatten(run.children);
4671
+ const facts = [
4672
+ fact("run.id", "Run id", run.runId, redactor),
4673
+ fact("run.name", "Run name", run.name ?? run.runId, redactor),
4674
+ fact("run.status", "Run status", run.status ?? "unknown", redactor),
4675
+ fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
4676
+ fact("run.stepCount", "Top-level step count", run.children.length, redactor),
4677
+ fact("run.nodeCount", "Total node count", nodes.length, redactor),
4678
+ fact("run.errorNodeCount", "Error node count", countErrorNodes(nodes), redactor),
4679
+ fact("run.kinds", "Observed kind mix", topKinds(run), redactor)
4680
+ ];
4681
+ if (run.durationMs !== void 0) {
4682
+ facts.push(fact("run.durationMs", "Run duration milliseconds", run.durationMs, redactor));
4683
+ }
4684
+ const slowest = slowestNode(nodes);
4685
+ if (slowest !== void 0) {
4686
+ facts.push(
4687
+ fact("run.slowestNode", "Slowest observed node", {
4688
+ name: slowest.node.event.name,
4689
+ kind: slowest.node.event.kind,
4690
+ durationMs: slowest.node.event.durationMs
4691
+ }, redactor)
4692
+ );
4693
+ }
4694
+ facts.push(...attributeFacts(nodes, redactor));
4695
+ return facts;
4696
+ }
4697
+ function buildInferences(run, facts) {
4698
+ const inferences = [];
4699
+ const errorFact = facts.find((item) => item.id === "run.errorNodeCount");
4700
+ const kindFact = facts.find((item) => item.id === "run.kinds");
4701
+ const durationFact = facts.find((item) => item.id === "run.durationMs");
4702
+ const errorNodeCount = typeof errorFact?.value === "number" ? errorFact.value : 0;
4703
+ if (run.status === "error" || errorNodeCount > 0) {
4704
+ inferences.push({
4705
+ id: "outcome.error",
4706
+ label: "Outcome",
4707
+ text: "The run recorded an error status or at least one error node.",
4708
+ evidence: ["run.status", "run.errorNodeCount"],
4709
+ confidence: "deterministic"
4710
+ });
4711
+ } else if (run.status === "ok") {
4712
+ inferences.push({
4713
+ id: "outcome.success",
4714
+ label: "Outcome",
4715
+ text: "The run completed without observed error nodes.",
4716
+ evidence: ["run.status", "run.errorNodeCount"],
4717
+ confidence: "deterministic"
4718
+ });
4719
+ }
4720
+ if (kindFact !== void 0) {
4721
+ inferences.push({
4722
+ id: "shape.kind-mix",
4723
+ label: "Trace shape",
4724
+ text: "The explanation is based on the observed event kind mix, not generated content.",
4725
+ evidence: [kindFact.id],
4726
+ confidence: "deterministic"
4727
+ });
4728
+ }
4729
+ if (durationFact !== void 0) {
4730
+ inferences.push({
4731
+ id: "timing.duration",
4732
+ label: "Timing",
4733
+ text: "Timing claims are limited to persisted duration fields in the trace.",
4734
+ evidence: [durationFact.id],
4735
+ confidence: "deterministic"
4736
+ });
4737
+ }
4738
+ return inferences;
4739
+ }
4740
+ function buildLocalExplanation(run, options = {}) {
4741
+ const redactionProfile = options.redactionProfile ?? "local";
4742
+ const resolved = resolveRedactionProfile(redactionProfile);
4743
+ const redactor = new Redactor({ extraKeys: resolved.extraKeys });
4744
+ const mode = options.mode ?? "local";
4745
+ const facts = buildFacts(run, redactor);
4746
+ return {
4747
+ mode,
4748
+ runId: String(redactValue(redactor, "runId", run.runId)),
4749
+ ...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
4750
+ ...run.status !== void 0 ? { status: run.status } : {},
4751
+ redactionProfile,
4752
+ facts,
4753
+ inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
4754
+ notes: [
4755
+ "Generated locally without provider or network calls.",
4756
+ "Facts are observed from normalized trace data; inferences are deterministic labels."
4757
+ ]
4758
+ };
4759
+ }
4760
+
4616
4761
  // packages/core/src/stats.ts
4617
4762
  function percentile(sorted, p) {
4618
4763
  if (sorted.length === 0) return void 0;
@@ -9214,6 +9359,7 @@ exports.TraceReadError = TraceReadError;
9214
9359
  exports.TreeBuilder = TreeBuilder;
9215
9360
  exports.agentInspectJsonlReader = agentInspectJsonlReader;
9216
9361
  exports.bufferedFileWriter = bufferedFileWriter;
9362
+ exports.buildLocalExplanation = buildLocalExplanation;
9217
9363
  exports.buildRunReport = buildRunReport;
9218
9364
  exports.buildRunSummary = buildRunSummary;
9219
9365
  exports.buildRunTimeline = buildRunTimeline;