@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,337 @@
|
|
|
1
|
+
import { createAcpClient } from '@agentcoordinationprotocol/sdk';
|
|
2
|
+
import { ClaimManager } from './claim-manager.js';
|
|
3
|
+
import { EventClient } from './event-client.js';
|
|
4
|
+
import { ProgressReporter } from './progress.js';
|
|
5
|
+
import { WebSocketEventClient } from './ws-event-client.js';
|
|
6
|
+
/**
|
|
7
|
+
* Invisible ACP coordination layer.
|
|
8
|
+
* Wraps AcpClient and provides:
|
|
9
|
+
* - Lazy file-level claims on writes
|
|
10
|
+
* - Event polling between iterations
|
|
11
|
+
* - Progress reporting
|
|
12
|
+
* - Control status (halt/pause) checking
|
|
13
|
+
*
|
|
14
|
+
* The LLM never sees coordination tools — it only gets environment tools from Propolis.
|
|
15
|
+
*/
|
|
16
|
+
export class AcpRuntime {
|
|
17
|
+
client;
|
|
18
|
+
claims;
|
|
19
|
+
events;
|
|
20
|
+
progress;
|
|
21
|
+
config;
|
|
22
|
+
iterationCount = 0;
|
|
23
|
+
wsClient = null;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.client = createAcpClient({
|
|
27
|
+
server: config.serverUrl,
|
|
28
|
+
agentId: config.agentId,
|
|
29
|
+
namespace: config.namespace,
|
|
30
|
+
});
|
|
31
|
+
this.claims = new ClaimManager(this.client);
|
|
32
|
+
this.events = new EventClient(this.client, config.agentId);
|
|
33
|
+
this.progress = new ProgressReporter(this.client, config.agentId);
|
|
34
|
+
if (config.useWebSocket) {
|
|
35
|
+
this.wsClient = new WebSocketEventClient(config.serverUrl, config.namespace, config.agentId, config.role);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Connect to incubator and register role.
|
|
40
|
+
*/
|
|
41
|
+
async connect() {
|
|
42
|
+
try {
|
|
43
|
+
await this.client.requestRole(this.config.role);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Server may not support role registration — continue
|
|
47
|
+
}
|
|
48
|
+
// Connect WebSocket for push-based events
|
|
49
|
+
if (this.wsClient) {
|
|
50
|
+
try {
|
|
51
|
+
await this.wsClient.connect();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// WS unavailable — fall back to polling
|
|
55
|
+
this.wsClient = null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Disconnect — release claims, close WS, and report completion.
|
|
61
|
+
*/
|
|
62
|
+
async disconnect() {
|
|
63
|
+
await this.claims.releaseAll();
|
|
64
|
+
if (this.wsClient) {
|
|
65
|
+
this.wsClient.close();
|
|
66
|
+
this.wsClient = null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Wait for a wake event. Used by sleep/wake agents between iterations.
|
|
71
|
+
* Returns formatted event strings, or empty array on timeout.
|
|
72
|
+
*/
|
|
73
|
+
async waitForWake(condition) {
|
|
74
|
+
if (this.wsClient) {
|
|
75
|
+
return this.wsClient.waitForWake(condition);
|
|
76
|
+
}
|
|
77
|
+
// Fallback: poll for events
|
|
78
|
+
const deadline = condition.timeout && condition.timeout > 0
|
|
79
|
+
? Date.now() + condition.timeout
|
|
80
|
+
: 0;
|
|
81
|
+
const POLL_INTERVAL = 2000;
|
|
82
|
+
while (deadline === 0 || Date.now() < deadline) {
|
|
83
|
+
const events = await this.events.drain();
|
|
84
|
+
if (events.length > 0) {
|
|
85
|
+
if (condition.types) {
|
|
86
|
+
const typeSet = new Set(condition.types);
|
|
87
|
+
const matching = events.filter(e => {
|
|
88
|
+
// Extract type from format "Event from X: [type] data"
|
|
89
|
+
const m = e.match(/\[([^\]]+)\]/);
|
|
90
|
+
return m && typeSet.has(m[1]);
|
|
91
|
+
});
|
|
92
|
+
if (matching.length > 0)
|
|
93
|
+
return matching;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return events;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
await new Promise(r => setTimeout(r, POLL_INTERVAL));
|
|
100
|
+
}
|
|
101
|
+
return []; // timeout
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get the last inject string from a dance-enabled WS connection.
|
|
105
|
+
* Consumed on read.
|
|
106
|
+
*/
|
|
107
|
+
getLastInject() {
|
|
108
|
+
return this.wsClient?.getLastInject() ?? null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Call a dance tool on the server via WebSocket.
|
|
112
|
+
*/
|
|
113
|
+
async callDanceTool(tool, args) {
|
|
114
|
+
if (!this.wsClient) {
|
|
115
|
+
throw new Error('Dance tool calls require WebSocket connection');
|
|
116
|
+
}
|
|
117
|
+
return this.wsClient.callDanceTool(tool, args);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get dance tool definitions from the server (received via WS).
|
|
121
|
+
*/
|
|
122
|
+
getDanceTools() {
|
|
123
|
+
return this.wsClient?.getDanceTools() ?? null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Called by runner before each iteration.
|
|
127
|
+
* Returns context messages to inject (events from other agents).
|
|
128
|
+
*/
|
|
129
|
+
async beforeIteration() {
|
|
130
|
+
this.iterationCount++;
|
|
131
|
+
await this.progress.reportIteration(this.iterationCount, this.config.maxIterations);
|
|
132
|
+
const messages = [];
|
|
133
|
+
// Drain events — prefer WS buffer, fall back to polling
|
|
134
|
+
if (this.wsClient) {
|
|
135
|
+
const wsEvents = this.wsClient.drain();
|
|
136
|
+
messages.push(...wsEvents);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const events = await this.events.drain();
|
|
140
|
+
messages.push(...events);
|
|
141
|
+
}
|
|
142
|
+
// Drain direct messages (always via polling — messages aren't on WS)
|
|
143
|
+
const directMessages = await this.events.drainMessages();
|
|
144
|
+
messages.push(...directMessages);
|
|
145
|
+
return messages;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Called when Propolis executes a file write.
|
|
149
|
+
* Auto-acquires file claim. Returns error message if conflict, null if OK.
|
|
150
|
+
*/
|
|
151
|
+
async onFileWrite(path) {
|
|
152
|
+
return this.claims.ensureClaim(path);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Called on task completion — release claims and report.
|
|
156
|
+
*/
|
|
157
|
+
async onComplete(summary, usage) {
|
|
158
|
+
await this.progress.reportComplete(summary, usage);
|
|
159
|
+
await this.claims.releaseAll();
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Fetch protocol from incubator for system prompt generation.
|
|
163
|
+
*/
|
|
164
|
+
async fetchProtocol() {
|
|
165
|
+
try {
|
|
166
|
+
const res = await this.client.getProtocol(this.config.role);
|
|
167
|
+
if (!res.ok)
|
|
168
|
+
return null;
|
|
169
|
+
const data = res.data;
|
|
170
|
+
// If the response has 'loaded' property, it's the raw spec format
|
|
171
|
+
if ('loaded' in data) {
|
|
172
|
+
return buildFromRawSpec(data, this.config.role);
|
|
173
|
+
}
|
|
174
|
+
// Otherwise it's already in ProtocolResponse format
|
|
175
|
+
return data;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Publish a coordination event (exposed as synthetic tool in invisible mode).
|
|
183
|
+
*/
|
|
184
|
+
async publishEvent(type, data = {}) {
|
|
185
|
+
try {
|
|
186
|
+
const res = await this.client.publishEvent(type, data);
|
|
187
|
+
if (!res.ok)
|
|
188
|
+
return JSON.stringify({ error: `Failed to publish event: ${res.status}` });
|
|
189
|
+
return JSON.stringify({ published: true, type });
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
return JSON.stringify({ error: `publishEvent failed: ${err.message}` });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Set shared state (exposed as synthetic tool in invisible mode).
|
|
197
|
+
*/
|
|
198
|
+
async setState(key, value) {
|
|
199
|
+
try {
|
|
200
|
+
const res = await this.client.setState(key, value);
|
|
201
|
+
if (!res.ok)
|
|
202
|
+
return JSON.stringify({ error: `Failed to set state: ${res.status}` });
|
|
203
|
+
return JSON.stringify({ ok: true, key });
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
return JSON.stringify({ error: `setState failed: ${err.message}` });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get shared state (exposed as synthetic tool in invisible mode).
|
|
211
|
+
*/
|
|
212
|
+
async getState() {
|
|
213
|
+
try {
|
|
214
|
+
const res = await this.client.getState();
|
|
215
|
+
if (!res.ok)
|
|
216
|
+
return JSON.stringify({ error: `Failed to get state: ${res.status}` });
|
|
217
|
+
return JSON.stringify(res.data);
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
return JSON.stringify({ error: `getState failed: ${err.message}` });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Claim exclusive ownership of a resource (exposed as synthetic tool).
|
|
225
|
+
*/
|
|
226
|
+
async claimResource(resource, reason) {
|
|
227
|
+
try {
|
|
228
|
+
const res = await this.client.claim(resource, reason ?? resource, { ttlMs: 5 * 60 * 1000 });
|
|
229
|
+
if (!res.ok)
|
|
230
|
+
return JSON.stringify({ error: `Failed to claim: ${res.status}` });
|
|
231
|
+
const data = res.data;
|
|
232
|
+
if (data.status === 'approved') {
|
|
233
|
+
return JSON.stringify({ status: 'approved', resource });
|
|
234
|
+
}
|
|
235
|
+
const owner = data.claim?.owner ?? 'another agent';
|
|
236
|
+
return JSON.stringify({ status: 'rejected', resource, owner, message: `Already claimed by ${owner}` });
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
return JSON.stringify({ error: `claimResource failed: ${err.message}` });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Release a previously claimed resource (exposed as synthetic tool).
|
|
244
|
+
*/
|
|
245
|
+
async releaseResource(resource) {
|
|
246
|
+
try {
|
|
247
|
+
const res = await this.client.releaseClaim(resource);
|
|
248
|
+
if (!res.ok)
|
|
249
|
+
return JSON.stringify({ error: `Failed to release: ${res.status}` });
|
|
250
|
+
return JSON.stringify({ released: true, resource });
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
return JSON.stringify({ error: `releaseResource failed: ${err.message}` });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Check halt/pause status.
|
|
258
|
+
*/
|
|
259
|
+
async checkControl() {
|
|
260
|
+
try {
|
|
261
|
+
const res = await this.client.getControlStatus();
|
|
262
|
+
if (!res.ok)
|
|
263
|
+
return { halted: false, paused: false };
|
|
264
|
+
const data = res.data;
|
|
265
|
+
return {
|
|
266
|
+
halted: data.halted ?? false,
|
|
267
|
+
paused: data.paused ?? false,
|
|
268
|
+
reason: data.reason,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return { halted: false, paused: false };
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Wait for resume after pause.
|
|
277
|
+
*/
|
|
278
|
+
async waitForResume(pollIntervalMs = 2000) {
|
|
279
|
+
while (true) {
|
|
280
|
+
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
|
|
281
|
+
const status = await this.checkControl();
|
|
282
|
+
if (!status.paused) {
|
|
283
|
+
return 'resumed';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Transform the raw spec from REST /api/protocol into ProtocolResponse format.
|
|
290
|
+
*/
|
|
291
|
+
function buildFromRawSpec(data, role) {
|
|
292
|
+
if (!data.loaded || !data.spec)
|
|
293
|
+
return null;
|
|
294
|
+
const spec = data.spec;
|
|
295
|
+
const roleNames = Object.keys(spec.roles);
|
|
296
|
+
const roleName = roleNames.includes(role) ? role : roleNames[0];
|
|
297
|
+
const roleDef = spec.roles[roleName];
|
|
298
|
+
if (!roleDef)
|
|
299
|
+
return null;
|
|
300
|
+
const phaseNames = Object.keys(spec.phases);
|
|
301
|
+
const currentPhase = phaseNames[0]; // default to first phase
|
|
302
|
+
const phases = {};
|
|
303
|
+
for (const [name, def] of Object.entries(spec.phases)) {
|
|
304
|
+
phases[name] = { description: def.description, ...(def.terminal ? { terminal: true } : {}) };
|
|
305
|
+
}
|
|
306
|
+
// Extract rules for this role (keyed by phase)
|
|
307
|
+
const roleRules = spec.rules?.[roleName];
|
|
308
|
+
const rules = {};
|
|
309
|
+
if (roleRules) {
|
|
310
|
+
for (const [phase, rule] of Object.entries(roleRules)) {
|
|
311
|
+
rules[phase] = rule;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Extract wait spec and context from role definition (if present)
|
|
315
|
+
const wait = roleDef.wait;
|
|
316
|
+
const context = roleDef.context;
|
|
317
|
+
const temperature = roleDef.temperature;
|
|
318
|
+
const reasoning = roleDef.reasoning;
|
|
319
|
+
const reasoning_effort = roleDef.reasoning_effort;
|
|
320
|
+
return {
|
|
321
|
+
protocol: { name: spec.name, title: spec.title },
|
|
322
|
+
role: { name: roleName, description: roleDef.description },
|
|
323
|
+
current_phase: currentPhase,
|
|
324
|
+
instructions: `Follow the ${spec.title} protocol as the ${roleName} role.`,
|
|
325
|
+
phases,
|
|
326
|
+
...(spec.governance ? { governance: spec.governance } : {}),
|
|
327
|
+
...(data.team?.length ? { team: data.team } : {}),
|
|
328
|
+
...(Object.keys(rules).length > 0 ? { rules } : {}),
|
|
329
|
+
...(spec.resources ? { resources: spec.resources } : {}),
|
|
330
|
+
...(wait ? { wait } : {}),
|
|
331
|
+
...(context !== undefined ? { context } : {}),
|
|
332
|
+
...(temperature !== undefined ? { temperature } : {}),
|
|
333
|
+
...(reasoning !== undefined ? { reasoning } : {}),
|
|
334
|
+
...(reasoning_effort ? { reasoning_effort } : {}),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/agent/acp/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface WakeCondition {
|
|
2
|
+
types?: string[] | null;
|
|
3
|
+
timeout?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class WebSocketEventClient {
|
|
6
|
+
private ws;
|
|
7
|
+
private buffer;
|
|
8
|
+
private agentId;
|
|
9
|
+
private role;
|
|
10
|
+
private serverUrl;
|
|
11
|
+
private namespace;
|
|
12
|
+
private lastCursor;
|
|
13
|
+
private closed;
|
|
14
|
+
private reconnecting;
|
|
15
|
+
private lastInject;
|
|
16
|
+
private danceCallResolvers;
|
|
17
|
+
private danceTools;
|
|
18
|
+
/** Pending waitForWake resolvers */
|
|
19
|
+
private waiters;
|
|
20
|
+
constructor(serverUrl: string, namespace: string, agentId: string, role?: string);
|
|
21
|
+
/**
|
|
22
|
+
* Connect to incubator's /ws endpoint with optional replay cursor.
|
|
23
|
+
*/
|
|
24
|
+
connect(since?: number): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Attempt to reconnect with exponential backoff.
|
|
27
|
+
* Replays from last cursor to catch missed events.
|
|
28
|
+
*/
|
|
29
|
+
private reconnect;
|
|
30
|
+
/**
|
|
31
|
+
* Non-blocking drain: return + clear buffer as formatted strings.
|
|
32
|
+
* Same format as polling EventClient.drain().
|
|
33
|
+
*/
|
|
34
|
+
drain(): string[];
|
|
35
|
+
/**
|
|
36
|
+
* Blocking: resolve when a matching event arrives.
|
|
37
|
+
* Checks buffer first (resolves immediately if match exists).
|
|
38
|
+
*/
|
|
39
|
+
waitForWake(condition: WakeCondition): Promise<string[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the last inject string received with an event.
|
|
42
|
+
* Consumed on read — returns null on subsequent calls until a new inject arrives.
|
|
43
|
+
*/
|
|
44
|
+
getLastInject(): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Get dance tool definitions received from the server.
|
|
47
|
+
* Returns null if no dance tools were sent.
|
|
48
|
+
*/
|
|
49
|
+
getDanceTools(): import('../types.js').ToolDef[] | null;
|
|
50
|
+
/**
|
|
51
|
+
* Call a dance tool on the server via WebSocket.
|
|
52
|
+
* Returns a promise that resolves with the tool result.
|
|
53
|
+
*/
|
|
54
|
+
callDanceTool(tool: string, args: Record<string, unknown>): Promise<unknown>;
|
|
55
|
+
/**
|
|
56
|
+
* Close the WebSocket and resolve all pending waiters.
|
|
57
|
+
*/
|
|
58
|
+
close(): void;
|
|
59
|
+
/** Get the last known cursor position for reconnection. */
|
|
60
|
+
get cursor(): number;
|
|
61
|
+
/** Whether the WebSocket is currently connected. */
|
|
62
|
+
get connected(): boolean;
|
|
63
|
+
private formatEvent;
|
|
64
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { createTypeMatcher } from './event-matcher.js';
|
|
3
|
+
/**
|
|
4
|
+
* WebSocket-based event client that connects to incubator's /ws endpoint.
|
|
5
|
+
* Replaces polling with push-based event delivery for reactive agents.
|
|
6
|
+
*/
|
|
7
|
+
const MAX_RECONNECTS = 10;
|
|
8
|
+
const MAX_RECONNECT_DELAY = 30_000;
|
|
9
|
+
export class WebSocketEventClient {
|
|
10
|
+
ws = null;
|
|
11
|
+
buffer = [];
|
|
12
|
+
agentId;
|
|
13
|
+
role;
|
|
14
|
+
serverUrl;
|
|
15
|
+
namespace;
|
|
16
|
+
lastCursor = 0;
|
|
17
|
+
closed = false;
|
|
18
|
+
reconnecting = false;
|
|
19
|
+
lastInject = null;
|
|
20
|
+
danceCallResolvers = new Map();
|
|
21
|
+
danceTools = null;
|
|
22
|
+
/** Pending waitForWake resolvers */
|
|
23
|
+
waiters = [];
|
|
24
|
+
constructor(serverUrl, namespace, agentId, role) {
|
|
25
|
+
this.serverUrl = serverUrl;
|
|
26
|
+
this.namespace = namespace;
|
|
27
|
+
this.agentId = agentId;
|
|
28
|
+
this.role = role ?? '';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Connect to incubator's /ws endpoint with optional replay cursor.
|
|
32
|
+
*/
|
|
33
|
+
connect(since) {
|
|
34
|
+
if (this.closed)
|
|
35
|
+
return Promise.reject(new Error('Client is closed'));
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const wsUrl = this.serverUrl.replace(/^http/, 'ws');
|
|
38
|
+
const params = new URLSearchParams({
|
|
39
|
+
namespace: this.namespace,
|
|
40
|
+
agentId: this.agentId,
|
|
41
|
+
role: this.role,
|
|
42
|
+
...(since !== undefined ? { since: String(since) } : {}),
|
|
43
|
+
});
|
|
44
|
+
this.ws = new WebSocket(`${wsUrl}/ws?${params}`);
|
|
45
|
+
this.ws.on('open', () => resolve());
|
|
46
|
+
this.ws.on('error', (err) => reject(err));
|
|
47
|
+
this.ws.on('message', (data) => {
|
|
48
|
+
try {
|
|
49
|
+
const msg = JSON.parse(data.toString());
|
|
50
|
+
if (msg.type === 'ping' || msg.type === 'replay_done')
|
|
51
|
+
return;
|
|
52
|
+
// Handle dance_tools — store tool definitions from server
|
|
53
|
+
if (msg.type === 'dance_tools' && Array.isArray(msg.tools)) {
|
|
54
|
+
this.danceTools = msg.tools;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Handle dance_result — resolve pending callDanceTool promise
|
|
58
|
+
if (msg.type === 'dance_result' && typeof msg.callId === 'string') {
|
|
59
|
+
const resolver = this.danceCallResolvers.get(msg.callId);
|
|
60
|
+
if (resolver) {
|
|
61
|
+
this.danceCallResolvers.delete(msg.callId);
|
|
62
|
+
resolver(msg.result);
|
|
63
|
+
}
|
|
64
|
+
return; // Don't process as regular event
|
|
65
|
+
}
|
|
66
|
+
// Track inject from event messages
|
|
67
|
+
if (msg.type === 'event' && typeof msg.inject === 'string') {
|
|
68
|
+
this.lastInject = msg.inject;
|
|
69
|
+
}
|
|
70
|
+
// Unwrap incubator WS envelope: { type: 'event', event: {...} }
|
|
71
|
+
const inner = (msg.type === 'event' && msg.event) ? msg.event : msg;
|
|
72
|
+
const event = {
|
|
73
|
+
type: inner.type ?? inner.event_type ?? msg.type ?? '',
|
|
74
|
+
data: inner.data ?? inner,
|
|
75
|
+
agentId: inner.publishedBy ?? inner.agentId ?? inner.agent_id ?? '',
|
|
76
|
+
seq: inner.id ?? inner.seq ?? msg.seq ?? 0,
|
|
77
|
+
};
|
|
78
|
+
// Filter own events
|
|
79
|
+
if (event.agentId === this.agentId)
|
|
80
|
+
return;
|
|
81
|
+
// Track cursor
|
|
82
|
+
if (event.seq > this.lastCursor) {
|
|
83
|
+
this.lastCursor = event.seq;
|
|
84
|
+
}
|
|
85
|
+
// Check waiters first
|
|
86
|
+
let consumed = false;
|
|
87
|
+
for (let i = this.waiters.length - 1; i >= 0; i--) {
|
|
88
|
+
const waiter = this.waiters[i];
|
|
89
|
+
if (!waiter.matcher || waiter.matcher(event.type)) {
|
|
90
|
+
if (waiter.timer)
|
|
91
|
+
clearTimeout(waiter.timer);
|
|
92
|
+
this.waiters.splice(i, 1);
|
|
93
|
+
waiter.resolve([this.formatEvent(event)]);
|
|
94
|
+
consumed = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!consumed) {
|
|
99
|
+
this.buffer.push(event);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Ignore malformed messages
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
this.ws.on('close', () => {
|
|
107
|
+
this.ws = null;
|
|
108
|
+
// Auto-reconnect if not intentionally closed
|
|
109
|
+
if (!this.closed && !this.reconnecting) {
|
|
110
|
+
this.reconnect();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Attempt to reconnect with exponential backoff.
|
|
117
|
+
* Replays from last cursor to catch missed events.
|
|
118
|
+
*/
|
|
119
|
+
async reconnect() {
|
|
120
|
+
this.reconnecting = true;
|
|
121
|
+
for (let attempt = 1; attempt <= MAX_RECONNECTS; attempt++) {
|
|
122
|
+
if (this.closed)
|
|
123
|
+
break;
|
|
124
|
+
const delay = Math.min(1000 * Math.pow(2, attempt - 1), MAX_RECONNECT_DELAY);
|
|
125
|
+
await new Promise(r => setTimeout(r, delay));
|
|
126
|
+
if (this.closed)
|
|
127
|
+
break;
|
|
128
|
+
try {
|
|
129
|
+
await this.connect(this.lastCursor);
|
|
130
|
+
this.reconnecting = false;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// retry
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
this.reconnecting = false;
|
|
138
|
+
// Exhausted retries — waiters will stay blocked until timeout or close
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Non-blocking drain: return + clear buffer as formatted strings.
|
|
142
|
+
* Same format as polling EventClient.drain().
|
|
143
|
+
*/
|
|
144
|
+
drain() {
|
|
145
|
+
if (this.buffer.length === 0)
|
|
146
|
+
return [];
|
|
147
|
+
const events = this.buffer.splice(0);
|
|
148
|
+
return events.map(e => this.formatEvent(e));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Blocking: resolve when a matching event arrives.
|
|
152
|
+
* Checks buffer first (resolves immediately if match exists).
|
|
153
|
+
*/
|
|
154
|
+
waitForWake(condition) {
|
|
155
|
+
const matcher = condition.types
|
|
156
|
+
? createTypeMatcher(condition.types)
|
|
157
|
+
: null;
|
|
158
|
+
// Check buffer first
|
|
159
|
+
const matchIdx = this.buffer.findIndex(e => !matcher || matcher(e.type));
|
|
160
|
+
if (matchIdx !== -1) {
|
|
161
|
+
const event = this.buffer.splice(matchIdx, 1)[0];
|
|
162
|
+
return Promise.resolve([this.formatEvent(event)]);
|
|
163
|
+
}
|
|
164
|
+
// If closed, return immediately
|
|
165
|
+
if (this.closed || !this.ws) {
|
|
166
|
+
return Promise.resolve([]);
|
|
167
|
+
}
|
|
168
|
+
// Register waiter
|
|
169
|
+
return new Promise((resolve) => {
|
|
170
|
+
const waiter = { resolve, matcher };
|
|
171
|
+
if (condition.timeout && condition.timeout > 0) {
|
|
172
|
+
waiter.timer = setTimeout(() => {
|
|
173
|
+
const idx = this.waiters.indexOf(waiter);
|
|
174
|
+
if (idx !== -1)
|
|
175
|
+
this.waiters.splice(idx, 1);
|
|
176
|
+
resolve([]);
|
|
177
|
+
}, condition.timeout);
|
|
178
|
+
}
|
|
179
|
+
this.waiters.push(waiter);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get the last inject string received with an event.
|
|
184
|
+
* Consumed on read — returns null on subsequent calls until a new inject arrives.
|
|
185
|
+
*/
|
|
186
|
+
getLastInject() {
|
|
187
|
+
const inject = this.lastInject;
|
|
188
|
+
this.lastInject = null;
|
|
189
|
+
return inject;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get dance tool definitions received from the server.
|
|
193
|
+
* Returns null if no dance tools were sent.
|
|
194
|
+
*/
|
|
195
|
+
getDanceTools() {
|
|
196
|
+
return this.danceTools;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Call a dance tool on the server via WebSocket.
|
|
200
|
+
* Returns a promise that resolves with the tool result.
|
|
201
|
+
*/
|
|
202
|
+
async callDanceTool(tool, args) {
|
|
203
|
+
const callId = `dance_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
206
|
+
reject(new Error('WebSocket not connected'));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Timeout after 30s
|
|
210
|
+
const timer = setTimeout(() => {
|
|
211
|
+
this.danceCallResolvers.delete(callId);
|
|
212
|
+
reject(new Error(`Dance tool call "${tool}" timed out`));
|
|
213
|
+
}, 30_000);
|
|
214
|
+
this.danceCallResolvers.set(callId, (result) => {
|
|
215
|
+
clearTimeout(timer);
|
|
216
|
+
resolve(result);
|
|
217
|
+
});
|
|
218
|
+
this.ws.send(JSON.stringify({
|
|
219
|
+
type: 'dance_call',
|
|
220
|
+
tool,
|
|
221
|
+
args,
|
|
222
|
+
callId,
|
|
223
|
+
agentId: this.agentId,
|
|
224
|
+
role: this.role,
|
|
225
|
+
}));
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Close the WebSocket and resolve all pending waiters.
|
|
230
|
+
*/
|
|
231
|
+
close() {
|
|
232
|
+
this.closed = true;
|
|
233
|
+
// Resolve all pending waiters with empty
|
|
234
|
+
for (const waiter of this.waiters) {
|
|
235
|
+
if (waiter.timer)
|
|
236
|
+
clearTimeout(waiter.timer);
|
|
237
|
+
waiter.resolve([]);
|
|
238
|
+
}
|
|
239
|
+
this.waiters = [];
|
|
240
|
+
// Reject all pending dance calls
|
|
241
|
+
for (const [, resolver] of this.danceCallResolvers) {
|
|
242
|
+
resolver({ error: 'Client closed' });
|
|
243
|
+
}
|
|
244
|
+
this.danceCallResolvers.clear();
|
|
245
|
+
if (this.ws) {
|
|
246
|
+
this.ws.close();
|
|
247
|
+
this.ws = null;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** Get the last known cursor position for reconnection. */
|
|
251
|
+
get cursor() {
|
|
252
|
+
return this.lastCursor;
|
|
253
|
+
}
|
|
254
|
+
/** Whether the WebSocket is currently connected. */
|
|
255
|
+
get connected() {
|
|
256
|
+
return this.ws?.readyState === WebSocket.OPEN;
|
|
257
|
+
}
|
|
258
|
+
formatEvent(e) {
|
|
259
|
+
const payload = typeof e.data === 'string' ? e.data : JSON.stringify(e.data);
|
|
260
|
+
return `Event from ${e.agentId}: [${e.type}] ${payload}`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=ws-event-client.js.map
|