agentfootprint-lens 0.67.1 → 0.68.1

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 (35) hide show
  1. package/README.md +107 -2
  2. package/dist/{Lens-BXekG6HU.d.cts → Lens-BTYtIG2P.d.cts} +12 -1
  3. package/dist/{Lens-ITTKEBkh.d.ts → Lens-D9v2O1_0.d.ts} +12 -1
  4. package/dist/{chunk-UFC3IZPT.js → chunk-AUEVEPXO.js} +2 -2
  5. package/dist/{chunk-S3WZBG5I.js → chunk-LDO7Y76D.js} +2 -2
  6. package/dist/{chunk-3HSMB6JF.js → chunk-M5P65VVK.js} +3 -3
  7. package/dist/{chunk-DU4VFDTY.js → chunk-ORT5OUHS.js} +3 -3
  8. package/dist/{chunk-4K45VV7M.js → chunk-WM5QJ6TD.js} +1076 -411
  9. package/dist/chunk-WM5QJ6TD.js.map +1 -0
  10. package/dist/{chunk-CO5R2ODI.js → chunk-XK74JIRU.js} +28 -3
  11. package/dist/chunk-XK74JIRU.js.map +1 -0
  12. package/dist/context.cjs +27 -2
  13. package/dist/context.cjs.map +1 -1
  14. package/dist/context.js +3 -3
  15. package/dist/index.cjs +2523 -1825
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +227 -4
  18. package/dist/index.d.ts +227 -4
  19. package/dist/index.js +40 -28
  20. package/dist/index.js.map +1 -1
  21. package/dist/skillgraph.cjs +27 -2
  22. package/dist/skillgraph.cjs.map +1 -1
  23. package/dist/skillgraph.js +3 -3
  24. package/dist/why.cjs +1458 -772
  25. package/dist/why.cjs.map +1 -1
  26. package/dist/why.d.cts +2 -2
  27. package/dist/why.d.ts +2 -2
  28. package/dist/why.js +4 -4
  29. package/package.json +4 -4
  30. package/dist/chunk-4K45VV7M.js.map +0 -1
  31. package/dist/chunk-CO5R2ODI.js.map +0 -1
  32. /package/dist/{chunk-UFC3IZPT.js.map → chunk-AUEVEPXO.js.map} +0 -0
  33. /package/dist/{chunk-S3WZBG5I.js.map → chunk-LDO7Y76D.js.map} +0 -0
  34. /package/dist/{chunk-3HSMB6JF.js.map → chunk-M5P65VVK.js.map} +0 -0
  35. /package/dist/{chunk-DU4VFDTY.js.map → chunk-ORT5OUHS.js.map} +0 -0
package/README.md CHANGED
@@ -951,7 +951,8 @@ if (recording.snapshot) {
951
951
  }
952
952
  ```
953
953
 
954
- (Under footprintjs 9.17 — still the peer floor — the same call needs
954
+ (Under footprintjs 9.17 — the floor when this narrowing landed, now below
955
+ the peer floor of `^9.26.0` — the same call needs
955
956
  `recording.snapshot as unknown as TimeTravelSource`, and a bad row throws
956
957
  inside the fold; a types-only difference the lens's `foldFactsAt` reports as
957
958
  `foldError`.) **Movement never needs a snapshot at all**: `openLensCursor`
@@ -981,6 +982,108 @@ not answer, since it takes an exact stop.
981
982
 
982
983
  ---
983
984
 
985
+ ## Explain this answer — In plain words
986
+
987
+ **One answer, explained for a reader who is not an engineer: seven rows, every
988
+ line from the run's record, with who says so.** `<PlainWords>` draws
989
+ agentfootprint's **answer account** — `accountForAnswer`, a pure Fold over one
990
+ answer's recording, computed on the SERVER by the `answer-account` hosting op —
991
+ as **In one line** plus seven rows: *You asked · It understood · It checked ·
992
+ It did not check · It found · How sure · Anything wrong*.
993
+
994
+ ### Why
995
+
996
+ Every sentence in the pane is filled from the record by one of the library's
997
+ fixed, versioned templates — no model writes it, and the lens writes none of
998
+ its own. Each line carries a **said by** chip (you · the library's record · a
999
+ tool · the model · the app), a fact the record does not hold says **not
1000
+ recorded** instead of a guess, and **show me** opens the leaf of the record the
1001
+ line came from. The component is props only: it fetches nothing and receives no
1002
+ recording — the op returns `{ account, shown }`, where `shown` holds only the
1003
+ leaf values the server's allow-list lets out.
1004
+
1005
+ ### Mount it
1006
+
1007
+ ```tsx
1008
+ import { PlainWords, printAnswerAccount } from 'agentfootprint-lens';
1009
+
1010
+ // One request per Explain — the op answers from the recording on the server.
1011
+ const res = await fetch('/invoke', {
1012
+ method: 'POST',
1013
+ headers: { 'content-type': 'application/json', 'x-session-id': sessionId },
1014
+ body: JSON.stringify({ op: 'answer-account', ref: reply.reasoning.ref }),
1015
+ });
1016
+ const { account, shown } = await res.json();
1017
+
1018
+ <PlainWords
1019
+ account={account}
1020
+ shown={shown}
1021
+ labelledBy="tab-plain" // your drawer's tab → role="tabpanel"
1022
+ focusOnMount // opened from "Explain this answer"
1023
+ onSaveAsPdf={() => printAnswerAccount(account)}
1024
+ onOpenInLens={debug ? openFlowLensAt : undefined} // only when the engineer lenses exist
1025
+ />
1026
+ ```
1027
+
1028
+ | Prop | Type | Description |
1029
+ |---|---|---|
1030
+ | `account` | `AnswerAccount` | **Required.** The op's `account` (type from `agentfootprint/observe`). |
1031
+ | `shown` | `Record<string, AnswerAccountShownLeaf>?` | The op's `shown`. Looked up by `answerAccountPointerKey`. Omit → "show me" lists the pointers as text. |
1032
+ | `onOpenInLens` | `(pointer) => void?` | Draws "Open in the Flow Lens" beside each record pointer in "show me". Pass it only where those lenses exist. |
1033
+ | `showQuestionAndAnswer` | `boolean?` | The question and the answer above the one-liner. Default `true`. |
1034
+ | `onSaveAsPdf` | `() => void?` | Draws **Save as PDF**; pass `() => printAnswerAccount(account)`. |
1035
+ | `templateIdsToggle` | `boolean?` | The "template ids" toggle (each line's `id@version`). Default `true`. |
1036
+ | `theme` | `{ mode: 'light' \| 'dark' }?` | Standalone: stamps the lens palette. Inside `<Lens theme>` leave it out. |
1037
+ | `labelledBy` | `string?` | Your tab's id: the pane becomes `role="tabpanel"` labelled by it. Otherwise a region named "In plain words". |
1038
+ | `focusOnMount` | `boolean?` | Focus the pane's "In one line" heading on mount. |
1039
+
1040
+ ### What it keeps
1041
+
1042
+ - **No sentence of its own.** Headings, lines, chips and the one-liner are the
1043
+ library's `text`; the pane's own strings are `PLAIN_WORDS_LABELS` — names,
1044
+ never claims (walked by `test/served/no-own-claims.test.ts`).
1045
+ - **No HTML from data.** A sentence renders from its typed `parts` as text:
1046
+ `code` → `<code>`, `quote` → `<q>`, a declared `label` → `<strong>` with its
1047
+ own voucher. A `<script>` in a question is shown as the characters `<script>`.
1048
+ - **Show me = leaves.** A withheld leaf says why (`not shown here`, `too large
1049
+ to show here`, …); a line into a call the model read without the tool's
1050
+ report-only fields says so softly.
1051
+ - **Said by, on the line.** The library puts one `said-by` chip per source on
1052
+ the row; the pane pairs each to its recorded lines by the library's own rule,
1053
+ and leaves them on the row if a row ever does not pair.
1054
+ - **Accessible.** `h2` "In one line", an `h3` per row, lists for lines and
1055
+ items, every "show me" a `<button aria-expanded aria-controls>`; the tone is
1056
+ a border AND a word; four tone tokens (`--fp-tone-ok|warn|bad|unknown`) in
1057
+ both palettes, each ≥ 4.5:1 on its surfaces.
1058
+
1059
+ ### Save as PDF
1060
+
1061
+ `printAnswerAccount(account, { recordedAt? })` prints a one-page report from a
1062
+ hidden, `aria-hidden` frame whose document is titled **Answer report** (so the
1063
+ browser's print header says that): the question, a meta line — run id, the
1064
+ recorded and printed times as ISO-8601 UTC, model, template set — the answer as
1065
+ plain text (folded at 1,200 characters), In one line, and the rows as a table
1066
+ with "said by …" and the template id under each line (lists fold at six items).
1067
+ It never prints "show me", makes no request, and removes the frame on
1068
+ `afterprint`. `<AnswerReportPrint account />` is the same report as a component.
1069
+ The account does not carry the recorded time; pass the answer's `turn_start`
1070
+ `meta.wallClockMs` as `recordedAt` when you hold it (`<Lens>` reads it off its
1071
+ recording), else the line says `not recorded`.
1072
+
1073
+ ### In the Lens: the analyst view
1074
+
1075
+ ```tsx
1076
+ <Lens recorder={recorder} view="analyst" account={account} accountShown={shown} />
1077
+ ```
1078
+
1079
+ With `account`, the analyst view leads with `<PlainWords>` and folds the
1080
+ summary card, the transport and the commentary under a native **More detail**
1081
+ `<details>`. Without it, the analyst view is byte-for-byte what it was. The
1082
+ `engineer` and `user` views never read the prop.
1083
+
1084
+ Needs agentfootprint ≥ 9.116.0 (the release that ships `AnswerAccount` and the
1085
+ op) — the lens's peer floor since 0.68.0.
1086
+
984
1087
  ## The Served tab
985
1088
 
986
1089
  **At every LLM call, exactly what the model was served — provable from the log.**
@@ -1499,7 +1602,7 @@ your `--lens-*` still wins.
1499
1602
  Every token has a built-in value, so nothing is ever unpainted. See
1500
1603
  `src/react/theme/tokens.ts` for the full list (surfaces / text / border /
1501
1604
  accent / 4 edge kinds / 7 injection-source chips / 8 agent swatches /
1502
- typography), all of it exported as `T`, `RAW_DEFAULTS`, `AGENT_COLORS` and
1605
+ 4 In plain words tones / typography), all of it exported as `T`, `RAW_DEFAULTS`, `AGENT_COLORS` and
1503
1606
  `MODE_PALETTES`.
1504
1607
 
1505
1608
  ### Server rendering
@@ -1564,6 +1667,8 @@ graph in one call. Returns an unsubscribe. Call it once per run.
1564
1667
  | `onStepChange` | `(step, at) => void?` | Fires on every cursor move — required for movement in controlled mode, an observation hook otherwise. `at` carries `runtimeStageId`, `commitIdx`, `label`, `kind` and `clamped`. |
1565
1668
  | `navigatorRef` | `Ref<LensNavigator>?` | Move the cursor to a stage **by its `runtimeStageId`**. `ref.current.navigateTo(id)` returns `{ ok: true, step, match, label }` or `{ ok: false, reason, message, nearest? }` — a miss never moves. See [Pointing at a step](#pointing-at-a-step-navigatorref). |
1566
1669
  | `slots` | `LensSlots?` | Slot overrides. `slots.detail` renders your content as the right rail's FIRST TAB (`slots.detailLabel` names it; `slots.detailOnly` takes the whole rail instead). The strip stays the library's. Omit for the built-in timeline. See [Rendering your own detail pane](#rendering-your-own-detail-pane). |
1670
+ | `account` | `AnswerAccount?` | With `view="analyst"`: lead with the In plain words pane and fold the rest under "More detail". See [Explain this answer](#explain-this-answer--in-plain-words). |
1671
+ | `accountShown` | `Record<string, AnswerAccountShownLeaf>?` | The op's `shown` leaves, for "show me". |
1567
1672
 
1568
1673
  ### `<LensFlow>` — the chart canvas on its own
1569
1674
 
@@ -1,5 +1,5 @@
1
1
  import * as agentfootprint_observe from 'agentfootprint/observe';
2
- import { ToolChoiceCall, ToolChoiceSummary } from 'agentfootprint/observe';
2
+ import { ToolChoiceCall, ToolChoiceSummary, AnswerAccount, AnswerAccountShownLeaf } from 'agentfootprint/observe';
3
3
  import * as agentfootprint from 'agentfootprint';
4
4
  import { CommentaryTemplates } from 'agentfootprint';
5
5
  import React__default, { Ref } from 'react';
@@ -547,6 +547,17 @@ interface LensProps {
547
547
  * scope or `useMemo`). Omit and the shipped panes render unchanged.
548
548
  */
549
549
  readonly slots?: LensSlots;
550
+ /**
551
+ * The answer's ACCOUNT (0.68.0) — `account` of the `answer-account` hosting
552
+ * op's reply (agentfootprint `accountForAnswer`, computed on the server).
553
+ * With `view="analyst"` the view then leads with `<PlainWords>` — the In
554
+ * plain words pane — and folds the summary card, the transport and the
555
+ * commentary under a native "More detail" `<details>`. Without it the
556
+ * analyst view is exactly 0.67.1's. `engineer` and `user` never read it.
557
+ */
558
+ readonly account?: AnswerAccount;
559
+ /** `shown` of the same reply — the leaves "show me" draws. */
560
+ readonly accountShown?: Readonly<Record<string, AnswerAccountShownLeaf>>;
550
561
  }
551
562
  /**
552
563
  * Slot overrides for `<Lens view="engineer">`.
@@ -1,5 +1,5 @@
1
1
  import * as agentfootprint_observe from 'agentfootprint/observe';
2
- import { ToolChoiceCall, ToolChoiceSummary } from 'agentfootprint/observe';
2
+ import { ToolChoiceCall, ToolChoiceSummary, AnswerAccount, AnswerAccountShownLeaf } from 'agentfootprint/observe';
3
3
  import * as agentfootprint from 'agentfootprint';
4
4
  import { CommentaryTemplates } from 'agentfootprint';
5
5
  import React__default, { Ref } from 'react';
@@ -547,6 +547,17 @@ interface LensProps {
547
547
  * scope or `useMemo`). Omit and the shipped panes render unchanged.
548
548
  */
549
549
  readonly slots?: LensSlots;
550
+ /**
551
+ * The answer's ACCOUNT (0.68.0) — `account` of the `answer-account` hosting
552
+ * op's reply (agentfootprint `accountForAnswer`, computed on the server).
553
+ * With `view="analyst"` the view then leads with `<PlainWords>` — the In
554
+ * plain words pane — and folds the summary card, the transport and the
555
+ * commentary under a native "More detail" `<details>`. Without it the
556
+ * analyst view is exactly 0.67.1's. `engineer` and `user` never read it.
557
+ */
558
+ readonly account?: AnswerAccount;
559
+ /** `shown` of the same reply — the leaves "show me" draws. */
560
+ readonly accountShown?: Readonly<Record<string, AnswerAccountShownLeaf>>;
550
561
  }
551
562
  /**
552
563
  * Slot overrides for `<Lens view="engineer">`.
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-XEAZRBOH.js";
12
12
  import {
13
13
  T
14
- } from "./chunk-CO5R2ODI.js";
14
+ } from "./chunk-XK74JIRU.js";
15
15
 
16
16
  // src/react/components/ServedBadge.tsx
17
17
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1579,4 +1579,4 @@ export {
1579
1579
  collapsedTicketOf,
1580
1580
  ServedTab
1581
1581
  };
1582
- //# sourceMappingURL=chunk-UFC3IZPT.js.map
1582
+ //# sourceMappingURL=chunk-AUEVEPXO.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  T
3
- } from "./chunk-CO5R2ODI.js";
3
+ } from "./chunk-XK74JIRU.js";
4
4
 
5
5
  // src/react/narrowLayout.ts
6
6
  import { useEffect, useState } from "react";
@@ -162,4 +162,4 @@ export {
162
162
  refusalDestinationFor,
163
163
  REFUSAL_GO_TO
164
164
  };
165
- //# sourceMappingURL=chunk-S3WZBG5I.js.map
165
+ //# sourceMappingURL=chunk-LDO7Y76D.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  ServedTab,
6
6
  collapsedTicketOf
7
- } from "./chunk-UFC3IZPT.js";
7
+ } from "./chunk-AUEVEPXO.js";
8
8
  import {
9
9
  snapshotLogKey,
10
10
  snapshotOfRunner,
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  T,
15
15
  TimeTravel
16
- } from "./chunk-CO5R2ODI.js";
16
+ } from "./chunk-XK74JIRU.js";
17
17
  import {
18
18
  lensCursorFrom,
19
19
  scrubAxisFor
@@ -2906,4 +2906,4 @@ export {
2906
2906
  CLIP3 as CLIP,
2907
2907
  storyMarks
2908
2908
  };
2909
- //# sourceMappingURL=chunk-3HSMB6JF.js.map
2909
+ //# sourceMappingURL=chunk-M5P65VVK.js.map
@@ -4,7 +4,7 @@ import {
4
4
  describeReceived,
5
5
  refusalDestinationFor,
6
6
  useNarrowRow
7
- } from "./chunk-S3WZBG5I.js";
7
+ } from "./chunk-LDO7Y76D.js";
8
8
  import {
9
9
  selectSkillBeatAt,
10
10
  selectSkillBeats,
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  T,
18
18
  TimeTravel
19
- } from "./chunk-CO5R2ODI.js";
19
+ } from "./chunk-XK74JIRU.js";
20
20
  import {
21
21
  scrubAxisFor
22
22
  } from "./chunk-BFAI2IPA.js";
@@ -1513,4 +1513,4 @@ export {
1513
1513
  SKILL_GRAPH_READS,
1514
1514
  SkillGraphDebugger
1515
1515
  };
1516
- //# sourceMappingURL=chunk-DU4VFDTY.js.map
1516
+ //# sourceMappingURL=chunk-ORT5OUHS.js.map