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/CHANGELOG.md +29 -0
- package/README-es.md +16 -4
- package/README-hi.md +16 -4
- package/README-pt.md +16 -4
- package/README-zh.md +16 -4
- package/README.md +15 -4
- package/lib/index.js +121 -28
- package/lib/types/collector.d.ts +16 -3
- package/lib/types/collector.d.ts.map +1 -1
- package/lib/types/collector.js +30 -7
- package/lib/types/collector.js.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +91 -25
- package/lib/types/index.js.map +1 -1
- package/lib/types/notices.d.ts +17 -0
- package/lib/types/notices.d.ts.map +1 -0
- package/lib/types/notices.js +23 -0
- package/lib/types/notices.js.map +1 -0
- package/lib/types/version.d.ts +1 -1
- package/lib/types/version.js +1 -1
- package/package.json +13 -9
- package/src/collector.ts +29 -7
- package/src/index.ts +119 -29
- package/src/notices.ts +25 -0
- package/src/version.ts +1 -1
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
|
|
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(
|
|
209
|
+
function effectiveSystemMessage(surfaceEvents) {
|
|
209
210
|
let effective;
|
|
210
|
-
for (const
|
|
211
|
-
|
|
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.
|
|
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)
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|
package/lib/types/collector.d.ts
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
|
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"}
|
package/lib/types/collector.js
CHANGED
|
@@ -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
|
|
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(
|
|
22
|
+
export function effectiveSystemMessage(surfaceEvents) {
|
|
22
23
|
let effective;
|
|
23
|
-
for (const
|
|
24
|
-
|
|
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
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/collector.ts"],"names":[],"mappings":"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"}
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/lib/types/index.js
CHANGED
|
@@ -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
|
-
|
|
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 —
|
|
161
|
+
// Service Provider — the lifecycle effect mounts the fast_report tool (the
|
|
106
162
|
// /fast slash command above registers on ctx.commands).
|
|
107
|
-
|
|
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
|
-
//
|
|
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
|
});
|