dsh-fast 0.1.1
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 +21 -0
- package/LICENSE +201 -0
- package/README.es.md +166 -0
- package/README.hi.md +166 -0
- package/README.md +166 -0
- package/README.pt.md +166 -0
- package/README.zh.md +166 -0
- package/THIRD_PARTY_NOTICES.md +20 -0
- package/cordis.patch.yml +55 -0
- package/lib/index.js +844 -0
- package/lib/types/analyze.d.ts +41 -0
- package/lib/types/analyze.d.ts.map +1 -0
- package/lib/types/analyze.js +121 -0
- package/lib/types/analyze.js.map +1 -0
- package/lib/types/collector.d.ts +82 -0
- package/lib/types/collector.d.ts.map +1 -0
- package/lib/types/collector.js +236 -0
- package/lib/types/collector.js.map +1 -0
- package/lib/types/config.d.ts +76 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +93 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/estimate.d.ts +24 -0
- package/lib/types/estimate.d.ts.map +1 -0
- package/lib/types/estimate.js +37 -0
- package/lib/types/estimate.js.map +1 -0
- package/lib/types/index.d.ts +35 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +201 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/model.d.ts +91 -0
- package/lib/types/model.d.ts.map +1 -0
- package/lib/types/model.js +11 -0
- package/lib/types/model.js.map +1 -0
- package/lib/types/sanitize.d.ts +33 -0
- package/lib/types/sanitize.d.ts.map +1 -0
- package/lib/types/sanitize.js +59 -0
- package/lib/types/sanitize.js.map +1 -0
- package/lib/types/store.d.ts +74 -0
- package/lib/types/store.d.ts.map +1 -0
- package/lib/types/store.js +84 -0
- package/lib/types/store.js.map +1 -0
- package/lib/types/version.d.ts +3 -0
- package/lib/types/version.d.ts.map +1 -0
- package/lib/types/version.js +3 -0
- package/lib/types/version.js.map +1 -0
- package/package.json +147 -0
- package/src/analyze.ts +148 -0
- package/src/collector.ts +289 -0
- package/src/config.ts +163 -0
- package/src/estimate.ts +41 -0
- package/src/index.ts +235 -0
- package/src/model.ts +98 -0
- package/src/sanitize.ts +60 -0
- package/src/store.ts +100 -0
- package/src/version.ts +2 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable metric storage over the harness storage domain. The `dsh-fast`
|
|
3
|
+
* domain keeps one bounded history per session, so `/fast` and `fast_report`
|
|
4
|
+
* metrics survive a restart and the trend stays queryable without touching the
|
|
5
|
+
* session log (the rc.6 `Session.append` offers no `ignorable` marker and no
|
|
6
|
+
* external event-registration surface, so a custom session event would make
|
|
7
|
+
* the persistence coordinator refuse the log on restore).
|
|
8
|
+
* @module dsh-fast/store
|
|
9
|
+
*/
|
|
10
|
+
import z from 'zod';
|
|
11
|
+
import type { StoredSample } from './model.ts';
|
|
12
|
+
/** The per-session value: a bounded history of samples. */
|
|
13
|
+
export declare const historySchema: z.ZodObject<{
|
|
14
|
+
samples: z.ZodArray<z.ZodObject<{
|
|
15
|
+
at: z.ZodNumber;
|
|
16
|
+
snapshot: z.ZodObject<{
|
|
17
|
+
load: z.ZodObject<{
|
|
18
|
+
kind: z.ZodEnum<{
|
|
19
|
+
open: "open";
|
|
20
|
+
restore: "restore";
|
|
21
|
+
}>;
|
|
22
|
+
seedEvents: z.ZodNumber;
|
|
23
|
+
timeToFirstRequestMs: z.ZodNullable<z.ZodNumber>;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
spill: z.ZodObject<{
|
|
26
|
+
detectedSpilledResults: z.ZodNumber;
|
|
27
|
+
heuristic: z.ZodBoolean;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
compaction: z.ZodObject<{
|
|
30
|
+
count: z.ZodNumber;
|
|
31
|
+
manual: z.ZodNumber;
|
|
32
|
+
automatic: z.ZodNumber;
|
|
33
|
+
shadowedTokens: z.ZodNumber;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
context: z.ZodObject<{
|
|
36
|
+
totalTokens: z.ZodNumber;
|
|
37
|
+
systemTokens: z.ZodNumber;
|
|
38
|
+
toolSchemaTokens: z.ZodNumber;
|
|
39
|
+
surfaceTokens: z.ZodNumber;
|
|
40
|
+
systemShare: z.ZodNumber;
|
|
41
|
+
toolsShare: z.ZodNumber;
|
|
42
|
+
surfaceShare: z.ZodNumber;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
cache: z.ZodObject<{
|
|
45
|
+
inputTokens: z.ZodNumber;
|
|
46
|
+
cacheReadTokens: z.ZodNumber;
|
|
47
|
+
cacheWriteTokens: z.ZodNumber;
|
|
48
|
+
outputTokens: z.ZodNumber;
|
|
49
|
+
hitRate: z.ZodNullable<z.ZodNumber>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
/** The per-session history value type. */
|
|
55
|
+
export interface HistoryValue {
|
|
56
|
+
samples: StoredSample[];
|
|
57
|
+
}
|
|
58
|
+
/** The `dsh-fast` storage-domain declaration. */
|
|
59
|
+
export declare const fastDomainSpec: {
|
|
60
|
+
name: string;
|
|
61
|
+
version: number;
|
|
62
|
+
tables: {
|
|
63
|
+
sessions: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, HistoryValue>;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Append one snapshot to a history, keeping only the newest `maxSamples`.
|
|
68
|
+
* @param history - the current history (may be absent).
|
|
69
|
+
* @param sample - the sample to append.
|
|
70
|
+
* @param maxSamples - the bounded length.
|
|
71
|
+
* @returns the new history.
|
|
72
|
+
*/
|
|
73
|
+
export declare function appendSample(history: HistoryValue | undefined, sample: StoredSample, maxSamples: number): HistoryValue;
|
|
74
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,CAAC,MAAM,KAAK,CAAA;AAEnB,OAAO,KAAK,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAA;AA0D5D,2DAA2D;AAC3D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAExB,CAAA;AAEF,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,EAAE,CAAA;CACxB;AAED,iDAAiD;AACjD,eAAO,MAAM,cAAc;;;;;;CAMzB,CAAA;AAEF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,CAGtH"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable metric storage over the harness storage domain. The `dsh-fast`
|
|
3
|
+
* domain keeps one bounded history per session, so `/fast` and `fast_report`
|
|
4
|
+
* metrics survive a restart and the trend stays queryable without touching the
|
|
5
|
+
* session log (the rc.6 `Session.append` offers no `ignorable` marker and no
|
|
6
|
+
* external event-registration surface, so a custom session event would make
|
|
7
|
+
* the persistence coordinator refuse the log on restore).
|
|
8
|
+
* @module dsh-fast/store
|
|
9
|
+
*/
|
|
10
|
+
import z from 'zod';
|
|
11
|
+
import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain';
|
|
12
|
+
/** Zod schema for the load section. */
|
|
13
|
+
const loadSchema = z.object({
|
|
14
|
+
kind: z.enum(['open', 'restore']),
|
|
15
|
+
seedEvents: z.number().int().nonnegative(),
|
|
16
|
+
timeToFirstRequestMs: z.number().int().nonnegative().nullable(),
|
|
17
|
+
});
|
|
18
|
+
/** Zod schema for the spill section. */
|
|
19
|
+
const spillSchema = z.object({
|
|
20
|
+
detectedSpilledResults: z.number().int().nonnegative(),
|
|
21
|
+
heuristic: z.boolean(),
|
|
22
|
+
});
|
|
23
|
+
/** Zod schema for the compaction section. */
|
|
24
|
+
const compactionSchema = z.object({
|
|
25
|
+
count: z.number().int().nonnegative(),
|
|
26
|
+
manual: z.number().int().nonnegative(),
|
|
27
|
+
automatic: z.number().int().nonnegative(),
|
|
28
|
+
shadowedTokens: z.number().int().nonnegative(),
|
|
29
|
+
});
|
|
30
|
+
/** Zod schema for the context section. */
|
|
31
|
+
const contextSchema = z.object({
|
|
32
|
+
totalTokens: z.number().nonnegative(),
|
|
33
|
+
systemTokens: z.number().nonnegative(),
|
|
34
|
+
toolSchemaTokens: z.number().nonnegative(),
|
|
35
|
+
surfaceTokens: z.number().nonnegative(),
|
|
36
|
+
systemShare: z.number(),
|
|
37
|
+
toolsShare: z.number(),
|
|
38
|
+
surfaceShare: z.number(),
|
|
39
|
+
});
|
|
40
|
+
/** Zod schema for the cache section. */
|
|
41
|
+
const cacheSchema = z.object({
|
|
42
|
+
inputTokens: z.number().int().nonnegative(),
|
|
43
|
+
cacheReadTokens: z.number().int().nonnegative(),
|
|
44
|
+
cacheWriteTokens: z.number().int().nonnegative(),
|
|
45
|
+
outputTokens: z.number().int().nonnegative(),
|
|
46
|
+
hitRate: z.number().nullable(),
|
|
47
|
+
});
|
|
48
|
+
/** Zod schema for one {@link FastSnapshot}. */
|
|
49
|
+
const snapshotSchema = z.object({
|
|
50
|
+
load: loadSchema,
|
|
51
|
+
spill: spillSchema,
|
|
52
|
+
compaction: compactionSchema,
|
|
53
|
+
context: contextSchema,
|
|
54
|
+
cache: cacheSchema,
|
|
55
|
+
});
|
|
56
|
+
/** Zod schema for one {@link StoredSample}. */
|
|
57
|
+
const sampleSchema = z.object({
|
|
58
|
+
at: z.number().int().nonnegative(),
|
|
59
|
+
snapshot: snapshotSchema,
|
|
60
|
+
});
|
|
61
|
+
/** The per-session value: a bounded history of samples. */
|
|
62
|
+
export const historySchema = z.object({
|
|
63
|
+
samples: z.array(sampleSchema),
|
|
64
|
+
});
|
|
65
|
+
/** The `dsh-fast` storage-domain declaration. */
|
|
66
|
+
export const fastDomainSpec = defineDomain({
|
|
67
|
+
name: 'dsh_fast',
|
|
68
|
+
version: 1,
|
|
69
|
+
tables: {
|
|
70
|
+
sessions: domainTable(historySchema),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Append one snapshot to a history, keeping only the newest `maxSamples`.
|
|
75
|
+
* @param history - the current history (may be absent).
|
|
76
|
+
* @param sample - the sample to append.
|
|
77
|
+
* @param maxSamples - the bounded length.
|
|
78
|
+
* @returns the new history.
|
|
79
|
+
*/
|
|
80
|
+
export function appendSample(history, sample, maxSamples) {
|
|
81
|
+
const samples = [...(history?.samples ?? []), sample];
|
|
82
|
+
return { samples: samples.slice(-maxSamples) };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,eAAO,MAAM,OAAO,UAAU,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-fast",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Read-only performance diagnostics for DeepSeek Harness: session load (open/restore) timing, spill-hit counts, compaction count and trigger, context-injection volume (AGENTS.md/skills/tool-schema token share), and LLM cache hit rate — surfaced via the /fast command and the fast_report tool, persisted as reconstructable fast/* session events with async sampling off the model path.",
|
|
5
|
+
"author": "dsh-fast contributors",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/PerryLink/dsh-fast.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/PerryLink/dsh-fast#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/PerryLink/dsh-fast/issues"
|
|
13
|
+
},
|
|
14
|
+
"private": false,
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./lib/index.js",
|
|
17
|
+
"types": "./lib/types/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./lib/types/index.d.ts",
|
|
21
|
+
"default": "./lib/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"lib",
|
|
27
|
+
"src",
|
|
28
|
+
"cordis.patch.yml",
|
|
29
|
+
"CHANGELOG.md",
|
|
30
|
+
"THIRD_PARTY_NOTICES.md",
|
|
31
|
+
"README.md",
|
|
32
|
+
"README.zh.md",
|
|
33
|
+
"README.es.md",
|
|
34
|
+
"README.pt.md",
|
|
35
|
+
"README.hi.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"dsh": {
|
|
40
|
+
"bundle": {
|
|
41
|
+
"patch": "./cordis.patch.yml"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"dshWorkshop": {
|
|
45
|
+
"schema": "omdsh-workshop-package/v1",
|
|
46
|
+
"type": "plugin",
|
|
47
|
+
"integration": {
|
|
48
|
+
"protocol": "harness-profile",
|
|
49
|
+
"artifact": "cordis.patch.yml"
|
|
50
|
+
},
|
|
51
|
+
"install": {
|
|
52
|
+
"mode": "transactional",
|
|
53
|
+
"adapter": "profile-bundle",
|
|
54
|
+
"failurePolicy": "generation-rollback",
|
|
55
|
+
"touchesCurrentBeforeActivation": false
|
|
56
|
+
},
|
|
57
|
+
"lifecycle": {
|
|
58
|
+
"activation": "restart-profile",
|
|
59
|
+
"dispose": "supported"
|
|
60
|
+
},
|
|
61
|
+
"permissions": [
|
|
62
|
+
"session:read",
|
|
63
|
+
"session:write",
|
|
64
|
+
"native-code:none"
|
|
65
|
+
],
|
|
66
|
+
"compatibility": {
|
|
67
|
+
"dshVersions": [
|
|
68
|
+
"0.1.0-rc.6"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"capability": {
|
|
72
|
+
"id": "fast",
|
|
73
|
+
"kind": "diagnostics",
|
|
74
|
+
"invocation": "mount the dsh-fast bundle row",
|
|
75
|
+
"expected": "observes session events read-only, persists fast/* metrics, and serves /fast plus the fast_report tool"
|
|
76
|
+
},
|
|
77
|
+
"evidence": {
|
|
78
|
+
"install": null,
|
|
79
|
+
"failureIsolation": null,
|
|
80
|
+
"hotReload": null,
|
|
81
|
+
"remove": null
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"keywords": [
|
|
85
|
+
"dsh",
|
|
86
|
+
"dsh-plugin",
|
|
87
|
+
"deepseek-harness",
|
|
88
|
+
"deepseek",
|
|
89
|
+
"cordis",
|
|
90
|
+
"performance",
|
|
91
|
+
"diagnostics",
|
|
92
|
+
"profiling",
|
|
93
|
+
"context-engineering",
|
|
94
|
+
"llm-cache"
|
|
95
|
+
],
|
|
96
|
+
"engines": {
|
|
97
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
98
|
+
},
|
|
99
|
+
"packageManager": "pnpm@11.7.0",
|
|
100
|
+
"peerDependencies": {
|
|
101
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
102
|
+
"@deepseek-ai/schemastery": "^3.18.0",
|
|
103
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.6",
|
|
104
|
+
"@deepseek-ai/dsh-tools": "0.1.0-rc.6",
|
|
105
|
+
"@deepseek-ai/dsh-commands": "0.1.0-rc.6",
|
|
106
|
+
"@deepseek-ai/dsh-compaction": "0.1.0-rc.6",
|
|
107
|
+
"@deepseek-ai/dsh-storage": "0.1.0-rc.6",
|
|
108
|
+
"@deepseek-ai/dsh-storage-json": "0.1.0-rc.6",
|
|
109
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.0-rc.6"
|
|
110
|
+
},
|
|
111
|
+
"dependencies": {
|
|
112
|
+
"tsdown": "^0.22.14",
|
|
113
|
+
"typescript": "^5.9.0",
|
|
114
|
+
"zod": "^4.4.3"
|
|
115
|
+
},
|
|
116
|
+
"devDependencies": {
|
|
117
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
118
|
+
"@deepseek-ai/schemastery": "^3.18.0",
|
|
119
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.6",
|
|
120
|
+
"@deepseek-ai/dsh-tools": "0.1.0-rc.6",
|
|
121
|
+
"@deepseek-ai/dsh-commands": "0.1.0-rc.6",
|
|
122
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.0-rc.6",
|
|
123
|
+
"@deepseek-ai/dsh-token-meter": "0.1.0-rc.6",
|
|
124
|
+
"@deepseek-ai/dsh-compaction": "0.1.0-rc.6",
|
|
125
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.0-rc.6",
|
|
126
|
+
"@deepseek-ai/dsh-storage": "0.1.0-rc.6",
|
|
127
|
+
"@deepseek-ai/dsh-storage-json": "0.1.0-rc.6",
|
|
128
|
+
"@deepseek-ai/dsh-llm": "0.1.0-rc.6",
|
|
129
|
+
"@deepseek-ai/dsh-agent": "0.1.0-rc.6",
|
|
130
|
+
"@types/node": "^22.19.0",
|
|
131
|
+
"@vitest/coverage-v8": "^3.2.0",
|
|
132
|
+
"vitest": "^3.2.0"
|
|
133
|
+
},
|
|
134
|
+
"scripts": {
|
|
135
|
+
"build": "node scripts/prepare.mjs",
|
|
136
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
137
|
+
"typecheck:ci": "tsc -p tsconfig.ci.json --noEmit",
|
|
138
|
+
"test": "vitest run",
|
|
139
|
+
"test:coverage": "vitest run --coverage",
|
|
140
|
+
"prepare": "node scripts/prepare.mjs",
|
|
141
|
+
"verify:self-contained": "node scripts/verify-self-contained.mjs",
|
|
142
|
+
"verify:artifacts": "node scripts/verify-artifacts.mjs",
|
|
143
|
+
"verify:readme-sync": "node scripts/check-readme-sync.mjs",
|
|
144
|
+
"pack:check": "node scripts/prepare.mjs && pnpm pack"
|
|
145
|
+
},
|
|
146
|
+
"license": "Apache-2.0"
|
|
147
|
+
}
|
package/src/analyze.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure report assembly: threshold-driven suggestions, the human-readable
|
|
3
|
+
* `/fast` text, and the final {@link FastReport}. Every function is pure of its
|
|
4
|
+
* inputs (no I/O, clock, random, or live-service access), so it is trivially
|
|
5
|
+
* unit-tested and safe to replay.
|
|
6
|
+
* @module dsh-fast/analyze
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FastReport, FastSnapshot } from './model.ts'
|
|
10
|
+
import type { ResolvedConfig } from './config.ts'
|
|
11
|
+
import { sanitizePath, sanitizeText } from './sanitize.ts'
|
|
12
|
+
|
|
13
|
+
/** Report metadata supplied by the caller (identity, optional cwd, time). */
|
|
14
|
+
export interface ReportMeta {
|
|
15
|
+
sessionId: string
|
|
16
|
+
cwd?: string
|
|
17
|
+
generatedAt: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build the optimization suggestions for a snapshot against the config
|
|
22
|
+
* thresholds. Suggestions are plain strings, one per distinct finding.
|
|
23
|
+
* @param snapshot - the metric snapshot.
|
|
24
|
+
* @param config - the resolved config (thresholds).
|
|
25
|
+
* @returns the ordered suggestions (may be empty).
|
|
26
|
+
*/
|
|
27
|
+
export function buildSuggestions(snapshot: FastSnapshot, config: ResolvedConfig): string[] {
|
|
28
|
+
const suggestions: string[] = []
|
|
29
|
+
const t = config.thresholds
|
|
30
|
+
const { context, compaction, cache, spill } = snapshot
|
|
31
|
+
|
|
32
|
+
if (context.systemTokens > t.systemPromptTokens) {
|
|
33
|
+
suggestions.push(
|
|
34
|
+
`System prompt is large (${context.systemTokens} tokens, threshold ${t.systemPromptTokens}); consider trimming AGENTS.md, the skill directory, or persona.`,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
if (context.toolSchemaTokens > t.toolSchemaTokens) {
|
|
38
|
+
suggestions.push(
|
|
39
|
+
`Tool schema is large (${context.toolSchemaTokens} tokens, threshold ${t.toolSchemaTokens}); consider mounting fewer tools or tightening parameter descriptions.`,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
if (context.surfaceTokens > t.surfaceTokens) {
|
|
43
|
+
suggestions.push(
|
|
44
|
+
`Session surface is large (${context.surfaceTokens} tokens, threshold ${t.surfaceTokens}); consider /compact or clearing old tool results.`,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
if (compaction.count >= t.compactionCountWarn) {
|
|
48
|
+
suggestions.push(
|
|
49
|
+
`This session has triggered ${compaction.count} compactions; context pressure is high — compact earlier or raise the compaction threshold.`,
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
if (compaction.count > 0) {
|
|
53
|
+
const average = compaction.shadowedTokens / compaction.count
|
|
54
|
+
if (average > t.compactionShadowTokens) {
|
|
55
|
+
suggestions.push(
|
|
56
|
+
`Average compaction shadows ${Math.round(average)} tokens (threshold ${t.compactionShadowTokens}); the compaction threshold may be too conservative.`,
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (cache.hitRate !== null && cache.hitRate < t.cacheHitRateFloor) {
|
|
61
|
+
suggestions.push(
|
|
62
|
+
`LLM cache hit rate is only ${Math.round(cache.hitRate * 100)}% (threshold ${Math.round(t.cacheHitRateFloor * 100)}%); consider enabling or tuning prompt caching.`,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
if (spill.detectedSpilledResults === 0 && context.surfaceTokens > t.surfaceTokens / 2) {
|
|
66
|
+
suggestions.push(
|
|
67
|
+
'Surface volume is high with no spill hits; if spill-policy is not enabled, consider enabling it to protect the context window.',
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
return suggestions
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Format one nullable millisecond duration. */
|
|
74
|
+
function formatMs(value: number | null): string {
|
|
75
|
+
return value === null ? 'n/a' : `${value} ms`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Format one nullable ratio as a percentage. */
|
|
79
|
+
function formatPercent(value: number | null): string {
|
|
80
|
+
return value === null ? 'n/a' : `${Math.round(value * 100)}%`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Render a report as the human-readable `/fast` body.
|
|
85
|
+
* @param report - the assembled report.
|
|
86
|
+
* @returns the report text.
|
|
87
|
+
*/
|
|
88
|
+
export function renderFastText(report: FastReport): string {
|
|
89
|
+
const { load, spill, compaction, context, cache } = report
|
|
90
|
+
const lines = [
|
|
91
|
+
`dsh-fast ${report.version} — performance report`,
|
|
92
|
+
`session: ${report.sessionId}`,
|
|
93
|
+
'',
|
|
94
|
+
'## Session load',
|
|
95
|
+
`kind: ${load.kind}`,
|
|
96
|
+
`seed events: ${load.seedEvents}`,
|
|
97
|
+
`time to first request: ${formatMs(load.timeToFirstRequestMs)}`,
|
|
98
|
+
'',
|
|
99
|
+
'## Spill',
|
|
100
|
+
`detected spilled results: ${spill.detectedSpilledResults} (heuristic)`,
|
|
101
|
+
'',
|
|
102
|
+
'## Compaction',
|
|
103
|
+
`count: ${compaction.count} (manual: ${compaction.manual}, automatic: ${compaction.automatic})`,
|
|
104
|
+
`shadowed tokens: ${compaction.shadowedTokens}`,
|
|
105
|
+
'',
|
|
106
|
+
'## Context volume',
|
|
107
|
+
`total: ${context.totalTokens} tokens`,
|
|
108
|
+
`system (AGENTS.md/skills/persona): ${context.systemTokens} (${formatPercent(context.systemShare)})`,
|
|
109
|
+
`tool schema: ${context.toolSchemaTokens} (${formatPercent(context.toolsShare)})`,
|
|
110
|
+
`surface: ${context.surfaceTokens} (${formatPercent(context.surfaceShare)})`,
|
|
111
|
+
'',
|
|
112
|
+
'## LLM cache',
|
|
113
|
+
`input: ${cache.inputTokens}, cache read: ${cache.cacheReadTokens}, cache write: ${cache.cacheWriteTokens}, output: ${cache.outputTokens}`,
|
|
114
|
+
`hit rate: ${formatPercent(cache.hitRate)}`,
|
|
115
|
+
]
|
|
116
|
+
if (report.cwd !== undefined) {
|
|
117
|
+
lines.splice(lines.length, 0, `cwd: ${report.cwd}`)
|
|
118
|
+
}
|
|
119
|
+
lines.push('', '## Suggestions')
|
|
120
|
+
if (report.suggestions.length === 0) {
|
|
121
|
+
lines.push('- none')
|
|
122
|
+
} else {
|
|
123
|
+
for (const suggestion of report.suggestions) lines.push(`- ${suggestion}`)
|
|
124
|
+
}
|
|
125
|
+
return lines.join('\n')
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Assemble the final report from a snapshot plus caller metadata. Suggestions
|
|
130
|
+
* are computed here and the identity/cwd fields are sanitized before any model
|
|
131
|
+
* or durable surface sees them.
|
|
132
|
+
* @param snapshot - the metric snapshot.
|
|
133
|
+
* @param meta - session identity, optional cwd, and generation time.
|
|
134
|
+
* @param config - the resolved config (thresholds).
|
|
135
|
+
* @param version - the plugin version.
|
|
136
|
+
* @returns the complete report.
|
|
137
|
+
*/
|
|
138
|
+
export function buildReport(snapshot: FastSnapshot, meta: ReportMeta, config: ResolvedConfig, version: string): FastReport {
|
|
139
|
+
return {
|
|
140
|
+
...snapshot,
|
|
141
|
+
generator: 'dsh-fast',
|
|
142
|
+
version,
|
|
143
|
+
sessionId: sanitizeText(meta.sessionId, 128),
|
|
144
|
+
generatedAt: meta.generatedAt,
|
|
145
|
+
suggestions: buildSuggestions(snapshot, config),
|
|
146
|
+
...(meta.cwd === undefined ? {} : { cwd: sanitizePath(meta.cwd, 256) }),
|
|
147
|
+
}
|
|
148
|
+
}
|