agentfootprint-lens 0.20.0 → 0.21.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/dist/{chunk-N3YJKWK5.js → chunk-BTVAAE66.js} +75 -6
- package/dist/chunk-BTVAAE66.js.map +1 -0
- package/dist/core.cjs +75 -5
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +78 -4
- package/dist/core.d.ts +78 -4
- package/dist/core.js +3 -1
- package/dist/index.cjs +398 -151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -5
- package/dist/index.d.ts +111 -5
- package/dist/index.js +312 -134
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-N3YJKWK5.js.map +0 -1
|
@@ -306,6 +306,7 @@ function relTime(runStartMs) {
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
// src/core/LensRecorder.ts
|
|
309
|
+
var DEFAULT_MAX_EVENTS = 5e4;
|
|
309
310
|
var KNOWN_EVENT_TYPES = new Set(ALL_EVENT_TYPES);
|
|
310
311
|
var LensRecorder = class {
|
|
311
312
|
constructor(rootLabel = "Run", options = {}) {
|
|
@@ -387,7 +388,18 @@ var LensRecorder = class {
|
|
|
387
388
|
/** Unknown types already warned about — warn ONCE per type, not per
|
|
388
389
|
* event, so a chatty unknown emitter can't flood the console. */
|
|
389
390
|
this.warnedUnknownTypes = /* @__PURE__ */ new Set();
|
|
391
|
+
/** Entries evicted by the cap so far. Surfaced via `getDiagnostics()`. */
|
|
392
|
+
this.droppedEventCount = 0;
|
|
393
|
+
/** Eviction already warned about — warn ONCE per run, not per batch. */
|
|
394
|
+
this.warnedEviction = false;
|
|
390
395
|
this.debug = options.debug;
|
|
396
|
+
const cap = options.maxEvents ?? DEFAULT_MAX_EVENTS;
|
|
397
|
+
if (cap !== Number.POSITIVE_INFINITY && (!Number.isInteger(cap) || cap < 1)) {
|
|
398
|
+
throw new RangeError(
|
|
399
|
+
`LensRecorder: maxEvents must be a positive integer or Infinity, got ${cap}`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
this.maxEvents = cap;
|
|
391
403
|
this.root = {
|
|
392
404
|
id: "run-root",
|
|
393
405
|
kind: "run",
|
|
@@ -417,6 +429,8 @@ var LensRecorder = class {
|
|
|
417
429
|
this.unknownEventTypes.clear();
|
|
418
430
|
this.bracketMismatchCount = 0;
|
|
419
431
|
this.warnedUnknownTypes.clear();
|
|
432
|
+
this.droppedEventCount = 0;
|
|
433
|
+
this.warnedEviction = false;
|
|
420
434
|
this.liveState.clear();
|
|
421
435
|
this.boundary.clear();
|
|
422
436
|
this.runtime.reset();
|
|
@@ -436,14 +450,18 @@ var LensRecorder = class {
|
|
|
436
450
|
* `composition.exit`, ...) whose kind didn't match the top of the
|
|
437
451
|
* build stack (malformed ordering). The close is skipped; the
|
|
438
452
|
* tree stays partially structured rather than crashing.
|
|
453
|
+
* - `droppedEvents` — entries evicted by the `maxEvents` FIFO cap
|
|
454
|
+
* (U3). When non-zero, log-derived views cover only the retained
|
|
455
|
+
* tail of the run.
|
|
439
456
|
*
|
|
440
|
-
*
|
|
441
|
-
* Returns a fresh snapshot object on every call.
|
|
457
|
+
* All are `{}` / `0` on a well-formed run that stayed under the cap.
|
|
458
|
+
* Reset by `clear()`. Returns a fresh snapshot object on every call.
|
|
442
459
|
*/
|
|
443
460
|
getDiagnostics() {
|
|
444
461
|
return {
|
|
445
462
|
unknownEventTypes: Object.fromEntries(this.unknownEventTypes),
|
|
446
|
-
bracketMismatches: this.bracketMismatchCount
|
|
463
|
+
bracketMismatches: this.bracketMismatchCount,
|
|
464
|
+
droppedEvents: this.droppedEventCount
|
|
447
465
|
};
|
|
448
466
|
}
|
|
449
467
|
/** Whether diagnostic warnings go to the console: explicit option
|
|
@@ -604,8 +622,52 @@ var LensRecorder = class {
|
|
|
604
622
|
this.top().events.push(entry);
|
|
605
623
|
this.noteUnknownType(event.type);
|
|
606
624
|
this.dispatch(event, runOffsetMs, entry);
|
|
625
|
+
this.enforceCap();
|
|
607
626
|
this.bumpVersion();
|
|
608
627
|
}
|
|
628
|
+
/**
|
|
629
|
+
* U3 — enforce the `maxEvents` FIFO cap. When the store exceeds the
|
|
630
|
+
* cap, evict the oldest entries down to ~90% of the cap in ONE batch
|
|
631
|
+
* (amortized O(1) per event: one O(retained) rebuild per ~10%-of-cap
|
|
632
|
+
* pushes), then prune the SAME evicted entries from every run-tree
|
|
633
|
+
* node's `events` list — entry objects are shared references, so
|
|
634
|
+
* skipping the tree would hide the memory, not release it.
|
|
635
|
+
*
|
|
636
|
+
* `SequenceStore` is append-only by design (no removal API), so the
|
|
637
|
+
* batch rebuild (clear + re-push retained) is the supported eviction
|
|
638
|
+
* path; the per-step key + range indices rebuild correctly during
|
|
639
|
+
* re-push.
|
|
640
|
+
*/
|
|
641
|
+
enforceCap() {
|
|
642
|
+
if (this.store.size <= this.maxEvents) return;
|
|
643
|
+
const all = this.store.getAll();
|
|
644
|
+
const evictBatch = Math.max(1, Math.floor(this.maxEvents / 10));
|
|
645
|
+
const retainCount = Math.max(1, this.maxEvents - evictBatch);
|
|
646
|
+
const dropCount = all.length - retainCount;
|
|
647
|
+
const retained = all.slice(dropCount);
|
|
648
|
+
this.store.clear();
|
|
649
|
+
for (const e of retained) this.store.push(e);
|
|
650
|
+
this.droppedEventCount += dropCount;
|
|
651
|
+
this.pruneNodeEvents(this.root, retained[0].seq);
|
|
652
|
+
if (this.debugEnabled() && !this.warnedEviction) {
|
|
653
|
+
this.warnedEviction = true;
|
|
654
|
+
console.warn(
|
|
655
|
+
`[lens] LensRecorder: maxEvents cap (${this.maxEvents}) reached \u2014 evicting oldest events (FIFO, ~10% per batch). Log-derived views now cover only the retained tail; evicted total in getDiagnostics().droppedEvents. Raise the cap via lensRecorder('Run', { maxEvents }) or pass Infinity to disable. (Warned once.)`
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
/** Drop entries with `seq < minSeq` from a node's `events` list (and
|
|
660
|
+
* its descendants'). Per-node lists are seq-ordered, so this is a
|
|
661
|
+
* prefix splice — in place, preserving the node object identity the
|
|
662
|
+
* build stack may still hold. */
|
|
663
|
+
pruneNodeEvents(node, minSeq) {
|
|
664
|
+
if (node.events.length > 0 && node.events[0].seq < minSeq) {
|
|
665
|
+
let keepFrom = 0;
|
|
666
|
+
while (keepFrom < node.events.length && node.events[keepFrom].seq < minSeq) keepFrom++;
|
|
667
|
+
node.events.splice(0, keepFrom);
|
|
668
|
+
}
|
|
669
|
+
for (const child of node.children) this.pruneNodeEvents(child, minSeq);
|
|
670
|
+
}
|
|
609
671
|
/** Notify all subscribers + bump version. Delegated to ChangeNotifier. */
|
|
610
672
|
bumpVersion() {
|
|
611
673
|
this.notifier.notify();
|
|
@@ -904,7 +966,13 @@ var LensRecorder = class {
|
|
|
904
966
|
}
|
|
905
967
|
/** Summary stats — computed lazily via `store.aggregate()`.
|
|
906
968
|
* Single-pass fold; types derived from the AgentfootprintEvent
|
|
907
|
-
* discriminated union.
|
|
969
|
+
* discriminated union.
|
|
970
|
+
*
|
|
971
|
+
* U3 caveat: once the `maxEvents` cap has evicted entries
|
|
972
|
+
* (`getDiagnostics().droppedEvents > 0`), the folded counts/tokens
|
|
973
|
+
* reflect only RETAINED events. `startedAt` / `durationMs` stay
|
|
974
|
+
* anchored to the true first event of the run (tracked outside the
|
|
975
|
+
* store), so the time axis never shifts. */
|
|
908
976
|
selectSummary() {
|
|
909
977
|
const init = {
|
|
910
978
|
llmCallCount: 0,
|
|
@@ -944,7 +1012,7 @@ var LensRecorder = class {
|
|
|
944
1012
|
}
|
|
945
1013
|
}, init);
|
|
946
1014
|
const entries = this.store.getAll();
|
|
947
|
-
const startedAt = entries[0]?.wallClockMs ?? 0;
|
|
1015
|
+
const startedAt = this.runStartMs ?? entries[0]?.wallClockMs ?? 0;
|
|
948
1016
|
const endedAt = entries[entries.length - 1]?.wallClockMs;
|
|
949
1017
|
return {
|
|
950
1018
|
startedAt,
|
|
@@ -2348,6 +2416,7 @@ export {
|
|
|
2348
2416
|
ChangeNotifier,
|
|
2349
2417
|
lensSnapshotRecorder,
|
|
2350
2418
|
LensSnapshotRecorder,
|
|
2419
|
+
DEFAULT_MAX_EVENTS,
|
|
2351
2420
|
LensRecorder,
|
|
2352
2421
|
lensRecorder,
|
|
2353
2422
|
buildStepGraphFromSnapshot,
|
|
@@ -2385,4 +2454,4 @@ export {
|
|
|
2385
2454
|
defaultSize,
|
|
2386
2455
|
layoutLensGraph
|
|
2387
2456
|
};
|
|
2388
|
-
//# sourceMappingURL=chunk-
|
|
2457
|
+
//# sourceMappingURL=chunk-BTVAAE66.js.map
|