agentfootprint-lens 0.38.0 → 0.40.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.
Files changed (56) hide show
  1. package/README.md +28 -3
  2. package/dist/chunk-2JAWSPNG.js +73 -0
  3. package/dist/chunk-2JAWSPNG.js.map +1 -0
  4. package/dist/{chunk-V35KQPQA.js → chunk-CHFRN2WV.js} +498 -2309
  5. package/dist/chunk-CHFRN2WV.js.map +1 -0
  6. package/dist/{chunk-KQOLJKKM.js → chunk-DEG2NT22.js} +5 -70
  7. package/dist/chunk-DEG2NT22.js.map +1 -0
  8. package/dist/chunk-EBQCTQQU.js +536 -0
  9. package/dist/chunk-EBQCTQQU.js.map +1 -0
  10. package/dist/chunk-EYCTYBSV.js +1053 -0
  11. package/dist/chunk-EYCTYBSV.js.map +1 -0
  12. package/dist/chunk-L2Z6HTJI.js +4159 -0
  13. package/dist/chunk-L2Z6HTJI.js.map +1 -0
  14. package/dist/chunk-P4F3RGXR.js +1192 -0
  15. package/dist/chunk-P4F3RGXR.js.map +1 -0
  16. package/dist/chunk-S7FLEXJ3.js +1329 -0
  17. package/dist/chunk-S7FLEXJ3.js.map +1 -0
  18. package/dist/copyForLLM-4K52C7AR.js +8 -0
  19. package/dist/core.cjs +419 -1
  20. package/dist/core.cjs.map +1 -1
  21. package/dist/core.d.cts +2885 -7
  22. package/dist/core.d.ts +2885 -7
  23. package/dist/core.js +60 -46
  24. package/dist/index.cjs +4021 -3817
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +24 -662
  27. package/dist/index.d.ts +24 -662
  28. package/dist/index.js +964 -7010
  29. package/dist/index.js.map +1 -1
  30. package/dist/selectSkillFrameContext-DdObTJz3.d.cts +617 -0
  31. package/dist/selectSkillFrameContext-Hjjf75t9.d.ts +617 -0
  32. package/dist/skillgraph.cjs +2712 -0
  33. package/dist/skillgraph.cjs.map +1 -0
  34. package/dist/skillgraph.d.cts +134 -0
  35. package/dist/skillgraph.d.ts +134 -0
  36. package/dist/skillgraph.js +24 -0
  37. package/dist/skillgraph.js.map +1 -0
  38. package/dist/stepForCommitIdx-PnR_Kael.d.ts +408 -0
  39. package/dist/stepForCommitIdx-feXP5i-2.d.cts +408 -0
  40. package/dist/stepForRuntimeStageId-Bl6cG9wB.d.cts +981 -0
  41. package/dist/stepForRuntimeStageId-Bl6cG9wB.d.ts +981 -0
  42. package/dist/useCursorPositions-B1HJiarC.d.ts +595 -0
  43. package/dist/useCursorPositions-CF9RDUw0.d.cts +595 -0
  44. package/dist/why.cjs +7780 -0
  45. package/dist/why.cjs.map +1 -0
  46. package/dist/why.d.cts +121 -0
  47. package/dist/why.d.ts +121 -0
  48. package/dist/why.js +66 -0
  49. package/dist/why.js.map +1 -0
  50. package/package.json +27 -1
  51. package/dist/chunk-KQOLJKKM.js.map +0 -1
  52. package/dist/chunk-V35KQPQA.js.map +0 -1
  53. package/dist/copyForLLM-RI3N2LM6.js +0 -7
  54. package/dist/index-ELSDgS1H.d.cts +0 -4710
  55. package/dist/index-ELSDgS1H.d.ts +0 -4710
  56. /package/dist/{copyForLLM-RI3N2LM6.js.map → copyForLLM-4K52C7AR.js.map} +0 -0
package/README.md CHANGED
@@ -68,6 +68,28 @@ Swap `mock(...)` for `anthropic(...)` / `openai(...)` / `ollama(...)` from
68
68
 
69
69
  ---
70
70
 
71
+ ## Doors
72
+
73
+ Two subpath imports name the lens you are mounting. They are additions —
74
+ everything behind them is also on the root barrel, and the root barrel never
75
+ changes.
76
+
77
+ | import | the job |
78
+ |---|---|
79
+ | `agentfootprint-lens/why` | Replay a recording as the agent's own milestones. `<WhyLens recording={...} />` takes the recording straight (`recordRun()`'s `{ snapshot, events, structure }`, or the `persistRecording` envelope), validates it at mount, and mounts the shipped `<Lens>` shell on the milestone axis — plus the axis helpers (`scrubAxisFor`, `stepForCommitIdx`, `stepForRuntimeStageId`) for hosts holding one cursor across views. |
80
+ | `agentfootprint-lens/skillgraph` | Debug how a run routed through its skills. `<SkillGraphDebugger recorder={...} />` plus its headless selectors (`selectSkillRoute`, `selectSkillBeats`, `selectSkillTopology`, `selectSkillFrameContext`, `stepForRuntimeStageId`). |
81
+
82
+ The axis model in three sentences: one run leaves one causal trace, and each
83
+ lens replays one AXIS of it — the Why reading scrubs the milestones, the Flow
84
+ reading scrubs every committed stage, the skill door scrubs the routing stops.
85
+ The cursor and the commentary are shared: a position travels between axes by
86
+ its commit index (`scrubAxisFor` + `stepForCommitIdx`), never by copying a
87
+ step number from one ruler to another. Hand a door the wrong thing and it
88
+ says so on screen — what it received and where to go — instead of rendering
89
+ a blank panel.
90
+
91
+ ---
92
+
71
93
  ## What you actually see
72
94
 
73
95
  The default view (`view="engineer"`) is one screen:
@@ -505,9 +527,12 @@ pane.
505
527
 
506
528
  ## Scrubbing by group — the active group is a named place
507
529
 
508
- One causal trace, replayed at two zoom levels. On the **per-step** ruler each
509
- commit is a stop; on the **grouped** ruler each boundary is a stop, and ◀ ▶ moves
510
- a whole group at a time.
530
+ One causal trace, replayed at two zoom levels. On the **per-step** ruler every
531
+ executed stage is a stop — the commit trace itself, nothing skippable, so the
532
+ ruler's count is the run's stage count. On the **grouped** ruler the stops are
533
+ the agent's milestones (iteration, context, LLM turn, route, tool call), drawn
534
+ as labelled iteration bands; ◀ ▶ still move one stop at a time, and clicking a
535
+ band jumps to its first stop.
511
536
 
512
537
  The chart used to paint both the same way, and that was wrong for the second one.
513
538
  A stage's styling is by TYPE — the LLM call carries a hero emphasis (accent
@@ -0,0 +1,73 @@
1
+ // src/core/selectors/selectAgentInstances.ts
2
+ function selectAgentInstances(graph) {
3
+ const allBoundaries = graph.nodes.filter((n) => n.isPrimitiveBoundary === true);
4
+ if (allBoundaries.length === 0) {
5
+ const rootSubflow = graph.nodes.find((n) => n.kind === "subflow");
6
+ const primitiveKind = rootSubflow?.primitiveKind;
7
+ return [
8
+ {
9
+ groupId: "agent-root",
10
+ llmId: "stage-llm-root",
11
+ toolId: "stage-tool-root",
12
+ label: primitiveKind ?? "Runner",
13
+ subflowPath: [],
14
+ ...primitiveKind ? { primitiveKind } : {}
15
+ }
16
+ ];
17
+ }
18
+ const boundaries = allBoundaries.filter(
19
+ (b) => !allBoundaries.some(
20
+ (other) => other !== b && isStrictDescendant(other.subflowPath, b.subflowPath)
21
+ )
22
+ );
23
+ return boundaries.map((b) => ({
24
+ groupId: `agent-group-${b.id}`,
25
+ llmId: `stage-llm-${b.id}`,
26
+ toolId: `stage-tool-${b.id}`,
27
+ label: b.label,
28
+ subflowPath: b.subflowPath,
29
+ ...b.primitiveKind ? { primitiveKind: b.primitiveKind } : {}
30
+ }));
31
+ }
32
+ function isStrictDescendant(child, parent) {
33
+ if (child.length <= parent.length) return false;
34
+ for (let i = 0; i < parent.length; i++) {
35
+ if (child[i] !== parent[i]) return false;
36
+ }
37
+ return true;
38
+ }
39
+
40
+ // src/core/selectors/selectStepAgentName.ts
41
+ function cleanLabel(label) {
42
+ return label.replace(/^step-/, "");
43
+ }
44
+ function selectStepAgentName(step, agents) {
45
+ if (agents.length < 2) return void 0;
46
+ const stepPath = step.subflowPath ?? [];
47
+ if (stepPath.length === 0) return void 0;
48
+ let best;
49
+ let bestDepth = -1;
50
+ for (const agent of agents) {
51
+ const ap = agent.subflowPath;
52
+ if (ap.length === 0) continue;
53
+ if (!isPrefix(ap, stepPath)) continue;
54
+ if (ap.length > bestDepth) {
55
+ best = agent;
56
+ bestDepth = ap.length;
57
+ }
58
+ }
59
+ return best ? cleanLabel(best.label) : void 0;
60
+ }
61
+ function isPrefix(prefix, path) {
62
+ if (prefix.length > path.length) return false;
63
+ for (let i = 0; i < prefix.length; i++) {
64
+ if (prefix[i] !== path[i]) return false;
65
+ }
66
+ return true;
67
+ }
68
+
69
+ export {
70
+ selectAgentInstances,
71
+ selectStepAgentName
72
+ };
73
+ //# sourceMappingURL=chunk-2JAWSPNG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/selectors/selectAgentInstances.ts","../src/core/selectors/selectStepAgentName.ts"],"sourcesContent":["/**\n * `selectAgentInstances` — derive AgentInstance[] from a StepGraph.\n *\n * Pattern: pure function over the `isPrimitiveBoundary` flag that\n * agentfootprint sets on every subflow StepNode whose root\n * description carries a known `<Kind>:` prefix (Agent /\n * LLMCall / Sequence / Parallel / Conditional / Loop).\n * Single-primitive runs produce one synthetic root instance;\n * composed runs produce one per primitive subflow.\n * Role: Feeds the top-level agent-grouping layer in Lens (one\n * container per primitive instance). Framework-agnostic.\n *\n * Naming: kept as `selectAgentInstances` for backwards compatibility —\n * \"Agent\" here means \"an outlined container in the run-tree view,\" not\n * specifically \"ReAct agent.\" The narrow flag (`isAgentBoundary`)\n * remains available on each StepNode for callers that care about the\n * distinction (cost / iteration attribution).\n */\n\nimport type { StepGraph } from 'agentfootprint/observe';\nimport type { AgentInstance } from './types.js';\n\n/**\n * Produce one AgentInstance per primitive boundary in the graph.\n *\n * Derivation:\n * - If ANY StepNode has `isPrimitiveBoundary === true`, use those.\n * Their `id` becomes the instance's `subflowPath` root segment.\n * - Otherwise, synthesize a single root instance covering the run.\n * Matches the common case of a standalone primitive run (e.g., a\n * standalone LLMCall whose chart has no top-level subflow).\n *\n * Each instance carries a `primitiveKind` (when the StepGraph supplies\n * one) so the renderer picks the correct icon + subtitle:\n * - Agent boundary → `'Agent'` → `'🤖 Agent · ReAct loop'`\n * - LLMCall boundary → `'LLMCall'` → `'📡 LLMCall · one-shot'`\n * - Sequence boundary → `'Sequence'` → `'➡️ Sequence · pipeline'`\n * - Parallel boundary → `'Parallel'` → `'🔀 Parallel · fan-out'`\n * - Conditional boundary → `'Conditional'` → `'🪧 Conditional · route'`\n * - Loop boundary → `'Loop'` → `'🔁 Loop · iterate'`\n *\n * IDs are stable within a run — safe to use as React keys.\n */\nexport function selectAgentInstances(graph: StepGraph): AgentInstance[] {\n const allBoundaries = graph.nodes.filter((n) => n.isPrimitiveBoundary === true);\n if (allBoundaries.length === 0) {\n // Synthetic root — peek at the first subflow node's `primitiveKind`\n // so we can label the container by what's actually running, not a\n // hardcoded `'Agent'`. Falls back to `'Runner'` when the graph\n // carries no taxonomy metadata.\n const rootSubflow = graph.nodes.find((n) => n.kind === 'subflow');\n const primitiveKind = rootSubflow?.primitiveKind;\n return [\n {\n groupId: 'agent-root',\n llmId: 'stage-llm-root',\n toolId: 'stage-tool-root',\n label: primitiveKind ?? 'Runner',\n subflowPath: [],\n ...(primitiveKind ? { primitiveKind } : {}),\n },\n ];\n }\n\n // LEAF-filter: keep only the DEEPEST primitive boundaries — the ones\n // that actually do work. Drop composition wrappers (Sequence /\n // Parallel / Conditional / Loop) when at least one of their children\n // is itself a primitive boundary, since the children fully describe\n // the run.\n //\n // Examples:\n // Sequence(LLMCall a, LLMCall b) → [a, b] (Sequence dropped)\n // Parallel(LLMCall x, LLMCall y, LLMCall z) → [x, y, z] (Parallel dropped)\n // Conditional(when a / otherwise b) → [a] OR [b] (only the chosen\n // runs has events;\n // boundaries with\n // no descendants\n // in graph.nodes\n // fall through)\n // Loop(body) → [body] (Loop dropped — the\n // body is the unit of\n // work)\n // Standalone Agent / LLMCall / RAG run → [self] (no nested primitive,\n // so it's already a leaf)\n const boundaries = allBoundaries.filter((b) =>\n !allBoundaries.some(\n (other) =>\n other !== b &&\n isStrictDescendant(other.subflowPath, b.subflowPath),\n ),\n );\n\n return boundaries.map((b) => ({\n groupId: `agent-group-${b.id}`,\n llmId: `stage-llm-${b.id}`,\n toolId: `stage-tool-${b.id}`,\n label: b.label,\n subflowPath: b.subflowPath,\n ...(b.primitiveKind ? { primitiveKind: b.primitiveKind } : {}),\n }));\n}\n\n/** True iff `child` is strictly deeper than `parent` (parent is a proper\n * prefix of child). Used to detect \"is this boundary nested inside another\n * boundary\" so we can drop the wrapper. */\nfunction isStrictDescendant(\n child: readonly string[],\n parent: readonly string[],\n): boolean {\n if (child.length <= parent.length) return false;\n for (let i = 0; i < parent.length; i++) {\n if (child[i] !== parent[i]) return false;\n }\n return true;\n}\n","/**\n * `selectStepAgentName` — pick the human-friendly agent name a step\n * \"belongs to\" in a multi-agent run.\n *\n * Pattern: walk the agent list, prefix-match the step's `subflowPath`,\n * and return the deepest matching agent's label. Used to\n * enrich step labels in multi-agent contexts so callers can\n * render \"user → classify\" instead of generic \"user → llm\".\n *\n * Returns `undefined` for single-agent runs (caller falls back to the\n * step's own label) and for steps that don't lift to any agent (root\n * synthetic nodes, the User actor, etc.).\n */\n\nimport type { StepNode } from \"agentfootprint/observe\";\nimport type { AgentInstance } from \"./types.js\";\n\n/**\n * Strip `'step-'` prefix that Sequence stages get from the runtime\n * (so `'step-classify'` reads as `'classify'`). Matches the breadcrumb\n * convention in Lens.tsx and the `extractAgentName` humanizer\n * convention from agentfootprint v2.14.4.\n */\nfunction cleanLabel(label: string): string {\n return label.replace(/^step-/, \"\");\n}\n\n/**\n * Find the agent whose `subflowPath` is the deepest prefix of the\n * step's `subflowPath`. Returns the cleaned label of that agent or\n * `undefined` when no agent matches (or only ONE agent exists, in\n * which case the caller already shows the agent in the container\n * header and prefixing every step would be redundant).\n */\nexport function selectStepAgentName(\n step: StepNode,\n agents: readonly AgentInstance[],\n): string | undefined {\n if (agents.length < 2) return undefined;\n const stepPath = step.subflowPath ?? [];\n if (stepPath.length === 0) return undefined;\n\n let best: AgentInstance | undefined;\n let bestDepth = -1;\n for (const agent of agents) {\n const ap = agent.subflowPath;\n if (ap.length === 0) continue;\n if (!isPrefix(ap, stepPath)) continue;\n if (ap.length > bestDepth) {\n best = agent;\n bestDepth = ap.length;\n }\n }\n return best ? cleanLabel(best.label) : undefined;\n}\n\nfunction isPrefix(prefix: readonly string[], path: readonly string[]): boolean {\n if (prefix.length > path.length) return false;\n for (let i = 0; i < prefix.length; i++) {\n if (prefix[i] !== path[i]) return false;\n }\n return true;\n}\n"],"mappings":";AA2CO,SAAS,qBAAqB,OAAmC;AACtE,QAAM,gBAAgB,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,wBAAwB,IAAI;AAC9E,MAAI,cAAc,WAAW,GAAG;AAK9B,UAAM,cAAc,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS;AAChE,UAAM,gBAAgB,aAAa;AACnC,WAAO;AAAA,MACL;AAAA,QACE,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO,iBAAiB;AAAA,QACxB,aAAa,CAAC;AAAA,QACd,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAsBA,QAAM,aAAa,cAAc;AAAA,IAAO,CAAC,MACvC,CAAC,cAAc;AAAA,MACb,CAAC,UACC,UAAU,KACV,mBAAmB,MAAM,aAAa,EAAE,WAAW;AAAA,IACvD;AAAA,EACF;AAEA,SAAO,WAAW,IAAI,CAAC,OAAO;AAAA,IAC5B,SAAS,eAAe,EAAE,EAAE;AAAA,IAC5B,OAAO,aAAa,EAAE,EAAE;AAAA,IACxB,QAAQ,cAAc,EAAE,EAAE;AAAA,IAC1B,OAAO,EAAE;AAAA,IACT,aAAa,EAAE;AAAA,IACf,GAAI,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,IAAI,CAAC;AAAA,EAC9D,EAAE;AACJ;AAKA,SAAS,mBACP,OACA,QACS;AACT,MAAI,MAAM,UAAU,OAAO,OAAQ,QAAO;AAC1C,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,QAAI,MAAM,CAAC,MAAM,OAAO,CAAC,EAAG,QAAO;AAAA,EACrC;AACA,SAAO;AACT;;;AC3FA,SAAS,WAAW,OAAuB;AACzC,SAAO,MAAM,QAAQ,UAAU,EAAE;AACnC;AASO,SAAS,oBACd,MACA,QACoB;AACpB,MAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,QAAM,WAAW,KAAK,eAAe,CAAC;AACtC,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,MAAI;AACJ,MAAI,YAAY;AAChB,aAAW,SAAS,QAAQ;AAC1B,UAAM,KAAK,MAAM;AACjB,QAAI,GAAG,WAAW,EAAG;AACrB,QAAI,CAAC,SAAS,IAAI,QAAQ,EAAG;AAC7B,QAAI,GAAG,SAAS,WAAW;AACzB,aAAO;AACP,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF;AACA,SAAO,OAAO,WAAW,KAAK,KAAK,IAAI;AACzC;AAEA,SAAS,SAAS,QAA2B,MAAkC;AAC7E,MAAI,OAAO,SAAS,KAAK,OAAQ,QAAO;AACxC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,QAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;","names":[]}