agentfootprint-lens 0.67.0 → 0.68.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 (37) hide show
  1. package/README.md +105 -1
  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-2RIRLJUN.js → chunk-M5P65VVK.js} +4 -3
  7. package/dist/{chunk-2RIRLJUN.js.map → chunk-M5P65VVK.js.map} +1 -1
  8. package/dist/{chunk-DU4VFDTY.js → chunk-ORT5OUHS.js} +3 -3
  9. package/dist/{chunk-4K45VV7M.js → chunk-WM5QJ6TD.js} +1076 -411
  10. package/dist/chunk-WM5QJ6TD.js.map +1 -0
  11. package/dist/{chunk-CO5R2ODI.js → chunk-XK74JIRU.js} +28 -3
  12. package/dist/chunk-XK74JIRU.js.map +1 -0
  13. package/dist/context.cjs +28 -2
  14. package/dist/context.cjs.map +1 -1
  15. package/dist/context.d.cts +1 -1
  16. package/dist/context.d.ts +1 -1
  17. package/dist/context.js +3 -3
  18. package/dist/index.cjs +2524 -1825
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +227 -4
  21. package/dist/index.d.ts +227 -4
  22. package/dist/index.js +40 -28
  23. package/dist/index.js.map +1 -1
  24. package/dist/skillgraph.cjs +27 -2
  25. package/dist/skillgraph.cjs.map +1 -1
  26. package/dist/skillgraph.js +3 -3
  27. package/dist/why.cjs +1458 -772
  28. package/dist/why.cjs.map +1 -1
  29. package/dist/why.d.cts +2 -2
  30. package/dist/why.d.ts +2 -2
  31. package/dist/why.js +4 -4
  32. package/package.json +3 -3
  33. package/dist/chunk-4K45VV7M.js.map +0 -1
  34. package/dist/chunk-CO5R2ODI.js.map +0 -1
  35. /package/dist/{chunk-UFC3IZPT.js.map → chunk-AUEVEPXO.js.map} +0 -0
  36. /package/dist/{chunk-S3WZBG5I.js.map → chunk-LDO7Y76D.js.map} +0 -0
  37. /package/dist/{chunk-DU4VFDTY.js.map → chunk-ORT5OUHS.js.map} +0 -0
package/README.md CHANGED
@@ -981,6 +981,108 @@ not answer, since it takes an exact stop.
981
981
 
982
982
  ---
983
983
 
984
+ ## Explain this answer — In plain words
985
+
986
+ **One answer, explained for a reader who is not an engineer: seven rows, every
987
+ line from the run's record, with who says so.** `<PlainWords>` draws
988
+ agentfootprint's **answer account** — `accountForAnswer`, a pure Fold over one
989
+ answer's recording, computed on the SERVER by the `answer-account` hosting op —
990
+ as **In one line** plus seven rows: *You asked · It understood · It checked ·
991
+ It did not check · It found · How sure · Anything wrong*.
992
+
993
+ ### Why
994
+
995
+ Every sentence in the pane is filled from the record by one of the library's
996
+ fixed, versioned templates — no model writes it, and the lens writes none of
997
+ its own. Each line carries a **said by** chip (you · the library's record · a
998
+ tool · the model · the app), a fact the record does not hold says **not
999
+ recorded** instead of a guess, and **show me** opens the leaf of the record the
1000
+ line came from. The component is props only: it fetches nothing and receives no
1001
+ recording — the op returns `{ account, shown }`, where `shown` holds only the
1002
+ leaf values the server's allow-list lets out.
1003
+
1004
+ ### Mount it
1005
+
1006
+ ```tsx
1007
+ import { PlainWords, printAnswerAccount } from 'agentfootprint-lens';
1008
+
1009
+ // One request per Explain — the op answers from the recording on the server.
1010
+ const res = await fetch('/invoke', {
1011
+ method: 'POST',
1012
+ headers: { 'content-type': 'application/json', 'x-session-id': sessionId },
1013
+ body: JSON.stringify({ op: 'answer-account', ref: reply.reasoning.ref }),
1014
+ });
1015
+ const { account, shown } = await res.json();
1016
+
1017
+ <PlainWords
1018
+ account={account}
1019
+ shown={shown}
1020
+ labelledBy="tab-plain" // your drawer's tab → role="tabpanel"
1021
+ focusOnMount // opened from "Explain this answer"
1022
+ onSaveAsPdf={() => printAnswerAccount(account)}
1023
+ onOpenInLens={debug ? openFlowLensAt : undefined} // only when the engineer lenses exist
1024
+ />
1025
+ ```
1026
+
1027
+ | Prop | Type | Description |
1028
+ |---|---|---|
1029
+ | `account` | `AnswerAccount` | **Required.** The op's `account` (type from `agentfootprint/observe`). |
1030
+ | `shown` | `Record<string, AnswerAccountShownLeaf>?` | The op's `shown`. Looked up by `answerAccountPointerKey`. Omit → "show me" lists the pointers as text. |
1031
+ | `onOpenInLens` | `(pointer) => void?` | Draws "Open in the Flow Lens" beside each record pointer in "show me". Pass it only where those lenses exist. |
1032
+ | `showQuestionAndAnswer` | `boolean?` | The question and the answer above the one-liner. Default `true`. |
1033
+ | `onSaveAsPdf` | `() => void?` | Draws **Save as PDF**; pass `() => printAnswerAccount(account)`. |
1034
+ | `templateIdsToggle` | `boolean?` | The "template ids" toggle (each line's `id@version`). Default `true`. |
1035
+ | `theme` | `{ mode: 'light' \| 'dark' }?` | Standalone: stamps the lens palette. Inside `<Lens theme>` leave it out. |
1036
+ | `labelledBy` | `string?` | Your tab's id: the pane becomes `role="tabpanel"` labelled by it. Otherwise a region named "In plain words". |
1037
+ | `focusOnMount` | `boolean?` | Focus the pane's "In one line" heading on mount. |
1038
+
1039
+ ### What it keeps
1040
+
1041
+ - **No sentence of its own.** Headings, lines, chips and the one-liner are the
1042
+ library's `text`; the pane's own strings are `PLAIN_WORDS_LABELS` — names,
1043
+ never claims (walked by `test/served/no-own-claims.test.ts`).
1044
+ - **No HTML from data.** A sentence renders from its typed `parts` as text:
1045
+ `code` → `<code>`, `quote` → `<q>`, a declared `label` → `<strong>` with its
1046
+ own voucher. A `<script>` in a question is shown as the characters `<script>`.
1047
+ - **Show me = leaves.** A withheld leaf says why (`not shown here`, `too large
1048
+ to show here`, …); a line into a call the model read without the tool's
1049
+ report-only fields says so softly.
1050
+ - **Said by, on the line.** The library puts one `said-by` chip per source on
1051
+ the row; the pane pairs each to its recorded lines by the library's own rule,
1052
+ and leaves them on the row if a row ever does not pair.
1053
+ - **Accessible.** `h2` "In one line", an `h3` per row, lists for lines and
1054
+ items, every "show me" a `<button aria-expanded aria-controls>`; the tone is
1055
+ a border AND a word; four tone tokens (`--fp-tone-ok|warn|bad|unknown`) in
1056
+ both palettes, each ≥ 4.5:1 on its surfaces.
1057
+
1058
+ ### Save as PDF
1059
+
1060
+ `printAnswerAccount(account, { recordedAt? })` prints a one-page report from a
1061
+ hidden, `aria-hidden` frame whose document is titled **Answer report** (so the
1062
+ browser's print header says that): the question, a meta line — run id, the
1063
+ recorded and printed times as ISO-8601 UTC, model, template set — the answer as
1064
+ plain text (folded at 1,200 characters), In one line, and the rows as a table
1065
+ with "said by …" and the template id under each line (lists fold at six items).
1066
+ It never prints "show me", makes no request, and removes the frame on
1067
+ `afterprint`. `<AnswerReportPrint account />` is the same report as a component.
1068
+ The account does not carry the recorded time; pass the answer's `turn_start`
1069
+ `meta.wallClockMs` as `recordedAt` when you hold it (`<Lens>` reads it off its
1070
+ recording), else the line says `not recorded`.
1071
+
1072
+ ### In the Lens: the analyst view
1073
+
1074
+ ```tsx
1075
+ <Lens recorder={recorder} view="analyst" account={account} accountShown={shown} />
1076
+ ```
1077
+
1078
+ With `account`, the analyst view leads with `<PlainWords>` and folds the
1079
+ summary card, the transport and the commentary under a native **More detail**
1080
+ `<details>`. Without it, the analyst view is byte-for-byte what it was. The
1081
+ `engineer` and `user` views never read the prop.
1082
+
1083
+ Needs agentfootprint ≥ 9.116.0 (the release that ships `AnswerAccount` and the
1084
+ op) — the lens's peer floor since 0.68.0.
1085
+
984
1086
  ## The Served tab
985
1087
 
986
1088
  **At every LLM call, exactly what the model was served — provable from the log.**
@@ -1499,7 +1601,7 @@ your `--lens-*` still wins.
1499
1601
  Every token has a built-in value, so nothing is ever unpainted. See
1500
1602
  `src/react/theme/tokens.ts` for the full list (surfaces / text / border /
1501
1603
  accent / 4 edge kinds / 7 injection-source chips / 8 agent swatches /
1502
- typography), all of it exported as `T`, `RAW_DEFAULTS`, `AGENT_COLORS` and
1604
+ 4 In plain words tones / typography), all of it exported as `T`, `RAW_DEFAULTS`, `AGENT_COLORS` and
1503
1605
  `MODE_PALETTES`.
1504
1606
 
1505
1607
  ### Server rendering
@@ -1564,6 +1666,8 @@ graph in one call. Returns an unsubscribe. Call it once per run.
1564
1666
  | `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
1667
  | `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
1668
  | `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). |
1669
+ | `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). |
1670
+ | `accountShown` | `Record<string, AnswerAccountShownLeaf>?` | The op's `shown` leaves, for "show me". |
1567
1671
 
1568
1672
  ### `<LensFlow>` — the chart canvas on its own
1569
1673
 
@@ -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
@@ -2777,6 +2777,7 @@ var LABELS7 = Object.freeze({
2777
2777
  });
2778
2778
  var isRecord6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
2779
2779
  function keysOf(record) {
2780
+ if (!isRecord6(record) && !Array.isArray(record)) return { rows: [], unsupportedValues: void 0 };
2780
2781
  if (Array.isArray(record)) {
2781
2782
  let ledger;
2782
2783
  let unsupported;
@@ -2905,4 +2906,4 @@ export {
2905
2906
  CLIP3 as CLIP,
2906
2907
  storyMarks
2907
2908
  };
2908
- //# sourceMappingURL=chunk-2RIRLJUN.js.map
2909
+ //# sourceMappingURL=chunk-M5P65VVK.js.map