olympus-ai 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +2 -0
  3. package/dist/__tests__/learning/aggregation.test.d.ts +2 -0
  4. package/dist/__tests__/learning/aggregation.test.d.ts.map +1 -0
  5. package/dist/__tests__/learning/aggregation.test.js +282 -0
  6. package/dist/__tests__/learning/aggregation.test.js.map +1 -0
  7. package/dist/__tests__/learning/anomaly.test.d.ts +2 -0
  8. package/dist/__tests__/learning/anomaly.test.d.ts.map +1 -0
  9. package/dist/__tests__/learning/anomaly.test.js +107 -0
  10. package/dist/__tests__/learning/anomaly.test.js.map +1 -0
  11. package/dist/__tests__/learning/baselines.test.d.ts +2 -0
  12. package/dist/__tests__/learning/baselines.test.d.ts.map +1 -0
  13. package/dist/__tests__/learning/baselines.test.js +155 -0
  14. package/dist/__tests__/learning/baselines.test.js.map +1 -0
  15. package/dist/__tests__/learning/efficiency.test.d.ts +2 -0
  16. package/dist/__tests__/learning/efficiency.test.d.ts.map +1 -0
  17. package/dist/__tests__/learning/efficiency.test.js +94 -0
  18. package/dist/__tests__/learning/efficiency.test.js.map +1 -0
  19. package/dist/__tests__/learning/feedback-loop-injection.test.d.ts +6 -0
  20. package/dist/__tests__/learning/feedback-loop-injection.test.d.ts.map +1 -0
  21. package/dist/__tests__/learning/feedback-loop-injection.test.js +288 -0
  22. package/dist/__tests__/learning/feedback-loop-injection.test.js.map +1 -0
  23. package/dist/__tests__/learning/learning-capture-integration.test.d.ts +6 -0
  24. package/dist/__tests__/learning/learning-capture-integration.test.d.ts.map +1 -0
  25. package/dist/__tests__/learning/learning-capture-integration.test.js +151 -0
  26. package/dist/__tests__/learning/learning-capture-integration.test.js.map +1 -0
  27. package/dist/__tests__/learning/token-metrics.test.d.ts +2 -0
  28. package/dist/__tests__/learning/token-metrics.test.d.ts.map +1 -0
  29. package/dist/__tests__/learning/token-metrics.test.js +308 -0
  30. package/dist/__tests__/learning/token-metrics.test.js.map +1 -0
  31. package/dist/__tests__/token-tracking-integration.test.d.ts +8 -0
  32. package/dist/__tests__/token-tracking-integration.test.d.ts.map +1 -0
  33. package/dist/__tests__/token-tracking-integration.test.js +669 -0
  34. package/dist/__tests__/token-tracking-integration.test.js.map +1 -0
  35. package/dist/cli/commands/metrics.d.ts +10 -2
  36. package/dist/cli/commands/metrics.d.ts.map +1 -1
  37. package/dist/cli/commands/metrics.js +25 -239
  38. package/dist/cli/commands/metrics.js.map +1 -1
  39. package/dist/cli/index.js +196 -1
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/config/loader.d.ts.map +1 -1
  42. package/dist/config/loader.js +14 -0
  43. package/dist/config/loader.js.map +1 -1
  44. package/dist/hooks/registrations/budget-warning.d.ts +8 -0
  45. package/dist/hooks/registrations/budget-warning.d.ts.map +1 -0
  46. package/dist/hooks/registrations/budget-warning.js +63 -0
  47. package/dist/hooks/registrations/budget-warning.js.map +1 -0
  48. package/dist/hooks/registrations/index.d.ts +3 -2
  49. package/dist/hooks/registrations/index.d.ts.map +1 -1
  50. package/dist/hooks/registrations/index.js +5 -3
  51. package/dist/hooks/registrations/index.js.map +1 -1
  52. package/dist/hooks/registrations/learning-capture.d.ts +19 -0
  53. package/dist/hooks/registrations/learning-capture.d.ts.map +1 -0
  54. package/dist/hooks/registrations/learning-capture.js +220 -0
  55. package/dist/hooks/registrations/learning-capture.js.map +1 -0
  56. package/dist/hooks/registrations/session-start.d.ts.map +1 -1
  57. package/dist/hooks/registrations/session-start.js +13 -0
  58. package/dist/hooks/registrations/session-start.js.map +1 -1
  59. package/dist/hooks/registrations/token-metrics.d.ts +10 -2
  60. package/dist/hooks/registrations/token-metrics.d.ts.map +1 -1
  61. package/dist/hooks/registrations/token-metrics.js +18 -4
  62. package/dist/hooks/registrations/token-metrics.js.map +1 -1
  63. package/dist/installer/index.d.ts +1 -1
  64. package/dist/installer/index.d.ts.map +1 -1
  65. package/dist/installer/index.js +56 -0
  66. package/dist/installer/index.js.map +1 -1
  67. package/dist/learning/aggregation.d.ts +39 -0
  68. package/dist/learning/aggregation.d.ts.map +1 -0
  69. package/dist/learning/aggregation.js +101 -0
  70. package/dist/learning/aggregation.js.map +1 -0
  71. package/dist/learning/anomaly.d.ts +30 -0
  72. package/dist/learning/anomaly.d.ts.map +1 -0
  73. package/dist/learning/anomaly.js +102 -0
  74. package/dist/learning/anomaly.js.map +1 -0
  75. package/dist/learning/baselines.d.ts +44 -0
  76. package/dist/learning/baselines.d.ts.map +1 -0
  77. package/dist/learning/baselines.js +126 -0
  78. package/dist/learning/baselines.js.map +1 -0
  79. package/dist/learning/efficiency.d.ts +23 -0
  80. package/dist/learning/efficiency.d.ts.map +1 -0
  81. package/dist/learning/efficiency.js +67 -0
  82. package/dist/learning/efficiency.js.map +1 -0
  83. package/dist/learning/hooks/learned-context.d.ts.map +1 -1
  84. package/dist/learning/hooks/learned-context.js +46 -0
  85. package/dist/learning/hooks/learned-context.js.map +1 -1
  86. package/dist/learning/pricing.d.ts +30 -0
  87. package/dist/learning/pricing.d.ts.map +1 -0
  88. package/dist/learning/pricing.js +98 -0
  89. package/dist/learning/pricing.js.map +1 -0
  90. package/dist/learning/session-state.d.ts +12 -2
  91. package/dist/learning/session-state.d.ts.map +1 -1
  92. package/dist/learning/session-state.js +72 -3
  93. package/dist/learning/session-state.js.map +1 -1
  94. package/dist/learning/storage.d.ts +21 -1
  95. package/dist/learning/storage.d.ts.map +1 -1
  96. package/dist/learning/storage.js +84 -0
  97. package/dist/learning/storage.js.map +1 -1
  98. package/dist/learning/token-estimator.d.ts +41 -0
  99. package/dist/learning/token-estimator.d.ts.map +1 -0
  100. package/dist/learning/token-estimator.js +111 -0
  101. package/dist/learning/token-estimator.js.map +1 -0
  102. package/dist/learning/types.d.ts +32 -0
  103. package/dist/learning/types.d.ts.map +1 -1
  104. package/dist/learning/utils.d.ts +42 -0
  105. package/dist/learning/utils.d.ts.map +1 -0
  106. package/dist/learning/utils.js +76 -0
  107. package/dist/learning/utils.js.map +1 -0
  108. package/dist/shared/types.d.ts +29 -0
  109. package/dist/shared/types.d.ts.map +1 -1
  110. package/package.json +1 -1
  111. package/scripts/dist/hooks/olympus-hooks.cjs +86 -84
@@ -0,0 +1,94 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { calculateEfficiencyScore, calculateTrend } from '../../learning/efficiency.js';
3
+ describe('calculateEfficiencyScore', () => {
4
+ it('should calculate efficiency score correctly', () => {
5
+ const score = calculateEfficiencyScore(0.9, 5000, 10000);
6
+ // successRate * (baseline / avgTokens)
7
+ // 0.9 * (10000 / 5000) = 0.9 * 2 = 1.8
8
+ expect(score).toBe(1.8);
9
+ });
10
+ it('should cap token factor at 2x', () => {
11
+ // Very low tokens should cap at 2x
12
+ const score = calculateEfficiencyScore(0.9, 1000, 10000);
13
+ // 0.9 * min(10, 2) = 0.9 * 2 = 1.8
14
+ expect(score).toBe(1.8);
15
+ });
16
+ it('should handle zero success rate', () => {
17
+ const score = calculateEfficiencyScore(0, 5000, 10000);
18
+ expect(score).toBe(0);
19
+ });
20
+ it('should handle zero tokens (return 0)', () => {
21
+ const score = calculateEfficiencyScore(0.9, 0, 10000);
22
+ expect(score).toBe(0);
23
+ });
24
+ it('should handle high token usage (low efficiency)', () => {
25
+ const score = calculateEfficiencyScore(0.9, 20000, 10000);
26
+ // 0.9 * (10000 / 20000) = 0.9 * 0.5 = 0.45
27
+ expect(score).toBe(0.45);
28
+ });
29
+ it('should throw on invalid success rate (negative)', () => {
30
+ expect(() => calculateEfficiencyScore(-0.1, 5000, 10000)).toThrow('Invalid success rate');
31
+ });
32
+ it('should throw on invalid success rate (> 1)', () => {
33
+ expect(() => calculateEfficiencyScore(1.5, 5000, 10000)).toThrow('Invalid success rate');
34
+ });
35
+ it('should throw on negative token counts', () => {
36
+ expect(() => calculateEfficiencyScore(0.9, -5000, 10000)).toThrow('Token counts cannot be negative');
37
+ expect(() => calculateEfficiencyScore(0.9, 5000, -10000)).toThrow('Token counts cannot be negative');
38
+ });
39
+ it('should handle perfect efficiency (100% success, half the tokens)', () => {
40
+ const score = calculateEfficiencyScore(1.0, 5000, 10000);
41
+ // 1.0 * (10000 / 5000) = 1.0 * 2 = 2.0
42
+ expect(score).toBe(2.0);
43
+ });
44
+ it('should handle baseline equal to average', () => {
45
+ const score = calculateEfficiencyScore(0.8, 10000, 10000);
46
+ // 0.8 * (10000 / 10000) = 0.8 * 1 = 0.8
47
+ expect(score).toBe(0.8);
48
+ });
49
+ });
50
+ describe('calculateTrend', () => {
51
+ it('should return insufficient_data when samples < 5', () => {
52
+ expect(calculateTrend(5000, 6000, 4)).toBe('insufficient_data');
53
+ expect(calculateTrend(5000, 6000, 0)).toBe('insufficient_data');
54
+ });
55
+ it('should detect improving trend (tokens decreasing)', () => {
56
+ // recentAvg is 10% lower than historical
57
+ const trend = calculateTrend(9000, 10000, 10);
58
+ expect(trend).toBe('improving');
59
+ });
60
+ it('should detect declining trend (tokens increasing)', () => {
61
+ // recentAvg is 10% higher than historical
62
+ const trend = calculateTrend(11000, 10000, 10);
63
+ expect(trend).toBe('declining');
64
+ });
65
+ it('should detect stable trend (within 10% threshold)', () => {
66
+ const trend = calculateTrend(10050, 10000, 10);
67
+ expect(trend).toBe('stable');
68
+ });
69
+ it('should handle edge case: historical avg is zero', () => {
70
+ const trend = calculateTrend(5000, 0, 10);
71
+ expect(trend).toBe('insufficient_data');
72
+ });
73
+ it('should throw on negative averages', () => {
74
+ expect(() => calculateTrend(-5000, 10000, 10)).toThrow('Average token counts cannot be negative');
75
+ expect(() => calculateTrend(5000, -10000, 10)).toThrow('Average token counts cannot be negative');
76
+ });
77
+ it('should detect improving trend at exactly -10%', () => {
78
+ const trend = calculateTrend(9000, 10000, 10);
79
+ expect(trend).toBe('improving');
80
+ });
81
+ it('should detect declining trend at exactly +10%', () => {
82
+ const trend = calculateTrend(11000, 10000, 10);
83
+ expect(trend).toBe('declining');
84
+ });
85
+ it('should detect stable at -9% (just under threshold)', () => {
86
+ const trend = calculateTrend(9100, 10000, 10);
87
+ expect(trend).toBe('stable');
88
+ });
89
+ it('should detect stable at +9% (just under threshold)', () => {
90
+ const trend = calculateTrend(10900, 10000, 10);
91
+ expect(trend).toBe('stable');
92
+ });
93
+ });
94
+ //# sourceMappingURL=efficiency.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"efficiency.test.js","sourceRoot":"","sources":["../../../src/__tests__/learning/efficiency.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for Phase 2.4 Feedback Loop (Injection)
3
+ * Verifies token metrics integration into session start and budget warnings
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=feedback-loop-injection.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-loop-injection.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/learning/feedback-loop-injection.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Tests for Phase 2.4 Feedback Loop (Injection)
3
+ * Verifies token metrics integration into session start and budget warnings
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { join } from 'path';
7
+ import { mkdirSync, rmSync, writeFileSync, existsSync } from 'fs';
8
+ import { generateLearnedContext } from '../../learning/hooks/learned-context.js';
9
+ import { loadSessionState, saveSessionState, updateTokenBudget, shouldIssueWarning, markWarningIssued, } from '../../learning/session-state.js';
10
+ import { getLearningDir } from '../../learning/storage.js';
11
+ const TEST_DIR = join(process.cwd(), '.test-injection-' + Date.now());
12
+ const GLOBAL_LEARNING_DIR = getLearningDir();
13
+ let agentPerfBackup = null;
14
+ beforeEach(() => {
15
+ mkdirSync(TEST_DIR, { recursive: true });
16
+ mkdirSync(join(TEST_DIR, '.olympus'), { recursive: true });
17
+ // Ensure global learning directory exists
18
+ mkdirSync(GLOBAL_LEARNING_DIR, { recursive: true });
19
+ // Backup existing agent-performance.json if it exists
20
+ const agentPerfPath = join(GLOBAL_LEARNING_DIR, 'agent-performance.json');
21
+ if (existsSync(agentPerfPath)) {
22
+ agentPerfBackup = agentPerfPath + '.backup.' + Date.now();
23
+ writeFileSync(agentPerfBackup, require('fs').readFileSync(agentPerfPath));
24
+ }
25
+ });
26
+ afterEach(() => {
27
+ // Restore backup if it exists
28
+ if (agentPerfBackup && existsSync(agentPerfBackup)) {
29
+ const agentPerfPath = join(GLOBAL_LEARNING_DIR, 'agent-performance.json');
30
+ writeFileSync(agentPerfPath, require('fs').readFileSync(agentPerfBackup));
31
+ rmSync(agentPerfBackup, { force: true });
32
+ agentPerfBackup = null;
33
+ }
34
+ else {
35
+ // Clean up test file if created
36
+ const agentPerfPath = join(GLOBAL_LEARNING_DIR, 'agent-performance.json');
37
+ if (existsSync(agentPerfPath)) {
38
+ rmSync(agentPerfPath, { force: true });
39
+ }
40
+ }
41
+ if (TEST_DIR.includes('.test-injection-')) {
42
+ rmSync(TEST_DIR, { recursive: true, force: true });
43
+ }
44
+ });
45
+ describe('Token Efficiency Injection', () => {
46
+ it('should include token efficiency in learned context when agent data exists', () => {
47
+ const globalLearningDir = GLOBAL_LEARNING_DIR;
48
+ // Create mock agent performance data with token efficiency
49
+ const agentPerformance = {
50
+ 'olympian': {
51
+ agent_name: 'olympian',
52
+ total_invocations: 10,
53
+ success_count: 9,
54
+ revision_count: 1,
55
+ cancellation_count: 0,
56
+ success_rate: 0.9,
57
+ failure_patterns: [],
58
+ strong_areas: [],
59
+ weak_areas: [],
60
+ last_updated: new Date().toISOString(),
61
+ token_efficiency: {
62
+ avg_tokens_per_success: 4200,
63
+ avg_tokens_per_failure: 5000,
64
+ total_tokens: 42000,
65
+ invocation_count: 10,
66
+ efficiency_score: 0.9,
67
+ trend: 'stable'
68
+ }
69
+ },
70
+ 'oracle-low': {
71
+ agent_name: 'oracle-low',
72
+ total_invocations: 8,
73
+ success_count: 8,
74
+ revision_count: 0,
75
+ cancellation_count: 0,
76
+ success_rate: 1.0,
77
+ failure_patterns: [],
78
+ strong_areas: [],
79
+ weak_areas: [],
80
+ last_updated: new Date().toISOString(),
81
+ token_efficiency: {
82
+ avg_tokens_per_success: 2100,
83
+ avg_tokens_per_failure: 0,
84
+ total_tokens: 16800,
85
+ invocation_count: 8,
86
+ efficiency_score: 1.2,
87
+ trend: 'improving'
88
+ }
89
+ }
90
+ };
91
+ writeFileSync(join(globalLearningDir, 'agent-performance.json'), JSON.stringify(agentPerformance, null, 2));
92
+ const context = generateLearnedContext(TEST_DIR);
93
+ // Should include efficiency section
94
+ expect(context).toContain('<olympus-efficiency>');
95
+ expect(context).toContain('AGENT EFFICIENCY');
96
+ expect(context).toContain('SESSION BUDGET');
97
+ expect(context).toContain('Quality remains priority');
98
+ // Should show agents in order of efficiency
99
+ expect(context).toMatch(/oracle-low.*\[PREFERRED\]/);
100
+ expect(context).toContain('olympian');
101
+ });
102
+ it('should gracefully handle missing token data', () => {
103
+ const globalLearningDir = GLOBAL_LEARNING_DIR;
104
+ // Create agent performance without token efficiency
105
+ const agentPerformance = {
106
+ 'olympian': {
107
+ agent_name: 'olympian',
108
+ total_invocations: 10,
109
+ success_count: 9,
110
+ revision_count: 1,
111
+ cancellation_count: 0,
112
+ success_rate: 0.9,
113
+ failure_patterns: [],
114
+ strong_areas: [],
115
+ weak_areas: [],
116
+ last_updated: new Date().toISOString()
117
+ // No token_efficiency
118
+ }
119
+ };
120
+ writeFileSync(join(globalLearningDir, 'agent-performance.json'), JSON.stringify(agentPerformance, null, 2));
121
+ const context = generateLearnedContext(TEST_DIR);
122
+ // Should not include efficiency section when no token data
123
+ expect(context).not.toContain('<olympus-efficiency>');
124
+ });
125
+ it('should respect 500 token total cap', () => {
126
+ const context = generateLearnedContext(TEST_DIR);
127
+ // Rough token estimate: 1 token ≈ 4 chars
128
+ const estimatedTokens = context.length / 4;
129
+ expect(estimatedTokens).toBeLessThanOrEqual(500);
130
+ });
131
+ });
132
+ describe('Session Budget Tracking', () => {
133
+ it('should initialize token budget at session start', () => {
134
+ const state = loadSessionState(TEST_DIR, 'test-session-1');
135
+ expect(state.token_budget).toBeDefined();
136
+ expect(state.token_budget.session_baseline).toBe(10000); // Default baseline
137
+ expect(state.token_budget.current_usage).toBe(0);
138
+ expect(state.token_budget.warning_threshold).toBe(1.5);
139
+ expect(state.token_budget.warning_issued).toBe(false);
140
+ });
141
+ it('should update current_usage after feedback entry', () => {
142
+ let state = loadSessionState(TEST_DIR, 'test-session-2');
143
+ // Simulate token usage
144
+ state = updateTokenBudget(state, 5000);
145
+ expect(state.token_budget.current_usage).toBe(5000);
146
+ state = updateTokenBudget(state, 3000);
147
+ expect(state.token_budget.current_usage).toBe(8000);
148
+ });
149
+ it('should track warning_issued to prevent spam', () => {
150
+ let state = loadSessionState(TEST_DIR, 'test-session-3');
151
+ expect(state.token_budget.warning_issued).toBe(false);
152
+ state = markWarningIssued(state);
153
+ expect(state.token_budget.warning_issued).toBe(true);
154
+ });
155
+ it('should persist state across hook invocations', () => {
156
+ let state = loadSessionState(TEST_DIR, 'test-session-4');
157
+ state = updateTokenBudget(state, 7000);
158
+ saveSessionState(TEST_DIR, state);
159
+ // Load state again (simulating new hook invocation)
160
+ const newState = loadSessionState(TEST_DIR, 'test-session-4');
161
+ expect(newState.token_budget.current_usage).toBe(7000);
162
+ });
163
+ });
164
+ describe('Budget Warning Logic', () => {
165
+ it('should detect when usage exceeds warning threshold', () => {
166
+ let state = loadSessionState(TEST_DIR, 'test-session-5');
167
+ // Baseline is 10k, threshold is 1.5x = 15k
168
+ expect(shouldIssueWarning(state)).toBe(false);
169
+ state = updateTokenBudget(state, 14000);
170
+ expect(shouldIssueWarning(state)).toBe(false);
171
+ state = updateTokenBudget(state, 2000); // Total: 16k > 15k
172
+ expect(shouldIssueWarning(state)).toBe(true);
173
+ });
174
+ it('should not issue warning if already warned', () => {
175
+ let state = loadSessionState(TEST_DIR, 'test-session-6');
176
+ state = updateTokenBudget(state, 16000); // Exceeds threshold
177
+ expect(shouldIssueWarning(state)).toBe(true);
178
+ state = markWarningIssued(state);
179
+ expect(shouldIssueWarning(state)).toBe(false); // Should not warn again
180
+ state = updateTokenBudget(state, 5000); // Even with more usage
181
+ expect(shouldIssueWarning(state)).toBe(false);
182
+ });
183
+ it('should be non-blocking (continue: true always)', () => {
184
+ // Warning logic never blocks - this is verified by the hook implementation
185
+ // The hook always returns { continue: true } regardless of budget status
186
+ expect(true).toBe(true); // Placeholder - hook behavior verified in integration tests
187
+ });
188
+ });
189
+ describe('Integration with Existing Learning Injection', () => {
190
+ it('should merge token guidance into existing SessionStart flow', () => {
191
+ const globalLearningDir = GLOBAL_LEARNING_DIR;
192
+ // Create mock data for both learning and token efficiency
193
+ const agentPerformance = {
194
+ 'olympian': {
195
+ agent_name: 'olympian',
196
+ total_invocations: 10,
197
+ success_count: 9,
198
+ revision_count: 1,
199
+ cancellation_count: 0,
200
+ success_rate: 0.9,
201
+ failure_patterns: [],
202
+ strong_areas: ['multi-file edits'],
203
+ weak_areas: ['complex debugging'],
204
+ last_updated: new Date().toISOString(),
205
+ token_efficiency: {
206
+ avg_tokens_per_success: 4200,
207
+ avg_tokens_per_failure: 5000,
208
+ total_tokens: 42000,
209
+ invocation_count: 10,
210
+ efficiency_score: 0.9,
211
+ trend: 'stable'
212
+ }
213
+ }
214
+ };
215
+ writeFileSync(join(globalLearningDir, 'agent-performance.json'), JSON.stringify(agentPerformance, null, 2));
216
+ const context = generateLearnedContext(TEST_DIR);
217
+ // Should include both learning context and token efficiency
218
+ expect(context).toContain('Agent Notes'); // Learning context
219
+ expect(context).toContain('<olympus-efficiency>'); // Token guidance
220
+ // Should be under 500 tokens total
221
+ const estimatedTokens = context.length / 4;
222
+ expect(estimatedTokens).toBeLessThanOrEqual(500);
223
+ });
224
+ it('should handle missing token data gracefully', () => {
225
+ const globalLearningDir = GLOBAL_LEARNING_DIR;
226
+ // Create agent performance without token metrics
227
+ const agentPerformance = {
228
+ 'olympian': {
229
+ agent_name: 'olympian',
230
+ total_invocations: 3,
231
+ success_count: 2,
232
+ revision_count: 1,
233
+ cancellation_count: 0,
234
+ success_rate: 0.67,
235
+ failure_patterns: [],
236
+ strong_areas: [],
237
+ weak_areas: ['debugging'],
238
+ last_updated: new Date().toISOString()
239
+ }
240
+ };
241
+ writeFileSync(join(globalLearningDir, 'agent-performance.json'), JSON.stringify(agentPerformance, null, 2));
242
+ const context = generateLearnedContext(TEST_DIR);
243
+ // Should include learning context but not token efficiency
244
+ expect(context).toContain('Agent Notes');
245
+ expect(context).not.toContain('<olympus-efficiency>');
246
+ });
247
+ it('should not produce duplicate injections', () => {
248
+ const context = generateLearnedContext(TEST_DIR);
249
+ // Count occurrences of key markers
250
+ const efficiencyCount = (context.match(/<olympus-efficiency>/g) || []).length;
251
+ expect(efficiencyCount).toBeLessThanOrEqual(1); // At most one efficiency section
252
+ });
253
+ it('should have consistent ordering (learning first, then token efficiency)', () => {
254
+ const globalLearningDir = GLOBAL_LEARNING_DIR;
255
+ const agentPerformance = {
256
+ 'olympian': {
257
+ agent_name: 'olympian',
258
+ total_invocations: 10,
259
+ success_count: 9,
260
+ revision_count: 1,
261
+ cancellation_count: 0,
262
+ success_rate: 0.9,
263
+ failure_patterns: [],
264
+ strong_areas: [],
265
+ weak_areas: ['debugging'],
266
+ last_updated: new Date().toISOString(),
267
+ token_efficiency: {
268
+ avg_tokens_per_success: 4200,
269
+ avg_tokens_per_failure: 5000,
270
+ total_tokens: 42000,
271
+ invocation_count: 10,
272
+ efficiency_score: 0.9,
273
+ trend: 'stable'
274
+ }
275
+ }
276
+ };
277
+ writeFileSync(join(globalLearningDir, 'agent-performance.json'), JSON.stringify(agentPerformance, null, 2));
278
+ const context = generateLearnedContext(TEST_DIR);
279
+ // Find positions of sections
280
+ const agentNotesPos = context.indexOf('Agent Notes');
281
+ const efficiencyPos = context.indexOf('<olympus-efficiency>');
282
+ if (agentNotesPos !== -1 && efficiencyPos !== -1) {
283
+ // Learning context should come before token efficiency
284
+ expect(agentNotesPos).toBeLessThan(efficiencyPos);
285
+ }
286
+ });
287
+ });
288
+ //# sourceMappingURL=feedback-loop-injection.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-loop-injection.test.js","sourceRoot":"","sources":["../../../src/__tests__/learning/feedback-loop-injection.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Integration tests for learning-capture hooks
3
+ * Tests the full flow: UserPromptSubmit → PostToolUse → Stop
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=learning-capture-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-capture-integration.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/learning/learning-capture-integration.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Integration tests for learning-capture hooks
3
+ * Tests the full flow: UserPromptSubmit → PostToolUse → Stop
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { mkdirSync, rmSync, existsSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { registerLearningCaptureHooks } from '../../hooks/registrations/learning-capture.js';
9
+ import { routeHook } from '../../hooks/router.js';
10
+ import { loadSessionState } from '../../learning/session-state.js';
11
+ import { loadFeedback } from '../../learning/storage.js';
12
+ const TEST_DIR = join(process.cwd(), '.test-learning-capture');
13
+ describe('Learning Capture Integration', () => {
14
+ beforeEach(() => {
15
+ // Create test directory
16
+ if (!existsSync(TEST_DIR)) {
17
+ mkdirSync(TEST_DIR, { recursive: true });
18
+ }
19
+ });
20
+ afterEach(() => {
21
+ // Clean up test directory
22
+ if (existsSync(TEST_DIR)) {
23
+ rmSync(TEST_DIR, { recursive: true, force: true });
24
+ }
25
+ });
26
+ it('should accumulate tokens across UserPromptSubmit and PostToolUse', async () => {
27
+ // Register hooks
28
+ registerLearningCaptureHooks();
29
+ const sessionId = 'test-session-123';
30
+ // 1. UserPromptSubmit - should estimate input tokens
31
+ const promptCtx = {
32
+ sessionId,
33
+ directory: TEST_DIR,
34
+ prompt: 'Write a function that adds two numbers',
35
+ };
36
+ await routeHook('UserPromptSubmit', promptCtx);
37
+ // Verify session state was updated with input tokens
38
+ let state = loadSessionState(TEST_DIR, sessionId);
39
+ expect(state.token_budget).toBeDefined();
40
+ expect(state.token_budget.current_usage).toBeGreaterThan(0);
41
+ const afterPrompt = state.token_budget.current_usage;
42
+ // 2. PostToolUse - should estimate output tokens
43
+ const toolCtx = {
44
+ sessionId,
45
+ directory: TEST_DIR,
46
+ toolName: 'Write',
47
+ toolOutput: { content: 'function add(a, b) { return a + b; }' },
48
+ };
49
+ await routeHook('PostToolUse', toolCtx);
50
+ // Verify tokens accumulated
51
+ state = loadSessionState(TEST_DIR, sessionId);
52
+ expect(state.token_budget.current_usage).toBeGreaterThan(afterPrompt);
53
+ const totalTokens = state.token_budget.current_usage;
54
+ // 3. Stop - should create FeedbackEntry and reset budget
55
+ const stopCtx = {
56
+ sessionId,
57
+ directory: TEST_DIR,
58
+ };
59
+ await routeHook('Stop', stopCtx);
60
+ // Verify feedback was created
61
+ const feedback = loadFeedback();
62
+ const sessionFeedback = feedback.filter(f => f.session_id === sessionId);
63
+ expect(sessionFeedback.length).toBeGreaterThan(0);
64
+ const entry = sessionFeedback[0];
65
+ expect(entry.token_usage).toBeDefined();
66
+ expect(entry.token_usage.total_tokens).toBe(totalTokens);
67
+ expect(entry.token_usage.estimated).toBe(true);
68
+ // Verify budget was reset
69
+ state = loadSessionState(TEST_DIR, sessionId);
70
+ expect(state.token_budget.current_usage).toBe(0);
71
+ });
72
+ it('should handle missing directory gracefully', async () => {
73
+ registerLearningCaptureHooks();
74
+ const ctx = {
75
+ sessionId: 'test-session-456',
76
+ // directory is missing
77
+ prompt: 'Test prompt',
78
+ };
79
+ // Should not throw
80
+ const result = await routeHook('UserPromptSubmit', ctx);
81
+ expect(result.continue).toBe(true);
82
+ });
83
+ it('should initialize token_budget if not present (backward compatibility)', async () => {
84
+ registerLearningCaptureHooks();
85
+ const sessionId = 'test-session-789';
86
+ // Create session state without token_budget
87
+ const olympusDir = join(TEST_DIR, '.olympus');
88
+ if (!existsSync(olympusDir)) {
89
+ mkdirSync(olympusDir, { recursive: true });
90
+ }
91
+ const ctx = {
92
+ sessionId,
93
+ directory: TEST_DIR,
94
+ prompt: 'Test prompt for backward compatibility',
95
+ };
96
+ await routeHook('UserPromptSubmit', ctx);
97
+ // Verify token_budget was created
98
+ const state = loadSessionState(TEST_DIR, sessionId);
99
+ expect(state.token_budget).toBeDefined();
100
+ expect(state.token_budget.session_baseline).toBe(10000);
101
+ expect(state.token_budget.warning_threshold).toBe(1.5);
102
+ });
103
+ it('should handle Stop without any prior token accumulation', async () => {
104
+ registerLearningCaptureHooks();
105
+ const sessionId = 'test-session-empty';
106
+ const stopCtx = {
107
+ sessionId,
108
+ directory: TEST_DIR,
109
+ };
110
+ // Stop without any prior events
111
+ const result = await routeHook('Stop', stopCtx);
112
+ expect(result.continue).toBe(true);
113
+ // Should not create feedback entry when tokens are 0
114
+ const feedback = loadFeedback();
115
+ const sessionFeedback = feedback.filter(f => f.session_id === sessionId);
116
+ expect(sessionFeedback.length).toBe(0);
117
+ });
118
+ it('should handle multiple tool uses correctly', async () => {
119
+ registerLearningCaptureHooks();
120
+ const sessionId = 'test-session-multi';
121
+ // Initial prompt
122
+ await routeHook('UserPromptSubmit', {
123
+ sessionId,
124
+ directory: TEST_DIR,
125
+ prompt: 'Create multiple files',
126
+ });
127
+ // Multiple tool uses
128
+ const tools = ['Read', 'Write', 'Edit', 'Bash'];
129
+ for (const tool of tools) {
130
+ await routeHook('PostToolUse', {
131
+ sessionId,
132
+ directory: TEST_DIR,
133
+ toolName: tool,
134
+ toolOutput: { content: `Output from ${tool} tool with some content` },
135
+ });
136
+ }
137
+ // Verify cumulative token count
138
+ const state = loadSessionState(TEST_DIR, sessionId);
139
+ expect(state.token_budget.current_usage).toBeGreaterThan(0);
140
+ // Stop and verify
141
+ await routeHook('Stop', {
142
+ sessionId,
143
+ directory: TEST_DIR,
144
+ });
145
+ const feedback = loadFeedback();
146
+ const entry = feedback.find(f => f.session_id === sessionId);
147
+ expect(entry).toBeDefined();
148
+ expect(entry.token_usage.total_tokens).toBeGreaterThan(0);
149
+ });
150
+ });
151
+ //# sourceMappingURL=learning-capture-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-capture-integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/learning/learning-capture-integration.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAgB,MAAM,IAAI,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,+CAA+C,CAAC;AAC7F,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;AAE/D,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,UAAU,CAAC,GAAG,EAAE;QACd,wBAAwB;QACxB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,0BAA0B;QAC1B,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,iBAAiB;QACjB,4BAA4B,EAAE,CAAC;QAE/B,MAAM,SAAS,GAAG,kBAAkB,CAAC;QAErC,qDAAqD;QACrD,MAAM,SAAS,GAAgB;YAC7B,SAAS;YACT,SAAS,EAAE,QAAQ;YACnB,MAAM,EAAE,wCAAwC;SACjD,CAAC;QAEF,MAAM,SAAS,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;QAE/C,qDAAqD;QACrD,IAAI,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,YAAa,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC7D,MAAM,WAAW,GAAG,KAAK,CAAC,YAAa,CAAC,aAAa,CAAC;QAEtD,iDAAiD;QACjD,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,SAAS,EAAE,QAAQ;YACnB,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,EAAE,OAAO,EAAE,sCAAsC,EAAE;SAChE,CAAC;QAEF,MAAM,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAExC,4BAA4B;QAC5B,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,YAAa,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,KAAK,CAAC,YAAa,CAAC,aAAa,CAAC;QAEtD,yDAAyD;QACzD,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,SAAS,EAAE,QAAQ;SACpB,CAAC;QAEF,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEjC,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;QACzE,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAElD,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,WAAY,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,WAAY,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhD,0BAA0B;QAC1B,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,YAAa,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,4BAA4B,EAAE,CAAC;QAE/B,MAAM,GAAG,GAAgB;YACvB,SAAS,EAAE,kBAAkB;YAC7B,uBAAuB;YACvB,MAAM,EAAE,aAAa;SACtB,CAAC;QAEF,mBAAmB;QACnB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,4BAA4B,EAAE,CAAC;QAE/B,MAAM,SAAS,GAAG,kBAAkB,CAAC;QAErC,4CAA4C;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,GAAG,GAAgB;YACvB,SAAS;YACT,SAAS,EAAE,QAAQ;YACnB,MAAM,EAAE,wCAAwC;SACjD,CAAC;QAEF,MAAM,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;QAEzC,kCAAkC;QAClC,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,YAAa,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,YAAa,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,4BAA4B,EAAE,CAAC;QAE/B,MAAM,SAAS,GAAG,oBAAoB,CAAC;QAEvC,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,SAAS,EAAE,QAAQ;SACpB,CAAC;QAEF,gCAAgC;QAChC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEnC,qDAAqD;QACrD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;QACzE,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,4BAA4B,EAAE,CAAC;QAE/B,MAAM,SAAS,GAAG,oBAAoB,CAAC;QAEvC,iBAAiB;QACjB,MAAM,SAAS,CAAC,kBAAkB,EAAE;YAClC,SAAS;YACT,SAAS,EAAE,QAAQ;YACnB,MAAM,EAAE,uBAAuB;SAChC,CAAC,CAAC;QAEH,qBAAqB;QACrB,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,SAAS,CAAC,aAAa,EAAE;gBAC7B,SAAS;gBACT,SAAS,EAAE,QAAQ;gBACnB,QAAQ,EAAE,IAAI;gBACd,UAAU,EAAE,EAAE,OAAO,EAAE,eAAe,IAAI,yBAAyB,EAAE;aACtE,CAAC,CAAC;QACL,CAAC;QAED,gCAAgC;QAChC,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,YAAa,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAE7D,kBAAkB;QAClB,MAAM,SAAS,CAAC,MAAM,EAAE;YACtB,SAAS;YACT,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAM,CAAC,WAAY,CAAC,YAAY,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=token-metrics.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-metrics.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/learning/token-metrics.test.ts"],"names":[],"mappings":""}