claude-mycelium 2.1.0 → 2.2.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/.agent-meta/tasks/_active.json +4 -0
- package/.agent-meta/tasks/task_0657b028-05a0-4b0c-b0b9-a4eae3d66cd9.json +168 -0
- package/README.md +6 -0
- package/dist/agent/task-worker.d.ts +11 -0
- package/dist/agent/task-worker.d.ts.map +1 -0
- package/dist/agent/task-worker.js +173 -0
- package/dist/agent/task-worker.js.map +1 -0
- package/dist/cli/gradients.d.ts.map +1 -1
- package/dist/cli/gradients.js +1 -0
- package/dist/cli/gradients.js.map +1 -1
- package/dist/cli/grow.d.ts +17 -0
- package/dist/cli/grow.d.ts.map +1 -0
- package/dist/cli/grow.js +373 -0
- package/dist/cli/grow.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/agent-executor.d.ts +4 -1
- package/dist/core/agent-executor.d.ts.map +1 -1
- package/dist/core/agent-executor.js +10 -2
- package/dist/core/agent-executor.js.map +1 -1
- package/dist/task/agent-coordinator.d.ts +40 -0
- package/dist/task/agent-coordinator.d.ts.map +1 -0
- package/dist/task/agent-coordinator.js +168 -0
- package/dist/task/agent-coordinator.js.map +1 -0
- package/dist/task/executor.d.ts +9 -2
- package/dist/task/executor.d.ts.map +1 -1
- package/dist/task/executor.js +64 -31
- package/dist/task/executor.js.map +1 -1
- package/docs/ROADMAP.md +139 -59
- package/package.json +10 -2
- package/src/agent/task-worker.ts +196 -0
- package/src/cli/gradients.ts +2 -0
- package/src/cli/grow.ts +416 -0
- package/src/cli/index.ts +2 -0
- package/src/core/agent-executor.ts +17 -4
- package/src/task/agent-coordinator.ts +220 -0
- package/src/task/executor.ts +71 -66
- package/tests/trace/trace-event.test.ts +62 -20
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Agent Coordinator
|
|
3
|
+
*
|
|
4
|
+
* Coordinates multi-agent execution of task steps using the mycelium
|
|
5
|
+
* process spawning system (Phase 3) for true RALPH-style parallelization.
|
|
6
|
+
*
|
|
7
|
+
* This replaces the simple Promise.all() approach with real agent processes
|
|
8
|
+
* that use file locks, inhibitors, and the full executeAgent() cycle.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { fork, ChildProcess } from 'child_process';
|
|
12
|
+
import { Task, TaskStep, Mode } from '../types/index.js';
|
|
13
|
+
import { logDebug, logError, logInfo } from '../utils/logger.js';
|
|
14
|
+
import { randomUUID } from 'crypto';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
import { dirname } from 'path';
|
|
18
|
+
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = dirname(__filename);
|
|
21
|
+
|
|
22
|
+
export interface StepAssignment {
|
|
23
|
+
stepOrder: number;
|
|
24
|
+
targetFile: string;
|
|
25
|
+
mode: Mode;
|
|
26
|
+
description: string;
|
|
27
|
+
taskId: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface AgentResult {
|
|
31
|
+
stepOrder: number;
|
|
32
|
+
success: boolean;
|
|
33
|
+
traceId?: string;
|
|
34
|
+
error?: string;
|
|
35
|
+
exitCode: number | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Spawn an agent for a specific task step
|
|
40
|
+
* Each agent runs as an independent process via child_process.fork()
|
|
41
|
+
*/
|
|
42
|
+
export function spawnAgentForStep(
|
|
43
|
+
task: Task,
|
|
44
|
+
step: TaskStep
|
|
45
|
+
): Promise<AgentResult> {
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
const agentId = `agent-${randomUUID().substring(0, 8)}`;
|
|
48
|
+
|
|
49
|
+
logDebug('Spawning agent for task step', {
|
|
50
|
+
agentId,
|
|
51
|
+
taskId: task.id,
|
|
52
|
+
stepOrder: step.order,
|
|
53
|
+
targetFile: step.target_file,
|
|
54
|
+
mode: step.mode,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Path to the compiled task worker file
|
|
58
|
+
const workerPath = path.join(__dirname, '../agent/task-worker.js');
|
|
59
|
+
|
|
60
|
+
// Spawn agent process with task context
|
|
61
|
+
const child = fork(workerPath, [], {
|
|
62
|
+
env: {
|
|
63
|
+
...process.env,
|
|
64
|
+
AGENT_ID: agentId,
|
|
65
|
+
TASK_ID: task.id,
|
|
66
|
+
STEP_ORDER: String(step.order),
|
|
67
|
+
TARGET_FILE: step.target_file,
|
|
68
|
+
MODE: step.mode,
|
|
69
|
+
STEP_DESCRIPTION: step.description,
|
|
70
|
+
},
|
|
71
|
+
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
let result: AgentResult = {
|
|
75
|
+
stepOrder: step.order,
|
|
76
|
+
success: false,
|
|
77
|
+
exitCode: null,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Set timeout (5 minutes)
|
|
81
|
+
const timeout = setTimeout(() => {
|
|
82
|
+
logError('Agent timeout', new Error('Agent timed out'), {
|
|
83
|
+
agentId,
|
|
84
|
+
stepOrder: step.order,
|
|
85
|
+
});
|
|
86
|
+
child.kill('SIGTERM');
|
|
87
|
+
result.error = 'Agent timed out after 5 minutes';
|
|
88
|
+
result.exitCode = -1;
|
|
89
|
+
resolve(result);
|
|
90
|
+
}, 300_000);
|
|
91
|
+
|
|
92
|
+
// Handle IPC messages from agent
|
|
93
|
+
child.on('message', (message: any) => {
|
|
94
|
+
if (message.type === 'result') {
|
|
95
|
+
logDebug('Agent result received', {
|
|
96
|
+
agentId,
|
|
97
|
+
stepOrder: step.order,
|
|
98
|
+
success: message.success,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
result = {
|
|
102
|
+
stepOrder: step.order,
|
|
103
|
+
success: message.success,
|
|
104
|
+
traceId: message.traceId,
|
|
105
|
+
error: message.error,
|
|
106
|
+
exitCode: 0,
|
|
107
|
+
};
|
|
108
|
+
} else if (message.type === 'progress') {
|
|
109
|
+
logInfo('Agent progress', {
|
|
110
|
+
agentId,
|
|
111
|
+
stepOrder: step.order,
|
|
112
|
+
message: message.message,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Handle agent exit
|
|
118
|
+
child.on('exit', (code, signal) => {
|
|
119
|
+
clearTimeout(timeout);
|
|
120
|
+
|
|
121
|
+
result.exitCode = code;
|
|
122
|
+
|
|
123
|
+
logInfo('Agent exited', {
|
|
124
|
+
agentId,
|
|
125
|
+
stepOrder: step.order,
|
|
126
|
+
code,
|
|
127
|
+
signal,
|
|
128
|
+
success: result.success,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// If we didn't receive a result message, mark as failure
|
|
132
|
+
if (!result.success && !result.error) {
|
|
133
|
+
result.error = `Agent exited with code ${code}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
resolve(result);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Handle errors
|
|
140
|
+
child.on('error', (error) => {
|
|
141
|
+
clearTimeout(timeout);
|
|
142
|
+
logError('Agent error', error, {
|
|
143
|
+
agentId,
|
|
144
|
+
stepOrder: step.order,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
result.error = error.message;
|
|
148
|
+
result.exitCode = -1;
|
|
149
|
+
resolve(result);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Forward stderr for debugging
|
|
153
|
+
if (child.stderr) {
|
|
154
|
+
child.stderr.on('data', (data) => {
|
|
155
|
+
logDebug('Agent stderr', {
|
|
156
|
+
agentId,
|
|
157
|
+
stepOrder: step.order,
|
|
158
|
+
output: data.toString(),
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Execute a wave of task steps in parallel using agent processes
|
|
167
|
+
* This is the true mycelium multi-agent coordination
|
|
168
|
+
*/
|
|
169
|
+
export async function executeWaveWithAgents(
|
|
170
|
+
task: Task,
|
|
171
|
+
wave: TaskStep[]
|
|
172
|
+
): Promise<AgentResult[]> {
|
|
173
|
+
logInfo('Executing wave with agent processes', {
|
|
174
|
+
taskId: task.id,
|
|
175
|
+
waveSize: wave.length,
|
|
176
|
+
steps: wave.map(s => s.order),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Spawn all agents in parallel
|
|
180
|
+
const agentPromises = wave.map(step => spawnAgentForStep(task, step));
|
|
181
|
+
|
|
182
|
+
// Wait for all agents to complete
|
|
183
|
+
const results = await Promise.all(agentPromises);
|
|
184
|
+
|
|
185
|
+
logInfo('Wave execution complete', {
|
|
186
|
+
taskId: task.id,
|
|
187
|
+
total: results.length,
|
|
188
|
+
successful: results.filter(r => r.success).length,
|
|
189
|
+
failed: results.filter(r => !r.success).length,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get parallelizable steps grouped by dependency waves
|
|
197
|
+
* Same logic as before, but now we spawn agents for each wave
|
|
198
|
+
*/
|
|
199
|
+
export function getParallelizableSteps(steps: TaskStep[]): TaskStep[][] {
|
|
200
|
+
const waves: TaskStep[][] = [];
|
|
201
|
+
const completed = new Set<number>();
|
|
202
|
+
|
|
203
|
+
while (completed.size < steps.length) {
|
|
204
|
+
// Find steps whose dependencies are all completed
|
|
205
|
+
const ready = steps.filter(
|
|
206
|
+
step =>
|
|
207
|
+
!completed.has(step.order) &&
|
|
208
|
+
step.depends_on.every(dep => completed.has(dep))
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (ready.length === 0) {
|
|
212
|
+
throw new Error('Circular dependency detected in task steps');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
waves.push(ready);
|
|
216
|
+
ready.forEach(step => completed.add(step.order));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return waves;
|
|
220
|
+
}
|
package/src/task/executor.ts
CHANGED
|
@@ -2,23 +2,33 @@
|
|
|
2
2
|
* Task Execution Implementation
|
|
3
3
|
* Per second-spec §12.2: Task Step Execution
|
|
4
4
|
*
|
|
5
|
-
* Executes task steps
|
|
6
|
-
*
|
|
5
|
+
* Executes task steps using the mycelium multi-agent system.
|
|
6
|
+
* Each step spawns an independent agent process that uses file locks,
|
|
7
|
+
* inhibitors, and the full RALPH-style executeAgent() cycle.
|
|
8
|
+
*
|
|
9
|
+
* This is TRUE multi-agent coordination as per ADR-004.
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
|
-
import { Task, TaskStep
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
import { Task, TaskStep } from '../types/index.js';
|
|
13
|
+
import { logDebug, logError, logInfo } from '../utils/logger.js';
|
|
14
|
+
import {
|
|
15
|
+
executeWaveWithAgents,
|
|
16
|
+
getParallelizableSteps,
|
|
17
|
+
type AgentResult,
|
|
18
|
+
} from './agent-coordinator.js';
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Execute a complete task by running all steps in dependency order
|
|
22
|
+
*
|
|
23
|
+
* This spawns independent agent processes for each step, coordinated
|
|
24
|
+
* via file locks. Multiple agents can work in parallel on different
|
|
25
|
+
* files, implementing true RALPH-style multi-agent coordination.
|
|
19
26
|
*/
|
|
20
27
|
export async function executeTask(task: Task): Promise<Task> {
|
|
21
|
-
|
|
28
|
+
logInfo('Executing task with multi-agent coordination', {
|
|
29
|
+
taskId: task.id,
|
|
30
|
+
steps: task.plan?.steps.length,
|
|
31
|
+
});
|
|
22
32
|
|
|
23
33
|
if (!task.plan) {
|
|
24
34
|
throw new Error('Cannot execute task without a plan');
|
|
@@ -26,83 +36,82 @@ export async function executeTask(task: Task): Promise<Task> {
|
|
|
26
36
|
|
|
27
37
|
const waves = getParallelizableSteps(task.plan.steps);
|
|
28
38
|
|
|
39
|
+
logInfo('Task execution plan', {
|
|
40
|
+
taskId: task.id,
|
|
41
|
+
totalSteps: task.plan.steps.length,
|
|
42
|
+
waves: waves.length,
|
|
43
|
+
waveSizes: waves.map(w => w.length),
|
|
44
|
+
});
|
|
45
|
+
|
|
29
46
|
for (let waveIndex = 0; waveIndex < waves.length; waveIndex++) {
|
|
30
47
|
const wave = waves[waveIndex];
|
|
31
|
-
|
|
48
|
+
logInfo('Executing wave', {
|
|
49
|
+
taskId: task.id,
|
|
50
|
+
wave: waveIndex + 1,
|
|
51
|
+
totalWaves: waves.length,
|
|
52
|
+
stepsInWave: wave.length,
|
|
53
|
+
});
|
|
32
54
|
|
|
33
|
-
// Execute all steps in this wave
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
);
|
|
55
|
+
// Execute all steps in this wave using agent processes
|
|
56
|
+
// Each agent runs in its own process with file locks
|
|
57
|
+
const results: AgentResult[] = await executeWaveWithAgents(task, wave);
|
|
37
58
|
|
|
38
59
|
// Check for failures
|
|
39
60
|
const failed = results.find(r => !r.success);
|
|
40
61
|
if (failed) {
|
|
41
62
|
task.status = 'failed';
|
|
42
|
-
task.error = failed.error;
|
|
43
|
-
logError('Task
|
|
63
|
+
task.error = failed.error || 'Agent execution failed';
|
|
64
|
+
logError('Task wave failed', new Error(task.error), {
|
|
65
|
+
taskId: task.id,
|
|
66
|
+
wave: waveIndex + 1,
|
|
67
|
+
failedStep: failed.stepOrder,
|
|
68
|
+
});
|
|
44
69
|
return task;
|
|
45
70
|
}
|
|
46
71
|
|
|
47
72
|
// Update completed steps
|
|
48
73
|
for (let i = 0; i < wave.length; i++) {
|
|
49
|
-
wave[i].
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
74
|
+
const result = results.find(r => r.stepOrder === wave[i].order);
|
|
75
|
+
if (result && result.success) {
|
|
76
|
+
wave[i].completed = true;
|
|
77
|
+
wave[i].trace_id = result.traceId;
|
|
78
|
+
task.steps_completed++;
|
|
79
|
+
|
|
80
|
+
// Track file changes
|
|
81
|
+
if (wave[i].mode === 'create') {
|
|
82
|
+
task.files_created.push(wave[i].target_file);
|
|
83
|
+
} else {
|
|
84
|
+
if (!task.files_modified.includes(wave[i].target_file)) {
|
|
85
|
+
task.files_modified.push(wave[i].target_file);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (wave[i].mode === 'create') {
|
|
57
|
-
task.files_created.push(wave[i].target_file);
|
|
58
|
-
} else {
|
|
59
|
-
if (!task.files_modified.includes(wave[i].target_file)) {
|
|
60
|
-
task.files_modified.push(wave[i].target_file);
|
|
89
|
+
if (result.traceId) {
|
|
90
|
+
task.traces.push(result.traceId);
|
|
61
91
|
}
|
|
62
92
|
}
|
|
63
|
-
const traceId = results[i].trace_id;
|
|
64
|
-
if (traceId !== undefined) {
|
|
65
|
-
task.traces.push(traceId);
|
|
66
|
-
}
|
|
67
93
|
}
|
|
94
|
+
|
|
95
|
+
logInfo('Wave complete', {
|
|
96
|
+
taskId: task.id,
|
|
97
|
+
wave: waveIndex + 1,
|
|
98
|
+
successCount: results.filter(r => r.success).length,
|
|
99
|
+
failureCount: results.filter(r => !r.success).length,
|
|
100
|
+
});
|
|
68
101
|
}
|
|
69
102
|
|
|
70
103
|
task.status = 'completed';
|
|
71
|
-
|
|
72
|
-
return task;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Execute a single task step
|
|
77
|
-
*/
|
|
78
|
-
export async function executeStep(
|
|
79
|
-
task: Task,
|
|
80
|
-
step: TaskStep
|
|
81
|
-
): Promise<{ success: boolean; trace_id?: string; error?: string }> {
|
|
82
|
-
logDebug('Executing step', {
|
|
104
|
+
logInfo('Task execution completed', {
|
|
83
105
|
taskId: task.id,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
stepsCompleted: task.steps_completed,
|
|
107
|
+
filesCreated: task.files_created.length,
|
|
108
|
+
filesModified: task.files_modified.length,
|
|
87
109
|
});
|
|
88
110
|
|
|
89
|
-
|
|
90
|
-
if (step.mode === 'create') {
|
|
91
|
-
return await executeCreateStep(task, step);
|
|
92
|
-
} else {
|
|
93
|
-
return await executeModifyStep(task, step);
|
|
94
|
-
}
|
|
95
|
-
} catch (error) {
|
|
96
|
-
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
97
|
-
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
98
|
-
logError('Step execution failed', errorObj, {
|
|
99
|
-
taskId: task.id,
|
|
100
|
-
stepOrder: step.order,
|
|
101
|
-
});
|
|
102
|
-
return { success: false, error: errorMsg };
|
|
103
|
-
}
|
|
111
|
+
return task;
|
|
104
112
|
}
|
|
105
113
|
|
|
114
|
+
|
|
106
115
|
/**
|
|
107
116
|
* Track progress of task execution
|
|
108
117
|
*/
|
|
@@ -124,10 +133,6 @@ export function trackProgress(task: Task): {
|
|
|
124
133
|
};
|
|
125
134
|
}
|
|
126
135
|
|
|
127
|
-
/**
|
|
128
|
-
* Execute a create mode step (new file)
|
|
129
|
-
*/
|
|
130
|
-
async function executeCreateStep(
|
|
131
136
|
task: Task,
|
|
132
137
|
step: TaskStep
|
|
133
138
|
): Promise<{ success: boolean; trace_id?: string; error?: string }> {
|
|
@@ -53,11 +53,21 @@ describe('Trace Event System', () => {
|
|
|
53
53
|
gradient_before: 0.8,
|
|
54
54
|
gradient_after: 0.6,
|
|
55
55
|
gradient_delta: 0.2,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
metabolic_cost: 0.05,
|
|
57
|
+
efficiency: 4.0,
|
|
58
|
+
ci_passed: true,
|
|
59
|
+
changes: {
|
|
60
|
+
additions: 5,
|
|
61
|
+
deletions: 2,
|
|
62
|
+
files_touched: ['src/test.ts'],
|
|
63
|
+
},
|
|
64
|
+
notes: ['fix null check', 'add error handling'],
|
|
65
|
+
cost: {
|
|
66
|
+
tokens_in: 500,
|
|
67
|
+
tokens_out: 500,
|
|
68
|
+
model: 'claude-sonnet-4',
|
|
69
|
+
estimated_usd: 0.05,
|
|
70
|
+
},
|
|
61
71
|
};
|
|
62
72
|
|
|
63
73
|
await recordTrace(trace);
|
|
@@ -82,11 +92,21 @@ describe('Trace Event System', () => {
|
|
|
82
92
|
gradient_before: 0.9,
|
|
83
93
|
gradient_after: 0.7,
|
|
84
94
|
gradient_delta: undefined as any,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
metabolic_cost: 0.03,
|
|
96
|
+
efficiency: 6.67,
|
|
97
|
+
ci_passed: true,
|
|
98
|
+
changes: {
|
|
99
|
+
additions: 3,
|
|
100
|
+
deletions: 1,
|
|
101
|
+
files_touched: ['src/auth.ts'],
|
|
102
|
+
},
|
|
103
|
+
notes: ['extract function'],
|
|
104
|
+
cost: {
|
|
105
|
+
tokens_in: 400,
|
|
106
|
+
tokens_out: 400,
|
|
107
|
+
model: 'claude-sonnet-4',
|
|
108
|
+
estimated_usd: 0.03,
|
|
109
|
+
},
|
|
90
110
|
};
|
|
91
111
|
|
|
92
112
|
await recordTrace(trace);
|
|
@@ -102,11 +122,22 @@ describe('Trace Event System', () => {
|
|
|
102
122
|
mode: 'debt_payer',
|
|
103
123
|
gradient_before: 0.5,
|
|
104
124
|
gradient_after: 0.4,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
gradient_delta: 0.1,
|
|
126
|
+
metabolic_cost: 0.02,
|
|
127
|
+
efficiency: 5.0,
|
|
128
|
+
ci_passed: true,
|
|
129
|
+
changes: {
|
|
130
|
+
additions: 2,
|
|
131
|
+
deletions: 1,
|
|
132
|
+
files_touched: ['src/test1.ts'],
|
|
133
|
+
},
|
|
134
|
+
notes: ['fix lint'],
|
|
135
|
+
cost: {
|
|
136
|
+
tokens_in: 250,
|
|
137
|
+
tokens_out: 250,
|
|
138
|
+
model: 'claude-sonnet-4',
|
|
139
|
+
estimated_usd: 0.02,
|
|
140
|
+
},
|
|
110
141
|
});
|
|
111
142
|
|
|
112
143
|
const trace2: TraceEvent = createTraceEvent({
|
|
@@ -115,11 +146,22 @@ describe('Trace Event System', () => {
|
|
|
115
146
|
mode: 'stabilizer',
|
|
116
147
|
gradient_before: 0.6,
|
|
117
148
|
gradient_after: 0.5,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
149
|
+
gradient_delta: 0.1,
|
|
150
|
+
metabolic_cost: 0.025,
|
|
151
|
+
efficiency: 4.0,
|
|
152
|
+
ci_passed: true,
|
|
153
|
+
changes: {
|
|
154
|
+
additions: 5,
|
|
155
|
+
deletions: 0,
|
|
156
|
+
files_touched: ['src/test2.ts'],
|
|
157
|
+
},
|
|
158
|
+
notes: ['add tests'],
|
|
159
|
+
cost: {
|
|
160
|
+
tokens_in: 300,
|
|
161
|
+
tokens_out: 300,
|
|
162
|
+
model: 'claude-sonnet-4',
|
|
163
|
+
estimated_usd: 0.025,
|
|
164
|
+
},
|
|
123
165
|
});
|
|
124
166
|
|
|
125
167
|
await recordTrace(trace1);
|