agentfootprint-lens 0.47.1 → 0.49.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/README.md +180 -0
- package/dist/{Lens-Ccs8UUDQ.d.cts → Lens-_IjGLEGt.d.cts} +15 -1
- package/dist/{Lens-9wZ84e70.d.ts → Lens-_hExvOXu.d.ts} +15 -1
- package/dist/{chunk-4PENVNUY.js → chunk-AIZIILHJ.js} +685 -17
- package/dist/chunk-AIZIILHJ.js.map +1 -0
- package/dist/{chunk-XFNFYUPC.js → chunk-K4CTXAB7.js} +2 -2
- package/dist/{chunk-UO6IZSBY.js → chunk-KS4AIWQJ.js} +1551 -599
- package/dist/chunk-KS4AIWQJ.js.map +1 -0
- package/dist/core.cjs +697 -15
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +249 -4
- package/dist/core.d.ts +249 -4
- package/dist/core.js +36 -2
- package/dist/index.cjs +2773 -1141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +260 -8
- package/dist/index.d.ts +260 -8
- package/dist/index.js +55 -3
- package/dist/index.js.map +1 -1
- package/dist/{lensStops-DfNxsaH0.d.cts → tagAxis-B598GxMJ.d.cts} +292 -3
- package/dist/{lensStops-Di41Rg3f.d.ts → tagAxis-C__DMHiD.d.ts} +292 -3
- package/dist/why.cjs +2230 -632
- package/dist/why.cjs.map +1 -1
- package/dist/why.d.cts +4 -4
- package/dist/why.d.ts +4 -4
- package/dist/why.js +22 -4
- package/dist/why.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-4PENVNUY.js.map +0 -1
- package/dist/chunk-UO6IZSBY.js.map +0 -1
- /package/dist/{chunk-XFNFYUPC.js.map → chunk-K4CTXAB7.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1059,6 +1059,165 @@ on every epoch, no receipt was minted, and the tab says so with the library's
|
|
|
1059
1059
|
`no-receipt-on-chart` gap and `cause: 'no-receipt-committed'` — every row
|
|
1060
1060
|
**Reconstructed**, never a fabricated **Verified**.
|
|
1061
1061
|
|
|
1062
|
+
### The Served graph (0.49.0)
|
|
1063
|
+
|
|
1064
|
+
A list is right for checking one row and wrong for seeing that the system string
|
|
1065
|
+
was assembled from a base plus one skill body plus two injections while three
|
|
1066
|
+
tools were withheld. That is one picture, and since 0.49.0 the Served tab has a
|
|
1067
|
+
**List ⇄ Graph** toggle (the list stays the default) that draws it: **HELD** —
|
|
1068
|
+
what the record holds at this stop, from the fold — then **SERVED** — what
|
|
1069
|
+
crossed into the call, one edge per system piece, message, request-only line and
|
|
1070
|
+
tool, each carrying its badge and, against the previous epoch, whether it
|
|
1071
|
+
*entered*, *left* or is *unchanged* — then **WITHHELD**: held and not sent. The
|
|
1072
|
+
withheld band is the reason to build it. The model never learns what it was
|
|
1073
|
+
denied; the operator should — the withheld tool list, the attention drops, the
|
|
1074
|
+
skills a role hid (read from the fold, since a receipt carries no authority
|
|
1075
|
+
names), a redacted fold, and every gap the view declares, each with the
|
|
1076
|
+
library's own sentence. Same cursor, same row, same badges: a Damaged row draws
|
|
1077
|
+
Damaged here too, and a field a gap covers draws the gap rather than an empty
|
|
1078
|
+
node.
|
|
1079
|
+
|
|
1080
|
+
| graph | what it draws | the question it answers |
|
|
1081
|
+
|---|---|---|
|
|
1082
|
+
| **skill graph** (`<SkillGraph>`) | the skills, their steps and their edges | where a run MAY go, and where it went |
|
|
1083
|
+
| **data graph** (*Where from*) | a value's writers, back through the commit log | where THIS value came from |
|
|
1084
|
+
| **Served graph** (Served tab · Graph) | one call: held · served · withheld | what this ONE CALL was made of, and what we held back |
|
|
1085
|
+
|
|
1086
|
+
```ts
|
|
1087
|
+
import { foldFactsAt, servedGraphAt, servedRowAt, verify } from 'agentfootprint-lens/core';
|
|
1088
|
+
|
|
1089
|
+
const cursor = { runtimeStageId: 'call-llm#18', commitIdx: 15 };
|
|
1090
|
+
const row = servedRowAt(snapshot, cursor)!;
|
|
1091
|
+
const graph = servedGraphAt({
|
|
1092
|
+
row,
|
|
1093
|
+
fold: foldFactsAt(snapshot, cursor),
|
|
1094
|
+
checks: verify(row.view, row.receipt, row.receipt?.basis.runId ?? '', row.receiptCause),
|
|
1095
|
+
});
|
|
1096
|
+
graph.served.map((s) => `${s.slot} ${s.rebuilt}`); // ['system-prompt 3', …]
|
|
1097
|
+
graph.edges.filter((e) => e.state === 'entered').map((e) => e.origin); // ['instructions']
|
|
1098
|
+
graph.withheld.filter((w) => w.from === 'fold').map((w) => w.name); // ['payroll']
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
`<ServedGraph graph>` is exported for shells that build the input themselves.
|
|
1102
|
+
**Deliberately absent:** an edge from a served piece back to the STAGE that
|
|
1103
|
+
wrote it. It needs a commit-log walk keyed by piece text or slot — the part most
|
|
1104
|
+
likely to rot — and the question above is answered without it.
|
|
1105
|
+
|
|
1106
|
+
---
|
|
1107
|
+
|
|
1108
|
+
## Bookmarks, and scrubbing by declared tag
|
|
1109
|
+
|
|
1110
|
+
**The reader's marks, kept beside the recording — and the author's tags, as a
|
|
1111
|
+
ruler.** Since 0.48.0 the Why Lens's right rail has a third tab, **Bookmarks**,
|
|
1112
|
+
and the grouped ruler carries a **Tags** strip.
|
|
1113
|
+
|
|
1114
|
+
### Why
|
|
1115
|
+
|
|
1116
|
+
footprintjs's design page for declared tags names three marks that end in the
|
|
1117
|
+
same operation ("keep these stops, fold the rest into them") and differ in who
|
|
1118
|
+
puts the mark and when:
|
|
1119
|
+
|
|
1120
|
+
| Mark | Who, when | Lives | In the lens |
|
|
1121
|
+
|---|---|---|---|
|
|
1122
|
+
| **Declared tag** | the author, at build time | the chart's structure → stamped into the commit bundle (`bundle.tags`) | the **Tags** strip: legend and picker |
|
|
1123
|
+
| **Derived tag** | the reader, at read time, from the fold | computed by a strategy; never stored | the lens's own grouping (milestones, banded by iteration) — the default axis |
|
|
1124
|
+
| **Bookmark** | the reader, at read time, by choice | on the cursor (`mark` / `marks` / `jumpToMark`); persisted beside a recording, never in it | the **Bookmarks** tab |
|
|
1125
|
+
|
|
1126
|
+
Only the first two had a place in the lens. footprintjs holds a bookmark on the
|
|
1127
|
+
cursor and, by its own law, nowhere else — the log and the snapshot are the
|
|
1128
|
+
run's record, not the reader's notes — so a bookmark vanished when the page
|
|
1129
|
+
closed. And a run's own tags (agentfootprint 9.90 declares every milestone as
|
|
1130
|
+
one) were in the recording with nothing to read them.
|
|
1131
|
+
|
|
1132
|
+
### Bookmarks
|
|
1133
|
+
|
|
1134
|
+
Stand on a stop and press **Bookmark this stop**. The library names the mark
|
|
1135
|
+
(its own `mark()`, seated on the lens's one cursor); the lens writes it to a
|
|
1136
|
+
**sidecar** — a small document keyed to the run, in a store you choose. Click a
|
|
1137
|
+
bookmark to jump: the port's `jumpToMark`, through the same funnel every other
|
|
1138
|
+
mover uses, so the chart, the timeline and the Served tab all follow. Add a
|
|
1139
|
+
note inline; remove with one click.
|
|
1140
|
+
|
|
1141
|
+
```tsx
|
|
1142
|
+
import { Lens } from 'agentfootprint-lens';
|
|
1143
|
+
import { memoryBookmarkStore } from 'agentfootprint-lens/core';
|
|
1144
|
+
|
|
1145
|
+
<Lens recorder={recorder} runner={agent} granularity="group" /> // localStorage, by default
|
|
1146
|
+
<Lens recorder={recorder} runner={agent} bookmarkStore={memoryBookmarkStore()} /> // this session only
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
The laws the tab keeps:
|
|
1150
|
+
|
|
1151
|
+
- **One cursor.** The tab holds a list, never a position. A jump moves the lens
|
|
1152
|
+
cursor (`onStepChange` fires); a miss never moves.
|
|
1153
|
+
- **Never in the record.** Nothing is written into the snapshot or the log.
|
|
1154
|
+
- **Omit, never deny.** A bookmark whose stop this recording does not hold —
|
|
1155
|
+
a truncated recording, a sidecar filed under another run — is shown greyed as
|
|
1156
|
+
*not in this recording*, never dropped.
|
|
1157
|
+
- **Persistence is a label.** A browser that refuses storage (private mode, a
|
|
1158
|
+
quota, a server render) makes the tab say *bookmarks not saved*; a snapshot
|
|
1159
|
+
with no `runId` says *no run id*. Nothing throws.
|
|
1160
|
+
- **No claim sentences.** Every string the tab prints is a label
|
|
1161
|
+
(`BOOKMARK_LABELS`) or computed data; `test/served/no-own-claims.test.ts`
|
|
1162
|
+
walks the file.
|
|
1163
|
+
|
|
1164
|
+
The root bookends (*Run · start* / *Run · end*) are not bookmarkable — Home and
|
|
1165
|
+
End reach them on every axis, and they share one synthetic address.
|
|
1166
|
+
|
|
1167
|
+
Headless, the sidecar is four functions in `/core`: `bookmarkKey(snapshot)`,
|
|
1168
|
+
`toSidecar(key, bookmarks)`, `fromSidecar(json, snapshot)` (reports
|
|
1169
|
+
`orphaned`), `bookmarksToMarks(bookmarks, positions)` to seed footprintjs's
|
|
1170
|
+
`timeTravel(snapshot, { marks })`; stores are `localStorageBookmarkStore()`,
|
|
1171
|
+
`memoryBookmarkStore()`, `noBookmarkStore()`, or any `BookmarkStore` of your
|
|
1172
|
+
own. See `src/core/bookmarks/README.md`.
|
|
1173
|
+
|
|
1174
|
+
### The Tags strip
|
|
1175
|
+
|
|
1176
|
+
On the grouped ruler, above the chart: one chip per declared tag, labelled with
|
|
1177
|
+
agentfootprint's milestone label when the tag is a milestone (*LLM turn*,
|
|
1178
|
+
*Route*) and its raw name otherwise (*audit*), with the number of bundles this
|
|
1179
|
+
run stamped it on. The list comes from the recording's **structure** — the
|
|
1180
|
+
chart advertises the tags it *can* produce, so the legend is drawn before a
|
|
1181
|
+
stop is reached — and the counts from the **log**. A recording that carried no
|
|
1182
|
+
structure lists only *tags this run hit* and says *no chart in this recording*.
|
|
1183
|
+
A declared tag the run never hit is shown and disabled.
|
|
1184
|
+
|
|
1185
|
+
**Pick a chip and the ruler is rebuilt** through footprintjs 9.21's
|
|
1186
|
+
`tagStops(names)`: the stops whose bundle carries any picked tag, the untagged
|
|
1187
|
+
stages folded into the tagged stop before them, the run's bookends kept. It is
|
|
1188
|
+
the same one cursor on a different list — the cursor **keeps its commit**, not
|
|
1189
|
+
its step number: it is re-seated at the stop that holds its commit (nearest
|
|
1190
|
+
preceding when the new axis has none there — `stepForCommitIdx`, the same rule
|
|
1191
|
+
the `granularity` doc gives a host), and the host hears it as an ordinary
|
|
1192
|
+
`onStepChange`. `stateAt` at a picked stop equals the default axis's fold at
|
|
1193
|
+
the same commit (`src/core/tags/tags.test.ts` pins the equivalence). *Clear*
|
|
1194
|
+
restores the lens's own grouping, by the same rule. The strip appears on
|
|
1195
|
+
`granularity="group"` at the root level only: the per-step reading's ruler is
|
|
1196
|
+
every commit, byte for byte, and a drilled level scrubs its own stops.
|
|
1197
|
+
|
|
1198
|
+
A pick scrubs the run's OWN log (`tagStops` reads no other), so a chip is
|
|
1199
|
+
pickable only when the tag was hit on the root log; a tag hit only inside
|
|
1200
|
+
mounted subflows (the grouped turn's *LLM turn*, the context slots) is shown
|
|
1201
|
+
disabled with *in subflows* — real, said, and not a stop on this axis. Counts
|
|
1202
|
+
walk each mount's log once (`subflowResults` is dual-keyed; only the `#n`
|
|
1203
|
+
entries are read).
|
|
1204
|
+
|
|
1205
|
+
```ts
|
|
1206
|
+
import { tagLegend, tagAxisPositions, scrubAxisFor } from 'agentfootprint-lens/core';
|
|
1207
|
+
|
|
1208
|
+
const legend = tagLegend(runner.getSpec().buildTimeStructure, runner.getLastSnapshot());
|
|
1209
|
+
legend.source; // 'structure' | 'log'
|
|
1210
|
+
legend.entries.map((e) => [e.label, e.hits]); // [['Iteration', 2], ['LLM turn', 2], ['audit', 0], …]
|
|
1211
|
+
|
|
1212
|
+
const axis = tagAxisPositions(snapshot, ['milestone:llm-turn'], scrubAxisFor(recorder, 'group'));
|
|
1213
|
+
axis?.map((p) => p.label); // ['Run · start', 'LLM turn 1', 'LLM turn 2', 'Run · end']
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
**Older peers.** `tagStops` (footprintjs 9.21) and `milestoneFromTags`
|
|
1217
|
+
(agentfootprint 9.90) are read off their module namespaces at call time: on a
|
|
1218
|
+
peer without them the legend prints raw names, the strip says *tag axis
|
|
1219
|
+
unavailable*, and nothing else changes. The peer ranges are untouched.
|
|
1220
|
+
|
|
1062
1221
|
---
|
|
1063
1222
|
|
|
1064
1223
|
## Rendering your own detail pane
|
|
@@ -1290,6 +1449,27 @@ field, the library's gap sentences verbatim, the fold's hidden skill ids, and a
|
|
|
1290
1449
|
since-previous diff. Headless: `servedRowAt` · `verify` · `sincePrevious` ·
|
|
1291
1450
|
`foldFactsAt` in `/core`. See "The Served tab" above.
|
|
1292
1451
|
|
|
1452
|
+
### `<BookmarksTab>` — the reader's marks, riding the one cursor
|
|
1453
|
+
|
|
1454
|
+
`<BookmarksTab bookmarks orphaned persistence positions step port moveTo onAdd
|
|
1455
|
+
onRemove onNote>`. The Why Lens mounts it as the right rail's third tab
|
|
1456
|
+
(`<Lens bookmarkStore?>` picks the store; default `localStorageBookmarkStore()`);
|
|
1457
|
+
exported for consumer-built shells, with `useBookmarkSidecar({ snapshot, store })`
|
|
1458
|
+
as the list and `openLensCursor(positions, { marks })` as the port. A jump is
|
|
1459
|
+
the port's `toMark` through `moveTo`; orphans are greyed and labelled; the
|
|
1460
|
+
store's availability is a label. Headless: `bookmarkKey` · `toSidecar` ·
|
|
1461
|
+
`fromSidecar` · `bookmarksToMarks` and the three stores in `/core`. See
|
|
1462
|
+
"Bookmarks, and scrubbing by declared tag" above.
|
|
1463
|
+
|
|
1464
|
+
### `<TagPicker>` — the declared-tag legend and picker
|
|
1465
|
+
|
|
1466
|
+
`<TagPicker legend picked onPick available>`. The engineer view mounts it above
|
|
1467
|
+
the chart on `granularity="group"` at the root level; `legend` is
|
|
1468
|
+
`tagLegend(structure, snapshot)` (`source: 'structure' | 'log'`), a pick is a
|
|
1469
|
+
list of tag names the lens hands to `tagAxisPositions(snapshot, picked, base)`
|
|
1470
|
+
(footprintjs 9.21's `tagStops`). Picking never moves the cursor; it changes the
|
|
1471
|
+
list the one cursor is a step into.
|
|
1472
|
+
|
|
1293
1473
|
### `<BugReportButton>` — report a bug with the run attached, consent first
|
|
1294
1474
|
|
|
1295
1475
|
A small button for a debug UI. The dialog it opens shows every selectable unit
|
|
@@ -4,7 +4,7 @@ import * as agentfootprint from 'agentfootprint';
|
|
|
4
4
|
import { CommentaryTemplates } from 'agentfootprint';
|
|
5
5
|
import React__default, { Ref } from 'react';
|
|
6
6
|
import { d as NavigationResult, C as CursorPosition, L as LensRecorder } from './resolveNavigation-Ckr2nXHY.cjs';
|
|
7
|
-
import { C as ChartGroupHighlight,
|
|
7
|
+
import { C as ChartGroupHighlight, c as LensCursorPort, H as Humanizer, b as BookmarkStore } from './tagAxis-B598GxMJ.cjs';
|
|
8
8
|
import { NodeTypes } from '@xyflow/react';
|
|
9
9
|
import { TraceGraph, TraceFlowLayout, RuntimeOverlay } from 'footprint-explainable-ui/flowchart';
|
|
10
10
|
|
|
@@ -523,8 +523,22 @@ interface LensProps {
|
|
|
523
523
|
* granularities carries it by `commitIdx`: build the target axis with
|
|
524
524
|
* `scrubAxisFor(recorder, granularity)` and resolve it with
|
|
525
525
|
* `stepForCommitIdx(positions, at.commitIdx)`.
|
|
526
|
+
*
|
|
527
|
+
* (0.48.0) The TAGS strip — the declared-tag legend and the picker that
|
|
528
|
+
* rebuilds the ruler through `tagStops` — appears on `'group'` at the root
|
|
529
|
+
* level only; `'step'` scrubs every commit and carries no strip. A pick
|
|
530
|
+
* re-seats the cursor by the same `stepForCommitIdx` rule.
|
|
526
531
|
*/
|
|
527
532
|
readonly granularity?: 'step' | 'group';
|
|
533
|
+
/**
|
|
534
|
+
* Where the reader's BOOKMARKS persist (0.48.0). A bookmark is the reader's
|
|
535
|
+
* mark — never written into the recording — kept in a sidecar keyed to the
|
|
536
|
+
* run and seeded onto the cursor when the recording is opened. Default:
|
|
537
|
+
* `localStorageBookmarkStore()`; a browser that refuses storage makes the
|
|
538
|
+
* Bookmarks tab say "bookmarks not saved" rather than throw. Pass
|
|
539
|
+
* `memoryBookmarkStore()` for a session-only reading, or your own store.
|
|
540
|
+
*/
|
|
541
|
+
readonly bookmarkStore?: BookmarkStore;
|
|
528
542
|
/**
|
|
529
543
|
* Controlled cursor (omit for uncontrolled). Omit it and the lens is
|
|
530
544
|
* self-driving exactly as it has always been: it holds the position itself,
|
|
@@ -4,7 +4,7 @@ import * as agentfootprint from 'agentfootprint';
|
|
|
4
4
|
import { CommentaryTemplates } from 'agentfootprint';
|
|
5
5
|
import React__default, { Ref } from 'react';
|
|
6
6
|
import { d as NavigationResult, C as CursorPosition, L as LensRecorder } from './resolveNavigation-Ckr2nXHY.js';
|
|
7
|
-
import { C as ChartGroupHighlight,
|
|
7
|
+
import { C as ChartGroupHighlight, c as LensCursorPort, H as Humanizer, b as BookmarkStore } from './tagAxis-C__DMHiD.js';
|
|
8
8
|
import { NodeTypes } from '@xyflow/react';
|
|
9
9
|
import { TraceGraph, TraceFlowLayout, RuntimeOverlay } from 'footprint-explainable-ui/flowchart';
|
|
10
10
|
|
|
@@ -523,8 +523,22 @@ interface LensProps {
|
|
|
523
523
|
* granularities carries it by `commitIdx`: build the target axis with
|
|
524
524
|
* `scrubAxisFor(recorder, granularity)` and resolve it with
|
|
525
525
|
* `stepForCommitIdx(positions, at.commitIdx)`.
|
|
526
|
+
*
|
|
527
|
+
* (0.48.0) The TAGS strip — the declared-tag legend and the picker that
|
|
528
|
+
* rebuilds the ruler through `tagStops` — appears on `'group'` at the root
|
|
529
|
+
* level only; `'step'` scrubs every commit and carries no strip. A pick
|
|
530
|
+
* re-seats the cursor by the same `stepForCommitIdx` rule.
|
|
526
531
|
*/
|
|
527
532
|
readonly granularity?: 'step' | 'group';
|
|
533
|
+
/**
|
|
534
|
+
* Where the reader's BOOKMARKS persist (0.48.0). A bookmark is the reader's
|
|
535
|
+
* mark — never written into the recording — kept in a sidecar keyed to the
|
|
536
|
+
* run and seeded onto the cursor when the recording is opened. Default:
|
|
537
|
+
* `localStorageBookmarkStore()`; a browser that refuses storage makes the
|
|
538
|
+
* Bookmarks tab say "bookmarks not saved" rather than throw. Pass
|
|
539
|
+
* `memoryBookmarkStore()` for a session-only reading, or your own store.
|
|
540
|
+
*/
|
|
541
|
+
readonly bookmarkStore?: BookmarkStore;
|
|
528
542
|
/**
|
|
529
543
|
* Controlled cursor (omit for uncontrolled). Omit it and the lens is
|
|
530
544
|
* self-driving exactly as it has always been: it holds the position itself,
|