dsh-fast 0.2.12 → 0.2.14

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/lib/index.js CHANGED
@@ -202,20 +202,39 @@ const SPILL_NOTICE_MARKERS = ["Full", "stored at:"];
202
202
  * surface order. 0.1.5-alpha.1 derives the prompt from surface node 0; an empty
203
203
  * node is dormant and never restores older text. Mirrors
204
204
  * `SystemPromptProjection` in the host agent loop.
205
- * @param session - the session to read.
205
+ * @param surfaceEvents - the current surface events in model-history order
206
+ * (from the optional `sessionQuery` service, or {@link surfaceEventsOf}).
206
207
  * @returns the effective system message, or undefined when none is active.
207
208
  */
208
- function effectiveSystemMessage(session) {
209
+ function effectiveSystemMessage(surfaceEvents) {
209
210
  let effective;
210
- for (const seq of session.surface.nodes) {
211
- const event = session.eventAt(seq);
212
- if (event?.type !== "system/message") continue;
211
+ for (const event of surfaceEvents) {
212
+ if (event.type !== "system/message") continue;
213
213
  const message = event.data.message;
214
214
  if (message.content.length === 0) continue;
215
215
  effective = message;
216
216
  }
217
217
  return effective;
218
218
  }
219
+ /**
220
+ * The current surface events of a live session, resolved from one snapshot of
221
+ * the accepted log. This is the fallback read for hosts that compose no
222
+ * `sessionQuery` service: it replaces the deprecated `Session.eventAt(seq)`
223
+ * accessor (new calls are prohibited) while keeping the same surface-node
224
+ * order and the same log as the source of truth.
225
+ * @param session - the session to read.
226
+ * @returns the surface events in model-history order.
227
+ */
228
+ function surfaceEventsOf(session) {
229
+ const bySeq = /* @__PURE__ */ new Map();
230
+ for (const event of session.snapshotEvents()) bySeq.set(event.seq, event);
231
+ const events = [];
232
+ for (const seq of session.surface.nodes) {
233
+ const event = bySeq.get(seq);
234
+ if (event !== void 0) events.push(event);
235
+ }
236
+ return events;
237
+ }
219
238
  /** The display/durable text of a system message (text blocks plus structural JSON). */
220
239
  function systemTextOf(message) {
221
240
  let text = "";
@@ -350,13 +369,15 @@ var FastCollector = class {
350
369
  * @param sections - optional named system-prompt sections (from the optional
351
370
  * `systemPrompt` service); absent = the whole rendered system prompt is
352
371
  * attributed to the `other` bucket.
372
+ * @param surfaceEvents - optional pre-read surface events (the async
373
+ * `sessionQuery` read path); absent = the sync fallback read.
353
374
  * @returns the snapshot.
354
375
  */
355
- snapshot(session, measure, sections) {
376
+ snapshot(session, measure, sections, surfaceEvents) {
356
377
  const state = this.live.get(session);
357
378
  if (state === void 0) return emptySnapshot();
358
379
  const measurement = measure === void 0 ? void 0 : measure(session);
359
- const systemMessage = effectiveSystemMessage(session);
380
+ const systemMessage = effectiveSystemMessage(surfaceEvents ?? surfaceEventsOf(session));
360
381
  const legacySystem = systemMessage === void 0 ? legacySystemText(state.lastHeader) : void 0;
361
382
  const systemTokens = systemMessage === void 0 ? estimateLegacySystemTokens(legacySystem) : estimateSystemTokens(systemMessage);
362
383
  const toolSchemaTokens = estimateToolsTokens(state.lastHeader);
@@ -745,9 +766,25 @@ function appendSample(history, sample, maxSamples) {
745
766
  return { samples: [...history?.samples ?? [], sample].slice(-maxSamples) };
746
767
  }
747
768
  //#endregion
769
+ //#region src/notices.ts
770
+ /**
771
+ * Build a {@link OnceNotifier} that forwards the first message per key to the
772
+ * sink and swallows every later one.
773
+ * @param sink - where the first message per key goes (typically `logger.warn`).
774
+ * @returns the notifier.
775
+ */
776
+ function createOnceNotifier(sink) {
777
+ const seen = /* @__PURE__ */ new Set();
778
+ return (key, message) => {
779
+ if (seen.has(key)) return;
780
+ seen.add(key);
781
+ sink(message);
782
+ };
783
+ }
784
+ //#endregion
748
785
  //#region src/version.ts
749
786
  /** Single-source plugin version, bumped by `scripts/release.mjs`. @module dsh-fast/version */
750
- const VERSION = "0.2.12";
787
+ const VERSION = "0.2.14";
751
788
  //#endregion
752
789
  //#region src/index.ts
753
790
  const name = "fast";
@@ -772,11 +809,37 @@ async function apply(ctx, config = {}) {
772
809
  }
773
810
  const collector = new FastCollector(resolved);
774
811
  const domain = await ctx.storageDomain.open(fastDomainSpec);
812
+ if (ctx.fiber.uid === null) {
813
+ await domain.close();
814
+ return;
815
+ }
775
816
  const sessions = domain.table("sessions");
817
+ /**
818
+ * One-time visible degradation notices: a subsystem fallback that used to be
819
+ * silent now says so once per process, so a report built from heuristics is
820
+ * never mistaken for a measured one.
821
+ */
822
+ const warnFallbackOnce = createOnceNotifier((message) => logger.warn(message));
823
+ /** The optional metrics outlet; a no-op when the service is absent or throws. */
824
+ const inspector = ctx.get("inspector");
825
+ const publishSnapshot = (session, snapshot) => {
826
+ if (inspector === void 0 || typeof inspector.publish !== "function") return;
827
+ try {
828
+ inspector.publish("dsh-fast/snapshot", {
829
+ sessionId: session.id,
830
+ snapshot
831
+ });
832
+ } catch (error) {
833
+ warnFallbackOnce("inspector", `inspector metric outlet failed, continuing with the report surfaces only: ${error instanceof Error ? error.message : String(error)}`);
834
+ }
835
+ };
776
836
  /** Lazy, contained lookup of the optional token meter. */
777
837
  const measure = (session) => {
778
838
  const meter = ctx.get("tokenMeter");
779
- if (meter === void 0) return void 0;
839
+ if (meter === void 0) {
840
+ warnFallbackOnce("tokenMeter", "tokenMeter is not composed: total/surface tokens fall back to the fixed-density heuristic (spill and compaction counters stay exact)");
841
+ return;
842
+ }
780
843
  try {
781
844
  const measurement = meter.measure(session);
782
845
  return {
@@ -791,7 +854,10 @@ async function apply(ctx, config = {}) {
791
854
  /** Assemble the named system-prompt sections for the per-section breakdown. */
792
855
  const assembleSections = async () => {
793
856
  const systemPrompt = ctx.get("systemPrompt");
794
- if (systemPrompt === void 0) return void 0;
857
+ if (systemPrompt === void 0) {
858
+ warnFallbackOnce("systemPrompt", "systemPrompt is not composed: the whole rendered prompt is attributed to the \"other\" bucket instead of the per-section breakdown");
859
+ return;
860
+ }
795
861
  try {
796
862
  return (await systemPrompt.assemble()).sections.map((section) => ({
797
863
  name: section.name,
@@ -802,9 +868,30 @@ async function apply(ctx, config = {}) {
802
868
  return;
803
869
  }
804
870
  };
871
+ /**
872
+ * Read the current surface events for one session through the optional
873
+ * `sessionQuery` service. This replaces the deprecated synchronous
874
+ * `Session.eventAt(seq)` read; a host that composes no `sessionQuery` leaves
875
+ * the collector on its own non-deprecated sync fallback, and a failing read
876
+ * degrades to that fallback with one warning instead of failing the report.
877
+ * @param session - the session to read.
878
+ * @returns the surface events in model-history order, or undefined to fall back.
879
+ */
880
+ const readSurfaceEvents = async (session) => {
881
+ const sessionQuery = ctx.get("sessionQuery");
882
+ if (sessionQuery === void 0) return void 0;
883
+ try {
884
+ return (await sessionQuery.readSurface(session.id)).events;
885
+ } catch (error) {
886
+ logger.warn(`session "${session.id}": surface read failed, falling back to the synchronous read: ${error instanceof Error ? error.message : String(error)}`);
887
+ return;
888
+ }
889
+ };
805
890
  /** Build the complete report for one session. */
806
891
  const reportFor = async (session) => {
807
- return buildReport(collector.snapshot(session, measure, await assembleSections()), {
892
+ const snapshot = collector.snapshot(session, measure, await assembleSections(), await readSurfaceEvents(session));
893
+ publishSnapshot(session, snapshot);
894
+ return buildReport(snapshot, {
808
895
  sessionId: session.id,
809
896
  ...resolved.includeCwd && session.header.cwd !== void 0 ? { cwd: session.header.cwd } : {},
810
897
  generatedAt: Date.now()
@@ -812,7 +899,8 @@ async function apply(ctx, config = {}) {
812
899
  };
813
900
  /** Append one snapshot to the session's durable history (fire-and-forget). */
814
901
  const persist = async (session) => {
815
- const snapshot = collector.snapshot(session, measure, await assembleSections());
902
+ const snapshot = collector.snapshot(session, measure, await assembleSections(), await readSurfaceEvents(session));
903
+ publishSnapshot(session, snapshot);
816
904
  const next = appendSample(sessions.get(session.id), {
817
905
  at: Date.now(),
818
906
  snapshot
@@ -821,7 +909,7 @@ async function apply(ctx, config = {}) {
821
909
  logger.warn(`session "${session.id}": persist failed: ${error instanceof Error ? error.message : String(error)}`);
822
910
  });
823
911
  };
824
- ctx.commands.register({
912
+ const fastCommand = {
825
913
  name: "fast",
826
914
  description: "Print the dsh-fast performance report for the active session.",
827
915
  async handler(invocation) {
@@ -830,8 +918,8 @@ async function apply(ctx, config = {}) {
830
918
  text: renderFastText(await reportFor(invocation.agent.session))
831
919
  };
832
920
  }
833
- });
834
- ctx.tools.register(defineTool({
921
+ };
922
+ const fastReportTool = defineTool({
835
923
  name: "fast_report",
836
924
  description: "Return the current dsh-fast performance report for the active session: session load timing, spill hits, compaction count and trigger, context-injection volume (AGENTS.md/skills/tool-schema token share), LLM cache hit rate, and optimization suggestions.",
837
925
  parameters: {},
@@ -1077,21 +1165,25 @@ async function apply(ctx, config = {}) {
1077
1165
  if (session === void 0) throw new Error("fast_report requires an agent-owned session");
1078
1166
  return await reportFor(session);
1079
1167
  }
1080
- }));
1081
- ctx.on("session/created", (session) => {
1082
- collector.handleSessionCreated(session);
1083
- });
1084
- ctx.on("session/disposed", (session) => {
1085
- collector.handleSessionDisposed(session);
1086
- });
1087
- ctx.on("session/event", (session, event) => {
1088
- try {
1089
- collector.handleEvent(session, event);
1090
- } catch (error) {
1091
- logger.warn(`session "${session.id}": event handling failed: ${error instanceof Error ? error.message : String(error)}`);
1092
- }
1093
1168
  });
1094
1169
  ctx.effect(() => {
1170
+ const disposers = [
1171
+ ctx.commands.register(fastCommand),
1172
+ ctx.tools.register(fastReportTool),
1173
+ ctx.on("session/created", (session) => {
1174
+ collector.handleSessionCreated(session);
1175
+ }),
1176
+ ctx.on("session/disposed", (session) => {
1177
+ collector.handleSessionDisposed(session);
1178
+ }),
1179
+ ctx.on("session/event", (session, event) => {
1180
+ try {
1181
+ collector.handleEvent(session, event);
1182
+ } catch (error) {
1183
+ logger.warn(`session "${session.id}": event handling failed: ${error instanceof Error ? error.message : String(error)}`);
1184
+ }
1185
+ })
1186
+ ];
1095
1187
  const timer = setInterval(() => {
1096
1188
  for (const session of collector.liveSessions()) {
1097
1189
  if (!collector.isDirty(session)) continue;
@@ -1101,6 +1193,7 @@ async function apply(ctx, config = {}) {
1101
1193
  }, resolved.snapshotIntervalMs);
1102
1194
  return async () => {
1103
1195
  clearInterval(timer);
1196
+ for (const dispose of disposers.reverse()) dispose();
1104
1197
  await domain.close();
1105
1198
  };
1106
1199
  });
@@ -30,10 +30,21 @@ export type MeasureFn = (session: Session) => TokenMeasurement | undefined;
30
30
  * surface order. 0.1.5-alpha.1 derives the prompt from surface node 0; an empty
31
31
  * node is dormant and never restores older text. Mirrors
32
32
  * `SystemPromptProjection` in the host agent loop.
33
- * @param session - the session to read.
33
+ * @param surfaceEvents - the current surface events in model-history order
34
+ * (from the optional `sessionQuery` service, or {@link surfaceEventsOf}).
34
35
  * @returns the effective system message, or undefined when none is active.
35
36
  */
36
- export declare function effectiveSystemMessage(session: Session): SystemMessage | undefined;
37
+ export declare function effectiveSystemMessage(surfaceEvents: readonly SessionEvent[]): SystemMessage | undefined;
38
+ /**
39
+ * The current surface events of a live session, resolved from one snapshot of
40
+ * the accepted log. This is the fallback read for hosts that compose no
41
+ * `sessionQuery` service: it replaces the deprecated `Session.eventAt(seq)`
42
+ * accessor (new calls are prohibited) while keeping the same surface-node
43
+ * order and the same log as the source of truth.
44
+ * @param session - the session to read.
45
+ * @returns the surface events in model-history order.
46
+ */
47
+ export declare function surfaceEventsOf(session: Session): readonly SessionEvent[];
37
48
  /** Flatten a tool result's model-facing text blocks to one string. */
38
49
  export declare function flattenToolResultText(message: ToolResultMessage): string;
39
50
  /**
@@ -84,9 +95,11 @@ export declare class FastCollector {
84
95
  * @param sections - optional named system-prompt sections (from the optional
85
96
  * `systemPrompt` service); absent = the whole rendered system prompt is
86
97
  * attributed to the `other` bucket.
98
+ * @param surfaceEvents - optional pre-read surface events (the async
99
+ * `sessionQuery` read path); absent = the sync fallback read.
87
100
  * @returns the snapshot.
88
101
  */
89
- snapshot(session: Session, measure?: MeasureFn, sections?: readonly SystemSection[]): FastSnapshot;
102
+ snapshot(session: Session, measure?: MeasureFn, sections?: readonly SystemSection[], surfaceEvents?: readonly SessionEvent[]): FastSnapshot;
90
103
  /** Aggregate cache counters into the report shape. */
91
104
  private cacheStats;
92
105
  /** Fold one provider usage record. */
@@ -1 +1 @@
1
- {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAe,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAGpH,OAAO,KAAK,EAAE,YAAY,EAAc,YAAY,EAAE,MAAM,YAAY,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAA;AAEtB;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,+CAA+C;AAC/C,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,gBAAgB,GAAG,SAAS,CAAA;AAK1E;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAUlF;AAqBD,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAQxE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAGvE;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC,CAOnE;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIzE;AAsBD;;;;GAIG;AACH,qBAAa,aAAa;IAIZ,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;IAErD,kDAAkD;gBACrB,MAAM,EAAE,cAAc;IAEnD,oDAAoD;IACpD,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI5C,wCAAwC;IACxC,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAmCxD,qDAAqD;IACrD,YAAY,IAAI,gBAAgB,CAAC,OAAO,CAAC;IAIzC,kEAAkE;IAClE,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAI9B,kDAAkD;IAClD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAIlC,yDAAyD;IACzD,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKjC;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,YAAY;IAgDlG,sDAAsD;IACtD,OAAO,CAAC,UAAU;IAUlB,sCAAsC;IACtC,OAAO,CAAC,SAAS;IAYjB,iEAAiE;IACjE,OAAO,CAAC,KAAK;CAwBd"}
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAe,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAGpH,OAAO,KAAK,EAAE,YAAY,EAAc,YAAY,EAAE,MAAM,YAAY,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAA;AAEtB;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,+CAA+C;AAC/C,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,gBAAgB,GAAG,SAAS,CAAA;AAK1E;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,GAAG,aAAa,GAAG,SAAS,CASxG;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,YAAY,EAAE,CASzE;AAqBD,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAQxE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAGvE;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC,CAOnE;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIzE;AAsBD;;;;GAIG;AACH,qBAAa,aAAa;IAIZ,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;IAErD,kDAAkD;gBACrB,MAAM,EAAE,cAAc;IAEnD,oDAAoD;IACpD,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI5C,wCAAwC;IACxC,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAmCxD,qDAAqD;IACrD,YAAY,IAAI,gBAAgB,CAAC,OAAO,CAAC;IAIzC,kEAAkE;IAClE,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAI9B,kDAAkD;IAClD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAIlC,yDAAyD;IACzD,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKjC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,EAAE,aAAa,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY;IAgD3I,sDAAsD;IACtD,OAAO,CAAC,UAAU;IAUlB,sCAAsC;IACtC,OAAO,CAAC,SAAS;IAYjB,iEAAiE;IACjE,OAAO,CAAC,KAAK;CAwBd"}
@@ -15,14 +15,14 @@ const SPILL_NOTICE_MARKERS = ['Full', 'stored at:'];
15
15
  * surface order. 0.1.5-alpha.1 derives the prompt from surface node 0; an empty
16
16
  * node is dormant and never restores older text. Mirrors
17
17
  * `SystemPromptProjection` in the host agent loop.
18
- * @param session - the session to read.
18
+ * @param surfaceEvents - the current surface events in model-history order
19
+ * (from the optional `sessionQuery` service, or {@link surfaceEventsOf}).
19
20
  * @returns the effective system message, or undefined when none is active.
20
21
  */
21
- export function effectiveSystemMessage(session) {
22
+ export function effectiveSystemMessage(surfaceEvents) {
22
23
  let effective;
23
- for (const seq of session.surface.nodes) {
24
- const event = session.eventAt(seq);
25
- if (event?.type !== 'system/message')
24
+ for (const event of surfaceEvents) {
25
+ if (event.type !== 'system/message')
26
26
  continue;
27
27
  const message = event.data.message;
28
28
  if (message.content.length === 0)
@@ -31,6 +31,27 @@ export function effectiveSystemMessage(session) {
31
31
  }
32
32
  return effective;
33
33
  }
34
+ /**
35
+ * The current surface events of a live session, resolved from one snapshot of
36
+ * the accepted log. This is the fallback read for hosts that compose no
37
+ * `sessionQuery` service: it replaces the deprecated `Session.eventAt(seq)`
38
+ * accessor (new calls are prohibited) while keeping the same surface-node
39
+ * order and the same log as the source of truth.
40
+ * @param session - the session to read.
41
+ * @returns the surface events in model-history order.
42
+ */
43
+ export function surfaceEventsOf(session) {
44
+ const bySeq = new Map();
45
+ for (const event of session.snapshotEvents())
46
+ bySeq.set(event.seq, event);
47
+ const events = [];
48
+ for (const seq of session.surface.nodes) {
49
+ const event = bySeq.get(seq);
50
+ if (event !== undefined)
51
+ events.push(event);
52
+ }
53
+ return events;
54
+ }
34
55
  /** The display/durable text of a system message (text blocks plus structural JSON). */
35
56
  function systemTextOf(message) {
36
57
  let text = '';
@@ -176,14 +197,16 @@ export class FastCollector {
176
197
  * @param sections - optional named system-prompt sections (from the optional
177
198
  * `systemPrompt` service); absent = the whole rendered system prompt is
178
199
  * attributed to the `other` bucket.
200
+ * @param surfaceEvents - optional pre-read surface events (the async
201
+ * `sessionQuery` read path); absent = the sync fallback read.
179
202
  * @returns the snapshot.
180
203
  */
181
- snapshot(session, measure, sections) {
204
+ snapshot(session, measure, sections, surfaceEvents) {
182
205
  const state = this.live.get(session);
183
206
  if (state === undefined)
184
207
  return emptySnapshot();
185
208
  const measurement = measure === undefined ? undefined : measure(session);
186
- const systemMessage = effectiveSystemMessage(session);
209
+ const systemMessage = effectiveSystemMessage(surfaceEvents ?? surfaceEventsOf(session));
187
210
  const legacySystem = systemMessage === undefined ? legacySystemText(state.lastHeader) : undefined;
188
211
  const systemTokens = systemMessage === undefined
189
212
  ? estimateLegacySystemTokens(legacySystem)
@@ -1 +1 @@
1
- {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,eAAe,CAAA;AAkBtB,+FAA+F;AAC/F,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,YAAY,CAAU,CAAA;AAE5D;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,IAAI,SAAoC,CAAA;IACxC,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAClC,IAAI,KAAK,EAAE,IAAI,KAAK,gBAAgB;YAAE,SAAQ;QAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAA;QAClC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAQ;QAC1C,SAAS,GAAG,OAAO,CAAA;IACrB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,uFAAuF;AACvF,SAAS,YAAY,CAAC,OAAsB;IAC1C,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO;QAAE,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACvG,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,MAA+B;IACvD,MAAM,MAAM,GAAI,MAA2C,EAAE,MAAM,CAAA;IACnE,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;AACxD,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,OAA0B;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAChC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAA;IAClC,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAA;IAC/C,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA0B;IAC5D,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;AACpE,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CACtB,KAAa,EACb,MAAc,EACd,KAAa,EACb,OAAe;IAEf,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAA;IACzE,OAAO;QACL,WAAW,EAAE,MAAM,GAAG,KAAK;QAC3B,UAAU,EAAE,KAAK,GAAG,KAAK;QACzB,YAAY,EAAE,OAAO,GAAG,KAAK;KAC9B,CAAA;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,SAAiB;IACxD,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAA;IACrC,IAAI,WAAW,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,OAAO,SAAS,GAAG,WAAW,CAAA;AAChC,CAAC;AAsBD;;;;GAIG;AACH,MAAM,OAAO,aAAa;IAIK;IAHZ,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAA;IAErD,kDAAkD;IAClD,YAA6B,MAAsB;QAAtB,WAAM,GAAN,MAAM,CAAgB;IAAG,CAAC;IAEvD,oDAAoD;IACpD,oBAAoB,CAAC,OAAgB;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACrB,CAAC;IAED,wCAAwC;IACxC,qBAAqB,CAAC,OAAgB;QACpC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3B,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,OAAgB,EAAE,KAAmB;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACjC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,gBAAgB;gBACnB,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAA;gBACpC,IAAI,KAAK,CAAC,oBAAoB,KAAK,IAAI,EAAE,CAAC;oBACxC,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,CAAA;oBACxE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;gBACpB,CAAC;gBACD,MAAK;YACP,KAAK,mBAAmB;gBACtB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBACvC,MAAK;YACP,KAAK,kBAAkB;gBACrB,KAAK,CAAC,eAAe,IAAI,CAAC,CAAA;gBAC1B,IAAI,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,SAAS;oBAAE,KAAK,CAAC,mBAAmB,IAAI,CAAC,CAAA;;oBACvE,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAA;gBAChC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;gBAClB,MAAK;YACP,KAAK,oBAAoB;gBACvB,KAAK,CAAC,wBAAwB,IAAI,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAA;gBAC/D,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;gBAClB,MAAK;YACP,KAAK,aAAa;gBAChB,IAAI,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAChF,KAAK,CAAC,cAAc,IAAI,CAAC,CAAA;oBACzB,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;gBACpB,CAAC;gBACD,MAAK;YACP;gBACE,2DAA2D;gBAC3D,MAAK;QACT,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,YAAY;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAED,kEAAkE;IAClE,GAAG,CAAC,OAAgB;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC/B,CAAC;IAED,kDAAkD;IAClD,OAAO,CAAC,OAAgB;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,IAAI,KAAK,CAAA;IAC/C,CAAC;IAED,yDAAyD;IACzD,SAAS,CAAC,OAAgB;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;IAC9C,CAAC;IAED;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAgB,EAAE,OAAmB,EAAE,QAAmC;QACjF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,aAAa,EAAE,CAAA;QAC/C,MAAM,WAAW,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACxE,MAAM,aAAa,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAA;QACrD,MAAM,YAAY,GAAG,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACjG,MAAM,YAAY,GAAG,aAAa,KAAK,SAAS;YAC9C,CAAC,CAAC,0BAA0B,CAAC,YAAY,CAAC;YAC1C,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;QACvC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QAC9D,MAAM,qBAAqB,GAAG,WAAW,EAAE,aAAa,IAAI,CAAC,CAAA;QAC7D,2EAA2E;QAC3E,4EAA4E;QAC5E,0EAA0E;QAC1E,MAAM,aAAa,GAAG,aAAa,KAAK,SAAS;YAC/C,CAAC,CAAC,qBAAqB;YACvB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,qBAAqB,GAAG,YAAY,CAAC,CAAA;QACrD,MAAM,WAAW,GAAG,WAAW,EAAE,WAAW,IAAI,CAAC,YAAY,GAAG,gBAAgB,GAAG,aAAa,CAAC,CAAA;QACjG,MAAM,UAAU,GAAG,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAA;QAC3F,MAAM,iBAAiB,GAA6B,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YACrG,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;QACzC,MAAM,eAAe,GAAG,sBAAsB,CAAC,QAAQ,IAAI,iBAAiB,CAAC,CAAA;QAC7E,OAAO;YACL,IAAI,EAAE;gBACJ,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,UAAU,EAAE,KAAK,CAAC,YAAY;gBAC9B,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;aACjD;YACD,KAAK,EAAE,EAAE,sBAAsB,EAAE,KAAK,CAAC,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE;YACxE,UAAU,EAAE;gBACV,KAAK,EAAE,KAAK,CAAC,eAAe;gBAC5B,MAAM,EAAE,KAAK,CAAC,gBAAgB;gBAC9B,SAAS,EAAE,KAAK,CAAC,mBAAmB;gBACpC,cAAc,EAAE,KAAK,CAAC,wBAAwB;aAC/C;YACD,OAAO,EAAE;gBACP,WAAW;gBACX,YAAY;gBACZ,gBAAgB;gBAChB,aAAa;gBACb,GAAG,QAAQ,CAAC,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,CAAC;gBACvE,eAAe;aAChB;YACD,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;SAC9B,CAAA;IACH,CAAC;IAED,sDAAsD;IAC9C,UAAU,CAAC,KAAgB;QACjC,OAAO;YACL,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC;SAC7D,CAAA;IACH,CAAC;IAED,sCAAsC;IAC9B,SAAS,CACf,KAAgB,EAChB,KAAqH;QAErH,IAAI,KAAK,KAAK,SAAS;YAAE,OAAM;QAC/B,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAA;QACtC,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAA;QACxC,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,eAAe,IAAI,CAAC,CAAA;QACnD,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAA;QACrD,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;IACpB,CAAC;IAED,iEAAiE;IACzD,KAAK,CAAC,OAAgB;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACvC,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,QAAQ,CAAA;QAC3C,MAAM,KAAK,GAAc;YACvB,OAAO;YACP,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;YACvB,IAAI,EAAE,OAAO,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;YACnD,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,oBAAoB,EAAE,IAAI;YAC1B,cAAc,EAAE,CAAC;YACjB,eAAe,EAAE,CAAC;YAClB,gBAAgB,EAAE,CAAC;YACnB,mBAAmB,EAAE,CAAC;YACtB,wBAAwB,EAAE,CAAC;YAC3B,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,CAAC;YAClB,gBAAgB,EAAE,CAAC;YACnB,YAAY,EAAE,CAAC;YACf,UAAU,EAAE,SAAS;YACrB,KAAK,EAAE,IAAI;SACZ,CAAA;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC7B,OAAO,KAAK,CAAA;IACd,CAAC;CACF;AAED,8DAA8D;AAC9D,SAAS,aAAa;IACpB,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE;QACjE,KAAK,EAAE,EAAE,sBAAsB,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;QACrD,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE;QACpE,OAAO,EAAE;YACP,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,gBAAgB,EAAE,CAAC;YACnB,aAAa,EAAE,CAAC;YAChB,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,YAAY,EAAE,CAAC;YACf,eAAe,EAAE;gBACf,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC3C,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;gBACzC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC1C,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;aACzC;SACF;QACD,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;KACnG,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/collector.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAA;AASnD,eAAO,MAAM,IAAI,SAAS,CAAA;AAC1B,kFAAkF;AAClF,eAAO,MAAM,MAAM,UAAyC,CAAA;AAE5D,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACnD,YAAY,EAAE,MAAM,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAClF,YAAY,EACV,UAAU,EACV,YAAY,EACZ,SAAS,EACT,UAAU,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/G,OAAO,EAAE,sBAAsB,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAcxE;;;;;GAKG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0M5E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAMlD,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAA;AAUnD,eAAO,MAAM,IAAI,SAAS,CAAA;AAC1B,kFAAkF;AAClF,eAAO,MAAM,MAAM,UAAyC,CAAA;AAE5D,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACnD,YAAY,EAAE,MAAM,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAClF,YAAY,EACV,UAAU,EACV,YAAY,EACZ,SAAS,EACT,UAAU,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/G,OAAO,EAAE,sBAAsB,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AA6BxE;;;;;GAKG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmR5E"}
@@ -17,6 +17,7 @@ import { resolveConfig } from "./config.js";
17
17
  import { FastCollector } from "./collector.js";
18
18
  import { buildReport, renderFastText } from "./analyze.js";
19
19
  import { fastDomainSpec, appendSample } from "./store.js";
20
+ import { createOnceNotifier } from "./notices.js";
20
21
  import { VERSION } from "./version.js";
21
22
  export const name = 'fast';
22
23
  /** The `/fast` command, the `fast_report` tool, and the durable metric domain. */
@@ -43,15 +44,43 @@ export async function apply(ctx, config = {}) {
43
44
  }
44
45
  const collector = new FastCollector(resolved);
45
46
  const domain = await ctx.storageDomain.open(fastDomainSpec);
47
+ // Disposal during the open await: the fiber is gone, so no effect may be
48
+ // registered any more — release the freshly opened handle instead of leaking
49
+ // it (the storage facility is single-open per name, so an unreleased handle
50
+ // also blocks a later remount).
51
+ if (ctx.fiber.uid === null) {
52
+ await domain.close();
53
+ return;
54
+ }
46
55
  const sessions = domain.table('sessions');
56
+ /**
57
+ * One-time visible degradation notices: a subsystem fallback that used to be
58
+ * silent now says so once per process, so a report built from heuristics is
59
+ * never mistaken for a measured one.
60
+ */
61
+ const warnFallbackOnce = createOnceNotifier(message => logger.warn(message));
62
+ /** The optional metrics outlet; a no-op when the service is absent or throws. */
63
+ const inspector = ctx.get('inspector');
64
+ const publishSnapshot = (session, snapshot) => {
65
+ if (inspector === undefined || typeof inspector.publish !== 'function')
66
+ return;
67
+ try {
68
+ inspector.publish('dsh-fast/snapshot', { sessionId: session.id, snapshot });
69
+ }
70
+ catch (error) {
71
+ warnFallbackOnce('inspector', `inspector metric outlet failed, continuing with the report surfaces only: ${error instanceof Error ? error.message : String(error)}`);
72
+ }
73
+ };
47
74
  // Consumer — the report paths use the optional tokenMeter/systemPrompt
48
75
  // services at call time; the /fast handler and the fast_report execute turn
49
76
  // the measurements into the model-visible report.
50
77
  /** Lazy, contained lookup of the optional token meter. */
51
78
  const measure = (session) => {
52
79
  const meter = ctx.get('tokenMeter');
53
- if (meter === undefined)
80
+ if (meter === undefined) {
81
+ warnFallbackOnce('tokenMeter', 'tokenMeter is not composed: total/surface tokens fall back to the fixed-density heuristic (spill and compaction counters stay exact)');
54
82
  return undefined;
83
+ }
55
84
  try {
56
85
  const measurement = meter.measure(session);
57
86
  return { totalTokens: measurement.totalTokens, surfaceTokens: measurement.surfaceTokens };
@@ -64,8 +93,10 @@ export async function apply(ctx, config = {}) {
64
93
  /** Assemble the named system-prompt sections for the per-section breakdown. */
65
94
  const assembleSections = async () => {
66
95
  const systemPrompt = ctx.get('systemPrompt');
67
- if (systemPrompt === undefined)
96
+ if (systemPrompt === undefined) {
97
+ warnFallbackOnce('systemPrompt', 'systemPrompt is not composed: the whole rendered prompt is attributed to the "other" bucket instead of the per-section breakdown');
68
98
  return undefined;
99
+ }
69
100
  try {
70
101
  const assembly = await systemPrompt.assemble();
71
102
  return assembly.sections.map(section => ({ name: section.name, text: section.text }));
@@ -75,9 +106,32 @@ export async function apply(ctx, config = {}) {
75
106
  return undefined;
76
107
  }
77
108
  };
109
+ /**
110
+ * Read the current surface events for one session through the optional
111
+ * `sessionQuery` service. This replaces the deprecated synchronous
112
+ * `Session.eventAt(seq)` read; a host that composes no `sessionQuery` leaves
113
+ * the collector on its own non-deprecated sync fallback, and a failing read
114
+ * degrades to that fallback with one warning instead of failing the report.
115
+ * @param session - the session to read.
116
+ * @returns the surface events in model-history order, or undefined to fall back.
117
+ */
118
+ const readSurfaceEvents = async (session) => {
119
+ const sessionQuery = ctx.get('sessionQuery');
120
+ if (sessionQuery === undefined)
121
+ return undefined;
122
+ try {
123
+ const surface = await sessionQuery.readSurface(session.id);
124
+ return surface.events;
125
+ }
126
+ catch (error) {
127
+ logger.warn(`session "${session.id}": surface read failed, falling back to the synchronous read: ${error instanceof Error ? error.message : String(error)}`);
128
+ return undefined;
129
+ }
130
+ };
78
131
  /** Build the complete report for one session. */
79
132
  const reportFor = async (session) => {
80
- const snapshot = collector.snapshot(session, measure, await assembleSections());
133
+ const snapshot = collector.snapshot(session, measure, await assembleSections(), await readSurfaceEvents(session));
134
+ publishSnapshot(session, snapshot);
81
135
  return buildReport(snapshot, {
82
136
  sessionId: session.id,
83
137
  ...(resolved.includeCwd && session.header.cwd !== undefined ? { cwd: session.header.cwd } : {}),
@@ -86,25 +140,27 @@ export async function apply(ctx, config = {}) {
86
140
  };
87
141
  /** Append one snapshot to the session's durable history (fire-and-forget). */
88
142
  const persist = async (session) => {
89
- const snapshot = collector.snapshot(session, measure, await assembleSections());
143
+ const snapshot = collector.snapshot(session, measure, await assembleSections(), await readSurfaceEvents(session));
144
+ publishSnapshot(session, snapshot);
90
145
  const next = appendSample(sessions.get(session.id), { at: Date.now(), snapshot }, resolved.maxHistorySamples);
91
146
  void sessions.put(session.id, next).catch((error) => {
92
147
  logger.warn(`session "${session.id}": persist failed: ${error instanceof Error ? error.message : String(error)}`);
93
148
  });
94
149
  };
95
- // Human slash command: the on-demand report.
96
- ctx.commands.register({
150
+ // Human slash command: the on-demand report. The definition is registered
151
+ // inside the single lifecycle effect below, which owns every registration.
152
+ const fastCommand = {
97
153
  name: 'fast',
98
154
  description: 'Print the dsh-fast performance report for the active session.',
99
155
  async handler(invocation) {
100
156
  const report = await reportFor(invocation.agent.session);
101
157
  return { kind: 'success', text: renderFastText(report) };
102
158
  },
103
- });
159
+ };
104
160
  // Model tool: the same report as structured data.
105
- // Service Provider — ctx.tools.register mounts the fast_report tool (the
161
+ // Service Provider — the lifecycle effect mounts the fast_report tool (the
106
162
  // /fast slash command above registers on ctx.commands).
107
- ctx.tools.register(defineTool({
163
+ const fastReportTool = defineTool({
108
164
  name: 'fast_report',
109
165
  description: 'Return the current dsh-fast performance report for the active session: session load timing, spill hits, compaction count and trigger, context-injection volume (AGENTS.md/skills/tool-schema token share), LLM cache hit rate, and optimization suggestions.',
110
166
  parameters: {},
@@ -197,24 +253,32 @@ export async function apply(ctx, config = {}) {
197
253
  }
198
254
  return await reportFor(session);
199
255
  },
200
- }));
201
- // Session lifecycle: adopt and fold.
202
- ctx.on('session/created', (session) => {
203
- collector.handleSessionCreated(session);
204
- });
205
- ctx.on('session/disposed', (session) => {
206
- collector.handleSessionDisposed(session);
207
- });
208
- ctx.on('session/event', (session, event) => {
209
- try {
210
- collector.handleEvent(session, event);
211
- }
212
- catch (error) {
213
- logger.warn(`session "${session.id}": event handling failed: ${error instanceof Error ? error.message : String(error)}`);
214
- }
215
256
  });
216
- // Async sampling: one effect owns the timer and the domain teardown.
257
+ // One effect owns every registration and resource: the /fast command, the
258
+ // fast_report tool, the three session listeners, the sampling timer and the
259
+ // domain handle. The disposer tears them down in reverse registration order
260
+ // (timer → listeners → tool → command → domain close), so an unmount during
261
+ // apply can neither lose a registration nor leak the domain — the previous
262
+ // shape registered all five outside any effect and had nothing to roll back.
217
263
  ctx.effect(() => {
264
+ const disposers = [
265
+ ctx.commands.register(fastCommand),
266
+ ctx.tools.register(fastReportTool),
267
+ ctx.on('session/created', (session) => {
268
+ collector.handleSessionCreated(session);
269
+ }),
270
+ ctx.on('session/disposed', (session) => {
271
+ collector.handleSessionDisposed(session);
272
+ }),
273
+ ctx.on('session/event', (session, event) => {
274
+ try {
275
+ collector.handleEvent(session, event);
276
+ }
277
+ catch (error) {
278
+ logger.warn(`session "${session.id}": event handling failed: ${error instanceof Error ? error.message : String(error)}`);
279
+ }
280
+ }),
281
+ ];
218
282
  const timer = setInterval(() => {
219
283
  for (const session of collector.liveSessions()) {
220
284
  if (!collector.isDirty(session))
@@ -225,6 +289,8 @@ export async function apply(ctx, config = {}) {
225
289
  }, resolved.snapshotIntervalMs);
226
290
  return async () => {
227
291
  clearInterval(timer);
292
+ for (const dispose of disposers.reverse())
293
+ dispose();
228
294
  await domain.close();
229
295
  };
230
296
  });