@honeybee-ai/incubator 1.1.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/README.md +586 -0
- package/dashboard/dist/assets/index-DFb8p7xI.js +9 -0
- package/dashboard/dist/assets/index-RKiEoHEo.css +1 -0
- package/dashboard/dist/index.html +13 -0
- package/dist/agent/acp/claim-manager.d.ts +24 -0
- package/dist/agent/acp/claim-manager.js +64 -0
- package/dist/agent/acp/claim-manager.js.map +1 -0
- package/dist/agent/acp/direct-runtime.d.ts +90 -0
- package/dist/agent/acp/direct-runtime.js +364 -0
- package/dist/agent/acp/direct-runtime.js.map +1 -0
- package/dist/agent/acp/event-client.d.ts +20 -0
- package/dist/agent/acp/event-client.js +60 -0
- package/dist/agent/acp/event-client.js.map +1 -0
- package/dist/agent/acp/event-matcher.d.ts +13 -0
- package/dist/agent/acp/event-matcher.js +31 -0
- package/dist/agent/acp/event-matcher.js.map +1 -0
- package/dist/agent/acp/progress.d.ts +23 -0
- package/dist/agent/acp/progress.js +54 -0
- package/dist/agent/acp/progress.js.map +1 -0
- package/dist/agent/acp/runtime.d.ts +156 -0
- package/dist/agent/acp/runtime.js +337 -0
- package/dist/agent/acp/runtime.js.map +1 -0
- package/dist/agent/acp/ws-event-client.d.ts +64 -0
- package/dist/agent/acp/ws-event-client.js +263 -0
- package/dist/agent/acp/ws-event-client.js.map +1 -0
- package/dist/agent/agent.d.ts +60 -0
- package/dist/agent/agent.js +121 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/cli.d.ts +2 -0
- package/dist/agent/cli.js +311 -0
- package/dist/agent/cli.js.map +1 -0
- package/dist/agent/mcp-client.d.ts +37 -0
- package/dist/agent/mcp-client.js +92 -0
- package/dist/agent/mcp-client.js.map +1 -0
- package/dist/agent/mock-runner.d.ts +14 -0
- package/dist/agent/mock-runner.js +159 -0
- package/dist/agent/mock-runner.js.map +1 -0
- package/dist/agent/native-client.d.ts +18 -0
- package/dist/agent/native-client.js +42 -0
- package/dist/agent/native-client.js.map +1 -0
- package/dist/agent/prompt.d.ts +45 -0
- package/dist/agent/prompt.js +115 -0
- package/dist/agent/prompt.js.map +1 -0
- package/dist/agent/providers.d.ts +25 -0
- package/dist/agent/providers.js +696 -0
- package/dist/agent/providers.js.map +1 -0
- package/dist/agent/runner.d.ts +15 -0
- package/dist/agent/runner.js +625 -0
- package/dist/agent/runner.js.map +1 -0
- package/dist/agent/tool-client.d.ts +12 -0
- package/dist/agent/tool-client.js +2 -0
- package/dist/agent/tool-client.js.map +1 -0
- package/dist/agent/types.d.ts +116 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/agent-pool.d.ts +44 -0
- package/dist/agent-pool.js +228 -0
- package/dist/agent-pool.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +7 -0
- package/dist/bin.js.map +1 -0
- package/dist/bus.d.ts +24 -0
- package/dist/bus.js +79 -0
- package/dist/bus.js.map +1 -0
- package/dist/dances.d.ts +73 -0
- package/dist/dances.js +122 -0
- package/dist/dances.js.map +1 -0
- package/dist/guard.d.ts +52 -0
- package/dist/guard.js +210 -0
- package/dist/guard.js.map +1 -0
- package/dist/heartbeat.d.ts +41 -0
- package/dist/heartbeat.js +104 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/honeycomb.d.ts +63 -0
- package/dist/honeycomb.js +222 -0
- package/dist/honeycomb.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +601 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/config.d.ts +15 -0
- package/dist/integrations/config.js +62 -0
- package/dist/integrations/config.js.map +1 -0
- package/dist/integrations/index.d.ts +4 -0
- package/dist/integrations/index.js +4 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/loader.d.ts +8 -0
- package/dist/integrations/loader.js +27 -0
- package/dist/integrations/loader.js.map +1 -0
- package/dist/integrations/manager.d.ts +29 -0
- package/dist/integrations/manager.js +108 -0
- package/dist/integrations/manager.js.map +1 -0
- package/dist/log.d.ts +25 -0
- package/dist/log.js +67 -0
- package/dist/log.js.map +1 -0
- package/dist/namespaces.d.ts +28 -0
- package/dist/namespaces.js +100 -0
- package/dist/namespaces.js.map +1 -0
- package/dist/orchestrator.d.ts +119 -0
- package/dist/orchestrator.js +463 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/persistence.d.ts +7 -0
- package/dist/persistence.js +62 -0
- package/dist/persistence.js.map +1 -0
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.js +3 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/loader.d.ts +12 -0
- package/dist/plugins/loader.js +122 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manager.d.ts +76 -0
- package/dist/plugins/manager.js +238 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/propolis/guard.d.ts +23 -0
- package/dist/propolis/guard.js +49 -0
- package/dist/propolis/guard.js.map +1 -0
- package/dist/propolis/tools/types.d.ts +9 -0
- package/dist/propolis/tools/types.js +9 -0
- package/dist/propolis/tools/types.js.map +1 -0
- package/dist/rest.d.ts +4 -0
- package/dist/rest.js +962 -0
- package/dist/rest.js.map +1 -0
- package/dist/run-watcher.d.ts +20 -0
- package/dist/run-watcher.js +74 -0
- package/dist/run-watcher.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +412 -0
- package/dist/server.js.map +1 -0
- package/dist/stores/backend.d.ts +15 -0
- package/dist/stores/backend.js +28 -0
- package/dist/stores/backend.js.map +1 -0
- package/dist/stores/claims.d.ts +14 -0
- package/dist/stores/claims.js +77 -0
- package/dist/stores/claims.js.map +1 -0
- package/dist/stores/conflicts.d.ts +10 -0
- package/dist/stores/conflicts.js +39 -0
- package/dist/stores/conflicts.js.map +1 -0
- package/dist/stores/control.d.ts +37 -0
- package/dist/stores/control.js +105 -0
- package/dist/stores/control.js.map +1 -0
- package/dist/stores/discoveries.d.ts +11 -0
- package/dist/stores/discoveries.js +45 -0
- package/dist/stores/discoveries.js.map +1 -0
- package/dist/stores/events.d.ts +14 -0
- package/dist/stores/events.js +42 -0
- package/dist/stores/events.js.map +1 -0
- package/dist/stores/help.d.ts +11 -0
- package/dist/stores/help.js +46 -0
- package/dist/stores/help.js.map +1 -0
- package/dist/stores/interfaces.d.ts +125 -0
- package/dist/stores/interfaces.js +2 -0
- package/dist/stores/interfaces.js.map +1 -0
- package/dist/stores/messages.d.ts +8 -0
- package/dist/stores/messages.js +29 -0
- package/dist/stores/messages.js.map +1 -0
- package/dist/stores/progress.d.ts +8 -0
- package/dist/stores/progress.js +21 -0
- package/dist/stores/progress.js.map +1 -0
- package/dist/stores/proposals.d.ts +11 -0
- package/dist/stores/proposals.js +46 -0
- package/dist/stores/proposals.js.map +1 -0
- package/dist/stores/redis/claims.d.ts +16 -0
- package/dist/stores/redis/claims.js +126 -0
- package/dist/stores/redis/claims.js.map +1 -0
- package/dist/stores/redis/db.d.ts +39 -0
- package/dist/stores/redis/db.js +34 -0
- package/dist/stores/redis/db.js.map +1 -0
- package/dist/stores/redis/discoveries.d.ts +13 -0
- package/dist/stores/redis/discoveries.js +54 -0
- package/dist/stores/redis/discoveries.js.map +1 -0
- package/dist/stores/redis/events.d.ts +17 -0
- package/dist/stores/redis/events.js +57 -0
- package/dist/stores/redis/events.js.map +1 -0
- package/dist/stores/redis/index.d.ts +3 -0
- package/dist/stores/redis/index.js +31 -0
- package/dist/stores/redis/index.js.map +1 -0
- package/dist/stores/redis/state.d.ts +14 -0
- package/dist/stores/redis/state.js +83 -0
- package/dist/stores/redis/state.js.map +1 -0
- package/dist/stores/reinforcements.d.ts +11 -0
- package/dist/stores/reinforcements.js +42 -0
- package/dist/stores/reinforcements.js.map +1 -0
- package/dist/stores/roles.d.ts +9 -0
- package/dist/stores/roles.js +22 -0
- package/dist/stores/roles.js.map +1 -0
- package/dist/stores/runs.d.ts +15 -0
- package/dist/stores/runs.js +50 -0
- package/dist/stores/runs.js.map +1 -0
- package/dist/stores/sqlite/claims.d.ts +17 -0
- package/dist/stores/sqlite/claims.js +121 -0
- package/dist/stores/sqlite/claims.js.map +1 -0
- package/dist/stores/sqlite/db.d.ts +16 -0
- package/dist/stores/sqlite/db.js +77 -0
- package/dist/stores/sqlite/db.js.map +1 -0
- package/dist/stores/sqlite/discoveries.d.ts +14 -0
- package/dist/stores/sqlite/discoveries.js +66 -0
- package/dist/stores/sqlite/discoveries.js.map +1 -0
- package/dist/stores/sqlite/events.d.ts +16 -0
- package/dist/stores/sqlite/events.js +75 -0
- package/dist/stores/sqlite/events.js.map +1 -0
- package/dist/stores/sqlite/index.d.ts +2 -0
- package/dist/stores/sqlite/index.js +33 -0
- package/dist/stores/sqlite/index.js.map +1 -0
- package/dist/stores/sqlite/state.d.ts +15 -0
- package/dist/stores/sqlite/state.js +99 -0
- package/dist/stores/sqlite/state.js.map +1 -0
- package/dist/stores/state.d.ts +11 -0
- package/dist/stores/state.js +67 -0
- package/dist/stores/state.js.map +1 -0
- package/dist/transports/broker.d.ts +20 -0
- package/dist/transports/broker.js +102 -0
- package/dist/transports/broker.js.map +1 -0
- package/dist/transports/index.d.ts +3 -0
- package/dist/transports/index.js +3 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/transports/ipc.d.ts +26 -0
- package/dist/transports/ipc.js +93 -0
- package/dist/transports/ipc.js.map +1 -0
- package/dist/transports/types.d.ts +39 -0
- package/dist/transports/types.js +8 -0
- package/dist/transports/types.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +36 -0
- package/dist/utils.js.map +1 -0
- package/dist/waggle/client.d.ts +16 -0
- package/dist/waggle/client.js +28 -0
- package/dist/waggle/client.js.map +1 -0
- package/dist/waggle/compound.d.ts +22 -0
- package/dist/waggle/compound.js +194 -0
- package/dist/waggle/compound.js.map +1 -0
- package/dist/waggle/index.d.ts +25 -0
- package/dist/waggle/index.js +77 -0
- package/dist/waggle/index.js.map +1 -0
- package/dist/waggle/types.d.ts +54 -0
- package/dist/waggle/types.js +2 -0
- package/dist/waggle/types.js.map +1 -0
- package/dist/webhooks.d.ts +26 -0
- package/dist/webhooks.js +79 -0
- package/dist/webhooks.js.map +1 -0
- package/dist/ws.d.ts +33 -0
- package/dist/ws.js +195 -0
- package/dist/ws.js.map +1 -0
- package/package.json +122 -0
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
import { chatCompletion, getToolCallArgs } from './providers.js';
|
|
2
|
+
import { generateSystemPrompt, generateFallbackPrompt } from './prompt.js';
|
|
3
|
+
import { createAcpClient } from '@agentcoordinationprotocol/sdk';
|
|
4
|
+
// ─── ANSI colors for agent logs ─────────────────────────────────────
|
|
5
|
+
const COLORS = [
|
|
6
|
+
'\x1b[36m', // cyan
|
|
7
|
+
'\x1b[33m', // yellow
|
|
8
|
+
'\x1b[35m', // magenta
|
|
9
|
+
'\x1b[32m', // green
|
|
10
|
+
'\x1b[34m', // blue
|
|
11
|
+
'\x1b[91m', // bright red
|
|
12
|
+
'\x1b[92m', // bright green
|
|
13
|
+
'\x1b[93m', // bright yellow
|
|
14
|
+
'\x1b[94m', // bright blue
|
|
15
|
+
'\x1b[95m', // bright magenta
|
|
16
|
+
'\x1b[96m', // bright cyan
|
|
17
|
+
];
|
|
18
|
+
const RESET = '\x1b[0m';
|
|
19
|
+
const DIM = '\x1b[2m';
|
|
20
|
+
let colorIndex = 0;
|
|
21
|
+
// ─── File write tools that trigger auto-claims ──────────────────────
|
|
22
|
+
const FILE_WRITE_TOOLS = new Set(['write_file', 'patch_file']);
|
|
23
|
+
// ─── Coordination tool presets ───────────────────────────────────────
|
|
24
|
+
/** Core ACP primitives — minimal coordination set */
|
|
25
|
+
const LITE_TOOLS = new Set([
|
|
26
|
+
'incubator_claim',
|
|
27
|
+
'incubator_releaseClaim',
|
|
28
|
+
'incubator_setState',
|
|
29
|
+
'incubator_publishEvent',
|
|
30
|
+
]);
|
|
31
|
+
// ─── Synthetic ACP tools (invisible mode) ───────────────────────────
|
|
32
|
+
/** Tool names handled by the ACP runtime, not by MCP clients */
|
|
33
|
+
const SYNTHETIC_TOOL_NAMES = new Set(['publish_event', 'set_state', 'get_state', 'claim_resource', 'release_resource']);
|
|
34
|
+
const SYNTHETIC_TOOLS = [
|
|
35
|
+
{
|
|
36
|
+
type: 'function',
|
|
37
|
+
function: {
|
|
38
|
+
name: 'publish_event',
|
|
39
|
+
description: 'Publish a coordination event to notify other agents of progress or milestones',
|
|
40
|
+
parameters: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
type: { type: 'string', description: 'Event type (e.g. section.written, review.complete)' },
|
|
44
|
+
data: { type: 'string', description: 'JSON object with event payload data (optional)' },
|
|
45
|
+
},
|
|
46
|
+
required: ['type'],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: 'function',
|
|
52
|
+
function: {
|
|
53
|
+
name: 'set_state',
|
|
54
|
+
description: 'Set a shared state key visible to all agents in this hive',
|
|
55
|
+
parameters: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
key: { type: 'string', description: 'State key name' },
|
|
59
|
+
value: { type: 'string', description: 'Value to set (string or JSON)' },
|
|
60
|
+
},
|
|
61
|
+
required: ['key', 'value'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: 'function',
|
|
67
|
+
function: {
|
|
68
|
+
name: 'get_state',
|
|
69
|
+
description: 'Get shared state for this hive. Use key="all" to get everything, or a specific key name.',
|
|
70
|
+
parameters: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
key: { type: 'string', description: 'State key to retrieve, or "all" for all state' },
|
|
74
|
+
},
|
|
75
|
+
required: ['key'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: 'function',
|
|
81
|
+
function: {
|
|
82
|
+
name: 'claim_resource',
|
|
83
|
+
description: 'Claim exclusive ownership of a resource (e.g. a topic, file, or task). Returns rejected if another agent already holds the claim.',
|
|
84
|
+
parameters: {
|
|
85
|
+
type: 'object',
|
|
86
|
+
properties: {
|
|
87
|
+
resource: { type: 'string', description: 'Resource identifier to claim (e.g. "topic:quantum-computing")' },
|
|
88
|
+
reason: { type: 'string', description: 'Why you need this resource' },
|
|
89
|
+
},
|
|
90
|
+
required: ['resource'],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: 'function',
|
|
96
|
+
function: {
|
|
97
|
+
name: 'release_resource',
|
|
98
|
+
description: 'Release a previously claimed resource so other agents can use it',
|
|
99
|
+
parameters: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
resource: { type: 'string', description: 'Resource identifier to release' },
|
|
103
|
+
},
|
|
104
|
+
required: ['resource'],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
// ─── Start trigger helpers ──────────────────────────────────────────
|
|
110
|
+
export function describeStartOn(config) {
|
|
111
|
+
const events = config.conditions
|
|
112
|
+
.map(c => c.count > 1 ? `${c.count}x ${c.event}` : c.event)
|
|
113
|
+
.join(' + ');
|
|
114
|
+
return config.timeout > 0
|
|
115
|
+
? `${events} (timeout: ${config.timeout}s)`
|
|
116
|
+
: `${events} (no timeout)`;
|
|
117
|
+
}
|
|
118
|
+
export async function waitForEvents(config, log) {
|
|
119
|
+
const { startOn } = config;
|
|
120
|
+
if (!startOn)
|
|
121
|
+
return;
|
|
122
|
+
const client = createAcpClient({
|
|
123
|
+
server: config.serverUrl,
|
|
124
|
+
agentId: config.agentId,
|
|
125
|
+
namespace: config.namespace,
|
|
126
|
+
});
|
|
127
|
+
const deadline = startOn.timeout > 0 ? Date.now() + startOn.timeout * 1000 : 0;
|
|
128
|
+
const POLL_INTERVAL = 2000;
|
|
129
|
+
while (deadline === 0 || Date.now() < deadline) {
|
|
130
|
+
let allMet = true;
|
|
131
|
+
for (const cond of startOn.conditions) {
|
|
132
|
+
const res = await client.getEvents(0, { type: cond.event });
|
|
133
|
+
if (!res.ok) {
|
|
134
|
+
allMet = false;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
// Incubator returns { events: [...], cursor: N }
|
|
138
|
+
const body = res.data;
|
|
139
|
+
const events = Array.isArray(body) ? body : body?.events;
|
|
140
|
+
if (!events || events.length < cond.count) {
|
|
141
|
+
allMet = false;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (allMet)
|
|
146
|
+
return;
|
|
147
|
+
await new Promise(r => setTimeout(r, POLL_INTERVAL));
|
|
148
|
+
}
|
|
149
|
+
log(`Timeout (${startOn.timeout}s) — starting anyway`);
|
|
150
|
+
}
|
|
151
|
+
// ─── Default context window sizes by provider ──────────────────────
|
|
152
|
+
const DEFAULT_CONTEXT_WINDOWS = {
|
|
153
|
+
cerebras: 128_000,
|
|
154
|
+
groq: 128_000,
|
|
155
|
+
ollama: 8_000,
|
|
156
|
+
openai: 128_000,
|
|
157
|
+
anthropic: 200_000,
|
|
158
|
+
};
|
|
159
|
+
const DEFAULT_COMPACT_THRESHOLD = 0.8;
|
|
160
|
+
const DEFAULT_KEEP_LAST_N = 6;
|
|
161
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
162
|
+
// ─── AgentRunner (renamed from DroneRunner) ─────────────────────────
|
|
163
|
+
export class AgentRunner {
|
|
164
|
+
stopFlag = false;
|
|
165
|
+
stop() {
|
|
166
|
+
this.stopFlag = true;
|
|
167
|
+
}
|
|
168
|
+
async run(config, toolClient, incubatorClient, runtime, protocolOverride, telemetry) {
|
|
169
|
+
const color = COLORS[colorIndex++ % COLORS.length];
|
|
170
|
+
const { agentId, role, provider, maxIterations } = config;
|
|
171
|
+
let iterations = 0;
|
|
172
|
+
let wakeCount = 0;
|
|
173
|
+
const startTime = Date.now();
|
|
174
|
+
const totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
175
|
+
const iterationUsage = [];
|
|
176
|
+
const log = (msg) => {
|
|
177
|
+
if (config.verbose) {
|
|
178
|
+
const ts = new Date().toISOString().slice(11, 23);
|
|
179
|
+
console.error(`${color} ${ts} [${agentId}] ${msg}${RESET}`);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
let exitReason = 'unknown';
|
|
183
|
+
try {
|
|
184
|
+
// 0a. Connect ACP runtime (invisible coordination)
|
|
185
|
+
if (runtime) {
|
|
186
|
+
await runtime.connect();
|
|
187
|
+
log('ACP runtime connected');
|
|
188
|
+
}
|
|
189
|
+
// 0b. Wait for start trigger if configured
|
|
190
|
+
if (config.startOn) {
|
|
191
|
+
log(`Waiting for trigger: ${describeStartOn(config.startOn)}`);
|
|
192
|
+
await waitForEvents(config, log);
|
|
193
|
+
log('Trigger conditions met — starting agent');
|
|
194
|
+
}
|
|
195
|
+
// 1. Build tool definitions (with optional filtering)
|
|
196
|
+
let toolDefs = [...toolClient.getToolDefs()];
|
|
197
|
+
// Filter tools if whitelist provided (only for MCP clients — NativeToolClient pre-filters)
|
|
198
|
+
if (config.toolFilter && config.mode === 'drone') {
|
|
199
|
+
const filterSet = new Set(config.toolFilter);
|
|
200
|
+
toolDefs = toolDefs.filter(t => filterSet.has(t.function.name));
|
|
201
|
+
}
|
|
202
|
+
// In --no-acp mode, also include incubator tools (with coordination filtering)
|
|
203
|
+
if (incubatorClient) {
|
|
204
|
+
let incTools = incubatorClient.getToolDefs();
|
|
205
|
+
const coord = config.coordination ?? 'full';
|
|
206
|
+
if (coord === 'lite') {
|
|
207
|
+
incTools = incTools.filter(t => LITE_TOOLS.has(t.function.name));
|
|
208
|
+
}
|
|
209
|
+
else if (coord === 'none') {
|
|
210
|
+
incTools = [];
|
|
211
|
+
}
|
|
212
|
+
else if (Array.isArray(coord)) {
|
|
213
|
+
const coordSet = new Set(coord);
|
|
214
|
+
incTools = incTools.filter(t => coordSet.has(t.function.name));
|
|
215
|
+
}
|
|
216
|
+
// 'full' = no filtering
|
|
217
|
+
toolDefs.push(...incTools);
|
|
218
|
+
log(`Tools: ${toolDefs.length} (env: ${toolDefs.length - incTools.length}, incubator: ${incTools.length})`);
|
|
219
|
+
}
|
|
220
|
+
else if (runtime && !config.noAcpInject) {
|
|
221
|
+
// Invisible ACP mode: add synthetic coordination tools
|
|
222
|
+
toolDefs.push(...SYNTHETIC_TOOLS);
|
|
223
|
+
log(`Tools: ${toolDefs.length} (env: ${toolDefs.length - SYNTHETIC_TOOLS.length}, acp: ${SYNTHETIC_TOOLS.length})`);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
log(`Tools: ${toolDefs.length} (env only)`);
|
|
227
|
+
}
|
|
228
|
+
// 2. Fetch protocol and generate system prompt
|
|
229
|
+
let protocolData = protocolOverride ?? null;
|
|
230
|
+
if (!protocolData && runtime) {
|
|
231
|
+
protocolData = await runtime.fetchProtocol();
|
|
232
|
+
}
|
|
233
|
+
// Check for dance tools from server — these REPLACE synthetic ACP tools
|
|
234
|
+
let danceToolNames = null;
|
|
235
|
+
if (runtime) {
|
|
236
|
+
const danceTools = runtime.getDanceTools();
|
|
237
|
+
if (danceTools && danceTools.length > 0) {
|
|
238
|
+
// Dance tools replace ALL other tools — the LLM only sees dance-defined tools
|
|
239
|
+
toolDefs = [...danceTools];
|
|
240
|
+
danceToolNames = new Set(danceTools.map(t => t.function.name));
|
|
241
|
+
log(`Dance tools: ${danceTools.map(t => t.function.name).join(', ')} (exclusive — replaced all env/acp tools)`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Derive wakeOn from spec wait field if not explicitly configured
|
|
245
|
+
let effectiveWakeOn = config.wakeOn ?? null;
|
|
246
|
+
if (protocolData && !effectiveWakeOn && protocolData.wait) {
|
|
247
|
+
effectiveWakeOn = {
|
|
248
|
+
types: protocolData.wait.types ?? null,
|
|
249
|
+
timeout: protocolData.wait.max_timeout ?? 0,
|
|
250
|
+
maxWakes: 50,
|
|
251
|
+
};
|
|
252
|
+
log(`Derived wakeOn from spec: types=${protocolData.wait.types?.join(',') ?? 'any'}`);
|
|
253
|
+
}
|
|
254
|
+
// Derive context retention from spec (0 = stateless, N = keep last N exchanges, undefined = full history)
|
|
255
|
+
const contextRetention = protocolData?.context;
|
|
256
|
+
if (contextRetention !== undefined) {
|
|
257
|
+
log(`Context retention: ${contextRetention === 0 ? 'stateless' : `last ${contextRetention} exchanges`}`);
|
|
258
|
+
}
|
|
259
|
+
// Spec temperature overrides config
|
|
260
|
+
const effectiveTemperature = protocolData?.temperature ?? config.temperature;
|
|
261
|
+
const disableReasoning = protocolData?.reasoning === false;
|
|
262
|
+
const reasoningEffort = protocolData?.reasoning_effort;
|
|
263
|
+
const systemPrompt = protocolData
|
|
264
|
+
? generateSystemPrompt(agentId, role, toolDefs, protocolData, { disableReasoning })
|
|
265
|
+
: generateFallbackPrompt(agentId, role, toolDefs);
|
|
266
|
+
// 3. Build initial messages
|
|
267
|
+
const messages = [
|
|
268
|
+
{ role: 'system', content: systemPrompt },
|
|
269
|
+
{ role: 'user', content: config.prompt ?? 'Begin your work. Explore the codebase, understand the task, and implement the required changes.' },
|
|
270
|
+
];
|
|
271
|
+
log(`Starting (role=${role}, model=${provider.model}, mode=${config.mode})`);
|
|
272
|
+
// SIGTERM handler for kill signal
|
|
273
|
+
const onKill = () => {
|
|
274
|
+
log('SIGTERM received — killing agent');
|
|
275
|
+
this.stopFlag = true;
|
|
276
|
+
};
|
|
277
|
+
process.on('SIGTERM', onKill);
|
|
278
|
+
// Context compaction config
|
|
279
|
+
const contextWindow = config.contextWindow ?? DEFAULT_CONTEXT_WINDOWS[provider.type] ?? 128_000;
|
|
280
|
+
const compactThreshold = Math.floor(contextWindow * DEFAULT_COMPACT_THRESHOLD);
|
|
281
|
+
const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
282
|
+
// 4. Initial sleep — wait for first wake event before running
|
|
283
|
+
if (effectiveWakeOn && runtime) {
|
|
284
|
+
log(`Sleeping — waiting for initial wake event`);
|
|
285
|
+
const wakeEvents = await runtime.waitForWake(effectiveWakeOn);
|
|
286
|
+
if (wakeEvents.length === 0) {
|
|
287
|
+
log('Initial wake timeout — no events, exiting');
|
|
288
|
+
if (runtime)
|
|
289
|
+
await runtime.onComplete('Wake timeout', totalUsage);
|
|
290
|
+
process.removeListener('SIGTERM', onKill);
|
|
291
|
+
return { iterations: 0, usage: totalUsage, agentId, role, status: 'completed' };
|
|
292
|
+
}
|
|
293
|
+
log(`Woke up with ${wakeEvents.length} event(s)`);
|
|
294
|
+
const inject = runtime.getLastInject();
|
|
295
|
+
if (inject) {
|
|
296
|
+
messages.push({ role: 'user', content: `[SYSTEM] ${inject}` });
|
|
297
|
+
log('Injected dance state context');
|
|
298
|
+
}
|
|
299
|
+
for (const evt of wakeEvents) {
|
|
300
|
+
messages.push({ role: 'user', content: `[SYSTEM] ${evt}` });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// 5. ReAct loop
|
|
304
|
+
while (iterations < maxIterations && !this.stopFlag) {
|
|
305
|
+
iterations++;
|
|
306
|
+
log(`Iteration ${iterations}/${maxIterations}`);
|
|
307
|
+
// Cost controls: maxTotalTokens
|
|
308
|
+
if (config.maxTotalTokens && config.maxTotalTokens > 0 && totalUsage.totalTokens >= config.maxTotalTokens) {
|
|
309
|
+
log(`Token budget exhausted (${totalUsage.totalTokens.toLocaleString()}/${config.maxTotalTokens.toLocaleString()})`);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
// Cost controls: maxRuntime
|
|
313
|
+
if (config.maxRuntime && config.maxRuntime > 0 && (Date.now() - startTime) >= config.maxRuntime) {
|
|
314
|
+
log(`Runtime limit reached (${config.maxRuntime}ms)`);
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
// Inject coordination context (invisible ACP events + dance state)
|
|
318
|
+
if (runtime) {
|
|
319
|
+
const contextMessages = await runtime.beforeIteration();
|
|
320
|
+
const inject = runtime.getLastInject();
|
|
321
|
+
// Context retention: trim history based on spec setting
|
|
322
|
+
if (contextRetention !== undefined && inject) {
|
|
323
|
+
if (contextRetention === 0) {
|
|
324
|
+
messages.length = 1; // stateless — keep system prompt only
|
|
325
|
+
}
|
|
326
|
+
else if (messages.length > 1 + contextRetention * 2) {
|
|
327
|
+
// Keep system prompt + last N exchanges (assistant + tool pairs)
|
|
328
|
+
const kept = messages.slice(-(contextRetention * 2));
|
|
329
|
+
messages.length = 1;
|
|
330
|
+
messages.push(...kept);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
for (const msg of contextMessages) {
|
|
334
|
+
messages.push({ role: 'user', content: `[SYSTEM] ${msg}` });
|
|
335
|
+
}
|
|
336
|
+
if (inject) {
|
|
337
|
+
messages.push({ role: 'user', content: `[SYSTEM] ${inject}` });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Call LLM with retry logic
|
|
341
|
+
let response;
|
|
342
|
+
let usage;
|
|
343
|
+
let retryCount = 0;
|
|
344
|
+
while (true) {
|
|
345
|
+
const llmStart = Date.now();
|
|
346
|
+
try {
|
|
347
|
+
const result = await chatCompletion(provider, messages, toolDefs, effectiveTemperature, {
|
|
348
|
+
...(disableReasoning ? { disableReasoning: true } : {}),
|
|
349
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
350
|
+
});
|
|
351
|
+
response = result.message;
|
|
352
|
+
usage = result.usage;
|
|
353
|
+
telemetry?.record('llm_call', {
|
|
354
|
+
agentId, role, provider: provider.type, model: provider.model,
|
|
355
|
+
promptTokens: usage.promptTokens, completionTokens: usage.completionTokens,
|
|
356
|
+
latency_ms: Date.now() - llmStart,
|
|
357
|
+
});
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
retryCount++;
|
|
362
|
+
telemetry?.record('llm_error', {
|
|
363
|
+
agentId, role, provider: provider.type, model: provider.model,
|
|
364
|
+
error: err.message, retryCount,
|
|
365
|
+
latency_ms: Date.now() - llmStart,
|
|
366
|
+
});
|
|
367
|
+
if (retryCount > maxRetries)
|
|
368
|
+
throw err;
|
|
369
|
+
const delay = 1000 * Math.pow(2, retryCount - 1);
|
|
370
|
+
log(`LLM call failed (attempt ${retryCount}/${maxRetries}): ${err.message} — retrying in ${delay}ms`);
|
|
371
|
+
await new Promise(r => setTimeout(r, delay));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
messages.push(response);
|
|
375
|
+
// Track token usage
|
|
376
|
+
totalUsage.promptTokens += usage.promptTokens;
|
|
377
|
+
totalUsage.completionTokens += usage.completionTokens;
|
|
378
|
+
totalUsage.totalTokens += usage.totalTokens;
|
|
379
|
+
iterationUsage.push(usage);
|
|
380
|
+
if (usage.totalTokens > 0) {
|
|
381
|
+
log(`Tokens: +${usage.promptTokens}/${usage.completionTokens} (total: ${totalUsage.totalTokens.toLocaleString()})`);
|
|
382
|
+
}
|
|
383
|
+
// Context compaction: when prompt tokens exceed threshold, trim messages
|
|
384
|
+
if (usage.promptTokens > compactThreshold && messages.length > DEFAULT_KEEP_LAST_N + 2) {
|
|
385
|
+
log(`Context compaction triggered (${usage.promptTokens.toLocaleString()} > ${compactThreshold.toLocaleString()} threshold)`);
|
|
386
|
+
// Keep system prompt (index 0) + last N messages
|
|
387
|
+
const kept = messages.slice(-DEFAULT_KEEP_LAST_N);
|
|
388
|
+
messages.length = 1; // keep system prompt
|
|
389
|
+
messages.push(...kept);
|
|
390
|
+
// Reload state if runtime available
|
|
391
|
+
if (runtime) {
|
|
392
|
+
const freshProtocol = await runtime.fetchProtocol();
|
|
393
|
+
if (freshProtocol) {
|
|
394
|
+
messages[0] = { role: 'system', content: generateSystemPrompt(agentId, role, toolDefs, freshProtocol) };
|
|
395
|
+
}
|
|
396
|
+
const stateStr = await runtime.getState();
|
|
397
|
+
messages.push({ role: 'user', content: `[SYSTEM] Context was compacted. Current state: ${stateStr}` });
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
messages.push({ role: 'user', content: '[SYSTEM] Context was compacted. Previous messages were trimmed.' });
|
|
401
|
+
}
|
|
402
|
+
telemetry?.record('context_compaction', {
|
|
403
|
+
agentId, role, iteration: iterations,
|
|
404
|
+
promptTokensBefore: usage.promptTokens, messagesAfter: messages.length,
|
|
405
|
+
});
|
|
406
|
+
log(`Compacted to ${messages.length} messages`);
|
|
407
|
+
}
|
|
408
|
+
// Log assistant response (full text so we can see LLM reasoning)
|
|
409
|
+
if (response.content) {
|
|
410
|
+
log(`${DIM}${response.content}${RESET}${color}`);
|
|
411
|
+
}
|
|
412
|
+
// Check for "DONE" in content — always exits, even in reactive mode
|
|
413
|
+
if (response.content && /\bDONE\b/.test(response.content)) {
|
|
414
|
+
log('Agent said DONE — finishing');
|
|
415
|
+
exitReason = 'done';
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
// No tool calls → sleep/wake or exit
|
|
419
|
+
if (!response.tool_calls || response.tool_calls.length === 0) {
|
|
420
|
+
if (effectiveWakeOn && runtime) {
|
|
421
|
+
const maxWakes = effectiveWakeOn.maxWakes ?? 0;
|
|
422
|
+
if (maxWakes > 0 && ++wakeCount >= maxWakes) {
|
|
423
|
+
log(`Max wakes reached (${maxWakes}) — exiting`);
|
|
424
|
+
exitReason = 'max_wakes';
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
if (maxWakes === 0)
|
|
428
|
+
wakeCount++;
|
|
429
|
+
log(`Sleeping — waiting for wake events (cycle ${wakeCount})`);
|
|
430
|
+
const wakeEvents = await runtime.waitForWake(effectiveWakeOn);
|
|
431
|
+
if (wakeEvents.length === 0) {
|
|
432
|
+
log('Wake timeout — no events, exiting');
|
|
433
|
+
exitReason = 'wake_timeout';
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
log(`Woke up with ${wakeEvents.length} event(s)`);
|
|
437
|
+
// Inject dance state context if available
|
|
438
|
+
const inject = runtime.getLastInject();
|
|
439
|
+
if (inject) {
|
|
440
|
+
messages.push({ role: 'user', content: `[SYSTEM] ${inject}` });
|
|
441
|
+
log('Injected dance state context');
|
|
442
|
+
}
|
|
443
|
+
for (const evt of wakeEvents) {
|
|
444
|
+
messages.push({ role: 'user', content: `[SYSTEM] ${evt}` });
|
|
445
|
+
}
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
log('No tool calls — agent finished');
|
|
449
|
+
exitReason = 'no_tool_calls';
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
// Execute each tool call
|
|
453
|
+
let halted = false;
|
|
454
|
+
for (const toolCall of response.tool_calls) {
|
|
455
|
+
const name = toolCall.function.name;
|
|
456
|
+
const args = getToolCallArgs(toolCall);
|
|
457
|
+
const argsStr = Object.keys(args).length > 0
|
|
458
|
+
? `(${Object.entries(args).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(', ')})`
|
|
459
|
+
: '()';
|
|
460
|
+
log(`Tool: ${name}${argsStr}`);
|
|
461
|
+
// Intercept file writes for auto-claims
|
|
462
|
+
if (runtime && FILE_WRITE_TOOLS.has(name) && args.path) {
|
|
463
|
+
const claimResult = await runtime.onFileWrite(args.path);
|
|
464
|
+
if (claimResult) {
|
|
465
|
+
// Claim conflict — return error to LLM
|
|
466
|
+
messages.push({
|
|
467
|
+
role: 'tool',
|
|
468
|
+
content: claimResult,
|
|
469
|
+
tool_call_id: toolCall.id ?? `call_${iterations}`,
|
|
470
|
+
});
|
|
471
|
+
log(`${DIM}→ claim conflict: ${claimResult}${RESET}${color}`);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// Route tool call to the right handler
|
|
476
|
+
let result;
|
|
477
|
+
if (danceToolNames && danceToolNames.has(name) && runtime) {
|
|
478
|
+
// Dance tool — route via WS to server
|
|
479
|
+
try {
|
|
480
|
+
const danceResult = await runtime.callDanceTool(name, args);
|
|
481
|
+
result = JSON.stringify(danceResult);
|
|
482
|
+
}
|
|
483
|
+
catch (err) {
|
|
484
|
+
result = JSON.stringify({ error: `Dance tool failed: ${err.message}` });
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
else if (runtime && SYNTHETIC_TOOL_NAMES.has(name)) {
|
|
488
|
+
// Synthetic ACP tools — route through runtime
|
|
489
|
+
if (name === 'publish_event') {
|
|
490
|
+
let eventData = {};
|
|
491
|
+
if (args.data) {
|
|
492
|
+
try {
|
|
493
|
+
eventData = typeof args.data === 'string' ? JSON.parse(args.data) : args.data;
|
|
494
|
+
}
|
|
495
|
+
catch { /* keep empty */ }
|
|
496
|
+
}
|
|
497
|
+
result = await runtime.publishEvent(args.type, eventData);
|
|
498
|
+
}
|
|
499
|
+
else if (name === 'set_state') {
|
|
500
|
+
result = await runtime.setState(args.key, args.value);
|
|
501
|
+
}
|
|
502
|
+
else if (name === 'get_state') {
|
|
503
|
+
result = await runtime.getState();
|
|
504
|
+
}
|
|
505
|
+
else if (name === 'claim_resource') {
|
|
506
|
+
result = await runtime.claimResource(args.resource, args.reason);
|
|
507
|
+
}
|
|
508
|
+
else if (name === 'release_resource') {
|
|
509
|
+
result = await runtime.releaseResource(args.resource);
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
result = JSON.stringify({ error: `Unknown synthetic tool: ${name}` });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
else if (incubatorClient && incubatorClient.hasToolName(name)) {
|
|
516
|
+
result = await incubatorClient.callTool(name, args);
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
try {
|
|
520
|
+
result = await toolClient.callTool(name, args);
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
result = JSON.stringify({ error: `Tool call failed: ${err.message}` });
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
telemetry?.record('tool_call', { agentId, role, tool: name });
|
|
527
|
+
// Log result
|
|
528
|
+
log(`${DIM}→ ${result}${RESET}${color}`);
|
|
529
|
+
messages.push({
|
|
530
|
+
role: 'tool',
|
|
531
|
+
content: result,
|
|
532
|
+
tool_call_id: toolCall.id ?? `call_${iterations}`,
|
|
533
|
+
});
|
|
534
|
+
// Check halt/pause status (via ACP runtime)
|
|
535
|
+
if (runtime) {
|
|
536
|
+
const controlStatus = await runtime.checkControl();
|
|
537
|
+
if (controlStatus.halted) {
|
|
538
|
+
log(`HALTED: ${controlStatus.reason ?? 'no reason'}`);
|
|
539
|
+
halted = true;
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
if (controlStatus.paused) {
|
|
543
|
+
log(`PAUSED: ${controlStatus.reason ?? 'no reason'} — waiting...`);
|
|
544
|
+
const resumeReason = await runtime.waitForResume();
|
|
545
|
+
log(`RESUMED: ${resumeReason}`);
|
|
546
|
+
messages.push({
|
|
547
|
+
role: 'user',
|
|
548
|
+
content: `[SYSTEM] You were paused (reason: ${controlStatus.reason ?? 'unknown'}). You have been resumed (reason: ${resumeReason}). Continue your work.`,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (halted) {
|
|
554
|
+
log('Agent halted — exiting loop');
|
|
555
|
+
exitReason = 'halted';
|
|
556
|
+
if (runtime)
|
|
557
|
+
await runtime.onComplete('Agent halted', totalUsage);
|
|
558
|
+
telemetry?.record('agent_complete', {
|
|
559
|
+
agentId, role, status: 'completed', iterations, exitReason,
|
|
560
|
+
provider: provider.type, model: provider.model,
|
|
561
|
+
totalTokens: totalUsage.totalTokens, duration_ms: Date.now() - startTime, wakeCount,
|
|
562
|
+
});
|
|
563
|
+
return { agentId, role, status: 'completed', iterations, usage: totalUsage, iterationUsage };
|
|
564
|
+
}
|
|
565
|
+
// Periodic prompt refresh (every 10 iterations)
|
|
566
|
+
if (iterations % 10 === 0 && runtime) {
|
|
567
|
+
const refreshed = await runtime.fetchProtocol();
|
|
568
|
+
if (refreshed) {
|
|
569
|
+
const newPrompt = generateSystemPrompt(agentId, role, toolDefs, refreshed);
|
|
570
|
+
messages[0] = { role: 'system', content: newPrompt };
|
|
571
|
+
log('Refreshed system prompt');
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (this.stopFlag) {
|
|
576
|
+
exitReason = 'stopped';
|
|
577
|
+
log('Stopped by runner');
|
|
578
|
+
}
|
|
579
|
+
else if (iterations >= maxIterations) {
|
|
580
|
+
exitReason = 'max_iterations';
|
|
581
|
+
log(`Hit max iterations (${maxIterations})`);
|
|
582
|
+
}
|
|
583
|
+
// Cleanup SIGTERM handler
|
|
584
|
+
process.off('SIGTERM', onKill);
|
|
585
|
+
// Complete
|
|
586
|
+
const summary = `Agent ${agentId} completed after ${iterations} iterations (${totalUsage.totalTokens.toLocaleString()} tokens)`;
|
|
587
|
+
if (runtime)
|
|
588
|
+
await runtime.onComplete(summary, totalUsage);
|
|
589
|
+
telemetry?.record('agent_complete', {
|
|
590
|
+
agentId, role, status: 'completed', iterations, exitReason,
|
|
591
|
+
provider: provider.type, model: provider.model,
|
|
592
|
+
promptTokens: totalUsage.promptTokens, completionTokens: totalUsage.completionTokens,
|
|
593
|
+
totalTokens: totalUsage.totalTokens, duration_ms: Date.now() - startTime, wakeCount,
|
|
594
|
+
});
|
|
595
|
+
log(`Done (${iterations} iterations, ${totalUsage.totalTokens.toLocaleString()} tokens)`);
|
|
596
|
+
return { agentId, role, status: 'completed', iterations, usage: totalUsage, iterationUsage };
|
|
597
|
+
}
|
|
598
|
+
catch (err) {
|
|
599
|
+
// Cleanup SIGTERM handler on error path too
|
|
600
|
+
try {
|
|
601
|
+
process.off('SIGTERM', () => { });
|
|
602
|
+
}
|
|
603
|
+
catch { /* ignore */ }
|
|
604
|
+
const errMsg = err.message;
|
|
605
|
+
if (config.verbose) {
|
|
606
|
+
console.error(`${color} [${agentId}] ERROR: ${errMsg}${RESET}`);
|
|
607
|
+
}
|
|
608
|
+
if (runtime) {
|
|
609
|
+
try {
|
|
610
|
+
await runtime.onComplete(`Error: ${errMsg}`, totalUsage);
|
|
611
|
+
}
|
|
612
|
+
catch { /* ignore */ }
|
|
613
|
+
}
|
|
614
|
+
telemetry?.record('agent_complete', {
|
|
615
|
+
agentId, role, status: 'error', iterations, exitReason: 'error', error: errMsg,
|
|
616
|
+
provider: provider.type, model: provider.model,
|
|
617
|
+
totalTokens: totalUsage.totalTokens, duration_ms: Date.now() - startTime,
|
|
618
|
+
});
|
|
619
|
+
return { agentId, role, status: 'error', iterations, error: errMsg, usage: totalUsage, iterationUsage };
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/** Backwards-compatible alias */
|
|
624
|
+
export { AgentRunner as DroneRunner };
|
|
625
|
+
//# sourceMappingURL=runner.js.map
|