claude-mycelium 2.0.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.
- package/.claude/settings.local.json +14 -0
- package/README.md +304 -0
- package/dist/coordination/gradient-cache.d.ts +48 -0
- package/dist/coordination/gradient-cache.d.ts.map +1 -0
- package/dist/coordination/gradient-cache.js +145 -0
- package/dist/coordination/gradient-cache.js.map +1 -0
- package/dist/coordination/index.d.ts +10 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +10 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/core/agent-executor.d.ts +31 -0
- package/dist/core/agent-executor.d.ts.map +1 -0
- package/dist/core/agent-executor.js +257 -0
- package/dist/core/agent-executor.js.map +1 -0
- package/dist/core/change-applier.d.ts +10 -0
- package/dist/core/change-applier.d.ts.map +1 -0
- package/dist/core/change-applier.js +32 -0
- package/dist/core/change-applier.js.map +1 -0
- package/dist/core/gradient.d.ts +60 -0
- package/dist/core/gradient.d.ts.map +1 -0
- package/dist/core/gradient.js +191 -0
- package/dist/core/gradient.js.map +1 -0
- package/dist/core/index.d.ts +24 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +24 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/mode-selector.d.ts +44 -0
- package/dist/core/mode-selector.d.ts.map +1 -0
- package/dist/core/mode-selector.js +208 -0
- package/dist/core/mode-selector.js.map +1 -0
- package/dist/core/signals/centrality.d.ts +44 -0
- package/dist/core/signals/centrality.d.ts.map +1 -0
- package/dist/core/signals/centrality.js +264 -0
- package/dist/core/signals/centrality.js.map +1 -0
- package/dist/core/signals/churn.d.ts +41 -0
- package/dist/core/signals/churn.d.ts.map +1 -0
- package/dist/core/signals/churn.js +188 -0
- package/dist/core/signals/churn.js.map +1 -0
- package/dist/core/signals/complexity.d.ts +29 -0
- package/dist/core/signals/complexity.d.ts.map +1 -0
- package/dist/core/signals/complexity.js +169 -0
- package/dist/core/signals/complexity.js.map +1 -0
- package/dist/core/signals/debt.d.ts +27 -0
- package/dist/core/signals/debt.d.ts.map +1 -0
- package/dist/core/signals/debt.js +80 -0
- package/dist/core/signals/debt.js.map +1 -0
- package/dist/core/signals/errors.d.ts +32 -0
- package/dist/core/signals/errors.d.ts.map +1 -0
- package/dist/core/signals/errors.js +73 -0
- package/dist/core/signals/errors.js.map +1 -0
- package/dist/core/signals/index.d.ts +19 -0
- package/dist/core/signals/index.d.ts.map +1 -0
- package/dist/core/signals/index.js +19 -0
- package/dist/core/signals/index.js.map +1 -0
- package/dist/cost/cost-tracker.d.ts +90 -0
- package/dist/cost/cost-tracker.d.ts.map +1 -0
- package/dist/cost/cost-tracker.js +305 -0
- package/dist/cost/cost-tracker.js.map +1 -0
- package/dist/cost/index.d.ts +56 -0
- package/dist/cost/index.d.ts.map +1 -0
- package/dist/cost/index.js +111 -0
- package/dist/cost/index.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic-client.d.ts +52 -0
- package/dist/llm/anthropic-client.d.ts.map +1 -0
- package/dist/llm/anthropic-client.js +310 -0
- package/dist/llm/anthropic-client.js.map +1 -0
- package/dist/llm/index.d.ts +27 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +34 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/prompts/complexity-reducer.d.ts +7 -0
- package/dist/prompts/complexity-reducer.d.ts.map +1 -0
- package/dist/prompts/complexity-reducer.js +55 -0
- package/dist/prompts/complexity-reducer.js.map +1 -0
- package/dist/prompts/debt-payer.d.ts +7 -0
- package/dist/prompts/debt-payer.d.ts.map +1 -0
- package/dist/prompts/debt-payer.js +55 -0
- package/dist/prompts/debt-payer.js.map +1 -0
- package/dist/prompts/error-reducer.d.ts +7 -0
- package/dist/prompts/error-reducer.d.ts.map +1 -0
- package/dist/prompts/error-reducer.js +54 -0
- package/dist/prompts/error-reducer.js.map +1 -0
- package/dist/prompts/index.d.ts +22 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +112 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/stabilizer.d.ts +7 -0
- package/dist/prompts/stabilizer.d.ts.map +1 -0
- package/dist/prompts/stabilizer.js +55 -0
- package/dist/prompts/stabilizer.js.map +1 -0
- package/dist/prompts/types.d.ts +14 -0
- package/dist/prompts/types.d.ts.map +1 -0
- package/dist/prompts/types.js +5 -0
- package/dist/prompts/types.js.map +1 -0
- package/dist/trace/index.d.ts +51 -0
- package/dist/trace/index.d.ts.map +1 -0
- package/dist/trace/index.js +60 -0
- package/dist/trace/index.js.map +1 -0
- package/dist/trace/trace-event.d.ts +72 -0
- package/dist/trace/trace-event.d.ts.map +1 -0
- package/dist/trace/trace-event.js +244 -0
- package/dist/trace/trace-event.js.map +1 -0
- package/dist/types/index.d.ts +206 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ci-provider.d.ts +43 -0
- package/dist/utils/ci-provider.d.ts.map +1 -0
- package/dist/utils/ci-provider.js +130 -0
- package/dist/utils/ci-provider.js.map +1 -0
- package/dist/utils/config.d.ts +31 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +85 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/error-provider.d.ts +51 -0
- package/dist/utils/error-provider.d.ts.map +1 -0
- package/dist/utils/error-provider.js +123 -0
- package/dist/utils/error-provider.js.map +1 -0
- package/dist/utils/file-utils.d.ts +18 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +95 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +74 -0
- package/dist/utils/logger.js.map +1 -0
- package/docs/IMPLEMENTATION-STATUS.md +199 -0
- package/docs/PHASE-0-COMPLETE.md +252 -0
- package/docs/PHASE-1-COMPLETE.md +204 -0
- package/docs/PHASE-2-COMPLETE.md +233 -0
- package/docs/PHASE2_COMPLETION_CHECKLIST.md +290 -0
- package/docs/PHASE2_INTEGRATION_SUMMARY.md +255 -0
- package/docs/PHASE2_QUICK_REFERENCE.md +365 -0
- package/docs/PHASE2_TEST_RESULTS.md +282 -0
- package/docs/ROADMAP.md +746 -0
- package/docs/SNAPSHOT.md +376 -0
- package/docs/adrs/ADR-001-signal-computation.md +76 -0
- package/docs/adrs/ADR-002-inhibitor-signals.md +108 -0
- package/docs/adrs/ADR-003-llm-integration.md +156 -0
- package/docs/adrs/ADR-004-process-architecture.md +175 -0
- package/docs/adrs/ADR-005-testing-strategy.md +243 -0
- package/docs/pitch.md +94 -0
- package/docs/specs/fourth-spec.md +1973 -0
- package/docs/specs/initial-spec.md +2096 -0
- package/docs/specs/second-spec.md +2690 -0
- package/package.json +50 -0
- package/src/coordination/gradient-cache.ts +185 -0
- package/src/coordination/index.ts +10 -0
- package/src/core/agent-executor.ts +327 -0
- package/src/core/change-applier.ts +338 -0
- package/src/core/gradient.ts +258 -0
- package/src/core/index.ts +24 -0
- package/src/core/mode-selector.ts +243 -0
- package/src/core/signals/centrality.ts +328 -0
- package/src/core/signals/churn.ts +239 -0
- package/src/core/signals/complexity.ts +206 -0
- package/src/core/signals/debt.ts +111 -0
- package/src/core/signals/errors.ts +93 -0
- package/src/core/signals/index.ts +19 -0
- package/src/cost/cost-tracker.ts +410 -0
- package/src/cost/index.ts +143 -0
- package/src/index.ts +43 -0
- package/src/llm/anthropic-client.ts +415 -0
- package/src/llm/index.ts +43 -0
- package/src/prompts/complexity-reducer.ts +59 -0
- package/src/prompts/debt-payer.ts +59 -0
- package/src/prompts/error-reducer.ts +58 -0
- package/src/prompts/index.ts +128 -0
- package/src/prompts/stabilizer.ts +59 -0
- package/src/prompts/types.ts +15 -0
- package/src/trace/README.md +178 -0
- package/src/trace/index.ts +88 -0
- package/src/trace/trace-event.ts +324 -0
- package/src/types/index.ts +271 -0
- package/src/utils/ci-provider.ts +145 -0
- package/src/utils/config.ts +95 -0
- package/src/utils/error-provider.ts +138 -0
- package/src/utils/file-utils.ts +111 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/logger.ts +94 -0
- package/test-8d713cc8-f4b7-403d-8153-57573172b94c.ts +3 -0
- package/tests/coordination/gradient-cache.test.ts +270 -0
- package/tests/core/agent-executor.test.ts +217 -0
- package/tests/core/change-applier.test.ts +336 -0
- package/tests/core/gradient.test.ts +263 -0
- package/tests/core/mode-selector.test.ts +239 -0
- package/tests/core/signals/centrality.test.ts +512 -0
- package/tests/core/signals/churn.test.ts +355 -0
- package/tests/core/signals/complexity.test.ts +284 -0
- package/tests/core/signals/debt.test.ts +437 -0
- package/tests/core/signals/errors.test.ts +350 -0
- package/tests/cost/cost-tracker.test.ts +475 -0
- package/tests/integration/phase2.test.ts +405 -0
- package/tests/llm/anthropic-client.test.ts +437 -0
- package/tests/prompts/prompts.test.ts +266 -0
- package/tests/trace/trace-event.test.ts +666 -0
- package/tests/utils/file-utils.test.ts +148 -0
- package/tsconfig.json +24 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Trace Event System
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import {
|
|
9
|
+
recordTrace,
|
|
10
|
+
readTraces,
|
|
11
|
+
getRecentEfficiency,
|
|
12
|
+
calculateEfficiency,
|
|
13
|
+
getTraceStats,
|
|
14
|
+
generateTraceId,
|
|
15
|
+
calculateCost,
|
|
16
|
+
createTraceEvent,
|
|
17
|
+
type TraceEvent,
|
|
18
|
+
type Mode,
|
|
19
|
+
} from '../../src/trace/trace-event.js';
|
|
20
|
+
|
|
21
|
+
const TEST_TRACES_FILE = '.agent-meta/traces.jsonl';
|
|
22
|
+
const TEST_ARCHIVE_DIR = '.agent-meta/traces-archive';
|
|
23
|
+
|
|
24
|
+
describe('Trace Event System', () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
// Clean up test files
|
|
27
|
+
if (fs.existsSync(TEST_TRACES_FILE)) {
|
|
28
|
+
fs.unlinkSync(TEST_TRACES_FILE);
|
|
29
|
+
}
|
|
30
|
+
if (fs.existsSync(TEST_ARCHIVE_DIR)) {
|
|
31
|
+
fs.rmSync(TEST_ARCHIVE_DIR, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
// Clean up after tests
|
|
37
|
+
if (fs.existsSync(TEST_TRACES_FILE)) {
|
|
38
|
+
fs.unlinkSync(TEST_TRACES_FILE);
|
|
39
|
+
}
|
|
40
|
+
if (fs.existsSync(TEST_ARCHIVE_DIR)) {
|
|
41
|
+
fs.rmSync(TEST_ARCHIVE_DIR, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('recordTrace', () => {
|
|
46
|
+
it('should record a trace event to JSONL file', async () => {
|
|
47
|
+
const trace: TraceEvent = {
|
|
48
|
+
id: 'test-1',
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
agent_id: 'agent-123',
|
|
51
|
+
file_path: 'src/test.ts',
|
|
52
|
+
mode: 'error_reducer',
|
|
53
|
+
gradient_before: 0.8,
|
|
54
|
+
gradient_after: 0.6,
|
|
55
|
+
gradient_delta: 0.2,
|
|
56
|
+
changes_made: ['fix null check', 'add error handling'],
|
|
57
|
+
tokens_used: 1000,
|
|
58
|
+
cost_usd: 0.05,
|
|
59
|
+
duration_ms: 30000,
|
|
60
|
+
success: true,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
await recordTrace(trace);
|
|
64
|
+
|
|
65
|
+
expect(fs.existsSync(TEST_TRACES_FILE)).toBe(true);
|
|
66
|
+
const content = fs.readFileSync(TEST_TRACES_FILE, 'utf-8');
|
|
67
|
+
const lines = content.trim().split('\n');
|
|
68
|
+
expect(lines).toHaveLength(1);
|
|
69
|
+
|
|
70
|
+
const recorded = JSON.parse(lines[0]);
|
|
71
|
+
expect(recorded.id).toBe('test-1');
|
|
72
|
+
expect(recorded.file_path).toBe('src/test.ts');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should calculate gradient_delta if not provided', async () => {
|
|
76
|
+
const trace = {
|
|
77
|
+
id: 'test-2',
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
agent_id: 'agent-456',
|
|
80
|
+
file_path: 'src/auth.ts',
|
|
81
|
+
mode: 'complexity_reducer' as Mode,
|
|
82
|
+
gradient_before: 0.9,
|
|
83
|
+
gradient_after: 0.7,
|
|
84
|
+
gradient_delta: undefined as any,
|
|
85
|
+
changes_made: ['extract function'],
|
|
86
|
+
tokens_used: 800,
|
|
87
|
+
cost_usd: 0.03,
|
|
88
|
+
duration_ms: 25000,
|
|
89
|
+
success: true,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
await recordTrace(trace);
|
|
93
|
+
|
|
94
|
+
const traces = await readTraces();
|
|
95
|
+
expect(traces[0].gradient_delta).toBeCloseTo(0.2);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should append multiple traces', async () => {
|
|
99
|
+
const trace1: TraceEvent = createTraceEvent({
|
|
100
|
+
agent_id: 'agent-1',
|
|
101
|
+
file_path: 'src/test1.ts',
|
|
102
|
+
mode: 'debt_payer',
|
|
103
|
+
gradient_before: 0.5,
|
|
104
|
+
gradient_after: 0.4,
|
|
105
|
+
changes_made: ['fix lint'],
|
|
106
|
+
tokens_used: 500,
|
|
107
|
+
cost_usd: 0.02,
|
|
108
|
+
duration_ms: 15000,
|
|
109
|
+
success: true,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const trace2: TraceEvent = createTraceEvent({
|
|
113
|
+
agent_id: 'agent-2',
|
|
114
|
+
file_path: 'src/test2.ts',
|
|
115
|
+
mode: 'stabilizer',
|
|
116
|
+
gradient_before: 0.6,
|
|
117
|
+
gradient_after: 0.5,
|
|
118
|
+
changes_made: ['add tests'],
|
|
119
|
+
tokens_used: 600,
|
|
120
|
+
cost_usd: 0.025,
|
|
121
|
+
duration_ms: 20000,
|
|
122
|
+
success: true,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await recordTrace(trace1);
|
|
126
|
+
await recordTrace(trace2);
|
|
127
|
+
|
|
128
|
+
const content = fs.readFileSync(TEST_TRACES_FILE, 'utf-8');
|
|
129
|
+
const lines = content.trim().split('\n');
|
|
130
|
+
expect(lines).toHaveLength(2);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('readTraces', () => {
|
|
135
|
+
it('should return empty array if no traces file', async () => {
|
|
136
|
+
const traces = await readTraces();
|
|
137
|
+
expect(traces).toEqual([]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should read all traces', async () => {
|
|
141
|
+
// Create test traces
|
|
142
|
+
const trace1 = createTraceEvent({
|
|
143
|
+
agent_id: 'agent-1',
|
|
144
|
+
file_path: 'src/test1.ts',
|
|
145
|
+
mode: 'error_reducer',
|
|
146
|
+
gradient_before: 0.8,
|
|
147
|
+
gradient_after: 0.6,
|
|
148
|
+
changes_made: ['fix'],
|
|
149
|
+
tokens_used: 1000,
|
|
150
|
+
cost_usd: 0.05,
|
|
151
|
+
duration_ms: 30000,
|
|
152
|
+
success: true,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const trace2 = createTraceEvent({
|
|
156
|
+
agent_id: 'agent-2',
|
|
157
|
+
file_path: 'src/test2.ts',
|
|
158
|
+
mode: 'debt_payer',
|
|
159
|
+
gradient_before: 0.5,
|
|
160
|
+
gradient_after: 0.4,
|
|
161
|
+
changes_made: ['lint'],
|
|
162
|
+
tokens_used: 500,
|
|
163
|
+
cost_usd: 0.02,
|
|
164
|
+
duration_ms: 15000,
|
|
165
|
+
success: true,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await recordTrace(trace1);
|
|
169
|
+
await recordTrace(trace2);
|
|
170
|
+
|
|
171
|
+
const traces = await readTraces();
|
|
172
|
+
expect(traces).toHaveLength(2);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should filter by file', async () => {
|
|
176
|
+
const trace1 = createTraceEvent({
|
|
177
|
+
agent_id: 'agent-1',
|
|
178
|
+
file_path: 'src/auth.ts',
|
|
179
|
+
mode: 'error_reducer',
|
|
180
|
+
gradient_before: 0.8,
|
|
181
|
+
gradient_after: 0.6,
|
|
182
|
+
changes_made: ['fix'],
|
|
183
|
+
tokens_used: 1000,
|
|
184
|
+
cost_usd: 0.05,
|
|
185
|
+
duration_ms: 30000,
|
|
186
|
+
success: true,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const trace2 = createTraceEvent({
|
|
190
|
+
agent_id: 'agent-2',
|
|
191
|
+
file_path: 'src/utils.ts',
|
|
192
|
+
mode: 'debt_payer',
|
|
193
|
+
gradient_before: 0.5,
|
|
194
|
+
gradient_after: 0.4,
|
|
195
|
+
changes_made: ['lint'],
|
|
196
|
+
tokens_used: 500,
|
|
197
|
+
cost_usd: 0.02,
|
|
198
|
+
duration_ms: 15000,
|
|
199
|
+
success: true,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await recordTrace(trace1);
|
|
203
|
+
await recordTrace(trace2);
|
|
204
|
+
|
|
205
|
+
const traces = await readTraces({ file: 'src/auth.ts' });
|
|
206
|
+
expect(traces).toHaveLength(1);
|
|
207
|
+
expect(traces[0].file_path).toBe('src/auth.ts');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should filter by mode', async () => {
|
|
211
|
+
const trace1 = createTraceEvent({
|
|
212
|
+
agent_id: 'agent-1',
|
|
213
|
+
file_path: 'src/test1.ts',
|
|
214
|
+
mode: 'error_reducer',
|
|
215
|
+
gradient_before: 0.8,
|
|
216
|
+
gradient_after: 0.6,
|
|
217
|
+
changes_made: ['fix'],
|
|
218
|
+
tokens_used: 1000,
|
|
219
|
+
cost_usd: 0.05,
|
|
220
|
+
duration_ms: 30000,
|
|
221
|
+
success: true,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const trace2 = createTraceEvent({
|
|
225
|
+
agent_id: 'agent-2',
|
|
226
|
+
file_path: 'src/test2.ts',
|
|
227
|
+
mode: 'debt_payer',
|
|
228
|
+
gradient_before: 0.5,
|
|
229
|
+
gradient_after: 0.4,
|
|
230
|
+
changes_made: ['lint'],
|
|
231
|
+
tokens_used: 500,
|
|
232
|
+
cost_usd: 0.02,
|
|
233
|
+
duration_ms: 15000,
|
|
234
|
+
success: true,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
await recordTrace(trace1);
|
|
238
|
+
await recordTrace(trace2);
|
|
239
|
+
|
|
240
|
+
const traces = await readTraces({ mode: 'debt_payer' });
|
|
241
|
+
expect(traces).toHaveLength(1);
|
|
242
|
+
expect(traces[0].mode).toBe('debt_payer');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should filter by date', async () => {
|
|
246
|
+
const oldDate = new Date('2025-01-01T00:00:00Z');
|
|
247
|
+
const recentDate = new Date();
|
|
248
|
+
|
|
249
|
+
const trace1: TraceEvent = {
|
|
250
|
+
id: 'old',
|
|
251
|
+
timestamp: oldDate.toISOString(),
|
|
252
|
+
agent_id: 'agent-1',
|
|
253
|
+
file_path: 'src/test.ts',
|
|
254
|
+
mode: 'error_reducer',
|
|
255
|
+
gradient_before: 0.8,
|
|
256
|
+
gradient_after: 0.6,
|
|
257
|
+
gradient_delta: 0.2,
|
|
258
|
+
changes_made: [],
|
|
259
|
+
tokens_used: 1000,
|
|
260
|
+
cost_usd: 0.05,
|
|
261
|
+
duration_ms: 30000,
|
|
262
|
+
success: true,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const trace2 = createTraceEvent({
|
|
266
|
+
agent_id: 'agent-2',
|
|
267
|
+
file_path: 'src/test.ts',
|
|
268
|
+
mode: 'debt_payer',
|
|
269
|
+
gradient_before: 0.5,
|
|
270
|
+
gradient_after: 0.4,
|
|
271
|
+
changes_made: [],
|
|
272
|
+
tokens_used: 500,
|
|
273
|
+
cost_usd: 0.02,
|
|
274
|
+
duration_ms: 15000,
|
|
275
|
+
success: true,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
await recordTrace(trace1);
|
|
279
|
+
await recordTrace(trace2);
|
|
280
|
+
|
|
281
|
+
const since = new Date('2025-01-15T00:00:00Z');
|
|
282
|
+
const traces = await readTraces({ since });
|
|
283
|
+
expect(traces).toHaveLength(1);
|
|
284
|
+
expect(new Date(traces[0].timestamp).getTime()).toBeGreaterThanOrEqual(since.getTime());
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should limit results', async () => {
|
|
288
|
+
for (let i = 0; i < 10; i++) {
|
|
289
|
+
const trace = createTraceEvent({
|
|
290
|
+
agent_id: `agent-${i}`,
|
|
291
|
+
file_path: 'src/test.ts',
|
|
292
|
+
mode: 'error_reducer',
|
|
293
|
+
gradient_before: 0.8,
|
|
294
|
+
gradient_after: 0.7,
|
|
295
|
+
changes_made: [],
|
|
296
|
+
tokens_used: 1000,
|
|
297
|
+
cost_usd: 0.05,
|
|
298
|
+
duration_ms: 30000,
|
|
299
|
+
success: true,
|
|
300
|
+
});
|
|
301
|
+
await recordTrace(trace);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const traces = await readTraces({ limit: 5 });
|
|
305
|
+
expect(traces).toHaveLength(5);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should sort by timestamp (newest first)', async () => {
|
|
309
|
+
// Create traces with different timestamps
|
|
310
|
+
for (let i = 0; i < 5; i++) {
|
|
311
|
+
const trace = createTraceEvent({
|
|
312
|
+
agent_id: `agent-${i}`,
|
|
313
|
+
file_path: 'src/test.ts',
|
|
314
|
+
mode: 'error_reducer',
|
|
315
|
+
gradient_before: 0.8,
|
|
316
|
+
gradient_after: 0.7,
|
|
317
|
+
changes_made: [],
|
|
318
|
+
tokens_used: 1000,
|
|
319
|
+
cost_usd: 0.05,
|
|
320
|
+
duration_ms: 30000,
|
|
321
|
+
success: true,
|
|
322
|
+
});
|
|
323
|
+
await recordTrace(trace);
|
|
324
|
+
// Small delay to ensure different timestamps
|
|
325
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const traces = await readTraces();
|
|
329
|
+
|
|
330
|
+
// Verify descending order
|
|
331
|
+
for (let i = 0; i < traces.length - 1; i++) {
|
|
332
|
+
const current = new Date(traces[i].timestamp).getTime();
|
|
333
|
+
const next = new Date(traces[i + 1].timestamp).getTime();
|
|
334
|
+
expect(current).toBeGreaterThanOrEqual(next);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe('getRecentEfficiency', () => {
|
|
340
|
+
it('should return null if insufficient data', async () => {
|
|
341
|
+
// Only 2 traces (need at least 3)
|
|
342
|
+
for (let i = 0; i < 2; i++) {
|
|
343
|
+
const trace = createTraceEvent({
|
|
344
|
+
agent_id: 'agent-1',
|
|
345
|
+
file_path: 'src/test.ts',
|
|
346
|
+
mode: 'error_reducer',
|
|
347
|
+
gradient_before: 0.8,
|
|
348
|
+
gradient_after: 0.6,
|
|
349
|
+
changes_made: [],
|
|
350
|
+
tokens_used: 1000,
|
|
351
|
+
cost_usd: 0.05,
|
|
352
|
+
duration_ms: 30000,
|
|
353
|
+
success: true,
|
|
354
|
+
});
|
|
355
|
+
await recordTrace(trace);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const efficiency = await getRecentEfficiency('src/test.ts', 5);
|
|
359
|
+
expect(efficiency).toBeNull();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('should calculate efficiency from recent traces', async () => {
|
|
363
|
+
// Create traces with known efficiency
|
|
364
|
+
for (let i = 0; i < 5; i++) {
|
|
365
|
+
const trace = createTraceEvent({
|
|
366
|
+
agent_id: 'agent-1',
|
|
367
|
+
file_path: 'src/test.ts',
|
|
368
|
+
mode: 'error_reducer',
|
|
369
|
+
gradient_before: 0.8,
|
|
370
|
+
gradient_after: 0.6, // delta = 0.2
|
|
371
|
+
changes_made: [],
|
|
372
|
+
tokens_used: 1000,
|
|
373
|
+
cost_usd: 0.1, // delta/cost = 2.0
|
|
374
|
+
duration_ms: 30000,
|
|
375
|
+
success: true,
|
|
376
|
+
});
|
|
377
|
+
await recordTrace(trace);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const efficiency = await getRecentEfficiency('src/test.ts', 5);
|
|
381
|
+
expect(efficiency).toBeCloseTo(2.0); // total delta 1.0 / total cost 0.5 = 2.0
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('should only consider last N traces', async () => {
|
|
385
|
+
// Create 10 traces, but only last 3 should be considered
|
|
386
|
+
for (let i = 0; i < 10; i++) {
|
|
387
|
+
const trace = createTraceEvent({
|
|
388
|
+
agent_id: 'agent-1',
|
|
389
|
+
file_path: 'src/test.ts',
|
|
390
|
+
mode: 'error_reducer',
|
|
391
|
+
gradient_before: 0.8,
|
|
392
|
+
gradient_after: 0.6,
|
|
393
|
+
changes_made: [],
|
|
394
|
+
tokens_used: 1000,
|
|
395
|
+
cost_usd: 0.1,
|
|
396
|
+
duration_ms: 30000,
|
|
397
|
+
success: true,
|
|
398
|
+
});
|
|
399
|
+
await recordTrace(trace);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const efficiency = await getRecentEfficiency('src/test.ts', 3);
|
|
403
|
+
expect(efficiency).not.toBeNull();
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
describe('calculateEfficiency', () => {
|
|
408
|
+
it('should return 0 for empty traces', () => {
|
|
409
|
+
const efficiency = calculateEfficiency([]);
|
|
410
|
+
expect(efficiency).toBe(0);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('should calculate efficiency correctly', () => {
|
|
414
|
+
const traces: TraceEvent[] = [
|
|
415
|
+
createTraceEvent({
|
|
416
|
+
agent_id: 'agent-1',
|
|
417
|
+
file_path: 'src/test.ts',
|
|
418
|
+
mode: 'error_reducer',
|
|
419
|
+
gradient_before: 0.8,
|
|
420
|
+
gradient_after: 0.6, // delta = 0.2
|
|
421
|
+
changes_made: [],
|
|
422
|
+
tokens_used: 1000,
|
|
423
|
+
cost_usd: 0.1,
|
|
424
|
+
duration_ms: 30000,
|
|
425
|
+
success: true,
|
|
426
|
+
}),
|
|
427
|
+
createTraceEvent({
|
|
428
|
+
agent_id: 'agent-2',
|
|
429
|
+
file_path: 'src/test.ts',
|
|
430
|
+
mode: 'debt_payer',
|
|
431
|
+
gradient_before: 0.6,
|
|
432
|
+
gradient_after: 0.5, // delta = 0.1
|
|
433
|
+
changes_made: [],
|
|
434
|
+
tokens_used: 500,
|
|
435
|
+
cost_usd: 0.05,
|
|
436
|
+
duration_ms: 15000,
|
|
437
|
+
success: true,
|
|
438
|
+
}),
|
|
439
|
+
];
|
|
440
|
+
|
|
441
|
+
// Total delta = 0.3, total cost = 0.15
|
|
442
|
+
// Efficiency = 0.3 / 0.15 = 2.0
|
|
443
|
+
const efficiency = calculateEfficiency(traces);
|
|
444
|
+
expect(efficiency).toBeCloseTo(2.0);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('should handle zero cost (return Infinity)', () => {
|
|
448
|
+
const traces: TraceEvent[] = [
|
|
449
|
+
createTraceEvent({
|
|
450
|
+
agent_id: 'agent-1',
|
|
451
|
+
file_path: 'src/test.ts',
|
|
452
|
+
mode: 'error_reducer',
|
|
453
|
+
gradient_before: 0.8,
|
|
454
|
+
gradient_after: 0.6,
|
|
455
|
+
changes_made: [],
|
|
456
|
+
tokens_used: 0,
|
|
457
|
+
cost_usd: 0,
|
|
458
|
+
duration_ms: 30000,
|
|
459
|
+
success: true,
|
|
460
|
+
}),
|
|
461
|
+
];
|
|
462
|
+
|
|
463
|
+
const efficiency = calculateEfficiency(traces);
|
|
464
|
+
expect(efficiency).toBe(Infinity);
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
describe('getTraceStats', () => {
|
|
469
|
+
it('should return zero stats for empty traces', () => {
|
|
470
|
+
const stats = getTraceStats([]);
|
|
471
|
+
expect(stats.totalCost).toBe(0);
|
|
472
|
+
expect(stats.avgDelta).toBe(0);
|
|
473
|
+
expect(stats.successRate).toBe(0);
|
|
474
|
+
expect(stats.totalTraces).toBe(0);
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('should calculate statistics correctly', () => {
|
|
478
|
+
const traces: TraceEvent[] = [
|
|
479
|
+
createTraceEvent({
|
|
480
|
+
agent_id: 'agent-1',
|
|
481
|
+
file_path: 'src/test.ts',
|
|
482
|
+
mode: 'error_reducer',
|
|
483
|
+
gradient_before: 0.8,
|
|
484
|
+
gradient_after: 0.6,
|
|
485
|
+
changes_made: [],
|
|
486
|
+
tokens_used: 1000,
|
|
487
|
+
cost_usd: 0.1,
|
|
488
|
+
duration_ms: 30000,
|
|
489
|
+
success: true,
|
|
490
|
+
}),
|
|
491
|
+
createTraceEvent({
|
|
492
|
+
agent_id: 'agent-2',
|
|
493
|
+
file_path: 'src/test.ts',
|
|
494
|
+
mode: 'debt_payer',
|
|
495
|
+
gradient_before: 0.6,
|
|
496
|
+
gradient_after: 0.5,
|
|
497
|
+
changes_made: [],
|
|
498
|
+
tokens_used: 500,
|
|
499
|
+
cost_usd: 0.05,
|
|
500
|
+
duration_ms: 15000,
|
|
501
|
+
success: true,
|
|
502
|
+
}),
|
|
503
|
+
createTraceEvent({
|
|
504
|
+
agent_id: 'agent-3',
|
|
505
|
+
file_path: 'src/test.ts',
|
|
506
|
+
mode: 'complexity_reducer',
|
|
507
|
+
gradient_before: 0.5,
|
|
508
|
+
gradient_after: 0.5,
|
|
509
|
+
changes_made: [],
|
|
510
|
+
tokens_used: 800,
|
|
511
|
+
cost_usd: 0.08,
|
|
512
|
+
duration_ms: 25000,
|
|
513
|
+
success: false,
|
|
514
|
+
}),
|
|
515
|
+
];
|
|
516
|
+
|
|
517
|
+
const stats = getTraceStats(traces);
|
|
518
|
+
expect(stats.totalCost).toBeCloseTo(0.23);
|
|
519
|
+
expect(stats.avgDelta).toBeCloseTo(0.1); // (0.2 + 0.1 + 0) / 3
|
|
520
|
+
expect(stats.successRate).toBeCloseTo(0.667); // 2/3
|
|
521
|
+
expect(stats.totalTraces).toBe(3);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
describe('generateTraceId', () => {
|
|
526
|
+
it('should generate unique IDs', () => {
|
|
527
|
+
const id1 = generateTraceId();
|
|
528
|
+
const id2 = generateTraceId();
|
|
529
|
+
|
|
530
|
+
expect(id1).toBeTruthy();
|
|
531
|
+
expect(id2).toBeTruthy();
|
|
532
|
+
expect(id1).not.toBe(id2);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('should generate valid UUIDs', () => {
|
|
536
|
+
const id = generateTraceId();
|
|
537
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
538
|
+
expect(id).toMatch(uuidRegex);
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
describe('calculateCost', () => {
|
|
543
|
+
it('should calculate cost for Sonnet 4', () => {
|
|
544
|
+
const cost = calculateCost(1_000_000, 1_000_000, 'claude-sonnet-4');
|
|
545
|
+
// Input: 1M tokens * $3/M = $3
|
|
546
|
+
// Output: 1M tokens * $15/M = $15
|
|
547
|
+
// Total: $18
|
|
548
|
+
expect(cost).toBeCloseTo(18.0);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it('should calculate cost for Haiku 4', () => {
|
|
552
|
+
const cost = calculateCost(1_000_000, 1_000_000, 'claude-haiku-4');
|
|
553
|
+
// Input: 1M tokens * $0.25/M = $0.25
|
|
554
|
+
// Output: 1M tokens * $1.25/M = $1.25
|
|
555
|
+
// Total: $1.50
|
|
556
|
+
expect(cost).toBeCloseTo(1.50);
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it('should default to Sonnet 4 for unknown models', () => {
|
|
560
|
+
const cost = calculateCost(1_000_000, 1_000_000, 'unknown-model');
|
|
561
|
+
expect(cost).toBeCloseTo(18.0);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
it('should calculate fractional costs', () => {
|
|
565
|
+
const cost = calculateCost(500_000, 100_000, 'claude-sonnet-4');
|
|
566
|
+
// Input: 0.5M tokens * $3/M = $1.50
|
|
567
|
+
// Output: 0.1M tokens * $15/M = $1.50
|
|
568
|
+
// Total: $3.00
|
|
569
|
+
expect(cost).toBeCloseTo(3.0);
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
describe('createTraceEvent', () => {
|
|
574
|
+
it('should create trace with generated ID and timestamp', () => {
|
|
575
|
+
const trace = createTraceEvent({
|
|
576
|
+
agent_id: 'agent-1',
|
|
577
|
+
file_path: 'src/test.ts',
|
|
578
|
+
mode: 'error_reducer',
|
|
579
|
+
gradient_before: 0.8,
|
|
580
|
+
gradient_after: 0.6,
|
|
581
|
+
changes_made: [],
|
|
582
|
+
tokens_used: 1000,
|
|
583
|
+
cost_usd: 0.05,
|
|
584
|
+
duration_ms: 30000,
|
|
585
|
+
success: true,
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
expect(trace.id).toBeTruthy();
|
|
589
|
+
expect(trace.timestamp).toBeTruthy();
|
|
590
|
+
expect(trace.gradient_delta).toBeCloseTo(0.2);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
it('should calculate gradient_delta automatically', () => {
|
|
594
|
+
const trace = createTraceEvent({
|
|
595
|
+
agent_id: 'agent-1',
|
|
596
|
+
file_path: 'src/test.ts',
|
|
597
|
+
mode: 'error_reducer',
|
|
598
|
+
gradient_before: 0.9,
|
|
599
|
+
gradient_after: 0.5,
|
|
600
|
+
changes_made: [],
|
|
601
|
+
tokens_used: 1000,
|
|
602
|
+
cost_usd: 0.05,
|
|
603
|
+
duration_ms: 30000,
|
|
604
|
+
success: true,
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
expect(trace.gradient_delta).toBeCloseTo(0.4);
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
describe('concurrent writes', () => {
|
|
612
|
+
it('should handle concurrent trace recording', async () => {
|
|
613
|
+
// Simulate multiple agents writing concurrently
|
|
614
|
+
const promises = [];
|
|
615
|
+
for (let i = 0; i < 10; i++) {
|
|
616
|
+
const trace = createTraceEvent({
|
|
617
|
+
agent_id: `agent-${i}`,
|
|
618
|
+
file_path: 'src/test.ts',
|
|
619
|
+
mode: 'error_reducer',
|
|
620
|
+
gradient_before: 0.8,
|
|
621
|
+
gradient_after: 0.6,
|
|
622
|
+
changes_made: [],
|
|
623
|
+
tokens_used: 1000,
|
|
624
|
+
cost_usd: 0.05,
|
|
625
|
+
duration_ms: 30000,
|
|
626
|
+
success: true,
|
|
627
|
+
});
|
|
628
|
+
promises.push(recordTrace(trace));
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
await Promise.all(promises);
|
|
632
|
+
|
|
633
|
+
const traces = await readTraces();
|
|
634
|
+
expect(traces).toHaveLength(10);
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
describe('JSONL format', () => {
|
|
639
|
+
it('should store each trace on a separate line', async () => {
|
|
640
|
+
for (let i = 0; i < 3; i++) {
|
|
641
|
+
const trace = createTraceEvent({
|
|
642
|
+
agent_id: `agent-${i}`,
|
|
643
|
+
file_path: 'src/test.ts',
|
|
644
|
+
mode: 'error_reducer',
|
|
645
|
+
gradient_before: 0.8,
|
|
646
|
+
gradient_after: 0.6,
|
|
647
|
+
changes_made: [],
|
|
648
|
+
tokens_used: 1000,
|
|
649
|
+
cost_usd: 0.05,
|
|
650
|
+
duration_ms: 30000,
|
|
651
|
+
success: true,
|
|
652
|
+
});
|
|
653
|
+
await recordTrace(trace);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const content = fs.readFileSync(TEST_TRACES_FILE, 'utf-8');
|
|
657
|
+
const lines = content.trim().split('\n');
|
|
658
|
+
expect(lines).toHaveLength(3);
|
|
659
|
+
|
|
660
|
+
// Each line should be valid JSON
|
|
661
|
+
lines.forEach(line => {
|
|
662
|
+
expect(() => JSON.parse(line)).not.toThrow();
|
|
663
|
+
});
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
});
|