agentfootprint 7.4.0 → 7.6.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 (166) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +108 -11
  4. package/ai-instructions/claude-code/SKILL.md +1 -1
  5. package/dist/core/Agent.js +19 -1
  6. package/dist/core/Agent.js.map +1 -1
  7. package/dist/core/RunnerBase.js +12 -1
  8. package/dist/core/RunnerBase.js.map +1 -1
  9. package/dist/core/agent/AgentBuilder.js +33 -1
  10. package/dist/core/agent/AgentBuilder.js.map +1 -1
  11. package/dist/core/agent/stages/toolCalls.js +225 -16
  12. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  13. package/dist/core/checkin.js +266 -0
  14. package/dist/core/checkin.js.map +1 -0
  15. package/dist/core/pause.js +17 -1
  16. package/dist/core/pause.js.map +1 -1
  17. package/dist/core/tools.js +3 -0
  18. package/dist/core/tools.js.map +1 -1
  19. package/dist/debug.js +17 -2
  20. package/dist/debug.js.map +1 -1
  21. package/dist/esm/core/Agent.d.ts +6 -1
  22. package/dist/esm/core/Agent.js +19 -1
  23. package/dist/esm/core/Agent.js.map +1 -1
  24. package/dist/esm/core/RunnerBase.js +12 -1
  25. package/dist/esm/core/RunnerBase.js.map +1 -1
  26. package/dist/esm/core/agent/AgentBuilder.d.ts +27 -0
  27. package/dist/esm/core/agent/AgentBuilder.js +33 -1
  28. package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
  29. package/dist/esm/core/agent/stages/toolCalls.d.ts +9 -0
  30. package/dist/esm/core/agent/stages/toolCalls.js +225 -16
  31. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  32. package/dist/esm/core/agent/types.d.ts +2 -0
  33. package/dist/esm/core/checkin.d.ts +263 -0
  34. package/dist/esm/core/checkin.js +254 -0
  35. package/dist/esm/core/checkin.js.map +1 -0
  36. package/dist/esm/core/pause.d.ts +24 -0
  37. package/dist/esm/core/pause.js +15 -0
  38. package/dist/esm/core/pause.js.map +1 -1
  39. package/dist/esm/core/tools.d.ts +19 -0
  40. package/dist/esm/core/tools.js +3 -0
  41. package/dist/esm/core/tools.js.map +1 -1
  42. package/dist/esm/debug.d.ts +3 -2
  43. package/dist/esm/debug.js +10 -2
  44. package/dist/esm/debug.js.map +1 -1
  45. package/dist/esm/events/dispatcher.d.ts +1 -1
  46. package/dist/esm/events/dispatcher.js.map +1 -1
  47. package/dist/esm/events/payloads.d.ts +19 -0
  48. package/dist/esm/events/registry.d.ts +7 -1
  49. package/dist/esm/events/registry.js +6 -0
  50. package/dist/esm/events/registry.js.map +1 -1
  51. package/dist/esm/index.d.ts +4 -1
  52. package/dist/esm/index.js +9 -1
  53. package/dist/esm/index.js.map +1 -1
  54. package/dist/esm/lib/context-bisect/index.d.ts +1 -0
  55. package/dist/esm/lib/context-bisect/index.js +3 -0
  56. package/dist/esm/lib/context-bisect/index.js.map +1 -1
  57. package/dist/esm/lib/context-bisect/localize.d.ts +6 -2
  58. package/dist/esm/lib/context-bisect/localize.js +19 -3
  59. package/dist/esm/lib/context-bisect/localize.js.map +1 -1
  60. package/dist/esm/lib/context-bisect/rerun.d.ts +123 -0
  61. package/dist/esm/lib/context-bisect/rerun.js +155 -0
  62. package/dist/esm/lib/context-bisect/rerun.js.map +1 -0
  63. package/dist/esm/lib/context-bisect/types.d.ts +8 -0
  64. package/dist/esm/lib/context-bisect/types.js.map +1 -1
  65. package/dist/esm/lib/influence-core/index.d.ts +2 -0
  66. package/dist/esm/lib/influence-core/index.js +2 -0
  67. package/dist/esm/lib/influence-core/index.js.map +1 -1
  68. package/dist/esm/lib/influence-core/lexical.d.ts +60 -0
  69. package/dist/esm/lib/influence-core/lexical.js +142 -0
  70. package/dist/esm/lib/influence-core/lexical.js.map +1 -0
  71. package/dist/esm/lib/influence-core/signals.d.ts +5 -0
  72. package/dist/esm/lib/influence-core/signals.js +6 -2
  73. package/dist/esm/lib/influence-core/signals.js.map +1 -1
  74. package/dist/esm/lib/influence-core/strategies.d.ts +51 -0
  75. package/dist/esm/lib/influence-core/strategies.js +29 -0
  76. package/dist/esm/lib/influence-core/strategies.js.map +1 -0
  77. package/dist/esm/lib/recorded-chat/index.d.ts +11 -0
  78. package/dist/esm/lib/recorded-chat/index.js +11 -0
  79. package/dist/esm/lib/recorded-chat/index.js.map +1 -0
  80. package/dist/esm/lib/recorded-chat/recordedChat.d.ts +20 -0
  81. package/dist/esm/lib/recorded-chat/recordedChat.js +240 -0
  82. package/dist/esm/lib/recorded-chat/recordedChat.js.map +1 -0
  83. package/dist/esm/lib/recorded-chat/types.d.ts +182 -0
  84. package/dist/esm/lib/recorded-chat/types.js +31 -0
  85. package/dist/esm/lib/recorded-chat/types.js.map +1 -0
  86. package/dist/esm/recorders/core/CheckInRecorder.d.ts +90 -0
  87. package/dist/esm/recorders/core/CheckInRecorder.js +109 -0
  88. package/dist/esm/recorders/core/CheckInRecorder.js.map +1 -0
  89. package/dist/events/dispatcher.js.map +1 -1
  90. package/dist/events/registry.js +6 -0
  91. package/dist/events/registry.js.map +1 -1
  92. package/dist/index.js +18 -1
  93. package/dist/index.js.map +1 -1
  94. package/dist/lib/context-bisect/index.js +6 -1
  95. package/dist/lib/context-bisect/index.js.map +1 -1
  96. package/dist/lib/context-bisect/localize.js +19 -3
  97. package/dist/lib/context-bisect/localize.js.map +1 -1
  98. package/dist/lib/context-bisect/rerun.js +160 -0
  99. package/dist/lib/context-bisect/rerun.js.map +1 -0
  100. package/dist/lib/context-bisect/types.js.map +1 -1
  101. package/dist/lib/influence-core/index.js +7 -1
  102. package/dist/lib/influence-core/index.js.map +1 -1
  103. package/dist/lib/influence-core/lexical.js +146 -0
  104. package/dist/lib/influence-core/lexical.js.map +1 -0
  105. package/dist/lib/influence-core/signals.js +8 -3
  106. package/dist/lib/influence-core/signals.js.map +1 -1
  107. package/dist/lib/influence-core/strategies.js +33 -0
  108. package/dist/lib/influence-core/strategies.js.map +1 -0
  109. package/dist/lib/recorded-chat/index.js +15 -0
  110. package/dist/lib/recorded-chat/index.js.map +1 -0
  111. package/dist/lib/recorded-chat/recordedChat.js +244 -0
  112. package/dist/lib/recorded-chat/recordedChat.js.map +1 -0
  113. package/dist/lib/recorded-chat/types.js +32 -0
  114. package/dist/lib/recorded-chat/types.js.map +1 -0
  115. package/dist/recorders/core/CheckInRecorder.js +114 -0
  116. package/dist/recorders/core/CheckInRecorder.js.map +1 -0
  117. package/dist/types/core/Agent.d.ts +6 -1
  118. package/dist/types/core/Agent.d.ts.map +1 -1
  119. package/dist/types/core/RunnerBase.d.ts.map +1 -1
  120. package/dist/types/core/agent/AgentBuilder.d.ts +27 -0
  121. package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
  122. package/dist/types/core/agent/stages/toolCalls.d.ts +9 -0
  123. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  124. package/dist/types/core/agent/types.d.ts +2 -0
  125. package/dist/types/core/agent/types.d.ts.map +1 -1
  126. package/dist/types/core/checkin.d.ts +264 -0
  127. package/dist/types/core/checkin.d.ts.map +1 -0
  128. package/dist/types/core/pause.d.ts +24 -0
  129. package/dist/types/core/pause.d.ts.map +1 -1
  130. package/dist/types/core/tools.d.ts +19 -0
  131. package/dist/types/core/tools.d.ts.map +1 -1
  132. package/dist/types/debug.d.ts +3 -2
  133. package/dist/types/debug.d.ts.map +1 -1
  134. package/dist/types/events/dispatcher.d.ts +1 -1
  135. package/dist/types/events/dispatcher.d.ts.map +1 -1
  136. package/dist/types/events/payloads.d.ts +19 -0
  137. package/dist/types/events/payloads.d.ts.map +1 -1
  138. package/dist/types/events/registry.d.ts +7 -1
  139. package/dist/types/events/registry.d.ts.map +1 -1
  140. package/dist/types/index.d.ts +4 -1
  141. package/dist/types/index.d.ts.map +1 -1
  142. package/dist/types/lib/context-bisect/index.d.ts +1 -0
  143. package/dist/types/lib/context-bisect/index.d.ts.map +1 -1
  144. package/dist/types/lib/context-bisect/localize.d.ts +6 -2
  145. package/dist/types/lib/context-bisect/localize.d.ts.map +1 -1
  146. package/dist/types/lib/context-bisect/rerun.d.ts +124 -0
  147. package/dist/types/lib/context-bisect/rerun.d.ts.map +1 -0
  148. package/dist/types/lib/context-bisect/types.d.ts +8 -0
  149. package/dist/types/lib/context-bisect/types.d.ts.map +1 -1
  150. package/dist/types/lib/influence-core/index.d.ts +2 -0
  151. package/dist/types/lib/influence-core/index.d.ts.map +1 -1
  152. package/dist/types/lib/influence-core/lexical.d.ts +61 -0
  153. package/dist/types/lib/influence-core/lexical.d.ts.map +1 -0
  154. package/dist/types/lib/influence-core/signals.d.ts +5 -0
  155. package/dist/types/lib/influence-core/signals.d.ts.map +1 -1
  156. package/dist/types/lib/influence-core/strategies.d.ts +52 -0
  157. package/dist/types/lib/influence-core/strategies.d.ts.map +1 -0
  158. package/dist/types/lib/recorded-chat/index.d.ts +12 -0
  159. package/dist/types/lib/recorded-chat/index.d.ts.map +1 -0
  160. package/dist/types/lib/recorded-chat/recordedChat.d.ts +21 -0
  161. package/dist/types/lib/recorded-chat/recordedChat.d.ts.map +1 -0
  162. package/dist/types/lib/recorded-chat/types.d.ts +183 -0
  163. package/dist/types/lib/recorded-chat/types.d.ts.map +1 -0
  164. package/dist/types/recorders/core/CheckInRecorder.d.ts +91 -0
  165. package/dist/types/recorders/core/CheckInRecorder.d.ts.map +1 -0
  166. package/package.json +1 -1
@@ -0,0 +1,60 @@
1
+ /**
2
+ * scoreLexicalInfluence — the DETERMINISTIC, zero-dependency influence
3
+ * scorer: the same four-signal FDL frame as `scoreInfluence`
4
+ * (fa / avg / persist / depth, adaptive weights, composite, stable desc
5
+ * sort), with ONE substitution — cosine-over-embeddings becomes set-cosine
6
+ * over word tokens. Nothing here embeds; nothing here calls the network.
7
+ *
8
+ * ## Honest claim (same discipline as `scoreInfluence`, one rung blinder)
9
+ *
10
+ * Every returned `InfluenceScore.signals` / `weights` / `adapted` is
11
+ * GENUINELY computed — nothing is fabricated. But the FA signal here means
12
+ * "shares words with the final answer", NOT "semantically close" and NOT
13
+ * "caused". It is cheaper and BLINDER than `'semantic-alignment'`: a
14
+ * paraphrase (different words, same meaning) is a miss. The claim-ladder
15
+ * guarantee is unchanged — a scorer only reorders suspects; ablation alone
16
+ * convicts. So the worst a lexical ranking does is confirm slower, never
17
+ * wrong.
18
+ *
19
+ * English / ASCII by construction (the tokenizer splits on non-alphanumerics
20
+ * and folds a single trailing plural `s`) — use `'semantic-alignment'` for
21
+ * other languages.
22
+ */
23
+ import type { Embedder, EvidenceInput, InfluenceScore, InfluenceWeights } from './types.js';
24
+ /**
25
+ * Args for `scoreLexicalInfluence` — a SUPERTYPE of `ScoreInfluenceArgs`:
26
+ * everything the embedding scorer takes, with `embedder` optional and NEVER
27
+ * called. That supertype relationship is what makes `scoreLexicalInfluence`
28
+ * assignable to `InfluenceScorer` (parameter contravariance) while remaining
29
+ * honestly callable with no embedder at all.
30
+ */
31
+ export interface ScoreLexicalInfluenceArgs {
32
+ /** Evidence items (tool results / context sources) with ancestors. */
33
+ readonly evidence: readonly EvidenceInput[];
34
+ /** The final answer text the evidence is scored against. */
35
+ readonly finalAnswerText: string;
36
+ /** Accepted only for `InfluenceScorer` compatibility. IGNORED — this scorer never embeds. */
37
+ readonly embedder?: Embedder;
38
+ /** Composite weights (same frame as `scoreInfluence`). Default 0.40/0.30/0.20/0.10. */
39
+ readonly weights?: InfluenceWeights;
40
+ /** PERSIST threshold on the LEXICAL overlap scale (set-cosine, 0..1). Default 0.30. */
41
+ readonly persistenceThreshold?: number;
42
+ /** Accepted for compatibility; unused (nothing async to abort — resolves immediately). */
43
+ readonly signal?: AbortSignal;
44
+ }
45
+ /**
46
+ * Score every evidence item on the four FDL signals — the LEXICAL kernel
47
+ * (set-cosine over word tokens instead of embedding cosine) — and rank by
48
+ * composite, descending. Ties keep input order (stable sort).
49
+ *
50
+ * Deterministic: same inputs → byte-identical output, every run, every
51
+ * machine. Zero dependencies, zero network, sync-fast (async only to satisfy
52
+ * the `InfluenceScorer` seam). Never touches `args.embedder` or `args.signal`.
53
+ *
54
+ * Honest claim: ranked WORD-OVERLAP proxies — cheaper and blinder than the
55
+ * embedding scorer (paraphrase = miss). NOT causal attribution — see module
56
+ * docs.
57
+ *
58
+ * @throws on duplicate evidence ids or invalid weights.
59
+ */
60
+ export declare function scoreLexicalInfluence(args: ScoreLexicalInfluenceArgs): Promise<InfluenceScore[]>;
@@ -0,0 +1,142 @@
1
+ import { DEFAULT_INFLUENCE_WEIGHTS, DEFAULT_PERSISTENCE_THRESHOLD } from './types.js';
2
+ import { adaptWeights, assertUniqueIds, assertValidWeights, compositeScore, structuralProximity, } from './signals.js';
3
+ /** Small, conservative stop list — fillers that would only add noise to
4
+ * the overlap. Copied verbatim from the injection-engine's `EntryScorer`
5
+ * (influence-core is a leaf — it restates rather than imports). */
6
+ const STOP_WORDS = new Set([
7
+ 'a',
8
+ 'an',
9
+ 'the',
10
+ 'and',
11
+ 'or',
12
+ 'but',
13
+ 'if',
14
+ 'to',
15
+ 'of',
16
+ 'for',
17
+ 'in',
18
+ 'on',
19
+ 'at',
20
+ 'by',
21
+ 'with',
22
+ 'is',
23
+ 'are',
24
+ 'was',
25
+ 'were',
26
+ 'be',
27
+ 'been',
28
+ 'it',
29
+ 'this',
30
+ 'that',
31
+ 'these',
32
+ 'those',
33
+ 'i',
34
+ 'you',
35
+ 'we',
36
+ 'my',
37
+ 'our',
38
+ 'me',
39
+ 'please',
40
+ 'can',
41
+ 'could',
42
+ 'would',
43
+ 'should',
44
+ 'do',
45
+ 'does',
46
+ 'how',
47
+ 'what',
48
+ 'need',
49
+ 'want',
50
+ ]);
51
+ /**
52
+ * Lowercase → split on non-alphanumerics → drop 1-char tokens + stop words →
53
+ * light plural fold → set. The plural fold (drop a single trailing `s` on
54
+ * tokens length ≥ 4, but never `-ss`) lets `refund` match `refunds` while
55
+ * `address` stays `address`. ASCII-only by construction (the regex splits
56
+ * away non-Latin/accented text — use `'semantic-alignment'` for other
57
+ * languages).
58
+ */
59
+ function tokenize(text) {
60
+ const out = new Set();
61
+ for (const raw of text.toLowerCase().split(/[^a-z0-9]+/)) {
62
+ if (raw.length < 2 || STOP_WORDS.has(raw))
63
+ continue;
64
+ const fold = raw.length >= 4 && raw.endsWith('s') && !raw.endsWith('ss');
65
+ out.add(fold ? raw.slice(0, -1) : raw);
66
+ }
67
+ return out;
68
+ }
69
+ /** |A ∩ B| / sqrt(|A| · |B|) — set cosine, range [0, 1]. Empty either side → 0.
70
+ * Iterates the smaller set (same kernel as EntryScorer's `setCosine`). */
71
+ function overlap(a, b) {
72
+ if (a.size === 0 || b.size === 0)
73
+ return 0;
74
+ const [small, large] = a.size <= b.size ? [a, b] : [b, a];
75
+ let shared = 0;
76
+ for (const t of small)
77
+ if (large.has(t))
78
+ shared += 1;
79
+ return shared / Math.sqrt(a.size * b.size);
80
+ }
81
+ /**
82
+ * Score every evidence item on the four FDL signals — the LEXICAL kernel
83
+ * (set-cosine over word tokens instead of embedding cosine) — and rank by
84
+ * composite, descending. Ties keep input order (stable sort).
85
+ *
86
+ * Deterministic: same inputs → byte-identical output, every run, every
87
+ * machine. Zero dependencies, zero network, sync-fast (async only to satisfy
88
+ * the `InfluenceScorer` seam). Never touches `args.embedder` or `args.signal`.
89
+ *
90
+ * Honest claim: ranked WORD-OVERLAP proxies — cheaper and blinder than the
91
+ * embedding scorer (paraphrase = miss). NOT causal attribution — see module
92
+ * docs.
93
+ *
94
+ * @throws on duplicate evidence ids or invalid weights.
95
+ */
96
+ export async function scoreLexicalInfluence(args) {
97
+ const weights = args.weights ?? DEFAULT_INFLUENCE_WEIGHTS;
98
+ assertValidWeights(weights, 'scoreLexicalInfluence');
99
+ const threshold = args.persistenceThreshold ?? DEFAULT_PERSISTENCE_THRESHOLD;
100
+ assertUniqueIds(args.evidence, 'scoreLexicalInfluence');
101
+ // One deduplicated tokenization pass over every distinct text.
102
+ const tokensByText = new Map();
103
+ const tokensOf = (text) => {
104
+ let set = tokensByText.get(text);
105
+ if (set === undefined) {
106
+ set = tokenize(text);
107
+ tokensByText.set(text, set);
108
+ }
109
+ return set;
110
+ };
111
+ const answerTokens = tokensOf(args.finalAnswerText);
112
+ const scored = args.evidence.map((item) => {
113
+ const evidenceTokens = tokensOf(item.text);
114
+ const ancestorTokens = item.ancestorTexts.map((t) => tokensOf(t));
115
+ const n = ancestorTokens.length;
116
+ let avgSum = 0;
117
+ let above = 0;
118
+ for (const ancestor of ancestorTokens) {
119
+ const sim = overlap(evidenceTokens, ancestor);
120
+ avgSum += sim;
121
+ if (sim > threshold)
122
+ above += 1;
123
+ }
124
+ const signals = {
125
+ fa: overlap(evidenceTokens, answerTokens),
126
+ avg: n === 0 ? 0 : avgSum / n,
127
+ persist: n === 0 ? 0 : above / n,
128
+ depth: structuralProximity(n),
129
+ };
130
+ const effective = adaptWeights(weights, n);
131
+ return {
132
+ id: item.id,
133
+ signals,
134
+ weights: effective.weights,
135
+ adapted: effective.adapted,
136
+ score: compositeScore(signals, effective.weights),
137
+ };
138
+ });
139
+ // Stable sort — equal scores keep evidence input order.
140
+ return scored.sort((a, b) => b.score - a.score);
141
+ }
142
+ //# sourceMappingURL=lexical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexical.js","sourceRoot":"","sources":["../../../../src/lib/influence-core/lexical.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAwBtB;;oEAEoE;AACpE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG;IACH,IAAI;IACJ,KAAK;IACL,KAAK;IACL,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,GAAG;IACH,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,QAAQ;IACR,KAAK;IACL,OAAO;IACP,OAAO;IACP,QAAQ;IACR,IAAI;IACJ,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QACzD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACpD,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;2EAC2E;AAC3E,SAAS,OAAO,CAAC,CAAsB,EAAE,CAAsB;IAC7D,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,CAAC,CAAC;IACrD,OAAO,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAA+B;IAE/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,yBAAyB,CAAC;IAC1D,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,IAAI,6BAA6B,CAAC;IAC7E,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;IAExD,+DAA+D;IAC/D,MAAM,YAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;IACpD,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAe,EAAE;QAC7C,IAAI,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YACrB,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAEpD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAkB,EAAE;QACxD,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAElE,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC;QAChC,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,CAAC;YACd,IAAI,GAAG,GAAG,SAAS;gBAAE,KAAK,IAAI,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,OAAO,GAAiB;YAC5B,EAAE,EAAE,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC;YACzC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;YAC7B,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;YAChC,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC;SAC9B,CAAC;QACF,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAE3C,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,OAAO;YACP,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,KAAK,EAAE,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC;SAClD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,wDAAwD;IACxD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC"}
@@ -126,3 +126,8 @@ export declare function embedAll(embedder: Embedder, texts: readonly string[], s
126
126
  * attributes the error to the actual caller.
127
127
  */
128
128
  export declare function assertValidWeights(weights: InfluenceWeights, fnName?: string): void;
129
+ /**
130
+ * Validate that every evidence id is unique. Shared by `scoreInfluence` and
131
+ * `scoreLexicalInfluence` — `fnName` attributes the error to the actual caller.
132
+ */
133
+ export declare function assertUniqueIds(evidence: readonly EvidenceInput[], fnName?: string): void;
@@ -225,11 +225,15 @@ export function assertValidWeights(weights, fnName = 'scoreInfluence') {
225
225
  throw new Error(`${fnName}: all weights are zero — the composite would always be 0`);
226
226
  }
227
227
  }
228
- function assertUniqueIds(evidence) {
228
+ /**
229
+ * Validate that every evidence id is unique. Shared by `scoreInfluence` and
230
+ * `scoreLexicalInfluence` — `fnName` attributes the error to the actual caller.
231
+ */
232
+ export function assertUniqueIds(evidence, fnName = 'scoreInfluence') {
229
233
  const seen = new Set();
230
234
  for (const item of evidence) {
231
235
  if (seen.has(item.id)) {
232
- throw new Error(`scoreInfluence: duplicate evidence id '${item.id}' — ids must be unique`);
236
+ throw new Error(`${fnName}: duplicate evidence id '${item.id}' — ids must be unique`);
233
237
  }
234
238
  seen.add(item.id);
235
239
  }
@@ -1 +1 @@
1
- {"version":3,"file":"signals.js","sourceRoot":"","sources":["../../../../src/lib/influence-core/signals.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"signals.js","sourceRoot":"","sources":["../../../../src/lib/influence-core/signals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Named influence strategies — a plain-named descriptor AROUND the already-
3
+ * public `InfluenceScorer` function seam, exactly the shape a host UI's
4
+ * strategy selector needs (mirrors the `EntryScorer` / `ConfidenceStrategy`
5
+ * "name shown in any strategy picker" precedent).
6
+ *
7
+ * A strategy is `{ name, description, requirements, scorer }`. Two ship:
8
+ * • `semanticAlignmentStrategy` — the FDL four-signal embedding composite
9
+ * (`scoreInfluence`). The default; needs an embedder.
10
+ * • `lexicalOverlapStrategy` — deterministic word overlap
11
+ * (`scoreLexicalInfluence`). Free, zero deps; requires nothing.
12
+ *
13
+ * `listInfluenceStrategies()` enumerates them so a selector can render the
14
+ * two options and grey out what the host can't run (`requirements`).
15
+ *
16
+ * Sugar, not a replacement: `localizeContextBug({ scorer })` still accepts a
17
+ * bare `InfluenceScorer` function; it now ALSO accepts one of these.
18
+ */
19
+ import type { InfluenceScorer } from './signals.js';
20
+ /**
21
+ * What a strategy needs the host to supply before it can run. A selector UI
22
+ * greys out strategies whose requirements the host can't meet. `'embedder'`
23
+ * is the only well-known value today; the type stays open for consumer
24
+ * strategies (`'llm'`, `'reference-run'`, …).
25
+ */
26
+ export type InfluenceStrategyRequirement = 'embedder' | (string & Record<never, never>);
27
+ /**
28
+ * A NAMED influence-scoring strategy — an `InfluenceScorer` plus the metadata
29
+ * a strategy picker needs. Sugar AROUND the function seam, not a replacement:
30
+ * `localizeContextBug({ scorer })` accepts either a bare `InfluenceScorer` or
31
+ * one of these.
32
+ */
33
+ export interface InfluenceStrategy {
34
+ /** Stable kebab-case id — shown in a selector, echoed on `ContextBugReport.rankedBy`. */
35
+ readonly name: string;
36
+ /** One-or-two-sentence plain description for the picker, honesty caveat included. */
37
+ readonly description: string;
38
+ /** What the host must supply to run this strategy (empty = runs anywhere, $0). */
39
+ readonly requirements: readonly InfluenceStrategyRequirement[];
40
+ /** The scorer itself — plugs into `localizeContextBug({ scorer })` directly. */
41
+ readonly scorer: InfluenceScorer;
42
+ }
43
+ /** The DEFAULT: the FDL four-signal embedding composite (`scoreInfluence`). */
44
+ export declare const semanticAlignmentStrategy: InfluenceStrategy;
45
+ /** The cheap option: deterministic word overlap (`scoreLexicalInfluence`), zero deps. */
46
+ export declare const lexicalOverlapStrategy: InfluenceStrategy;
47
+ /**
48
+ * The built-in strategies, default first. Frozen — a host UI renders its
49
+ * selector straight off this (concat your own custom strategies after).
50
+ */
51
+ export declare function listInfluenceStrategies(): readonly InfluenceStrategy[];
@@ -0,0 +1,29 @@
1
+ import { scoreInfluence } from './signals.js';
2
+ import { scoreLexicalInfluence } from './lexical.js';
3
+ /** The DEFAULT: the FDL four-signal embedding composite (`scoreInfluence`). */
4
+ export const semanticAlignmentStrategy = Object.freeze({
5
+ name: 'semantic-alignment',
6
+ description: 'Ranks sources by how semantically close their content is to the final answer, using ' +
7
+ 'embeddings (the four-signal composite). The default. Needs an embedder; scores are a ' +
8
+ 'proxy for alignment, never proof of cause.',
9
+ requirements: Object.freeze(['embedder']),
10
+ scorer: scoreInfluence,
11
+ });
12
+ /** The cheap option: deterministic word overlap (`scoreLexicalInfluence`), zero deps. */
13
+ export const lexicalOverlapStrategy = Object.freeze({
14
+ name: 'lexical-overlap',
15
+ description: 'Ranks sources by plain word overlap with the final answer. Deterministic, free, no ' +
16
+ 'dependencies — the simpler, cheaper option. Misses paraphrases; same proxy caveat: ' +
17
+ 'overlap is not cause.',
18
+ requirements: Object.freeze([]),
19
+ scorer: scoreLexicalInfluence,
20
+ });
21
+ const BUILT_IN = Object.freeze([semanticAlignmentStrategy, lexicalOverlapStrategy]);
22
+ /**
23
+ * The built-in strategies, default first. Frozen — a host UI renders its
24
+ * selector straight off this (concat your own custom strategies after).
25
+ */
26
+ export function listInfluenceStrategies() {
27
+ return BUILT_IN;
28
+ }
29
+ //# sourceMappingURL=strategies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategies.js","sourceRoot":"","sources":["../../../../src/lib/influence-core/strategies.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AA2BrD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,yBAAyB,GAAsB,MAAM,CAAC,MAAM,CAAC;IACxE,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EACT,sFAAsF;QACtF,uFAAuF;QACvF,4CAA4C;IAC9C,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,CAAU,CAAC;IAClD,MAAM,EAAE,cAAc;CACvB,CAAC,CAAC;AAEH,yFAAyF;AACzF,MAAM,CAAC,MAAM,sBAAsB,GAAsB,MAAM,CAAC,MAAM,CAAC;IACrE,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,qFAAqF;QACrF,qFAAqF;QACrF,uBAAuB;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAW,CAAC;IACxC,MAAM,EAAE,qBAAqB;CAC9B,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,yBAAyB,EAAE,sBAAsB,CAAC,CAAC,CAAC;AAEpF;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * recorded-chat — the session-scoped turn recorder over the context-bisect
3
+ * product loop. Absorbs the three correctness traps every chat host re-writes
4
+ * (per-turn artifact freezing, byte-exact history threading, same-factory
5
+ * runner derivation) while COMPOSING with the 7.5 surface, not duplicating it.
6
+ *
7
+ * Exported from `agentfootprint/debug` (every symbol it composes with lives
8
+ * there). Named exports — `export *` is not the house style.
9
+ */
10
+ export { recordedChat } from './recordedChat.js';
11
+ export type { ChatFormat, ChatMessage, ChatTurn, ForkOptions, ForkOrigin, MakeChatAgent, ReasonOptions, RecordedChat, RecordedChatOptions, RerunTurnOptions, SendOptions, } from './types.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * recorded-chat — the session-scoped turn recorder over the context-bisect
3
+ * product loop. Absorbs the three correctness traps every chat host re-writes
4
+ * (per-turn artifact freezing, byte-exact history threading, same-factory
5
+ * runner derivation) while COMPOSING with the 7.5 surface, not duplicating it.
6
+ *
7
+ * Exported from `agentfootprint/debug` (every symbol it composes with lives
8
+ * there). Named exports — `export *` is not the house style.
9
+ */
10
+ export { recordedChat } from './recordedChat.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/recorded-chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * recordedChat — the session-scoped turn recorder.
3
+ *
4
+ * `recordedChat({ makeAgent })` returns a `RecordedChat`: `send()` runs one
5
+ * recorded turn through the consumer's agent factory and freezes that turn's
6
+ * evidence immediately; `reason(k)` / `rerunTurn(k)` / `fork(k)` are the
7
+ * per-turn transparency loop, composing with the existing context-bisect
8
+ * surface (`localizeContextBug`, `rerunWithoutSources`) rather than
9
+ * duplicating it. See `./types.ts` for the three traps this owns.
10
+ *
11
+ * Compose-don't-inherit house style: a module-private session class,
12
+ * factory-returned; no base classes.
13
+ */
14
+ import type { RecordedChat, RecordedChatOptions } from './types.js';
15
+ /**
16
+ * Record a chat turn-by-turn so any reply can be explained, counterfactually
17
+ * re-run, and forked — without re-writing the correctness-critical glue every
18
+ * chat host gets subtly wrong. See the [recordedChat guide](doc:recorded-chat).
19
+ */
20
+ export declare function recordedChat(options: RecordedChatOptions): RecordedChat;
@@ -0,0 +1,240 @@
1
+ /**
2
+ * recordedChat — the session-scoped turn recorder.
3
+ *
4
+ * `recordedChat({ makeAgent })` returns a `RecordedChat`: `send()` runs one
5
+ * recorded turn through the consumer's agent factory and freezes that turn's
6
+ * evidence immediately; `reason(k)` / `rerunTurn(k)` / `fork(k)` are the
7
+ * per-turn transparency loop, composing with the existing context-bisect
8
+ * surface (`localizeContextBug`, `rerunWithoutSources`) rather than
9
+ * duplicating it. See `./types.ts` for the three traps this owns.
10
+ *
11
+ * Compose-don't-inherit house style: a module-private session class,
12
+ * factory-returned; no base classes.
13
+ */
14
+ import { llmCallIdsFromEvents, localizeContextBug, rerunWithoutSources, } from '../context-bisect/index.js';
15
+ const DEFAULT_HEADER = 'Recent conversation:';
16
+ const DEFAULT_USER_LABEL = 'User';
17
+ const DEFAULT_ASSISTANT_LABEL = 'Assistant';
18
+ /** Deterministic key for spec dedup — recursively sorts object keys. */
19
+ function canonicalKey(value) {
20
+ return JSON.stringify(value, (_key, val) => {
21
+ if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
22
+ const sorted = {};
23
+ for (const k of Object.keys(val).sort()) {
24
+ sorted[k] = val[k];
25
+ }
26
+ return sorted;
27
+ }
28
+ return val;
29
+ });
30
+ }
31
+ /** Union of ablation specs, deduped by canonical JSON (order-preserving, first wins). */
32
+ function dedupeSpecs(specs) {
33
+ const seen = new Set();
34
+ const out = [];
35
+ for (const spec of specs) {
36
+ const key = canonicalKey(spec);
37
+ if (seen.has(key))
38
+ continue;
39
+ seen.add(key);
40
+ out.push(spec);
41
+ }
42
+ return out;
43
+ }
44
+ class RecordedChatSession {
45
+ makeAgentFn;
46
+ formatOpt;
47
+ header;
48
+ userLabel;
49
+ assistantLabel;
50
+ /** seed + one (user, assistant) pair per recorded turn. */
51
+ entries;
52
+ seedMessages;
53
+ removedSpecs;
54
+ turnsInternal = [];
55
+ reports = new Map();
56
+ /** result -> turnIndex, the in-process fork-provenance guard. */
57
+ rerunOwner = new WeakMap();
58
+ sending = false;
59
+ forkedFromValue = undefined;
60
+ constructor(options) {
61
+ this.makeAgentFn = options.makeAgent;
62
+ this.formatOpt = options.format;
63
+ this.header = options.format?.header ?? DEFAULT_HEADER;
64
+ this.userLabel = options.format?.userLabel ?? DEFAULT_USER_LABEL;
65
+ this.assistantLabel = options.format?.assistantLabel ?? DEFAULT_ASSISTANT_LABEL;
66
+ this.seedMessages = Object.freeze((options.seed ?? []).map((m) => ({ ...m })));
67
+ this.entries = [...this.seedMessages];
68
+ this.removedSpecs = Object.freeze([...(options.removed ?? [])]);
69
+ }
70
+ get turns() {
71
+ return this.turnsInternal;
72
+ }
73
+ get seed() {
74
+ return this.seedMessages;
75
+ }
76
+ get removed() {
77
+ return this.removedSpecs;
78
+ }
79
+ get forkedFrom() {
80
+ return this.forkedFromValue;
81
+ }
82
+ renderLine(message) {
83
+ const label = message.role === 'user' ? this.userLabel : this.assistantLabel;
84
+ return `${label}: ${message.text}`;
85
+ }
86
+ composeMessage(lines, userMessage) {
87
+ if (lines.length === 0)
88
+ return `${this.userLabel}: ${userMessage}`;
89
+ return `${this.header}\n${lines.join('\n')}\n\n${this.userLabel}: ${userMessage}`;
90
+ }
91
+ async send(userMessage, options) {
92
+ if (this.sending) {
93
+ throw new Error('recordedChat.send: a turn is already in flight — one turn at a time; await the previous send');
94
+ }
95
+ this.sending = true;
96
+ try {
97
+ // Compose the message ONCE, at record time, from the frozen transcript
98
+ // (trap 2 — byte-exact history is threaded HERE and replayed verbatim).
99
+ const transcriptBefore = Object.freeze(this.entries.map((m) => this.renderLine(m)));
100
+ const message = this.composeMessage(transcriptBefore, userMessage);
101
+ const agent = await this.makeAgentFn({ specs: this.removedSpecs, seed: 0 });
102
+ const events = [];
103
+ // Attach the tap BEFORE run() — listener-presence gating drops events
104
+ // otherwise (agentfootprint invariant). Unsubscribe in finally.
105
+ const off = agent.on('*', (event) => {
106
+ events.push(event);
107
+ });
108
+ let out;
109
+ try {
110
+ const raw = await agent.run({
111
+ message,
112
+ ...(options?.identity !== undefined ? { identity: options.identity } : {}),
113
+ });
114
+ if (typeof raw !== 'string') {
115
+ throw new Error("recordedChat.send: the run paused (askHuman/checkIn) — recorded chat turns don't " +
116
+ 'support pauses; drive pausing agents with agent.run() directly');
117
+ }
118
+ out = raw;
119
+ }
120
+ finally {
121
+ off();
122
+ }
123
+ // Capture IMMEDIATELY (trap 1) — getLastSnapshot() is last-run-only, but
124
+ // the per-turn agent is discarded here, so clobbering is impossible.
125
+ const snapshot = agent.getLastSnapshot();
126
+ if (snapshot === undefined) {
127
+ throw new Error('recordedChat.send: the run produced no snapshot — cannot record the turn');
128
+ }
129
+ const lastLlmCallId = llmCallIdsFromEvents(events).at(-1);
130
+ const index = this.turnsInternal.length;
131
+ this.entries.push({ role: 'user', text: userMessage }, { role: 'assistant', text: out });
132
+ const turn = Object.freeze({
133
+ index,
134
+ userMessage,
135
+ reply: out,
136
+ message,
137
+ transcriptBefore,
138
+ artifacts: Object.freeze({ snapshot, events: Object.freeze(events) }),
139
+ lastLlmCallId,
140
+ identity: options?.identity,
141
+ });
142
+ this.turnsInternal.push(turn);
143
+ return turn;
144
+ }
145
+ finally {
146
+ this.sending = false;
147
+ }
148
+ }
149
+ turn(k) {
150
+ const n = this.turnsInternal.length;
151
+ if (!Number.isInteger(k) || k < 0 || k >= n) {
152
+ const range = n === 0 ? '(no turns recorded yet)' : `0..${n - 1}`;
153
+ throw new RangeError(`recordedChat.turn: no turn ${k} — valid range is ${range}`);
154
+ }
155
+ return this.turnsInternal[k];
156
+ }
157
+ async reason(k, options) {
158
+ const turn = this.turn(k);
159
+ const { fresh, atStep, ...rest } = options;
160
+ const memo = this.reports.get(k);
161
+ if (memo !== undefined && fresh !== true)
162
+ return memo;
163
+ const resolvedAtStep = atStep ?? turn.lastLlmCallId;
164
+ const report = await localizeContextBug({
165
+ ...rest,
166
+ artifacts: turn.artifacts,
167
+ ...(resolvedAtStep !== undefined ? { atStep: resolvedAtStep } : {}),
168
+ });
169
+ this.reports.set(k, report);
170
+ return report;
171
+ }
172
+ async rerunTurn(k, options) {
173
+ const turn = this.turn(k);
174
+ const { report: reportOption, ...rerunRest } = options;
175
+ let report = reportOption ?? this.reports.get(k);
176
+ if (report === undefined) {
177
+ report = await this.reason(k, { embedder: options.embedder });
178
+ }
179
+ // Derive the runner from the SAME factory (traps 2 + 3): the frozen
180
+ // message bytes are replayed verbatim, and the session's persistent
181
+ // removals ALWAYS apply on top of the probe's specs (empty specs = the
182
+ // baseline probe, which replays the identical turn).
183
+ const runner = async (specs, run) => {
184
+ const agent = await this.makeAgentFn({
185
+ specs: [...this.removedSpecs, ...specs],
186
+ seed: run.seed,
187
+ });
188
+ const out = await agent.run({
189
+ message: turn.message,
190
+ ...(turn.identity !== undefined ? { identity: turn.identity } : {}),
191
+ });
192
+ if (typeof out !== 'string') {
193
+ throw new Error('recordedChat.rerunTurn: a probe run paused (askHuman/checkIn) — recorded chat re-runs ' +
194
+ "don't support pauses");
195
+ }
196
+ return out;
197
+ };
198
+ const result = await rerunWithoutSources({
199
+ ...rerunRest,
200
+ report,
201
+ runner,
202
+ originalAnswer: turn.reply,
203
+ });
204
+ this.rerunOwner.set(result, k);
205
+ return result;
206
+ }
207
+ fork(k, options) {
208
+ const turn = this.turn(k);
209
+ const fromRerun = options?.fromRerun;
210
+ if (fromRerun !== undefined && this.rerunOwner.get(fromRerun) !== k) {
211
+ throw new Error(`recordedChat.fork: that result was not produced by this session's rerunTurn for turn ${k} — ` +
212
+ 're-run this turn first, then fork');
213
+ }
214
+ const reply = fromRerun?.answer ?? turn.reply;
215
+ const cut = this.seedMessages.length + 2 * k;
216
+ const seed = [
217
+ ...this.entries.slice(0, cut).map((m) => ({ ...m })),
218
+ { role: 'user', text: turn.userMessage },
219
+ { role: 'assistant', text: reply },
220
+ ];
221
+ const removed = dedupeSpecs([...this.removedSpecs, ...(fromRerun?.removed ?? [])]);
222
+ const child = new RecordedChatSession({
223
+ makeAgent: this.makeAgentFn,
224
+ ...(this.formatOpt !== undefined ? { format: this.formatOpt } : {}),
225
+ seed,
226
+ removed,
227
+ });
228
+ child.forkedFromValue = { parent: this, turnIndex: k, viaRerun: fromRerun !== undefined };
229
+ return child;
230
+ }
231
+ }
232
+ /**
233
+ * Record a chat turn-by-turn so any reply can be explained, counterfactually
234
+ * re-run, and forked — without re-writing the correctness-critical glue every
235
+ * chat host gets subtly wrong. See the [recordedChat guide](doc:recorded-chat).
236
+ */
237
+ export function recordedChat(options) {
238
+ return new RecordedChatSession(options);
239
+ }
240
+ //# sourceMappingURL=recordedChat.js.map