token-optimizer-opencode 1.0.3

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.
Files changed (90) hide show
  1. package/README.md +127 -0
  2. package/dist/activity/intel.d.ts +10 -0
  3. package/dist/activity/intel.d.ts.map +1 -0
  4. package/dist/activity/intel.js +26 -0
  5. package/dist/activity/intel.js.map +1 -0
  6. package/dist/activity/tracker.d.ts +12 -0
  7. package/dist/activity/tracker.d.ts.map +1 -0
  8. package/dist/activity/tracker.js +101 -0
  9. package/dist/activity/tracker.js.map +1 -0
  10. package/dist/compaction/checkpoint.d.ts +17 -0
  11. package/dist/compaction/checkpoint.d.ts.map +1 -0
  12. package/dist/compaction/checkpoint.js +82 -0
  13. package/dist/compaction/checkpoint.js.map +1 -0
  14. package/dist/compaction/dynamic-instructions.d.ts +3 -0
  15. package/dist/compaction/dynamic-instructions.d.ts.map +1 -0
  16. package/dist/compaction/dynamic-instructions.js +54 -0
  17. package/dist/compaction/dynamic-instructions.js.map +1 -0
  18. package/dist/continuity/matcher.d.ts +14 -0
  19. package/dist/continuity/matcher.d.ts.map +1 -0
  20. package/dist/continuity/matcher.js +57 -0
  21. package/dist/continuity/matcher.js.map +1 -0
  22. package/dist/continuity/restore.d.ts +4 -0
  23. package/dist/continuity/restore.d.ts.map +1 -0
  24. package/dist/continuity/restore.js +53 -0
  25. package/dist/continuity/restore.js.map +1 -0
  26. package/dist/dashboard/generator.d.ts +8 -0
  27. package/dist/dashboard/generator.d.ts.map +1 -0
  28. package/dist/dashboard/generator.js +282 -0
  29. package/dist/dashboard/generator.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +447 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/nudges/loop-detection.d.ts +6 -0
  35. package/dist/nudges/loop-detection.d.ts.map +1 -0
  36. package/dist/nudges/loop-detection.js +56 -0
  37. package/dist/nudges/loop-detection.js.map +1 -0
  38. package/dist/nudges/quality-nudge.d.ts +7 -0
  39. package/dist/nudges/quality-nudge.d.ts.map +1 -0
  40. package/dist/nudges/quality-nudge.js +28 -0
  41. package/dist/nudges/quality-nudge.js.map +1 -0
  42. package/dist/nudges/tool-call-warn.d.ts +7 -0
  43. package/dist/nudges/tool-call-warn.d.ts.map +1 -0
  44. package/dist/nudges/tool-call-warn.js +20 -0
  45. package/dist/nudges/tool-call-warn.js.map +1 -0
  46. package/dist/plugin.d.ts +9 -0
  47. package/dist/plugin.d.ts.map +1 -0
  48. package/dist/plugin.js +5 -0
  49. package/dist/plugin.js.map +1 -0
  50. package/dist/quality/curves.d.ts +5 -0
  51. package/dist/quality/curves.d.ts.map +1 -0
  52. package/dist/quality/curves.js +102 -0
  53. package/dist/quality/curves.js.map +1 -0
  54. package/dist/quality/scoring.d.ts +39 -0
  55. package/dist/quality/scoring.d.ts.map +1 -0
  56. package/dist/quality/scoring.js +239 -0
  57. package/dist/quality/scoring.js.map +1 -0
  58. package/dist/quality/signals.d.ts +23 -0
  59. package/dist/quality/signals.d.ts.map +1 -0
  60. package/dist/quality/signals.js +100 -0
  61. package/dist/quality/signals.js.map +1 -0
  62. package/dist/storage/session-store.d.ts +73 -0
  63. package/dist/storage/session-store.d.ts.map +1 -0
  64. package/dist/storage/session-store.js +259 -0
  65. package/dist/storage/session-store.js.map +1 -0
  66. package/dist/storage/trends.d.ts +28 -0
  67. package/dist/storage/trends.d.ts.map +1 -0
  68. package/dist/storage/trends.js +125 -0
  69. package/dist/storage/trends.js.map +1 -0
  70. package/dist/tools/dashboard.d.ts +3 -0
  71. package/dist/tools/dashboard.d.ts.map +1 -0
  72. package/dist/tools/dashboard.js +45 -0
  73. package/dist/tools/dashboard.js.map +1 -0
  74. package/dist/tools/token-status.d.ts +9 -0
  75. package/dist/tools/token-status.d.ts.map +1 -0
  76. package/dist/tools/token-status.js +51 -0
  77. package/dist/tools/token-status.js.map +1 -0
  78. package/dist/util/context-window.d.ts +2 -0
  79. package/dist/util/context-window.d.ts.map +1 -0
  80. package/dist/util/context-window.js +83 -0
  81. package/dist/util/context-window.js.map +1 -0
  82. package/dist/util/env.d.ts +23 -0
  83. package/dist/util/env.d.ts.map +1 -0
  84. package/dist/util/env.js +63 -0
  85. package/dist/util/env.js.map +1 -0
  86. package/dist/util/grade.d.ts +4 -0
  87. package/dist/util/grade.d.ts.map +1 -0
  88. package/dist/util/grade.js +32 -0
  89. package/dist/util/grade.js.map +1 -0
  90. package/package.json +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,eAAO,MAAM,EAAE,6BAA6B,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,CAAC;;;;;AAChC,wBAA2E"}
package/dist/plugin.js ADDED
@@ -0,0 +1,5 @@
1
+ import { TokenOptimizerPlugin } from "./index.js";
2
+ export const id = "token-optimizer-opencode";
3
+ export { TokenOptimizerPlugin };
4
+ export default { id, server: TokenOptimizerPlugin };
5
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,CAAC,MAAM,EAAE,GAAG,0BAA0B,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAChC,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAyB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function estimateQualityFromFill(fillPct: number, model?: string, contextWindow?: number): {
2
+ quality: number;
3
+ curveName: string;
4
+ };
5
+ //# sourceMappingURL=curves.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curves.d.ts","sourceRoot":"","sources":["../../src/quality/curves.ts"],"names":[],"mappings":"AAsGA,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAYxC"}
@@ -0,0 +1,102 @@
1
+ // Anthropic default (fill fraction 0-1)
2
+ const ANTHROPIC_MRCR = [
3
+ [0.0, 98],
4
+ [0.10, 96],
5
+ [0.25, 93],
6
+ [0.50, 88],
7
+ [0.60, 84],
8
+ [0.70, 80],
9
+ [0.80, 78],
10
+ [0.90, 77],
11
+ [1.0, 76],
12
+ ];
13
+ // OpenAI GPT-5.5 (absolute tokens)
14
+ const OPENAI_GPT55_MRCR = [
15
+ [0, 98],
16
+ [8_000, 98],
17
+ [16_000, 96],
18
+ [32_000, 94],
19
+ [64_000, 90],
20
+ [128_000, 86],
21
+ [256_000, 84],
22
+ [512_000, 81],
23
+ [1_000_000, 74],
24
+ ];
25
+ // OpenAI GPT-5 family fallback (absolute tokens)
26
+ const OPENAI_GPT5_MRCR = [
27
+ [0, 98],
28
+ [32_000, 94],
29
+ [64_000, 90],
30
+ [128_000, 85],
31
+ [256_000, 80],
32
+ [512_000, 72],
33
+ [1_000_000, 64],
34
+ ];
35
+ // GPT-4.1 family (1M window, extrapolated from GPT-5 shape)
36
+ const OPENAI_GPT41_MRCR = [
37
+ [0, 98],
38
+ [32_000, 95],
39
+ [64_000, 92],
40
+ [128_000, 88],
41
+ [256_000, 82],
42
+ [512_000, 74],
43
+ [1_000_000, 66],
44
+ ];
45
+ // Gemini (steepest degradation among frontier models)
46
+ const GEMINI_MRCR = [
47
+ [0, 98],
48
+ [8_000, 97],
49
+ [32_000, 95],
50
+ [64_000, 92],
51
+ [128_000, 85],
52
+ [256_000, 72],
53
+ [512_000, 50],
54
+ [1_000_000, 26],
55
+ [2_000_000, 15],
56
+ ];
57
+ function interpolate(curve, x) {
58
+ if (curve.length === 0)
59
+ return 76;
60
+ if (x <= curve[0][0])
61
+ return curve[0][1];
62
+ if (x >= curve[curve.length - 1][0])
63
+ return curve[curve.length - 1][1];
64
+ for (let i = 1; i < curve.length; i++) {
65
+ if (x <= curve[i][0]) {
66
+ const [x0, y0] = curve[i - 1];
67
+ const [x1, y1] = curve[i];
68
+ const t = (x - x0) / (x1 - x0);
69
+ return y0 + t * (y1 - y0);
70
+ }
71
+ }
72
+ return curve[curve.length - 1][1];
73
+ }
74
+ function selectCurve(model) {
75
+ const m = (model ?? "").toLowerCase();
76
+ if (m.includes("gemini")) {
77
+ return { family: "google-gemini", curve: GEMINI_MRCR, mode: "absolute_tokens" };
78
+ }
79
+ if (m.includes("gpt-5.5") || m.includes("gpt-5.4")) {
80
+ return { family: "openai-gpt-5.5", curve: OPENAI_GPT55_MRCR, mode: "absolute_tokens" };
81
+ }
82
+ if (m.includes("gpt-4.1")) {
83
+ return { family: "openai-gpt-4.1", curve: OPENAI_GPT41_MRCR, mode: "absolute_tokens" };
84
+ }
85
+ if (m.includes("gpt-5") || m.includes("gpt-4")) {
86
+ return { family: "openai-gpt-5", curve: OPENAI_GPT5_MRCR, mode: "absolute_tokens" };
87
+ }
88
+ return { family: "anthropic-default", curve: ANTHROPIC_MRCR, mode: "fill_fraction" };
89
+ }
90
+ export function estimateQualityFromFill(fillPct, model, contextWindow) {
91
+ const fill = Math.max(0, Math.min(1, fillPct));
92
+ const { family, curve, mode } = selectCurve(model);
93
+ let quality;
94
+ if (mode === "absolute_tokens" && contextWindow) {
95
+ quality = interpolate(curve, fill * contextWindow);
96
+ }
97
+ else {
98
+ quality = interpolate(curve, fill);
99
+ }
100
+ return { quality: Math.round(quality), curveName: family };
101
+ }
102
+ //# sourceMappingURL=curves.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curves.js","sourceRoot":"","sources":["../../src/quality/curves.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { SessionStore } from "../storage/session-store.js";
2
+ import type { TokenOptimizerConfig } from "../util/env.js";
3
+ export interface QualityResult {
4
+ score: number;
5
+ grade: string;
6
+ resourceHealth: number;
7
+ resourceHealthGrade: string;
8
+ sessionEfficiency: number;
9
+ sessionEfficiencyGrade: string;
10
+ signals: Record<string, number>;
11
+ breakdown: Record<string, SignalBreakdown>;
12
+ fillWarning: FillWarning | null;
13
+ toolCallWarning: ToolCallWarning | null;
14
+ regimeChange: RegimeChange | null;
15
+ toolCalls: number;
16
+ fillPct: number;
17
+ }
18
+ export interface SignalBreakdown {
19
+ score: number;
20
+ detail: string;
21
+ [key: string]: unknown;
22
+ }
23
+ export interface FillWarning {
24
+ level: string;
25
+ fillPct: number;
26
+ message: string;
27
+ }
28
+ export interface ToolCallWarning {
29
+ level: string;
30
+ toolCalls: number;
31
+ message: string;
32
+ }
33
+ export interface RegimeChange {
34
+ fillPct: number;
35
+ message: string;
36
+ }
37
+ export declare function computeQualityScore(store: SessionStore, fillPct: number, model: string | undefined, contextWindow: number, config: TokenOptimizerConfig): QualityResult;
38
+ export declare function enforceMonotonicity(newResult: QualityResult, cachedResourceHealth: number | null, cachedCompactions: number, currentCompactions: number): QualityResult;
39
+ //# sourceMappingURL=scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../src/quality/scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAShE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAoB3D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AASD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,oBAAoB,GAC3B,aAAa,CAuMf;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,aAAa,EACxB,oBAAoB,EAAE,MAAM,GAAG,IAAI,EACnC,iBAAiB,EAAE,MAAM,EACzB,kBAAkB,EAAE,MAAM,GACzB,aAAa,CAcf"}
@@ -0,0 +1,239 @@
1
+ import { scoreToGrade, degradationBand } from "../util/grade.js";
2
+ import { estimateQualityFromFill } from "./curves.js";
3
+ import { detectStaleReads, detectBloatedResults, computeDecisionDensity, computeAgentEfficiency, } from "./signals.js";
4
+ const RESOURCE_HEALTH_WEIGHTS = {
5
+ context_fill_degradation: 0.5,
6
+ compaction_depth: 0.3,
7
+ absolute_waste_tokens: 0.2,
8
+ };
9
+ const SESSION_EFFICIENCY_WEIGHTS = {
10
+ stale_reads: 0.3,
11
+ bloated_results: 0.3,
12
+ decision_density: 0.2,
13
+ agent_efficiency: 0.2,
14
+ };
15
+ const FILL_WARN_THRESHOLDS = [
16
+ [0.85, "CRITICAL", "85% context fill, compact now"],
17
+ [0.75, "WARNING", "75% context fill, consider compacting"],
18
+ ];
19
+ function scaledToolCallThresholds(contextWindow, config) {
20
+ const scale = Math.max(1.0, (contextWindow / 200_000) ** 1.3);
21
+ const warn = Math.max(1, config.toolCallWarnThreshold ?? Math.floor(25 * scale));
22
+ const critical = Math.max(1, config.toolCallCriticalThreshold ?? Math.floor(40 * scale));
23
+ return { warn, critical };
24
+ }
25
+ export function computeQualityScore(store, fillPct, model, contextWindow, config) {
26
+ const window = config.qualityWindow;
27
+ // Signal 0: Context fill degradation (MRCR-based)
28
+ const { quality: fillQuality, curveName } = estimateQualityFromFill(fillPct, model, contextWindow);
29
+ const fillScore = Math.max(0, Math.min(100, ((fillQuality - 76) / (98 - 76)) * 100));
30
+ // Signal 1: Stale reads (rolling window)
31
+ const staleData = detectStaleReads(store, window);
32
+ const recentReads = store.getRecentReads(window);
33
+ let staleScore;
34
+ if (recentReads.length > 0) {
35
+ const staleRatio = Math.min(1, staleData.count / recentReads.length);
36
+ staleScore = Math.max(0, Math.min(100, 100 - staleRatio * 100));
37
+ }
38
+ else {
39
+ staleScore = 100;
40
+ }
41
+ // Signal 2: Bloated results (rolling window)
42
+ const bloatedData = detectBloatedResults(store, window);
43
+ const recentResults = store.getRecentToolResults(window);
44
+ let bloatedScore;
45
+ if (recentResults.length > 0) {
46
+ const bloatedRatio = Math.min(1, bloatedData.count / recentResults.length);
47
+ bloatedScore = Math.max(0, Math.min(100, 100 - bloatedRatio * 300));
48
+ }
49
+ else {
50
+ bloatedScore = 100;
51
+ }
52
+ // Signal 3: Compaction depth
53
+ const compactions = store.getCompactionCount();
54
+ let compactionScore;
55
+ if (compactions === 0)
56
+ compactionScore = 100;
57
+ else if (compactions === 1)
58
+ compactionScore = 75;
59
+ else if (compactions === 2)
60
+ compactionScore = 45;
61
+ else
62
+ compactionScore = 20;
63
+ // Signal 4: Decision density (rolling window)
64
+ const densityData = computeDecisionDensity(store, window);
65
+ const densityScore = densityData.total > 0 ? Math.min(100, densityData.ratio * 200) : 50;
66
+ // Signal 5: Agent efficiency (rolling window)
67
+ const agentData = computeAgentEfficiency(store, window);
68
+ const agentScore = agentData.dispatches > 0 ? Math.min(100, agentData.efficiency * 150) : 80;
69
+ // Signal 6: Absolute waste tokens
70
+ const totalWaste = staleData.estimatedWasteTokens + bloatedData.estimatedWasteTokens;
71
+ const wasteFraction = contextWindow > 0 ? totalWaste / contextWindow : 0;
72
+ const wasteScore = Math.max(0, Math.min(100, 100 - wasteFraction * 1000));
73
+ const signals = {
74
+ context_fill_degradation: round1(fillScore),
75
+ stale_reads: round1(staleScore),
76
+ bloated_results: round1(bloatedScore),
77
+ compaction_depth: round1(compactionScore),
78
+ decision_density: round1(densityScore),
79
+ agent_efficiency: round1(agentScore),
80
+ absolute_waste_tokens: round1(wasteScore),
81
+ };
82
+ // Dual composite
83
+ const resourceHealth = signals.context_fill_degradation * RESOURCE_HEALTH_WEIGHTS.context_fill_degradation +
84
+ signals.compaction_depth * RESOURCE_HEALTH_WEIGHTS.compaction_depth +
85
+ signals.absolute_waste_tokens * RESOURCE_HEALTH_WEIGHTS.absolute_waste_tokens;
86
+ const sessionEfficiency = signals.stale_reads * SESSION_EFFICIENCY_WEIGHTS.stale_reads +
87
+ signals.bloated_results * SESSION_EFFICIENCY_WEIGHTS.bloated_results +
88
+ signals.decision_density * SESSION_EFFICIENCY_WEIGHTS.decision_density +
89
+ signals.agent_efficiency * SESSION_EFFICIENCY_WEIGHTS.agent_efficiency;
90
+ // Compaction loss estimate
91
+ let compactionLossPct = 0;
92
+ if (compactions === 1)
93
+ compactionLossPct = 65;
94
+ else if (compactions === 2)
95
+ compactionLossPct = 88;
96
+ else if (compactions >= 3)
97
+ compactionLossPct = 95;
98
+ const bandName = degradationBand(fillPct);
99
+ const breakdown = {
100
+ context_fill_degradation: {
101
+ score: signals.context_fill_degradation,
102
+ fillPct: round1(fillPct * 100),
103
+ qualityEstimate: fillQuality,
104
+ qualityCurve: curveName,
105
+ model: model ?? "unknown",
106
+ modelContextWindow: contextWindow,
107
+ band: bandName,
108
+ detail: `${Math.round(fillPct * 100)}% fill, ${bandName.toLowerCase()} (${curveName})`,
109
+ },
110
+ stale_reads: {
111
+ score: signals.stale_reads,
112
+ count: staleData.count,
113
+ windowReads: recentReads.length,
114
+ estimatedWasteTokens: staleData.estimatedWasteTokens,
115
+ detail: staleData.count > 0
116
+ ? `${staleData.count} stale file reads (${recentReads.length} in window)`
117
+ : "No stale reads",
118
+ },
119
+ bloated_results: {
120
+ score: signals.bloated_results,
121
+ count: bloatedData.count,
122
+ windowResults: recentResults.length,
123
+ estimatedWasteTokens: bloatedData.estimatedWasteTokens,
124
+ detail: bloatedData.count > 0
125
+ ? `${bloatedData.count} bloated results (${recentResults.length} in window)`
126
+ : "No bloated results",
127
+ },
128
+ compaction_depth: {
129
+ score: signals.compaction_depth,
130
+ compactions,
131
+ cumulativeLossPct: compactionLossPct,
132
+ detail: compactions > 0
133
+ ? `${compactions} compaction(s) (~${compactionLossPct}% cumulative context loss)`
134
+ : "No compactions",
135
+ },
136
+ decision_density: {
137
+ score: signals.decision_density,
138
+ substantiveMessages: densityData.substantive,
139
+ windowMessages: densityData.total,
140
+ ratio: round2(densityData.ratio),
141
+ detail: densityData.total > 0
142
+ ? `${Math.round(densityData.ratio * 100)}% substantive (${densityData.total} in window)`
143
+ : "No messages",
144
+ },
145
+ agent_efficiency: {
146
+ score: signals.agent_efficiency,
147
+ dispatchCount: agentData.dispatches,
148
+ detail: agentData.dispatches > 0
149
+ ? `${agentData.dispatches} agent dispatches`
150
+ : "No agents used",
151
+ },
152
+ absolute_waste_tokens: {
153
+ score: signals.absolute_waste_tokens,
154
+ totalWasteTokens: totalWaste,
155
+ wasteFraction: round4(wasteFraction),
156
+ detail: totalWaste > 0
157
+ ? `${totalWaste} waste tokens (${round1(wasteFraction * 100)}% of window)`
158
+ : "No measurable waste",
159
+ },
160
+ };
161
+ // Fill warnings (independent of composite)
162
+ let fillWarning = null;
163
+ for (const [threshold, level, message] of FILL_WARN_THRESHOLDS) {
164
+ if (fillPct >= threshold) {
165
+ fillWarning = { level, fillPct: round1(fillPct * 100), message };
166
+ break;
167
+ }
168
+ }
169
+ // Tool call fatigue (gated on fill >= 50%)
170
+ const toolCalls = store.getToolCallCount();
171
+ let toolCallWarning = null;
172
+ if (fillPct >= 0.5) {
173
+ const { warn, critical } = scaledToolCallThresholds(contextWindow, config);
174
+ if (toolCalls >= critical) {
175
+ toolCallWarning = {
176
+ level: "CRITICAL",
177
+ toolCalls,
178
+ message: `${critical}+ tool calls, instruction adherence severely degraded`,
179
+ };
180
+ }
181
+ else if (toolCalls >= warn) {
182
+ toolCallWarning = {
183
+ level: "WARNING",
184
+ toolCalls,
185
+ message: `${warn}+ tool calls, consider a fresh session`,
186
+ };
187
+ }
188
+ }
189
+ // 50% fill regime change
190
+ let regimeChange = null;
191
+ if (fillPct > 0.5) {
192
+ regimeChange = {
193
+ fillPct: round1(fillPct * 100),
194
+ message: "System prompt erosion accelerating, middle content at highest risk",
195
+ };
196
+ }
197
+ const rhRounded = round1(resourceHealth);
198
+ const seRounded = round1(sessionEfficiency);
199
+ return {
200
+ score: rhRounded,
201
+ grade: scoreToGrade(Math.round(resourceHealth)),
202
+ resourceHealth: rhRounded,
203
+ resourceHealthGrade: scoreToGrade(Math.round(resourceHealth)),
204
+ sessionEfficiency: seRounded,
205
+ sessionEfficiencyGrade: scoreToGrade(Math.round(sessionEfficiency)),
206
+ signals,
207
+ breakdown,
208
+ fillWarning,
209
+ toolCallWarning,
210
+ regimeChange,
211
+ toolCalls,
212
+ fillPct,
213
+ };
214
+ }
215
+ export function enforceMonotonicity(newResult, cachedResourceHealth, cachedCompactions, currentCompactions) {
216
+ if (cachedResourceHealth === null)
217
+ return newResult;
218
+ if (currentCompactions > cachedCompactions)
219
+ return newResult;
220
+ if (newResult.resourceHealth > cachedResourceHealth) {
221
+ const clamped = { ...newResult };
222
+ clamped.resourceHealth = cachedResourceHealth;
223
+ clamped.score = cachedResourceHealth;
224
+ clamped.grade = scoreToGrade(Math.round(cachedResourceHealth));
225
+ clamped.resourceHealthGrade = clamped.grade;
226
+ return clamped;
227
+ }
228
+ return newResult;
229
+ }
230
+ function round1(n) {
231
+ return Math.round(n * 10) / 10;
232
+ }
233
+ function round2(n) {
234
+ return Math.round(n * 100) / 100;
235
+ }
236
+ function round4(n) {
237
+ return Math.round(n * 10000) / 10000;
238
+ }
239
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/quality/scoring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { SessionStore } from "../storage/session-store.js";
2
+ export interface StaleReadResult {
3
+ count: number;
4
+ estimatedWasteTokens: number;
5
+ }
6
+ export declare function detectStaleReads(store: SessionStore, limit: number): StaleReadResult;
7
+ export interface BloatedResultsResult {
8
+ count: number;
9
+ estimatedWasteTokens: number;
10
+ }
11
+ export declare function detectBloatedResults(store: SessionStore, limit: number): BloatedResultsResult;
12
+ export interface DecisionDensityResult {
13
+ substantive: number;
14
+ total: number;
15
+ ratio: number;
16
+ }
17
+ export declare function computeDecisionDensity(store: SessionStore, windowSize: number): DecisionDensityResult;
18
+ export interface AgentEfficiencyResult {
19
+ dispatches: number;
20
+ efficiency: number;
21
+ }
22
+ export declare function computeAgentEfficiency(store: SessionStore, windowSize: number): AgentEfficiencyResult;
23
+ //# sourceMappingURL=signals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/quality/signals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAMhE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAkDpF;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAiC7F;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAMrG;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAerG"}
@@ -0,0 +1,100 @@
1
+ const STALE_READ_DISTANCE_THRESHOLD = 120;
2
+ const BLOAT_THRESHOLD_CHARS = 4000;
3
+ const CHARS_PER_TOKEN = 4;
4
+ export function detectStaleReads(store, limit) {
5
+ const reads = store.getRecentReads(limit);
6
+ const writes = store.getRecentWrites(limit * 2);
7
+ // The DB returns rows DESC by id. Group ascending by operation index so that
8
+ // `laterWrites[0]` below is the FIRST write after a read, not the last.
9
+ writes.sort((a, b) => a.idx - b.idx);
10
+ const writesByPath = new Map();
11
+ for (const w of writes) {
12
+ const arr = writesByPath.get(w.path) ?? [];
13
+ arr.push(w.idx);
14
+ writesByPath.set(w.path, arr);
15
+ }
16
+ const readsByPath = new Map();
17
+ for (const r of reads) {
18
+ const arr = readsByPath.get(r.path) ?? [];
19
+ arr.push(r.idx);
20
+ readsByPath.set(r.path, arr);
21
+ }
22
+ let staleCount = 0;
23
+ let wasteTokens = 0;
24
+ const AVG_READ_TOKENS = 2000;
25
+ for (const r of reads) {
26
+ const pathWrites = writesByPath.get(r.path);
27
+ if (!pathWrites || pathWrites.length === 0)
28
+ continue;
29
+ const priorWrites = pathWrites.filter((w) => w < r.idx);
30
+ if (priorWrites.length > 0) {
31
+ staleCount++;
32
+ wasteTokens += AVG_READ_TOKENS;
33
+ continue;
34
+ }
35
+ const laterWrites = pathWrites.filter((w) => w > r.idx);
36
+ if (laterWrites.length === 0)
37
+ continue;
38
+ const firstLaterWrite = laterWrites[0];
39
+ if (firstLaterWrite - r.idx > STALE_READ_DISTANCE_THRESHOLD) {
40
+ const laterReads = (readsByPath.get(r.path) ?? []).filter((lr) => lr > r.idx);
41
+ if (laterReads.length === 0) {
42
+ staleCount++;
43
+ wasteTokens += AVG_READ_TOKENS / 2;
44
+ }
45
+ }
46
+ }
47
+ return { count: staleCount, estimatedWasteTokens: wasteTokens };
48
+ }
49
+ export function detectBloatedResults(store, limit) {
50
+ const results = store.getRecentToolResults(limit);
51
+ const messages = store.getRecentMessages(limit);
52
+ // Sort ascending by idx so the early-break on idx > r.idx + 10 works correctly
53
+ // (DB returns DESC by id, but we need ASC by operation index for lookahead).
54
+ // `results` order does not affect the per-result scan, but sort it too so the
55
+ // two arrays share one ordering invariant and future edits stay correct.
56
+ messages.sort((a, b) => a.idx - b.idx);
57
+ results.sort((a, b) => a.idx - b.idx);
58
+ let bloatedCount = 0;
59
+ let wasteTokens = 0;
60
+ for (const r of results) {
61
+ if (r.result_size < BLOAT_THRESHOLD_CHARS)
62
+ continue;
63
+ let wasReferenced = false;
64
+ for (const m of messages) {
65
+ if (m.idx > r.idx && m.role === "assistant" && m.is_substantive) {
66
+ wasReferenced = true;
67
+ break;
68
+ }
69
+ if (m.idx > r.idx + 10)
70
+ break;
71
+ }
72
+ if (!wasReferenced) {
73
+ bloatedCount++;
74
+ wasteTokens += Math.floor(r.result_size / CHARS_PER_TOKEN);
75
+ }
76
+ }
77
+ return { count: bloatedCount, estimatedWasteTokens: wasteTokens };
78
+ }
79
+ export function computeDecisionDensity(store, windowSize) {
80
+ const messages = store.getRecentMessages(windowSize);
81
+ const substantive = messages.filter((m) => m.is_substantive).length;
82
+ const total = messages.length;
83
+ const ratio = total > 0 ? substantive / total : 0;
84
+ return { substantive, total, ratio };
85
+ }
86
+ export function computeAgentEfficiency(store, windowSize) {
87
+ const dispatches = store.getRecentAgentDispatches(windowSize);
88
+ if (dispatches.length === 0) {
89
+ return { dispatches: 0, efficiency: 0.8 };
90
+ }
91
+ const totalPrompt = dispatches.reduce((s, d) => s + d.prompt_size, 0);
92
+ const totalResult = dispatches.reduce((s, d) => s + d.result_size, 0);
93
+ if (totalPrompt <= 0) {
94
+ return { dispatches: dispatches.length, efficiency: 0.8 };
95
+ }
96
+ const total = totalPrompt + totalResult;
97
+ const efficiency = total > 0 ? totalResult / total : 0.5;
98
+ return { dispatches: dispatches.length, efficiency };
99
+ }
100
+ //# sourceMappingURL=signals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.js","sourceRoot":"","sources":["../../src/quality/signals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import { Database } from "bun:sqlite";
2
+ /** Reduce a session id to the charset used for its DB filename and for echoing
3
+ * the id into checkpoint content. Single source of truth for all three callers. */
4
+ export declare function sanitizeSessionId(id: string): string;
5
+ export declare class SessionStore {
6
+ private db;
7
+ private dbPath;
8
+ constructor(dataDir: string, sessionId: string);
9
+ connect(): Database;
10
+ close(): void;
11
+ getMeta(key: string): string | undefined;
12
+ setMeta(key: string, value: string): void;
13
+ getQualityCache(): QualityCacheRow | null;
14
+ writeQualityCache(cache: Omit<QualityCacheRow, "id" | "updated_at">): void;
15
+ recordRead(idx: number, path: string): void;
16
+ recordWrite(idx: number, path: string): void;
17
+ recordToolResult(idx: number, toolName: string, resultSize: number, isFailure: boolean): void;
18
+ recordMessage(idx: number, role: string, textLength: number, isSubstantive: boolean): void;
19
+ recordAgentDispatch(idx: number, promptSize: number, resultSize: number): void;
20
+ getRecentReads(limit: number): Array<{
21
+ idx: number;
22
+ path: string;
23
+ }>;
24
+ getRecentWrites(limit: number): Array<{
25
+ idx: number;
26
+ path: string;
27
+ }>;
28
+ getRecentToolResults(limit: number): Array<{
29
+ idx: number;
30
+ tool_name: string;
31
+ result_size: number;
32
+ is_failure: number;
33
+ }>;
34
+ getRecentMessages(limit: number): Array<{
35
+ idx: number;
36
+ role: string;
37
+ text_length: number;
38
+ is_substantive: number;
39
+ }>;
40
+ getRecentAgentDispatches(limit: number): Array<{
41
+ idx: number;
42
+ prompt_size: number;
43
+ result_size: number;
44
+ }>;
45
+ private safeParseInt;
46
+ private atomicIncrement;
47
+ /**
48
+ * Cap each per-session signal table to its most recent `maxRows` rows.
49
+ * Without this, a long session that never compacts grows these tables
50
+ * unbounded. Table names are a fixed allowlist, never user input.
51
+ */
52
+ capSignalTables(maxRows: number): void;
53
+ getCompactionCount(): number;
54
+ incrementCompaction(): number;
55
+ getToolCallCount(): number;
56
+ incrementToolCallCount(): number;
57
+ getOperationIndex(): number;
58
+ incrementOperationIndex(): number;
59
+ resetSignalAccumulators(): void;
60
+ }
61
+ export interface QualityCacheRow {
62
+ id: number;
63
+ resource_health: number | null;
64
+ session_efficiency: number | null;
65
+ fill_pct: number | null;
66
+ compactions: number;
67
+ tool_calls: number;
68
+ last_nudge_time: number;
69
+ nudge_count: number;
70
+ data: string | null;
71
+ updated_at: number;
72
+ }
73
+ //# sourceMappingURL=session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/storage/session-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC;mFACmF;AACnF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEpD;AAoFD,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQ9C,OAAO,IAAI,QAAQ;IAUnB,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAQxC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC,eAAe,IAAI,eAAe,GAAG,IAAI;IAMzC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,YAAY,CAAC,GAAG,IAAI;IA+B1E,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK5C,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI;IAQ7F,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,IAAI;IAQ1F,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAQ9E,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAOnE,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAOpE,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAOnH,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAOzG,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,eAAe;IAYvB;;;;OAIG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAYtC,kBAAkB,IAAI,MAAM;IAI5B,mBAAmB,IAAI,MAAM;IAI7B,gBAAgB,IAAI,MAAM;IAI1B,sBAAsB,IAAI,MAAM;IAIhC,iBAAiB,IAAI,MAAM;IAI3B,uBAAuB,IAAI,MAAM;IAIjC,uBAAuB,IAAI,IAAI;CAQhC;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB"}