agentfootprint 7.1.0 → 7.2.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/CLAUDE.md +1 -1
- package/dist/esm/lib/context-ledger/contextLedger.d.ts +35 -0
- package/dist/esm/lib/context-ledger/contextLedger.js +309 -0
- package/dist/esm/lib/context-ledger/contextLedger.js.map +1 -0
- package/dist/esm/lib/context-ledger/gates.d.ts +63 -0
- package/dist/esm/lib/context-ledger/gates.js +105 -0
- package/dist/esm/lib/context-ledger/gates.js.map +1 -0
- package/dist/esm/lib/context-ledger/index.d.ts +10 -0
- package/dist/esm/lib/context-ledger/index.js +10 -0
- package/dist/esm/lib/context-ledger/index.js.map +1 -0
- package/dist/esm/lib/context-ledger/types.d.ts +107 -0
- package/dist/esm/lib/context-ledger/types.js +28 -0
- package/dist/esm/lib/context-ledger/types.js.map +1 -0
- package/dist/esm/observe.d.ts +2 -0
- package/dist/esm/observe.js +4 -0
- package/dist/esm/observe.js.map +1 -1
- package/dist/lib/context-ledger/contextLedger.js +313 -0
- package/dist/lib/context-ledger/contextLedger.js.map +1 -0
- package/dist/lib/context-ledger/gates.js +111 -0
- package/dist/lib/context-ledger/gates.js.map +1 -0
- package/dist/lib/context-ledger/index.js +17 -0
- package/dist/lib/context-ledger/index.js.map +1 -0
- package/dist/lib/context-ledger/types.js +29 -0
- package/dist/lib/context-ledger/types.js.map +1 -0
- package/dist/observe.js +9 -1
- package/dist/observe.js.map +1 -1
- package/dist/types/lib/context-ledger/contextLedger.d.ts +36 -0
- package/dist/types/lib/context-ledger/contextLedger.d.ts.map +1 -0
- package/dist/types/lib/context-ledger/gates.d.ts +64 -0
- package/dist/types/lib/context-ledger/gates.d.ts.map +1 -0
- package/dist/types/lib/context-ledger/index.d.ts +11 -0
- package/dist/types/lib/context-ledger/index.d.ts.map +1 -0
- package/dist/types/lib/context-ledger/types.d.ts +108 -0
- package/dist/types/lib/context-ledger/types.d.ts.map +1 -0
- package/dist/types/observe.d.ts +2 -0
- package/dist/types/observe.d.ts.map +1 -1
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -16,7 +16,7 @@ Entry points (package.json exports): `.` core API · `/observe` ALL observabilit
|
|
|
16
16
|
| adapters/ | hexagonal ports (types.ts = ALL port interfaces) + vendor impls (llm/, memory/, identity/, observability/) |
|
|
17
17
|
| recorders/core/ | bridges footprintjs events → typed EventDispatcher (ContextRecorder, EmitBridge, typedEmit) — auto-attached by Agent.createExecutor; most factories also exported via `/observe` for manual wiring (EmitBridge itself stays internal) |
|
|
18
18
|
| recorders/observability/ | consumer recorders over the typed stream (RunStepRecorder, FlowchartRecorder, Status, Trace replay) |
|
|
19
|
-
| lib/ | first-party sub-libraries: injection-engine/, context-bisect/ (localizeContextBug, toBacktrackTrace + sliceToBacktrackTrace — the atui board serializers), influence-core/, trace-toolpack/ (selfExplain; 6 tools incl. variable-first `backtrack(variable, element?)`), mcp/, rag/, tool-lint/ |
|
|
19
|
+
| lib/ | first-party sub-libraries: injection-engine/, context-bisect/ (localizeContextBug, toBacktrackTrace + sliceToBacktrackTrace — the atui board serializers), influence-core/, trace-toolpack/ (selfExplain; 6 tools incl. variable-first `backtrack(variable, element?)`), context-ledger/ (which pieces EARNED their tokens — post-run offers/uses/outcomes bookkeeping + demote-never-starve gates `ledgerToolGate`/`ledgerEntryScorer`/`ledgerGated`; grouped-mode folds sf-llm-call inner logs, unmeterable runs → undefined; /observe), mcp/, rag/, tool-lint/ |
|
|
20
20
|
| memory/ | store/ (MemoryStore port) + pipeline presets + stages + beats/facts + causal/ (dev-only, TOP_K+search()-only) + wire/mountMemoryPipeline |
|
|
21
21
|
| events/ | EventDispatcher (wildcard subs), registry (EVENT_NAMES, AgentfootprintEventMap), payloads |
|
|
22
22
|
| conventions.ts | THE builder↔recorder protocol: SUBFLOW_IDS/STAGE_IDS (internal), INJECTION_KEYS/stageRole/milestoneFor (exported, Lens-facing) |
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* contextLedger — the post-run bookkeeper (see types.ts for the WHY).
|
|
3
|
+
*
|
|
4
|
+
* DESIGN: a pure POST-RUN analyzer over the run's own commit log — no live
|
|
5
|
+
* recorder lifecycle, no event-order coupling. Everything it counts is
|
|
6
|
+
* already durably recorded by the engine (dogfooding: offers come from
|
|
7
|
+
* `commitValueAt` folds, answer attribution from `sliceForKey` — the same
|
|
8
|
+
* canonical queries every triage surface uses):
|
|
9
|
+
*
|
|
10
|
+
* offers — the context IN EFFECT at each LLM call. Call marker: a
|
|
11
|
+
* commit that wrote `totalInputTokens` (monotonic — never
|
|
12
|
+
* net-change-dropped) and did NOT write `userMessage` (which
|
|
13
|
+
* only the seed writes). At each call index, fold
|
|
14
|
+
* `activeInjections` + `dynamicToolSchemas`, and add the
|
|
15
|
+
* STATIC tool registry (duck-read from the runner's public
|
|
16
|
+
* `getUIGroup().extra.toolNames` — static registries live in a
|
|
17
|
+
* closure, never in scope state). NOTE offers are deliberately
|
|
18
|
+
* NOT "per context-key commit": the net-change filter drops
|
|
19
|
+
* identical re-commits, so stable context appears once in the
|
|
20
|
+
* log while still being offered (and paying tokens) per call.
|
|
21
|
+
* Static-registry tools count offers with approxTokens 0 in L1
|
|
22
|
+
* (their schema JSON isn't in the log) — earnRate, the gate
|
|
23
|
+
* signal, is unaffected; dynamicToolSchemas carries real sizes.
|
|
24
|
+
* uses — tool: assistant messages' toolCalls in the final history;
|
|
25
|
+
* skill: `activatedInjectionIds`;
|
|
26
|
+
* injection: its SLOT's write sits on the final answer's
|
|
27
|
+
* backward slice (slot-granular, labeled).
|
|
28
|
+
* outcome — consumer label per run, credited to every offered piece.
|
|
29
|
+
*
|
|
30
|
+
* The slot→slice join needs NO id conventions: for each slot key
|
|
31
|
+
* (INJECTION_KEYS.*), `findLastWriter` names the commit that fed the final
|
|
32
|
+
* LLM call; membership of that writer in the answer slice IS the signal.
|
|
33
|
+
*/
|
|
34
|
+
import type { ContextLedger } from './types.js';
|
|
35
|
+
export declare function contextLedger(): ContextLedger;
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* contextLedger — the post-run bookkeeper (see types.ts for the WHY).
|
|
3
|
+
*
|
|
4
|
+
* DESIGN: a pure POST-RUN analyzer over the run's own commit log — no live
|
|
5
|
+
* recorder lifecycle, no event-order coupling. Everything it counts is
|
|
6
|
+
* already durably recorded by the engine (dogfooding: offers come from
|
|
7
|
+
* `commitValueAt` folds, answer attribution from `sliceForKey` — the same
|
|
8
|
+
* canonical queries every triage surface uses):
|
|
9
|
+
*
|
|
10
|
+
* offers — the context IN EFFECT at each LLM call. Call marker: a
|
|
11
|
+
* commit that wrote `totalInputTokens` (monotonic — never
|
|
12
|
+
* net-change-dropped) and did NOT write `userMessage` (which
|
|
13
|
+
* only the seed writes). At each call index, fold
|
|
14
|
+
* `activeInjections` + `dynamicToolSchemas`, and add the
|
|
15
|
+
* STATIC tool registry (duck-read from the runner's public
|
|
16
|
+
* `getUIGroup().extra.toolNames` — static registries live in a
|
|
17
|
+
* closure, never in scope state). NOTE offers are deliberately
|
|
18
|
+
* NOT "per context-key commit": the net-change filter drops
|
|
19
|
+
* identical re-commits, so stable context appears once in the
|
|
20
|
+
* log while still being offered (and paying tokens) per call.
|
|
21
|
+
* Static-registry tools count offers with approxTokens 0 in L1
|
|
22
|
+
* (their schema JSON isn't in the log) — earnRate, the gate
|
|
23
|
+
* signal, is unaffected; dynamicToolSchemas carries real sizes.
|
|
24
|
+
* uses — tool: assistant messages' toolCalls in the final history;
|
|
25
|
+
* skill: `activatedInjectionIds`;
|
|
26
|
+
* injection: its SLOT's write sits on the final answer's
|
|
27
|
+
* backward slice (slot-granular, labeled).
|
|
28
|
+
* outcome — consumer label per run, credited to every offered piece.
|
|
29
|
+
*
|
|
30
|
+
* The slot→slice join needs NO id conventions: for each slot key
|
|
31
|
+
* (INJECTION_KEYS.*), `findLastWriter` names the commit that fed the final
|
|
32
|
+
* LLM call; membership of that writer in the answer slice IS the signal.
|
|
33
|
+
*/
|
|
34
|
+
import { commitValueAt, findLastWriter, flattenCausalDAG, keysReadFromExecutionTree, sliceForKey, } from 'footprintjs/trace';
|
|
35
|
+
import { parseRuntimeStageId, splitStageId } from 'footprintjs/trace';
|
|
36
|
+
import { INJECTION_KEYS, SUBFLOW_IDS } from '../../conventions.js';
|
|
37
|
+
/** chars ÷ 4 — a serialized-length ESTIMATE, deliberately rough and cheap. */
|
|
38
|
+
function approxTokens(value) {
|
|
39
|
+
try {
|
|
40
|
+
return Math.ceil(JSON.stringify(value).length / 4);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** sf-llm-call mount keys in loop order — grouped-mode iterations live in
|
|
47
|
+
* their own retained inner logs (the same projection context-bisect's
|
|
48
|
+
* assembleGroupedTrajectory uses). */
|
|
49
|
+
function llmCallMountKeys(subflowResults) {
|
|
50
|
+
if (!subflowResults)
|
|
51
|
+
return [];
|
|
52
|
+
return Object.keys(subflowResults)
|
|
53
|
+
.filter((k) => k.includes('#') && splitStageId(k.split('#')[0]).localStageId === SUBFLOW_IDS.LLM_CALL)
|
|
54
|
+
.sort((a, b) => parseRuntimeStageId(a).executionIndex - parseRuntimeStageId(b).executionIndex);
|
|
55
|
+
}
|
|
56
|
+
function snapshotOf(source) {
|
|
57
|
+
const maybeRunner = source;
|
|
58
|
+
if (typeof maybeRunner?.getLastSnapshot === 'function') {
|
|
59
|
+
return maybeRunner.getLastSnapshot();
|
|
60
|
+
}
|
|
61
|
+
return source;
|
|
62
|
+
}
|
|
63
|
+
/** Static tool registry names, duck-read from the runner's public UI-group
|
|
64
|
+
* metadata (Agent fills `extra.toolNames`). Empty for non-runner sources. */
|
|
65
|
+
function staticToolNamesOf(source) {
|
|
66
|
+
const maybeRunner = source;
|
|
67
|
+
if (typeof maybeRunner?.getUIGroup !== 'function')
|
|
68
|
+
return [];
|
|
69
|
+
try {
|
|
70
|
+
const names = maybeRunner.getUIGroup()?.extra?.toolNames;
|
|
71
|
+
return Array.isArray(names) ? names.filter((n) => typeof n === 'string') : [];
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function contextLedger() {
|
|
78
|
+
const table = new Map(); // key: `${kind}:${id}`
|
|
79
|
+
const runOffers = new Map(); // runRef → offered keys
|
|
80
|
+
let runsRecorded = 0;
|
|
81
|
+
let lastRunRef;
|
|
82
|
+
function rowOf(kind, id) {
|
|
83
|
+
const key = `${kind}:${id}`;
|
|
84
|
+
let row = table.get(key);
|
|
85
|
+
if (!row) {
|
|
86
|
+
row = { id, kind, offered: 0, approxTokensSpent: 0, used: 0, usedVia: {}, runsSeen: 0, outcomes: {} };
|
|
87
|
+
table.set(key, row);
|
|
88
|
+
}
|
|
89
|
+
return row;
|
|
90
|
+
}
|
|
91
|
+
function markUsed(kind, id, via) {
|
|
92
|
+
const row = rowOf(kind, id);
|
|
93
|
+
row.used += 1;
|
|
94
|
+
row.usedVia[via] = (row.usedVia[via] ?? 0) + 1;
|
|
95
|
+
}
|
|
96
|
+
function recordRun(source) {
|
|
97
|
+
const snapshot = snapshotOf(source);
|
|
98
|
+
const log = snapshot?.commitLog;
|
|
99
|
+
if (!log?.length)
|
|
100
|
+
return undefined;
|
|
101
|
+
runsRecorded += 1;
|
|
102
|
+
const runRef = `run-${runsRecorded}`;
|
|
103
|
+
const offeredKeys = new Set();
|
|
104
|
+
const offer = (kind, id, tokens) => {
|
|
105
|
+
const row = rowOf(kind, id);
|
|
106
|
+
row.offered += 1;
|
|
107
|
+
row.approxTokensSpent += tokens;
|
|
108
|
+
offeredKeys.add(`${kind}:${id}`);
|
|
109
|
+
};
|
|
110
|
+
// ── OFFERS: the context IN EFFECT at each LLM call ───────────────────
|
|
111
|
+
// Call marker: wrote totalInputTokens (monotonic — survives the
|
|
112
|
+
// net-change filter) and NOT userMessage (the seed's unique write).
|
|
113
|
+
// A SINGLE forward pass per log tracks the latest context values as
|
|
114
|
+
// writes appear (one commitValueAt per actual write — O(N), review
|
|
115
|
+
// finding #3), so each marker reads the context in effect exactly even
|
|
116
|
+
// though identical re-commits are dropped from the log.
|
|
117
|
+
//
|
|
118
|
+
// GROUPED reactMode (review finding #1): call-llm + the slots live
|
|
119
|
+
// INSIDE per-iteration `sf-llm-call#k` subflow logs (their context keys
|
|
120
|
+
// never bubble to the root), so offers fold over each retained inner
|
|
121
|
+
// log — the same projection context-bisect's grouped trajectory uses.
|
|
122
|
+
const staticTools = staticToolNamesOf(source);
|
|
123
|
+
let callMarkers = 0;
|
|
124
|
+
const foldOffersFrom = (bundles) => {
|
|
125
|
+
let injections = [];
|
|
126
|
+
let schemas = [];
|
|
127
|
+
for (let i = 0; i < bundles.length; i++) {
|
|
128
|
+
const paths = new Set(bundles[i].trace.map((t) => t.path));
|
|
129
|
+
if (paths.has('activeInjections')) {
|
|
130
|
+
const v = commitValueAt(bundles, i, 'activeInjections');
|
|
131
|
+
if (Array.isArray(v))
|
|
132
|
+
injections = v;
|
|
133
|
+
}
|
|
134
|
+
if (paths.has('dynamicToolSchemas')) {
|
|
135
|
+
const v = commitValueAt(bundles, i, 'dynamicToolSchemas');
|
|
136
|
+
if (Array.isArray(v))
|
|
137
|
+
schemas = v;
|
|
138
|
+
}
|
|
139
|
+
if (!paths.has('totalInputTokens') || paths.has('userMessage'))
|
|
140
|
+
continue;
|
|
141
|
+
callMarkers += 1;
|
|
142
|
+
for (const inj of injections) {
|
|
143
|
+
if (!inj?.id)
|
|
144
|
+
continue;
|
|
145
|
+
const kind = inj.flavor === 'skill' ? 'skill' : 'injection';
|
|
146
|
+
offer(kind, inj.id, approxTokens(inj));
|
|
147
|
+
}
|
|
148
|
+
// Tools: dynamic schemas (real sizes) + the static registry (offer
|
|
149
|
+
// counted, size unknowable from the log in L1 — earnRate unaffected).
|
|
150
|
+
const offeredToolsThisCall = new Set();
|
|
151
|
+
for (const schema of schemas) {
|
|
152
|
+
if (!schema?.name || offeredToolsThisCall.has(schema.name))
|
|
153
|
+
continue;
|
|
154
|
+
offeredToolsThisCall.add(schema.name);
|
|
155
|
+
offer('tool', schema.name, approxTokens(schema));
|
|
156
|
+
}
|
|
157
|
+
for (const name of staticTools) {
|
|
158
|
+
if (offeredToolsThisCall.has(name))
|
|
159
|
+
continue;
|
|
160
|
+
offeredToolsThisCall.add(name);
|
|
161
|
+
offer('tool', name, 0);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const mountKeys = llmCallMountKeys(snapshot?.subflowResults);
|
|
166
|
+
if (mountKeys.length > 0) {
|
|
167
|
+
for (const key of mountKeys) {
|
|
168
|
+
const inner = snapshot?.subflowResults?.[key]?.treeContext?.history;
|
|
169
|
+
if (Array.isArray(inner))
|
|
170
|
+
foldOffersFrom(inner);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
foldOffersFrom(log);
|
|
175
|
+
}
|
|
176
|
+
// A run with NO call markers anywhere is a shape this ledger cannot
|
|
177
|
+
// meter (e.g. the LLMCall runner, which never writes totalInputTokens)
|
|
178
|
+
// — report honestly instead of confidently recording zero offers.
|
|
179
|
+
if (callMarkers === 0) {
|
|
180
|
+
runsRecorded -= 1;
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
// ── USES: tool calls (assistant messages in the final history) ───────
|
|
184
|
+
const lastIdx = log.length - 1;
|
|
185
|
+
const history = commitValueAt(log, lastIdx, 'history');
|
|
186
|
+
if (Array.isArray(history)) {
|
|
187
|
+
for (const msg of history) {
|
|
188
|
+
if (msg?.role !== 'assistant' || !Array.isArray(msg.toolCalls))
|
|
189
|
+
continue;
|
|
190
|
+
for (const call of msg.toolCalls) {
|
|
191
|
+
if (call?.name)
|
|
192
|
+
markUsed('tool', call.name, 'tool-called');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// ── USES: skill activations ──────────────────────────────────────────
|
|
197
|
+
const activated = commitValueAt(log, lastIdx, 'activatedInjectionIds');
|
|
198
|
+
if (Array.isArray(activated)) {
|
|
199
|
+
for (const id of activated) {
|
|
200
|
+
if (typeof id === 'string' && id.length > 0)
|
|
201
|
+
markUsed('skill', id, 'skill-activated');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ── USES: answer-slice membership per slot (slot-granular, honest) ───
|
|
205
|
+
// Slice the final answer; a slot counts as "on the answer's dependency
|
|
206
|
+
// chain" when its key's LAST WRITER is a slice member. Every injection
|
|
207
|
+
// in the FINAL context of that slot gets the (shared) credit.
|
|
208
|
+
let sliceAvailable = false;
|
|
209
|
+
const tree = snapshot?.executionTree;
|
|
210
|
+
if (tree) {
|
|
211
|
+
const reads = keysReadFromExecutionTree(tree);
|
|
212
|
+
const slice = sliceForKey(log, 'finalContent', reads);
|
|
213
|
+
if (slice.root) {
|
|
214
|
+
sliceAvailable = true;
|
|
215
|
+
const memberIds = new Set(flattenCausalDAG(slice.root).map((n) => n.runtimeStageId));
|
|
216
|
+
const finalInjections = commitValueAt(log, lastIdx, 'activeInjections');
|
|
217
|
+
const finalBySlotKey = new Map();
|
|
218
|
+
// Which slot carried each injection is projected per-slot into the
|
|
219
|
+
// INJECTION_KEYS records — fold each slot key's final value.
|
|
220
|
+
for (const slotKey of Object.values(INJECTION_KEYS)) {
|
|
221
|
+
const writer = findLastWriter(log, slotKey);
|
|
222
|
+
if (!writer || !memberIds.has(writer.runtimeStageId))
|
|
223
|
+
continue;
|
|
224
|
+
const slotRecords = commitValueAt(log, lastIdx, slotKey);
|
|
225
|
+
if (Array.isArray(slotRecords))
|
|
226
|
+
finalBySlotKey.set(slotKey, slotRecords);
|
|
227
|
+
}
|
|
228
|
+
// Credit: injections present in a slice-member slot's final records.
|
|
229
|
+
const activeById = new Map();
|
|
230
|
+
if (Array.isArray(finalInjections)) {
|
|
231
|
+
for (const inj of finalInjections) {
|
|
232
|
+
if (inj?.id)
|
|
233
|
+
activeById.set(inj.id, inj);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
for (const records of finalBySlotKey.values()) {
|
|
237
|
+
for (const rec of records) {
|
|
238
|
+
const id = rec?.id;
|
|
239
|
+
if (!id)
|
|
240
|
+
continue;
|
|
241
|
+
const flavor = activeById.get(id)?.flavor ?? rec.source;
|
|
242
|
+
const kind = flavor === 'skill' ? 'skill' : 'injection';
|
|
243
|
+
markUsed(kind, id, 'answer-slice(slot)');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// runsSeen: once per run per offered piece.
|
|
249
|
+
for (const key of offeredKeys) {
|
|
250
|
+
const row = table.get(key);
|
|
251
|
+
if (row)
|
|
252
|
+
row.runsSeen += 1;
|
|
253
|
+
}
|
|
254
|
+
runOffers.set(runRef, offeredKeys);
|
|
255
|
+
lastRunRef = runRef;
|
|
256
|
+
return { runRef, offeredPieces: [...offeredKeys], sliceAvailable };
|
|
257
|
+
}
|
|
258
|
+
function recordOutcome(label, runRef) {
|
|
259
|
+
const ref = runRef ?? lastRunRef;
|
|
260
|
+
if (!ref)
|
|
261
|
+
return false;
|
|
262
|
+
const offered = runOffers.get(ref);
|
|
263
|
+
if (!offered)
|
|
264
|
+
return false;
|
|
265
|
+
for (const key of offered) {
|
|
266
|
+
const row = table.get(key);
|
|
267
|
+
if (row)
|
|
268
|
+
row.outcomes[label] = (row.outcomes[label] ?? 0) + 1;
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
function freeze(row) {
|
|
273
|
+
return {
|
|
274
|
+
...row,
|
|
275
|
+
usedVia: { ...row.usedVia },
|
|
276
|
+
outcomes: { ...row.outcomes },
|
|
277
|
+
earnRate: row.offered > 0 ? row.used / row.offered : 0,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
recordRun,
|
|
282
|
+
recordOutcome,
|
|
283
|
+
rows: () => [...table.values()].map(freeze).sort((a, b) => a.earnRate - b.earnRate),
|
|
284
|
+
row: (kind, id) => {
|
|
285
|
+
const row = table.get(`${kind}:${id}`);
|
|
286
|
+
return row ? freeze(row) : undefined;
|
|
287
|
+
},
|
|
288
|
+
exportJSON: () => ({ version: 1, rows: [...table.values()].map(freeze), runsRecorded }),
|
|
289
|
+
importJSON: (json) => {
|
|
290
|
+
if (json?.version !== 1)
|
|
291
|
+
return;
|
|
292
|
+
for (const r of json.rows) {
|
|
293
|
+
const row = rowOf(r.kind, r.id);
|
|
294
|
+
row.offered += r.offered;
|
|
295
|
+
row.approxTokensSpent += r.approxTokensSpent;
|
|
296
|
+
row.used += r.used;
|
|
297
|
+
row.runsSeen += r.runsSeen;
|
|
298
|
+
for (const [via, n] of Object.entries(r.usedVia)) {
|
|
299
|
+
row.usedVia[via] = (row.usedVia[via] ?? 0) + (n ?? 0);
|
|
300
|
+
}
|
|
301
|
+
for (const [label, n] of Object.entries(r.outcomes)) {
|
|
302
|
+
row.outcomes[label] = (row.outcomes[label] ?? 0) + n;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
runsRecorded += json.runsRecorded;
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=contextLedger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextLedger.js","sourceRoot":"","sources":["../../../../src/lib/context-ledger/contextLedger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context-ledger/gates.ts — L2: the ledger's rows feed what gets included.
|
|
3
|
+
*
|
|
4
|
+
* Three gates, one policy, each hooking an EXISTING seam (no new framework
|
|
5
|
+
* surface): `gatedTools(inner, predicate)` for tools, `skillGraph().entryBy`
|
|
6
|
+
* for skills, and a rule-trigger wrapper for injections.
|
|
7
|
+
*
|
|
8
|
+
* THE POLICY PRINCIPLE — demote, never starve: a piece the ledger judges
|
|
9
|
+
* poorly is demoted, but every `refreshEvery`-th decision lets it through
|
|
10
|
+
* anyway ("parole"), so it keeps generating fresh ledger data. Without
|
|
11
|
+
* parole a piece demoted once could never earn again — a self-fulfilling
|
|
12
|
+
* verdict. And the ledger never judges a piece it barely knows: below
|
|
13
|
+
* `minOffers` everything passes.
|
|
14
|
+
*/
|
|
15
|
+
import type { EntryScorer } from '../injection-engine/entryScorer.js';
|
|
16
|
+
import type { Injection } from '../injection-engine/types.js';
|
|
17
|
+
import type { ToolGatePredicate } from '../../tool-providers/types.js';
|
|
18
|
+
import type { ContextLedger } from './types.js';
|
|
19
|
+
/**
|
|
20
|
+
* When the ledger is allowed to judge, and how harshly.
|
|
21
|
+
* Plain-named knobs — a bookkeeper's rules, not ML hyperparameters.
|
|
22
|
+
*/
|
|
23
|
+
export interface LedgerPolicy {
|
|
24
|
+
/** Don't judge a piece until it has been offered this many times. Default 5. */
|
|
25
|
+
readonly minOffers?: number;
|
|
26
|
+
/** Demote below this used÷offered rate. Default 0.05 (essentially "never used"). */
|
|
27
|
+
readonly earnRateFloor?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Parole: let a demoted piece through anyway every Nth demotion decision,
|
|
30
|
+
* so it keeps earning fresh data. Default 10. `Infinity` disables parole
|
|
31
|
+
* (NOT recommended — a starved piece can never redeem itself).
|
|
32
|
+
*/
|
|
33
|
+
readonly refreshEvery?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* TOOL GATE — plug into the existing provider combinator:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { gatedTools, staticTools } from 'agentfootprint/tool-providers';
|
|
40
|
+
* builder.toolProvider(gatedTools(staticTools(tools), ledgerToolGate(ledger)));
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Unused tool schemas are usually the biggest silent token cost — this is
|
|
44
|
+
* the gate to start with.
|
|
45
|
+
*/
|
|
46
|
+
export declare function ledgerToolGate(ledger: ContextLedger, policy?: LedgerPolicy): ToolGatePredicate;
|
|
47
|
+
/**
|
|
48
|
+
* SKILL GATE — an `EntryScorer` for `skillGraph().entryBy(...)` that wraps
|
|
49
|
+
* another scorer (keyword, embedding, …) and demotes candidates the ledger
|
|
50
|
+
* says never earn. Demotion multiplies the inner score toward the floor —
|
|
51
|
+
* ranking pressure, not exclusion — and parole restores full weight
|
|
52
|
+
* periodically, so a demoted skill can still win when nothing else fits.
|
|
53
|
+
*/
|
|
54
|
+
export declare function ledgerEntryScorer(ledger: ContextLedger, inner: EntryScorer, policy?: LedgerPolicy): EntryScorer;
|
|
55
|
+
/**
|
|
56
|
+
* INJECTION GATE — wrap ONE injection so the ledger's verdict joins its
|
|
57
|
+
* trigger. `always` becomes a ledger-backed rule; an existing `rule` is
|
|
58
|
+
* AND-ed with the verdict. `on-tool-return` / `llm-activated` are returned
|
|
59
|
+
* UNCHANGED (they are already demand-driven — the ledger has nothing to
|
|
60
|
+
* add). `always` pieces are exempt unless you explicitly wrap them — the
|
|
61
|
+
* safety-first default from the design.
|
|
62
|
+
*/
|
|
63
|
+
export declare function ledgerGated(injection: Injection, ledger: ContextLedger, policy?: LedgerPolicy): Injection;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context-ledger/gates.ts — L2: the ledger's rows feed what gets included.
|
|
3
|
+
*
|
|
4
|
+
* Three gates, one policy, each hooking an EXISTING seam (no new framework
|
|
5
|
+
* surface): `gatedTools(inner, predicate)` for tools, `skillGraph().entryBy`
|
|
6
|
+
* for skills, and a rule-trigger wrapper for injections.
|
|
7
|
+
*
|
|
8
|
+
* THE POLICY PRINCIPLE — demote, never starve: a piece the ledger judges
|
|
9
|
+
* poorly is demoted, but every `refreshEvery`-th decision lets it through
|
|
10
|
+
* anyway ("parole"), so it keeps generating fresh ledger data. Without
|
|
11
|
+
* parole a piece demoted once could never earn again — a self-fulfilling
|
|
12
|
+
* verdict. And the ledger never judges a piece it barely knows: below
|
|
13
|
+
* `minOffers` everything passes.
|
|
14
|
+
*/
|
|
15
|
+
import { rankEntries } from '../injection-engine/entryScorer.js';
|
|
16
|
+
const DEFAULTS = { minOffers: 5, earnRateFloor: 0.05, refreshEvery: 10 };
|
|
17
|
+
/**
|
|
18
|
+
* The shared verdict: should this piece be included right now?
|
|
19
|
+
* Stateful per gate instance (the parole counter), pure otherwise.
|
|
20
|
+
*/
|
|
21
|
+
function makeVerdict(ledger, policy) {
|
|
22
|
+
const p = { ...DEFAULTS, ...policy };
|
|
23
|
+
const demotions = new Map();
|
|
24
|
+
return (kind, id) => {
|
|
25
|
+
const row = ledger.row(kind, id);
|
|
26
|
+
if (!row)
|
|
27
|
+
return true; // unknown to the ledger → always include
|
|
28
|
+
if (row.offered < p.minOffers)
|
|
29
|
+
return true; // not enough data to judge
|
|
30
|
+
if (row.earnRate >= p.earnRateFloor)
|
|
31
|
+
return true; // earning its tokens
|
|
32
|
+
// Demoted — but parole every Nth decision keeps the data flowing.
|
|
33
|
+
const key = `${kind}:${id}`;
|
|
34
|
+
const count = (demotions.get(key) ?? 0) + 1;
|
|
35
|
+
demotions.set(key, count);
|
|
36
|
+
return p.refreshEvery !== Infinity && count % p.refreshEvery === 0;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* TOOL GATE — plug into the existing provider combinator:
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { gatedTools, staticTools } from 'agentfootprint/tool-providers';
|
|
44
|
+
* builder.toolProvider(gatedTools(staticTools(tools), ledgerToolGate(ledger)));
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* Unused tool schemas are usually the biggest silent token cost — this is
|
|
48
|
+
* the gate to start with.
|
|
49
|
+
*/
|
|
50
|
+
export function ledgerToolGate(ledger, policy) {
|
|
51
|
+
const verdict = makeVerdict(ledger, policy);
|
|
52
|
+
return (toolName) => verdict('tool', toolName);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* SKILL GATE — an `EntryScorer` for `skillGraph().entryBy(...)` that wraps
|
|
56
|
+
* another scorer (keyword, embedding, …) and demotes candidates the ledger
|
|
57
|
+
* says never earn. Demotion multiplies the inner score toward the floor —
|
|
58
|
+
* ranking pressure, not exclusion — and parole restores full weight
|
|
59
|
+
* periodically, so a demoted skill can still win when nothing else fits.
|
|
60
|
+
*/
|
|
61
|
+
export function ledgerEntryScorer(ledger, inner, policy) {
|
|
62
|
+
const verdict = makeVerdict(ledger, policy);
|
|
63
|
+
const DEMOTION_WEIGHT = 0.25;
|
|
64
|
+
return {
|
|
65
|
+
name: `ledger(${inner.name})`,
|
|
66
|
+
async score(input, signal) {
|
|
67
|
+
const base = await inner.score(input, signal);
|
|
68
|
+
// Re-rank through rankEntries so `chosen`, `score` AND `relevance` are
|
|
69
|
+
// recomputed TOGETHER from the demoted scores — preserving the
|
|
70
|
+
// entryScorer contract (argmax-score == argmax-relevance; the "Why
|
|
71
|
+
// this skill?" panel and the pick can never disagree).
|
|
72
|
+
const candidates = base.ranked.map((r) => ({
|
|
73
|
+
id: r.id,
|
|
74
|
+
description: input.candidates.find((c) => c.id === r.id)?.description ?? '',
|
|
75
|
+
}));
|
|
76
|
+
const demotedScores = base.ranked.map((r) => verdict('skill', r.id) ? r.score : r.score * DEMOTION_WEIGHT);
|
|
77
|
+
return rankEntries(`ledger(${base.scorer})`, candidates, demotedScores);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* INJECTION GATE — wrap ONE injection so the ledger's verdict joins its
|
|
83
|
+
* trigger. `always` becomes a ledger-backed rule; an existing `rule` is
|
|
84
|
+
* AND-ed with the verdict. `on-tool-return` / `llm-activated` are returned
|
|
85
|
+
* UNCHANGED (they are already demand-driven — the ledger has nothing to
|
|
86
|
+
* add). `always` pieces are exempt unless you explicitly wrap them — the
|
|
87
|
+
* safety-first default from the design.
|
|
88
|
+
*/
|
|
89
|
+
export function ledgerGated(injection, ledger, policy) {
|
|
90
|
+
const verdict = makeVerdict(ledger, policy);
|
|
91
|
+
const kind = injection.flavor === 'skill' ? 'skill' : 'injection';
|
|
92
|
+
const trigger = injection.trigger;
|
|
93
|
+
if (trigger.kind === 'always') {
|
|
94
|
+
return { ...injection, trigger: { kind: 'rule', activeWhen: () => verdict(kind, injection.id) } };
|
|
95
|
+
}
|
|
96
|
+
if (trigger.kind === 'rule') {
|
|
97
|
+
const original = trigger.activeWhen;
|
|
98
|
+
return {
|
|
99
|
+
...injection,
|
|
100
|
+
trigger: { kind: 'rule', activeWhen: (ctx) => original(ctx) && verdict(kind, injection.id) },
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return injection; // demand-driven triggers pass through untouched
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=gates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gates.js","sourceRoot":"","sources":["../../../../src/lib/context-ledger/gates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context-ledger — which context pieces EARNED their tokens?
|
|
3
|
+
*
|
|
4
|
+
* Post-run bookkeeping over the run's own commit log (offers, structural
|
|
5
|
+
* uses, consumer outcomes) whose rows feed the gating seams so future turns
|
|
6
|
+
* include less. See README.md for the honesty model and the L2 gates.
|
|
7
|
+
*/
|
|
8
|
+
export { contextLedger } from './contextLedger.js';
|
|
9
|
+
export type { ContextLedger, LedgerJSON, LedgerRow, PieceKind, RecordedRun, UsedSignal, } from './types.js';
|
|
10
|
+
export { ledgerToolGate, ledgerEntryScorer, ledgerGated, type LedgerPolicy } from './gates.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context-ledger — which context pieces EARNED their tokens?
|
|
3
|
+
*
|
|
4
|
+
* Post-run bookkeeping over the run's own commit log (offers, structural
|
|
5
|
+
* uses, consumer outcomes) whose rows feed the gating seams so future turns
|
|
6
|
+
* include less. See README.md for the honesty model and the L2 gates.
|
|
7
|
+
*/
|
|
8
|
+
export { contextLedger } from './contextLedger.js';
|
|
9
|
+
export { ledgerToolGate, ledgerEntryScorer, ledgerGated } from './gates.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/context-ledger/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AASnD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAC"}
|