@coderage-labs/openclaw-fleet-agent 0.7.1
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 +59 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +974 -0
- package/dist/index.js.map +1 -0
- package/dist/openclaw.plugin.json +34 -0
- package/openclaw.plugin.json +34 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# openclaw-fleet-agent
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin for fleet-managed instances. Provides hierarchical team communication with ACL, status reporting, and maintenance support.
|
|
4
|
+
|
|
5
|
+
Unlike the peer-to-peer [openclaw-agent-mesh](https://github.com/Kriskit/openclaw-agent-mesh), this plugin is designed for managed fleet deployments where fleet-control provisions instances with explicit contact lists.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Direct instance-to-instance communication** via OpenClaw hooks endpoints
|
|
10
|
+
- **ACL enforcement** — only configured contacts can send/receive tasks
|
|
11
|
+
- **Org-level auth** — shared hooks token per organisation
|
|
12
|
+
- **Status reporting** — `/fleet/status` for idle/busy/draining state
|
|
13
|
+
- **Maintenance support** — `/fleet/drain` to gracefully stop accepting work
|
|
14
|
+
- **Health endpoint** — `/fleet/health` for fleet-control polling
|
|
15
|
+
|
|
16
|
+
## Tools
|
|
17
|
+
|
|
18
|
+
| Tool | Description |
|
|
19
|
+
|------|-------------|
|
|
20
|
+
| `fleet_task(target, message)` | Send async task to a contact. Results delivered automatically. |
|
|
21
|
+
| `fleet_contacts()` | List configured contacts and their status. |
|
|
22
|
+
|
|
23
|
+
## Configuration
|
|
24
|
+
|
|
25
|
+
In `openclaw.json` (generated by fleet-control):
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"plugins": {
|
|
30
|
+
"entries": {
|
|
31
|
+
"openclaw-fleet-agent": {
|
|
32
|
+
"enabled": true,
|
|
33
|
+
"config": {
|
|
34
|
+
"org": "fixli",
|
|
35
|
+
"instanceName": "forge",
|
|
36
|
+
"role": "development",
|
|
37
|
+
"hooksToken": "${FLEET_HOOKS_TOKEN}",
|
|
38
|
+
"contacts": [
|
|
39
|
+
{ "name": "nexus", "url": "http://nexus:18789", "role": "project-manager" }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How It Works
|
|
49
|
+
|
|
50
|
+
1. Fleet-control spawns instances with contact lists and org tokens
|
|
51
|
+
2. Plugin registers HTTP routes on the gateway (`/hooks/fleet/*`)
|
|
52
|
+
3. Instances communicate directly via these endpoints
|
|
53
|
+
4. Auth: org-level hooks token. ACL: contact list in config.
|
|
54
|
+
5. Results injected into caller's session via `callGateway('agent')`
|
|
55
|
+
|
|
56
|
+
## Related
|
|
57
|
+
|
|
58
|
+
- [openclaw-fleet](https://github.com/Kriskit/openclaw-fleet) — Fleet control plane
|
|
59
|
+
- [openclaw-agent-mesh](https://github.com/Kriskit/openclaw-agent-mesh) — Standalone peer-to-peer mesh (no fleet required)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openclaw-fleet-agent — Fleet communication plugin for managed OpenClaw instances.
|
|
3
|
+
*
|
|
4
|
+
* Event-driven architecture:
|
|
5
|
+
* - Inbound tasks create an InboundContext, fire a dispatchTurn, return immediately
|
|
6
|
+
* - Outbound fleet_task calls create OutboundTask entries, return immediately
|
|
7
|
+
* - Results arriving at /fleet/result trigger new dispatchTurn calls or inject via agent RPC
|
|
8
|
+
* - Finalization (callback) happens when TASK_COMPLETE + no pending sub-tasks
|
|
9
|
+
*
|
|
10
|
+
* No blocking loops. Each event fires a turn and returns.
|
|
11
|
+
*/
|
|
12
|
+
export default function register(api: any): void;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8VH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QAsuBxC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,974 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openclaw-fleet-agent — Fleet communication plugin for managed OpenClaw instances.
|
|
3
|
+
*
|
|
4
|
+
* Event-driven architecture:
|
|
5
|
+
* - Inbound tasks create an InboundContext, fire a dispatchTurn, return immediately
|
|
6
|
+
* - Outbound fleet_task calls create OutboundTask entries, return immediately
|
|
7
|
+
* - Results arriving at /fleet/result trigger new dispatchTurn calls or inject via agent RPC
|
|
8
|
+
* - Finalization (callback) happens when TASK_COMPLETE + no pending sub-tasks
|
|
9
|
+
*
|
|
10
|
+
* No blocking loops. Each event fires a turn and returns.
|
|
11
|
+
*/
|
|
12
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
13
|
+
import { writeFileSync, readFileSync, renameSync, existsSync, mkdirSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { generateId, readBody, sendJson, getOrCreateGlobalMap, decodeAttachments, decodeAttachmentsAsMarkers, dispatchFleetTask, callGatewayRpc, createInboundContext, dispatchTurn, finalizeInbound, maybeFinalize, resetInboundIdleTimer, resetPingWatchdog, serializeTaskMap, deserializeTaskMap, TASK_STALE_MS, FLEET_OUTBOUND_SYM, FLEET_INBOUND_SYM, } from './shared-dist/index.js';
|
|
16
|
+
// ── Task reporting to control plane ─────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* Report a task event to the fleet control plane API.
|
|
19
|
+
* Fire-and-forget — failures are logged but don't block.
|
|
20
|
+
*/
|
|
21
|
+
async function reportTask(action, data) {
|
|
22
|
+
if (!_config?.fleetApiUrl)
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
const url = action === 'create'
|
|
26
|
+
? `${_config.fleetApiUrl}/api/tasks`
|
|
27
|
+
: `${_config.fleetApiUrl}/api/tasks/${encodeURIComponent(data.id)}`;
|
|
28
|
+
const method = action === 'create' ? 'POST' : 'PUT';
|
|
29
|
+
await fetch(url, {
|
|
30
|
+
method,
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
..._config.fleetApiToken ? { 'Authorization': `Bearer ${_config.fleetApiToken}` } : {},
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(data),
|
|
36
|
+
signal: AbortSignal.timeout(5_000),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
_logger.warn(`[fleet-agent] Failed to report task: ${err.message}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ── State (globalThis to survive jiti re-evaluation) ────────────────
|
|
44
|
+
const outboundTasks = getOrCreateGlobalMap(FLEET_OUTBOUND_SYM);
|
|
45
|
+
const inboundContexts = getOrCreateGlobalMap(FLEET_INBOUND_SYM);
|
|
46
|
+
let _config = null;
|
|
47
|
+
let _draining = false;
|
|
48
|
+
let _activeTasks = 0;
|
|
49
|
+
let _api = null;
|
|
50
|
+
let _logger = console;
|
|
51
|
+
// ── Task persistence ────────────────────────────────────────────────
|
|
52
|
+
const _dataDir = join(process.env.HOME || '/home/node', '.openclaw');
|
|
53
|
+
const _tasksFilePath = join(_dataDir, 'fleet-agent-tasks.json');
|
|
54
|
+
/** Atomically save outbound tasks and inbound contexts to disk */
|
|
55
|
+
function saveAgentTasks() {
|
|
56
|
+
try {
|
|
57
|
+
mkdirSync(_dataDir, { recursive: true });
|
|
58
|
+
// Serialize outbound tasks (already simple data)
|
|
59
|
+
const outboundData = new Map();
|
|
60
|
+
for (const [id, task] of outboundTasks) {
|
|
61
|
+
outboundData.set(id, {
|
|
62
|
+
taskId: task.taskId,
|
|
63
|
+
target: task.target,
|
|
64
|
+
sessionKey: task.sessionKey,
|
|
65
|
+
sentAt: Date.now(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// Serialize inbound contexts (only persistable fields)
|
|
69
|
+
const inboundData = new Map();
|
|
70
|
+
for (const [key, ctx] of inboundContexts) {
|
|
71
|
+
inboundData.set(key, {
|
|
72
|
+
sessionKey: ctx.sessionKey,
|
|
73
|
+
callbackUrl: ctx.callbackUrl,
|
|
74
|
+
callbackToken: ctx.hooksToken,
|
|
75
|
+
taskId: ctx.taskId,
|
|
76
|
+
startedAt: Date.now(),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const data = JSON.stringify({
|
|
80
|
+
outbound: JSON.parse(serializeTaskMap(outboundData)),
|
|
81
|
+
inbound: JSON.parse(serializeTaskMap(inboundData)),
|
|
82
|
+
}, null, 2);
|
|
83
|
+
const tmpPath = _tasksFilePath + '.tmp';
|
|
84
|
+
writeFileSync(tmpPath, data, 'utf-8');
|
|
85
|
+
renameSync(tmpPath, _tasksFilePath);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
_logger.warn(`[fleet-agent] Failed to save tasks: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Load persisted tasks from disk and send error callbacks for restored inbound contexts */
|
|
92
|
+
function loadAgentTasks() {
|
|
93
|
+
try {
|
|
94
|
+
if (!existsSync(_tasksFilePath))
|
|
95
|
+
return;
|
|
96
|
+
const raw = readFileSync(_tasksFilePath, 'utf-8');
|
|
97
|
+
const data = JSON.parse(raw);
|
|
98
|
+
// Restore outbound tasks
|
|
99
|
+
if (data.outbound) {
|
|
100
|
+
const restored = deserializeTaskMap(JSON.stringify(data.outbound));
|
|
101
|
+
let count = 0;
|
|
102
|
+
for (const [id, task] of restored) {
|
|
103
|
+
outboundTasks.set(id, {
|
|
104
|
+
taskId: task.taskId,
|
|
105
|
+
target: task.target,
|
|
106
|
+
sessionKey: task.sessionKey,
|
|
107
|
+
});
|
|
108
|
+
count++;
|
|
109
|
+
}
|
|
110
|
+
if (count > 0)
|
|
111
|
+
_logger.info(`[fleet-agent] Restored ${count} outbound tasks from disk`);
|
|
112
|
+
}
|
|
113
|
+
// Restore inbound contexts — send error callbacks since we can't resume them
|
|
114
|
+
if (data.inbound) {
|
|
115
|
+
const restored = deserializeTaskMap(JSON.stringify(data.inbound));
|
|
116
|
+
let count = 0;
|
|
117
|
+
for (const [, ctx] of restored) {
|
|
118
|
+
if (ctx.callbackUrl) {
|
|
119
|
+
_logger.info(`[fleet-agent] Sending restart error callback for inbound task ${ctx.taskId}`);
|
|
120
|
+
fetch(ctx.callbackUrl, {
|
|
121
|
+
method: 'POST',
|
|
122
|
+
headers: {
|
|
123
|
+
'Content-Type': 'application/json',
|
|
124
|
+
'Authorization': `Bearer ${ctx.callbackToken || ''}`,
|
|
125
|
+
},
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
taskId: ctx.taskId,
|
|
128
|
+
from: _config?.instanceName || 'unknown',
|
|
129
|
+
status: 'failed',
|
|
130
|
+
error: 'Task lost due to agent restart. Please retry.',
|
|
131
|
+
}),
|
|
132
|
+
}).catch((err) => {
|
|
133
|
+
_logger.warn(`[fleet-agent] Failed to send restart callback for ${ctx.taskId}: ${err.message}`);
|
|
134
|
+
});
|
|
135
|
+
count++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (count > 0)
|
|
139
|
+
_logger.info(`[fleet-agent] Sent ${count} restart error callbacks for inbound tasks`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
_logger.warn(`[fleet-agent] Failed to load tasks: ${err.message}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Remove stale outbound tasks (>2h old) on startup */
|
|
147
|
+
function cleanupStaleAgentTasks() {
|
|
148
|
+
const now = Date.now();
|
|
149
|
+
let removed = 0;
|
|
150
|
+
for (const [id, task] of outboundTasks) {
|
|
151
|
+
const sentAt = task.sentAt;
|
|
152
|
+
if (sentAt && now - sentAt > TASK_STALE_MS) {
|
|
153
|
+
outboundTasks.delete(id);
|
|
154
|
+
removed++;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (removed > 0) {
|
|
158
|
+
_logger.info(`[fleet-agent] Cleaned up ${removed} stale outbound tasks (>2h old)`);
|
|
159
|
+
saveAgentTasks();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
163
|
+
function getContact(name) {
|
|
164
|
+
return _config?.contacts.find(c => c.name.toLowerCase() === name.toLowerCase());
|
|
165
|
+
}
|
|
166
|
+
// ── Dynamic Fleet Tool Loading ──────────────────────────────────────
|
|
167
|
+
// Tool names that are already registered natively (skip if returned by API)
|
|
168
|
+
const NATIVE_TOOLS = new Set(['fleet_task', 'fleet_contacts', 'fleet_share', 'fleet_steer', 'fleet_status']);
|
|
169
|
+
async function loadFleetTools(api) {
|
|
170
|
+
if (!_config?.fleetApiUrl || !_config?.fleetApiToken)
|
|
171
|
+
return;
|
|
172
|
+
try {
|
|
173
|
+
const resp = await fetch(`${_config.fleetApiUrl}/api/meta/tools`, {
|
|
174
|
+
headers: {
|
|
175
|
+
'Authorization': `Bearer ${_config.fleetApiToken}`,
|
|
176
|
+
'X-Agent-Name': _config.instanceName,
|
|
177
|
+
},
|
|
178
|
+
signal: AbortSignal.timeout(10_000),
|
|
179
|
+
});
|
|
180
|
+
if (!resp.ok) {
|
|
181
|
+
_logger.warn(`[fleet-agent] Failed to fetch fleet tools: ${resp.status}`);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const tools = (await resp.json());
|
|
185
|
+
let registered = 0;
|
|
186
|
+
for (const def of tools) {
|
|
187
|
+
if (NATIVE_TOOLS.has(def.name))
|
|
188
|
+
continue; // Already registered natively
|
|
189
|
+
// Convert tool def parameters to JSON Schema for registerTool
|
|
190
|
+
const properties = {};
|
|
191
|
+
const required = [];
|
|
192
|
+
for (const p of def.parameters) {
|
|
193
|
+
properties[p.name] = { type: p.type, description: p.description };
|
|
194
|
+
if (p.required)
|
|
195
|
+
required.push(p.name);
|
|
196
|
+
}
|
|
197
|
+
api.registerTool({
|
|
198
|
+
name: def.name,
|
|
199
|
+
description: def.description,
|
|
200
|
+
parameters: { type: 'object', properties, ...(required.length > 0 ? { required } : {}) },
|
|
201
|
+
execute: async (_id, args) => {
|
|
202
|
+
return executeFleetTool(def, args);
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
registered++;
|
|
206
|
+
}
|
|
207
|
+
_logger.info(`[fleet-agent] Loaded ${registered} fleet tools from control plane`);
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
_logger.warn(`[fleet-agent] Error loading fleet tools: ${err.message}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function executeFleetTool(def, args) {
|
|
214
|
+
if (!_config?.fleetApiUrl || !_config?.fleetApiToken) {
|
|
215
|
+
return { error: 'Fleet API not configured' };
|
|
216
|
+
}
|
|
217
|
+
// Resolve path params
|
|
218
|
+
let resolvedPath = def.path;
|
|
219
|
+
const pathParams = new Set();
|
|
220
|
+
const pathParamRegex = /:(\w+)/g;
|
|
221
|
+
let match;
|
|
222
|
+
while ((match = pathParamRegex.exec(def.path)) !== null) {
|
|
223
|
+
const paramName = match[1];
|
|
224
|
+
const value = args[paramName] ?? args.target;
|
|
225
|
+
if (!value)
|
|
226
|
+
return { error: `Missing parameter: ${paramName}` };
|
|
227
|
+
resolvedPath = resolvedPath.replace(`:${paramName}`, encodeURIComponent(value));
|
|
228
|
+
pathParams.add(paramName);
|
|
229
|
+
}
|
|
230
|
+
pathParams.add('target');
|
|
231
|
+
const url = `${_config.fleetApiUrl}${resolvedPath}`;
|
|
232
|
+
const headers = {
|
|
233
|
+
'Authorization': `Bearer ${_config.fleetApiToken}`,
|
|
234
|
+
'X-Agent-Name': _config.instanceName,
|
|
235
|
+
};
|
|
236
|
+
try {
|
|
237
|
+
if (def.method === 'GET') {
|
|
238
|
+
const queryParams = [];
|
|
239
|
+
for (const p of def.parameters) {
|
|
240
|
+
if (args[p.name] !== undefined && !pathParams.has(p.name)) {
|
|
241
|
+
queryParams.push(`${p.name}=${encodeURIComponent(args[p.name])}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const queryStr = queryParams.length > 0 ? `?${queryParams.join('&')}` : '';
|
|
245
|
+
const resp = await fetch(`${url}${queryStr}`, { headers, signal: AbortSignal.timeout(30_000) });
|
|
246
|
+
if (!resp.ok)
|
|
247
|
+
return { error: `Fleet API ${resp.status}: ${await resp.text().catch(() => '')}` };
|
|
248
|
+
return resp.json().catch(() => ({ status: 'ok' }));
|
|
249
|
+
}
|
|
250
|
+
// POST/PUT/DELETE
|
|
251
|
+
const body = {};
|
|
252
|
+
for (const p of def.parameters) {
|
|
253
|
+
if (args[p.name] !== undefined && !pathParams.has(p.name)) {
|
|
254
|
+
body[p.name] = args[p.name];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const resp = await fetch(url, {
|
|
258
|
+
method: def.method,
|
|
259
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
260
|
+
body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,
|
|
261
|
+
signal: AbortSignal.timeout(60_000),
|
|
262
|
+
});
|
|
263
|
+
if (!resp.ok)
|
|
264
|
+
return { error: `Fleet API ${resp.status}: ${await resp.text().catch(() => '')}` };
|
|
265
|
+
const text = await resp.text();
|
|
266
|
+
try {
|
|
267
|
+
return JSON.parse(text);
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return { status: 'ok' };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
return { error: `Fleet API request failed: ${err.message}` };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// ── Plugin Entry ────────────────────────────────────────────────────
|
|
278
|
+
export default function register(api) {
|
|
279
|
+
_api = api;
|
|
280
|
+
_logger = api.logger ?? console;
|
|
281
|
+
const pluginConfig = api.pluginConfig || api.config?.plugins?.entries?.['openclaw-fleet-agent']?.config || {};
|
|
282
|
+
_config = {
|
|
283
|
+
org: pluginConfig.org || 'default',
|
|
284
|
+
instanceName: pluginConfig.instanceName || 'unknown',
|
|
285
|
+
role: pluginConfig.role || 'general',
|
|
286
|
+
hooksToken: pluginConfig.hooksToken || '',
|
|
287
|
+
contacts: pluginConfig.contacts || [],
|
|
288
|
+
progressTimeoutMs: pluginConfig.progressTimeoutMs ?? pluginConfig.idleTimeoutMs ?? 600_000,
|
|
289
|
+
pingWatchdogMs: pluginConfig.pingWatchdogMs ?? 60_000,
|
|
290
|
+
hardTimeoutMs: pluginConfig.hardTimeoutMs ?? 1_800_000,
|
|
291
|
+
fleetApiUrl: pluginConfig.fleetApiUrl || '',
|
|
292
|
+
fleetApiToken: pluginConfig.fleetApiToken || '',
|
|
293
|
+
projects: pluginConfig.projects || [],
|
|
294
|
+
};
|
|
295
|
+
_logger.info(`[fleet-agent] ${_config.instanceName} (${_config.role}) — ${_config.contacts.length} contacts`);
|
|
296
|
+
// ── AsyncLocalStorage for session key propagation ───────────────
|
|
297
|
+
// Solves the concurrent inbound task problem: when multiple sessions
|
|
298
|
+
// are active simultaneously, tool handlers need to know which session
|
|
299
|
+
// invoked them. ALS propagates the session key through the async chain
|
|
300
|
+
// from beforeAgentTurn → tool execution without global state races.
|
|
301
|
+
const turnSessionStore = new AsyncLocalStorage();
|
|
302
|
+
if (typeof api.registerHook === 'function') {
|
|
303
|
+
api.registerHook('beforeAgentTurn', (context) => {
|
|
304
|
+
if (context?.sessionKey) {
|
|
305
|
+
turnSessionStore.enterWith(context.sessionKey);
|
|
306
|
+
}
|
|
307
|
+
// Reset idle timer — agent is taking a turn
|
|
308
|
+
for (const inbound of inboundContexts.values()) {
|
|
309
|
+
if (!inbound.finalized)
|
|
310
|
+
resetInboundIdleTimer(inbound, _logger);
|
|
311
|
+
}
|
|
312
|
+
}, { name: 'fleet-agent-session-tracker' });
|
|
313
|
+
api.registerHook('beforeToolCall', (context) => {
|
|
314
|
+
// Reset idle timer — agent is calling a tool (may be long-running like npm install)
|
|
315
|
+
for (const inbound of inboundContexts.values()) {
|
|
316
|
+
if (!inbound.finalized)
|
|
317
|
+
resetInboundIdleTimer(inbound, _logger);
|
|
318
|
+
}
|
|
319
|
+
}, { name: 'fleet-agent-tool-progress' });
|
|
320
|
+
_logger.info('[fleet-agent] Registered beforeAgentTurn + beforeToolCall hooks');
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
_logger.warn('[fleet-agent] registerHook not available — session key propagation disabled');
|
|
324
|
+
}
|
|
325
|
+
// ── Tool: fleet_task ────────────────────────────────────────────
|
|
326
|
+
api.registerTool({
|
|
327
|
+
name: 'fleet_task',
|
|
328
|
+
description: 'Send an async task to a fleet contact. Results are delivered automatically when complete. Use this to delegate work to other teams in your fleet.',
|
|
329
|
+
parameters: {
|
|
330
|
+
type: 'object',
|
|
331
|
+
properties: {
|
|
332
|
+
target: { type: 'string', description: 'Contact name to send the task to' },
|
|
333
|
+
message: { type: 'string', description: 'Task message/instructions' },
|
|
334
|
+
project: { type: 'string', description: 'Project name for context injection (optional)' },
|
|
335
|
+
},
|
|
336
|
+
required: ['target', 'message'],
|
|
337
|
+
},
|
|
338
|
+
execute: async (_id, args, context) => {
|
|
339
|
+
if (_draining)
|
|
340
|
+
return { error: 'Instance is draining — not accepting new outbound tasks' };
|
|
341
|
+
const contact = getContact(args.target);
|
|
342
|
+
if (!contact) {
|
|
343
|
+
const available = _config.contacts.map(c => `${c.name} (${c.role})`).join(', ');
|
|
344
|
+
return { error: `Unknown contact: ${args.target}. Available: ${available}` };
|
|
345
|
+
}
|
|
346
|
+
const taskId = generateId();
|
|
347
|
+
const selfUrl = `http://fleet-${_config.instanceName}:18789`;
|
|
348
|
+
// Resolve session key: prefer context, then ALS (from beforeAgentTurn hook), then fallback
|
|
349
|
+
let sessionKey = context?.sessionKey || turnSessionStore.getStore();
|
|
350
|
+
if (!sessionKey) {
|
|
351
|
+
// Final fallback: if there's exactly one inbound context, use it
|
|
352
|
+
if (inboundContexts.size === 1) {
|
|
353
|
+
sessionKey = [...inboundContexts.keys()][0];
|
|
354
|
+
}
|
|
355
|
+
else if (inboundContexts.size > 1) {
|
|
356
|
+
_logger.warn(`[fleet-agent] fleet_task called without context.sessionKey or ALS, and ${inboundContexts.size} active inbound contexts — picking first`);
|
|
357
|
+
sessionKey = [...inboundContexts.keys()][0]; // best effort
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
sessionKey = 'unknown';
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// Track outbound
|
|
364
|
+
outboundTasks.set(taskId, { taskId, sessionKey, target: args.target });
|
|
365
|
+
saveAgentTasks();
|
|
366
|
+
// If there's an inbound context for this session, add to its pending sub-tasks
|
|
367
|
+
const inbound = inboundContexts.get(sessionKey);
|
|
368
|
+
if (inbound) {
|
|
369
|
+
inbound.pendingSubTasks.add(taskId);
|
|
370
|
+
_logger.info(`[fleet-agent] Outbound ${taskId} to ${args.target} tracked as sub-task of inbound ${inbound.taskId}`);
|
|
371
|
+
}
|
|
372
|
+
const result = await dispatchFleetTask({
|
|
373
|
+
targetUrl: contact.url,
|
|
374
|
+
taskId,
|
|
375
|
+
from: _config.instanceName,
|
|
376
|
+
fromRole: _config.role,
|
|
377
|
+
message: args.message,
|
|
378
|
+
callbackUrl: `${selfUrl}/fleet/result`,
|
|
379
|
+
hooksToken: _config.hooksToken,
|
|
380
|
+
// Include targetAgent so multi-agent instances can route to the correct agent
|
|
381
|
+
targetAgent: args.target,
|
|
382
|
+
...(args.project ? { project: args.project } : {}),
|
|
383
|
+
}, _logger);
|
|
384
|
+
if (!result.ok) {
|
|
385
|
+
outboundTasks.delete(taskId);
|
|
386
|
+
saveAgentTasks();
|
|
387
|
+
if (inbound)
|
|
388
|
+
inbound.pendingSubTasks.delete(taskId);
|
|
389
|
+
return { error: `Failed to send task to ${args.target}: ${result.error}` };
|
|
390
|
+
}
|
|
391
|
+
_logger.info(`[fleet-agent] Task ${taskId} sent to ${args.target} (session: ${sessionKey})`);
|
|
392
|
+
// Report delegation to control plane
|
|
393
|
+
reportTask('create', {
|
|
394
|
+
id: taskId,
|
|
395
|
+
fromAgent: _config.instanceName,
|
|
396
|
+
toAgent: args.target,
|
|
397
|
+
taskText: args.message.slice(0, 5000),
|
|
398
|
+
status: 'pending',
|
|
399
|
+
...(args.project ? { projectId: args.project } : {}),
|
|
400
|
+
});
|
|
401
|
+
return { taskId, target: args.target, status: 'sent', message: `Task sent to ${args.target}. Result will be delivered when complete.` };
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
// ── Tool: fleet_contacts ────────────────────────────────────────
|
|
405
|
+
api.registerTool({
|
|
406
|
+
name: 'fleet_contacts',
|
|
407
|
+
description: 'List your fleet contacts — the teams you can communicate with.',
|
|
408
|
+
parameters: { type: 'object', properties: {} },
|
|
409
|
+
execute: async () => ({
|
|
410
|
+
contacts: (_config?.contacts || []).map(c => ({ name: c.name, role: c.role || 'unknown', url: c.url })),
|
|
411
|
+
}),
|
|
412
|
+
});
|
|
413
|
+
// ── Tool: fleet_share ──────────────────────────────────────────
|
|
414
|
+
api.registerTool({
|
|
415
|
+
name: 'fleet_share',
|
|
416
|
+
description: 'Share a file from your workspace so other agents can access it. Returns a reference marker to include in task messages. The receiving agent\'s fleet plugin will auto-download the file to their workspace.',
|
|
417
|
+
parameters: {
|
|
418
|
+
type: 'object',
|
|
419
|
+
properties: {
|
|
420
|
+
path: { type: 'string', description: 'Path to the file to share (absolute or relative to workspace)' },
|
|
421
|
+
},
|
|
422
|
+
required: ['path'],
|
|
423
|
+
},
|
|
424
|
+
execute: async (_id, args) => {
|
|
425
|
+
if (!args?.path)
|
|
426
|
+
return { error: 'Missing path' };
|
|
427
|
+
if (!_config?.fleetApiUrl)
|
|
428
|
+
return { error: 'Fleet API URL not configured' };
|
|
429
|
+
try {
|
|
430
|
+
const res = await fetch(`${_config.fleetApiUrl}/api/files/share`, {
|
|
431
|
+
method: 'POST',
|
|
432
|
+
headers: {
|
|
433
|
+
'Content-Type': 'application/json',
|
|
434
|
+
...(_config.fleetApiToken ? { 'Authorization': `Bearer ${_config.fleetApiToken}` } : {}),
|
|
435
|
+
},
|
|
436
|
+
body: JSON.stringify({ agent: _config.instanceName, path: args.path }),
|
|
437
|
+
signal: AbortSignal.timeout(10_000),
|
|
438
|
+
});
|
|
439
|
+
const data = await res.json();
|
|
440
|
+
if (!res.ok)
|
|
441
|
+
return { error: data.error || `Share failed (${res.status})` };
|
|
442
|
+
return {
|
|
443
|
+
shared: true,
|
|
444
|
+
ref: data.ref,
|
|
445
|
+
filename: data.filename,
|
|
446
|
+
marker: data.marker,
|
|
447
|
+
instructions: `Include "${data.marker}" in your task message. The receiving agent will automatically get the file downloaded to their workspace.`,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
catch (err) {
|
|
451
|
+
return { error: `Share failed: ${err.message}` };
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
// ── Tool: fleet_steer ──────────────────────────────────────────
|
|
456
|
+
api.registerTool({
|
|
457
|
+
name: 'fleet_steer',
|
|
458
|
+
description: 'Inject a message into another agent\'s active task. Use to course-correct, provide additional context, or tell an agent to retry something.',
|
|
459
|
+
parameters: {
|
|
460
|
+
type: 'object',
|
|
461
|
+
properties: {
|
|
462
|
+
target: { type: 'string', description: 'Agent name to steer' },
|
|
463
|
+
taskId: { type: 'string', description: 'Task ID to steer (required — check your outbound tasks)' },
|
|
464
|
+
message: { type: 'string', description: 'Message to inject' },
|
|
465
|
+
},
|
|
466
|
+
required: ['target', 'taskId', 'message'],
|
|
467
|
+
},
|
|
468
|
+
execute: async (_id, args) => {
|
|
469
|
+
if (!args?.target || !args?.taskId || !args?.message)
|
|
470
|
+
return { error: 'Missing target, taskId, or message' };
|
|
471
|
+
const contact = _config?.contacts.find(c => c.name.toLowerCase() === args.target.toLowerCase());
|
|
472
|
+
if (!contact)
|
|
473
|
+
return { error: `No contact found for ${args.target}. Available: ${_config?.contacts.map(c => c.name).join(', ')}` };
|
|
474
|
+
try {
|
|
475
|
+
const res = await fetch(`${contact.url}/fleet/steer`, {
|
|
476
|
+
method: 'POST',
|
|
477
|
+
headers: {
|
|
478
|
+
'Content-Type': 'application/json',
|
|
479
|
+
'Authorization': `Bearer ${_config.hooksToken}`,
|
|
480
|
+
},
|
|
481
|
+
body: JSON.stringify({ taskId: args.taskId, message: args.message }),
|
|
482
|
+
signal: AbortSignal.timeout(10_000),
|
|
483
|
+
});
|
|
484
|
+
const data = await res.json();
|
|
485
|
+
if (!res.ok)
|
|
486
|
+
return { error: data.error || `Steer failed (${res.status})` };
|
|
487
|
+
return { status: 'steered', taskId: args.taskId, target: args.target };
|
|
488
|
+
}
|
|
489
|
+
catch (err) {
|
|
490
|
+
return { error: `Failed to steer ${args.target}: ${err.message}` };
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
// ── Tool: fleet_status ──────────────────────────────────────────
|
|
495
|
+
api.registerTool({
|
|
496
|
+
name: 'fleet_status',
|
|
497
|
+
description: 'Check the status of fleet instances.',
|
|
498
|
+
parameters: { type: 'object', properties: {} },
|
|
499
|
+
execute: async () => ({
|
|
500
|
+
instanceName: _config.instanceName,
|
|
501
|
+
role: _config.role,
|
|
502
|
+
status: _draining ? 'draining' : (_activeTasks > 0 ? 'busy' : 'idle'),
|
|
503
|
+
activeTasks: _activeTasks,
|
|
504
|
+
inboundContexts: inboundContexts.size,
|
|
505
|
+
outboundPending: outboundTasks.size,
|
|
506
|
+
contacts: _config.contacts.map(c => ({ name: c.name, role: c.role })),
|
|
507
|
+
}),
|
|
508
|
+
});
|
|
509
|
+
// ── Dynamic tool loading from fleet control ────────────────────
|
|
510
|
+
// Fetch tool definitions from /api/meta/tools, filtered by role.
|
|
511
|
+
// These are proxy tools (issue tracker, etc.) that agents use
|
|
512
|
+
// without seeing credentials.
|
|
513
|
+
if (_config.fleetApiUrl && _config.fleetApiToken) {
|
|
514
|
+
loadFleetTools(api).catch(err => {
|
|
515
|
+
_logger.warn(`[fleet-agent] Failed to load fleet tools: ${err.message}`);
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
// ── HTTP Routes ─────────────────────────────────────────────────
|
|
519
|
+
if (typeof api.registerHttpRoute !== 'function') {
|
|
520
|
+
_logger.warn('[fleet-agent] registerHttpRoute not available — HTTP endpoints disabled');
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
// ── HTTP: Receive task ──────────────────────────────────────────
|
|
524
|
+
api.registerHttpRoute({
|
|
525
|
+
auth: 'plugin',
|
|
526
|
+
path: '/fleet/task',
|
|
527
|
+
handler: async (req, res) => {
|
|
528
|
+
const body = await readBody(req);
|
|
529
|
+
const { taskId, from, fromRole, message, callbackUrl, attachments, project, targetAgent } = body;
|
|
530
|
+
if (!taskId || !from || !message || !callbackUrl) {
|
|
531
|
+
return sendJson(res, 400, { error: 'Missing required fields: taskId, from, message, callbackUrl' });
|
|
532
|
+
}
|
|
533
|
+
const sender = getContact(from);
|
|
534
|
+
if (!sender) {
|
|
535
|
+
// If authenticated by hooks token (auth: 'plugin'), allow system senders (e.g. control plane dispatcher)
|
|
536
|
+
// The token auth already proves this is a trusted request
|
|
537
|
+
_logger.info(`[fleet-agent] Task from system sender: ${from} (not in contacts, accepted via token auth)`);
|
|
538
|
+
}
|
|
539
|
+
if (_draining)
|
|
540
|
+
return sendJson(res, 503, { error: 'Instance is draining' });
|
|
541
|
+
_activeTasks++;
|
|
542
|
+
_logger.info(`[fleet-agent] Received task ${taskId} from ${from}${targetAgent ? ` (targetAgent: ${targetAgent})` : ''}: ${message.slice(0, 100)}`);
|
|
543
|
+
// Report task received to control plane
|
|
544
|
+
reportTask('create', {
|
|
545
|
+
id: taskId,
|
|
546
|
+
fromAgent: from,
|
|
547
|
+
toAgent: targetAgent || _config.instanceName,
|
|
548
|
+
taskText: message.slice(0, 5000),
|
|
549
|
+
status: 'running',
|
|
550
|
+
...(project ? { projectId: project } : {}),
|
|
551
|
+
});
|
|
552
|
+
// Decode any attached files to local filesystem
|
|
553
|
+
const attachmentNote = decodeAttachments(attachments, _logger);
|
|
554
|
+
// Acknowledge receipt immediately
|
|
555
|
+
sendJson(res, 200, { status: 'accepted', taskId });
|
|
556
|
+
// Create inbound context (non-blocking)
|
|
557
|
+
// When targetAgent is specified, the context is scoped to that agent's session
|
|
558
|
+
try {
|
|
559
|
+
const inbound = await createInboundContext(_api, {
|
|
560
|
+
taskId,
|
|
561
|
+
from,
|
|
562
|
+
callbackUrl,
|
|
563
|
+
hooksToken: _config.hooksToken,
|
|
564
|
+
instanceName: _config.instanceName,
|
|
565
|
+
targetAgent,
|
|
566
|
+
progressTimeoutMs: _config.progressTimeoutMs,
|
|
567
|
+
pingWatchdogMs: _config.pingWatchdogMs,
|
|
568
|
+
hardTimeoutMs: _config.hardTimeoutMs,
|
|
569
|
+
}, _logger);
|
|
570
|
+
// Report status changes back to control plane
|
|
571
|
+
inbound.onFinalize = (taskId, status, result) => {
|
|
572
|
+
reportTask('update', { id: taskId, status, result });
|
|
573
|
+
};
|
|
574
|
+
inboundContexts.set(inbound.sessionKey, inbound);
|
|
575
|
+
saveAgentTasks();
|
|
576
|
+
// Fetch project context if a project is specified
|
|
577
|
+
let projectContext = '';
|
|
578
|
+
const projectName = project || body.group;
|
|
579
|
+
if (projectName && _config?.fleetApiUrl) {
|
|
580
|
+
try {
|
|
581
|
+
const projResp = await fetch(`${_config.fleetApiUrl}/api/projects/${encodeURIComponent(projectName)}/context`, {
|
|
582
|
+
headers: {
|
|
583
|
+
..._config.fleetApiToken ? { 'Authorization': `Bearer ${_config.fleetApiToken}` } : {},
|
|
584
|
+
},
|
|
585
|
+
signal: AbortSignal.timeout(5_000),
|
|
586
|
+
});
|
|
587
|
+
if (projResp.ok) {
|
|
588
|
+
const contextMd = await projResp.text();
|
|
589
|
+
if (contextMd.trim()) {
|
|
590
|
+
projectContext = `## Project: ${projectName}\n${contextMd}\n\n---\n\n`;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
catch (err) {
|
|
595
|
+
_logger.warn(`[fleet-agent] Failed to fetch project context for "${projectName}": ${err.message}`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// Report running status to control plane
|
|
599
|
+
reportTask('update', { id: taskId, status: 'running' });
|
|
600
|
+
// Resolve {{shared:ref:filename}} markers — download files to workspace
|
|
601
|
+
let resolvedMessage = message;
|
|
602
|
+
const sharedPattern = /\{\{shared:([^:}]+):([^}]+)\}\}/g;
|
|
603
|
+
let sharedMatch;
|
|
604
|
+
while ((sharedMatch = sharedPattern.exec(message)) !== null) {
|
|
605
|
+
const [fullMatch, ref, filename] = sharedMatch;
|
|
606
|
+
if (_config?.fleetApiUrl) {
|
|
607
|
+
try {
|
|
608
|
+
const deliverResp = await fetch(`${_config.fleetApiUrl}/api/files/deliver`, {
|
|
609
|
+
method: 'POST',
|
|
610
|
+
headers: {
|
|
611
|
+
'Content-Type': 'application/json',
|
|
612
|
+
...(_config.fleetApiToken ? { 'Authorization': `Bearer ${_config.fleetApiToken}` } : {}),
|
|
613
|
+
},
|
|
614
|
+
body: JSON.stringify({ ref, toAgent: _config.instanceName }),
|
|
615
|
+
signal: AbortSignal.timeout(15_000),
|
|
616
|
+
});
|
|
617
|
+
const deliverData = await deliverResp.json();
|
|
618
|
+
if (deliverResp.ok && deliverData.containerPath) {
|
|
619
|
+
resolvedMessage = resolvedMessage.replace(fullMatch, `${filename} (downloaded to ${deliverData.containerPath})`);
|
|
620
|
+
_logger.info(`[fleet-agent] Resolved shared file ${ref} → ${deliverData.containerPath}`);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
_logger.warn(`[fleet-agent] Failed to deliver shared file ${ref}: ${deliverData.error || 'unknown'}`);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
catch (err) {
|
|
627
|
+
_logger.warn(`[fleet-agent] Failed to resolve shared file ${ref}: ${err.message}`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
// Fire first turn — non-blocking
|
|
632
|
+
const taskMessage = `${projectContext}[Fleet Task from ${from}] ${resolvedMessage}${attachmentNote}\n\n[To attach files in your reply, use {{file:/path/to/file}} markers. They will be transferred automatically.]`;
|
|
633
|
+
const taskComplete = await dispatchTurn(_api, inbound, taskMessage, _logger);
|
|
634
|
+
// Check if done (simple task, no delegation)
|
|
635
|
+
if (maybeFinalize(inbound, taskComplete, _logger)) {
|
|
636
|
+
_activeTasks--;
|
|
637
|
+
reportTask('update', { id: taskId, status: 'completed', result: inbound.accumulator.join('\n').slice(0, 5000) });
|
|
638
|
+
saveAgentTasks();
|
|
639
|
+
}
|
|
640
|
+
// If not finalized, we return and wait for events (result callbacks, timeouts)
|
|
641
|
+
}
|
|
642
|
+
catch (err) {
|
|
643
|
+
_logger.error(`[fleet-agent] Task ${taskId} failed during setup: ${err.message}`);
|
|
644
|
+
_activeTasks--;
|
|
645
|
+
// Send error callback
|
|
646
|
+
try {
|
|
647
|
+
await fetch(callbackUrl, {
|
|
648
|
+
method: 'POST',
|
|
649
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${_config.hooksToken}` },
|
|
650
|
+
body: JSON.stringify({ taskId, from: _config.instanceName, status: 'failed', error: err.message }),
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
catch { /* best effort */ }
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
});
|
|
657
|
+
// ── HTTP: Receive result (callback from remote agent) ───────────
|
|
658
|
+
api.registerHttpRoute({
|
|
659
|
+
auth: 'plugin',
|
|
660
|
+
path: '/fleet/result',
|
|
661
|
+
handler: async (req, res) => {
|
|
662
|
+
const body = await readBody(req);
|
|
663
|
+
const { taskId, from, result, status, error, progress } = body;
|
|
664
|
+
if (!taskId || !from)
|
|
665
|
+
return sendJson(res, 400, { error: 'Missing required fields: taskId, from' });
|
|
666
|
+
sendJson(res, 200, { status: 'received' });
|
|
667
|
+
// Find the outbound task
|
|
668
|
+
const outbound = outboundTasks.get(taskId);
|
|
669
|
+
// ── Process ping (agent alive but no LLM progress) ──
|
|
670
|
+
if (body.type === 'ping') {
|
|
671
|
+
if (outbound) {
|
|
672
|
+
const inbound = inboundContexts.get(outbound.sessionKey);
|
|
673
|
+
if (inbound)
|
|
674
|
+
resetPingWatchdog(inbound, _logger); // alive, but don't reset progress timer
|
|
675
|
+
}
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
// ── Progress update (tool output, working status) ──
|
|
679
|
+
if (status === 'working' || progress) {
|
|
680
|
+
if (outbound) {
|
|
681
|
+
const inbound = inboundContexts.get(outbound.sessionKey);
|
|
682
|
+
if (inbound)
|
|
683
|
+
resetInboundIdleTimer(inbound, _logger); // real progress — reset both timers
|
|
684
|
+
}
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
// ── Final result ──
|
|
688
|
+
if (!outbound) {
|
|
689
|
+
_logger.warn(`[fleet-agent] Received result for unknown task ${taskId}`);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
outboundTasks.delete(taskId);
|
|
693
|
+
saveAgentTasks();
|
|
694
|
+
_logger.info(`[fleet-agent] Result for ${taskId} from ${from}: ${status}`);
|
|
695
|
+
// Report result to control plane
|
|
696
|
+
reportTask('update', {
|
|
697
|
+
id: taskId,
|
|
698
|
+
status: status === 'failed' ? 'failed' : 'completed',
|
|
699
|
+
result: (result || '').slice(0, 5000),
|
|
700
|
+
});
|
|
701
|
+
// Decode attachments as {{file:...}} markers — when this context finalizes,
|
|
702
|
+
// extractFileMarkers will re-encode them for forwarding up the chain
|
|
703
|
+
const attachmentMarkers = decodeAttachmentsAsMarkers(body.attachments, _logger);
|
|
704
|
+
const resultText = status === 'failed'
|
|
705
|
+
? `Error: ${error || 'Unknown error'}`
|
|
706
|
+
: (result || '') + (attachmentMarkers ? '\n' + attachmentMarkers : '');
|
|
707
|
+
// Find inbound context for the session that sent this task
|
|
708
|
+
const inbound = inboundContexts.get(outbound.sessionKey);
|
|
709
|
+
if (inbound) {
|
|
710
|
+
// Reset idle timer — result arrived, agent is processing
|
|
711
|
+
resetInboundIdleTimer(inbound, _logger);
|
|
712
|
+
// Part of an inbound task — inject result as a new turn
|
|
713
|
+
inbound.pendingSubTasks.delete(taskId);
|
|
714
|
+
const resultMessage = [
|
|
715
|
+
`## Fleet Task Result from ${from}`,
|
|
716
|
+
`Task ID: ${taskId}`,
|
|
717
|
+
status === 'failed' ? `Error: ${error || 'Unknown error'}` : `Result:\n${resultText}`,
|
|
718
|
+
`\nContinue your work. Use fleet_task for the next step, or provide your final answer with TASK_COMPLETE.`,
|
|
719
|
+
].join('\n');
|
|
720
|
+
try {
|
|
721
|
+
const turnComplete = await dispatchTurn(_api, inbound, resultMessage, _logger);
|
|
722
|
+
if (maybeFinalize(inbound, turnComplete, _logger)) {
|
|
723
|
+
_activeTasks--;
|
|
724
|
+
reportTask('update', { id: inbound.taskId, status: 'completed', result: inbound.accumulator.join('\n').slice(0, 5000) });
|
|
725
|
+
saveAgentTasks();
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
catch (err) {
|
|
729
|
+
_logger.error(`[fleet-agent] Failed to dispatch result turn: ${err.message}`);
|
|
730
|
+
finalizeInbound(inbound, `Failed to process result: ${err.message}`, 'failed', _logger);
|
|
731
|
+
_activeTasks--;
|
|
732
|
+
reportTask('update', { id: inbound.taskId, status: 'failed', result: err.message });
|
|
733
|
+
saveAgentTasks();
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
// Organic — no inbound context, inject into originating session
|
|
738
|
+
_logger.info(`[fleet-agent] Organic result for session ${outbound.sessionKey} — injecting via agent RPC`);
|
|
739
|
+
const injectionText = status === 'failed'
|
|
740
|
+
? `## Fleet Task Failed — ${from}\n\nTask ID: ${taskId}\nError: ${error || 'Unknown error'}`
|
|
741
|
+
: `## Fleet Task Complete — ${from}\n\nTask ID: ${taskId}\n\n${resultText}`;
|
|
742
|
+
callGatewayRpc(_api, 'agent', {
|
|
743
|
+
sessionKey: outbound.sessionKey,
|
|
744
|
+
message: injectionText,
|
|
745
|
+
deliver: true,
|
|
746
|
+
bestEffortDeliver: true,
|
|
747
|
+
idempotencyKey: `fleet-result-${taskId}`,
|
|
748
|
+
}, 120_000).catch((err) => {
|
|
749
|
+
_logger.error(`[fleet-agent] Failed to inject organic result: ${err.message}`);
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
},
|
|
753
|
+
});
|
|
754
|
+
// ── HTTP: Status / Health / Drain ───────────────────────────────
|
|
755
|
+
api.registerHttpRoute({
|
|
756
|
+
auth: 'plugin', path: '/fleet/status',
|
|
757
|
+
handler: async (_req, res) => {
|
|
758
|
+
sendJson(res, 200, {
|
|
759
|
+
instanceName: _config.instanceName, org: _config.org, role: _config.role,
|
|
760
|
+
status: _draining ? 'draining' : (_activeTasks > 0 ? 'busy' : 'idle'),
|
|
761
|
+
activeTasks: _activeTasks, inboundContexts: inboundContexts.size,
|
|
762
|
+
outboundPending: outboundTasks.size, contacts: _config.contacts.length,
|
|
763
|
+
uptime: process.uptime(),
|
|
764
|
+
});
|
|
765
|
+
},
|
|
766
|
+
});
|
|
767
|
+
api.registerHttpRoute({
|
|
768
|
+
auth: 'plugin', path: '/fleet/health',
|
|
769
|
+
handler: async (_req, res) => {
|
|
770
|
+
sendJson(res, 200, { healthy: !_draining, instanceName: _config.instanceName, uptime: process.uptime() });
|
|
771
|
+
},
|
|
772
|
+
});
|
|
773
|
+
// ── HTTP: Steer — inject a message into an active task ─────────
|
|
774
|
+
api.registerHttpRoute({
|
|
775
|
+
auth: 'plugin',
|
|
776
|
+
path: '/fleet/steer',
|
|
777
|
+
handler: async (req, res) => {
|
|
778
|
+
const body = await readBody(req);
|
|
779
|
+
const { taskId, message } = body;
|
|
780
|
+
if (!taskId || !message)
|
|
781
|
+
return sendJson(res, 400, { error: 'Missing required fields: taskId, message' });
|
|
782
|
+
// Find the inbound context for this task
|
|
783
|
+
let inbound;
|
|
784
|
+
for (const [, ctx] of inboundContexts) {
|
|
785
|
+
if (ctx.taskId === taskId) {
|
|
786
|
+
inbound = ctx;
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
if (!inbound) {
|
|
791
|
+
return sendJson(res, 404, { error: `No active inbound context for task ${taskId}` });
|
|
792
|
+
}
|
|
793
|
+
if (inbound.finalized) {
|
|
794
|
+
return sendJson(res, 409, { error: `Task ${taskId} is already finalized` });
|
|
795
|
+
}
|
|
796
|
+
sendJson(res, 200, { status: 'steered', taskId });
|
|
797
|
+
_logger.info(`[fleet-agent] Steer message injected into task ${taskId}`);
|
|
798
|
+
try {
|
|
799
|
+
resetInboundIdleTimer(inbound, _logger);
|
|
800
|
+
const steerText = `## Operator Steer Message\n\n${message}\n\nAct on this instruction and continue your work.`;
|
|
801
|
+
const turnComplete = await dispatchTurn(_api, inbound, steerText, _logger);
|
|
802
|
+
if (maybeFinalize(inbound, turnComplete, _logger)) {
|
|
803
|
+
_activeTasks--;
|
|
804
|
+
reportTask('update', { id: taskId, status: 'completed', result: inbound.accumulator.join('\n').slice(0, 5000) });
|
|
805
|
+
saveAgentTasks();
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
catch (err) {
|
|
809
|
+
_logger.error(`[fleet-agent] Failed to dispatch steer turn: ${err.message}`);
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
api.registerHttpRoute({
|
|
814
|
+
auth: 'plugin', path: '/fleet/drain',
|
|
815
|
+
handler: async (_req, res) => {
|
|
816
|
+
_draining = true;
|
|
817
|
+
_logger.info(`[fleet-agent] Drain mode activated`);
|
|
818
|
+
sendJson(res, 200, { status: 'draining', activeTasks: _activeTasks });
|
|
819
|
+
},
|
|
820
|
+
});
|
|
821
|
+
// Load persisted tasks on startup
|
|
822
|
+
loadAgentTasks();
|
|
823
|
+
cleanupStaleAgentTasks();
|
|
824
|
+
// ── Service lifecycle ─────────────────────────────────────────────
|
|
825
|
+
let heartbeatTimer = null;
|
|
826
|
+
let _openclawVersion;
|
|
827
|
+
let _pluginVersions;
|
|
828
|
+
let _skillVersions;
|
|
829
|
+
function readOpenClawVersion() {
|
|
830
|
+
try {
|
|
831
|
+
const fs = require('fs');
|
|
832
|
+
const pkg = JSON.parse(fs.readFileSync('/app/package.json', 'utf8'));
|
|
833
|
+
return pkg.version;
|
|
834
|
+
}
|
|
835
|
+
catch {
|
|
836
|
+
return undefined;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
function readPluginVersions() {
|
|
840
|
+
const versions = {};
|
|
841
|
+
try {
|
|
842
|
+
const fs = require('fs');
|
|
843
|
+
const path = require('path');
|
|
844
|
+
const extDir = '/home/node/.openclaw/extensions';
|
|
845
|
+
if (!fs.existsSync(extDir))
|
|
846
|
+
return versions;
|
|
847
|
+
for (const entry of fs.readdirSync(extDir)) {
|
|
848
|
+
const pkgPath = path.join(extDir, entry, 'package.json');
|
|
849
|
+
if (fs.existsSync(pkgPath)) {
|
|
850
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
851
|
+
versions[entry] = pkg.version || 'unknown';
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
catch { }
|
|
856
|
+
return versions;
|
|
857
|
+
}
|
|
858
|
+
function readSkillVersions() {
|
|
859
|
+
const versions = {};
|
|
860
|
+
try {
|
|
861
|
+
const fs = require('fs');
|
|
862
|
+
const path = require('path');
|
|
863
|
+
const skillsDir = '/home/node/.openclaw/workspace/skills';
|
|
864
|
+
if (!fs.existsSync(skillsDir))
|
|
865
|
+
return versions;
|
|
866
|
+
for (const entry of fs.readdirSync(skillsDir)) {
|
|
867
|
+
const pkgPath = path.join(skillsDir, entry, 'package.json');
|
|
868
|
+
if (fs.existsSync(pkgPath)) {
|
|
869
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
870
|
+
versions[entry] = pkg.version || 'installed';
|
|
871
|
+
}
|
|
872
|
+
else if (fs.existsSync(path.join(skillsDir, entry, 'SKILL.md'))) {
|
|
873
|
+
versions[entry] = 'installed';
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
catch { }
|
|
878
|
+
return versions;
|
|
879
|
+
}
|
|
880
|
+
async function sendHeartbeats() {
|
|
881
|
+
if (!_config?.fleetApiUrl || !_config?.fleetApiToken)
|
|
882
|
+
return;
|
|
883
|
+
if (!_openclawVersion)
|
|
884
|
+
_openclawVersion = readOpenClawVersion();
|
|
885
|
+
// Re-read versions each heartbeat so updates are detected promptly
|
|
886
|
+
_pluginVersions = readPluginVersions();
|
|
887
|
+
_skillVersions = readSkillVersions();
|
|
888
|
+
// Discover loaded agents from the gateway config
|
|
889
|
+
const loadedAgents = [];
|
|
890
|
+
try {
|
|
891
|
+
const agentsList = _api?.config?.agents?.list;
|
|
892
|
+
if (Array.isArray(agentsList)) {
|
|
893
|
+
for (const a of agentsList) {
|
|
894
|
+
loadedAgents.push({
|
|
895
|
+
id: a.id || a.name || 'unknown',
|
|
896
|
+
name: a.name || a.id || 'unknown',
|
|
897
|
+
model: a.model || undefined,
|
|
898
|
+
status: 'active',
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
catch { /* config not available */ }
|
|
904
|
+
try {
|
|
905
|
+
const resp = await fetch(`${_config.fleetApiUrl}/api/instances/heartbeat`, {
|
|
906
|
+
method: 'POST',
|
|
907
|
+
headers: {
|
|
908
|
+
'Authorization': `Bearer ${_config.fleetApiToken}`,
|
|
909
|
+
'Content-Type': 'application/json',
|
|
910
|
+
},
|
|
911
|
+
body: JSON.stringify({
|
|
912
|
+
instanceName: _config.instanceName,
|
|
913
|
+
activeTasks: inboundContexts.size,
|
|
914
|
+
version: _openclawVersion,
|
|
915
|
+
pluginVersions: _pluginVersions,
|
|
916
|
+
skillVersions: _skillVersions,
|
|
917
|
+
agents: loadedAgents,
|
|
918
|
+
status: 'ready',
|
|
919
|
+
}),
|
|
920
|
+
});
|
|
921
|
+
if (!resp.ok) {
|
|
922
|
+
// Maybe instance heartbeat endpoint doesn't exist yet — fall back to per-agent
|
|
923
|
+
const agentsResp = await fetch(`${_config.fleetApiUrl}/api/agents`, {
|
|
924
|
+
headers: { 'Authorization': `Bearer ${_config.fleetApiToken}` },
|
|
925
|
+
});
|
|
926
|
+
if (agentsResp.ok) {
|
|
927
|
+
const allAgents = await agentsResp.json();
|
|
928
|
+
const myAgents = allAgents.filter((a) => a.instanceName === _config.instanceName);
|
|
929
|
+
for (const agent of myAgents) {
|
|
930
|
+
await fetch(`${_config.fleetApiUrl}/api/agents/${encodeURIComponent(agent.name)}/heartbeat`, {
|
|
931
|
+
method: 'POST',
|
|
932
|
+
headers: {
|
|
933
|
+
'Authorization': `Bearer ${_config.fleetApiToken}`,
|
|
934
|
+
'Content-Type': 'application/json',
|
|
935
|
+
},
|
|
936
|
+
body: JSON.stringify({
|
|
937
|
+
status: 'idle',
|
|
938
|
+
activeTasks: inboundContexts.size,
|
|
939
|
+
instance: _config.instanceName,
|
|
940
|
+
}),
|
|
941
|
+
}).catch(() => { });
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
catch {
|
|
947
|
+
// Control plane unreachable — will retry next cycle
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
api.registerService({
|
|
951
|
+
id: 'fleet-agent',
|
|
952
|
+
start: async () => {
|
|
953
|
+
_logger.info(`[fleet-agent] Started — ${_config.instanceName} (${_config.role}) in org ${_config.org}`);
|
|
954
|
+
_logger.info(`[fleet-agent] Contacts: ${_config.contacts.map(c => c.name).join(', ') || 'none'}`);
|
|
955
|
+
// Start periodic heartbeats to control plane (every 30s)
|
|
956
|
+
sendHeartbeats();
|
|
957
|
+
heartbeatTimer = setInterval(sendHeartbeats, 30_000);
|
|
958
|
+
},
|
|
959
|
+
stop: async () => {
|
|
960
|
+
_draining = true;
|
|
961
|
+
if (heartbeatTimer) {
|
|
962
|
+
clearInterval(heartbeatTimer);
|
|
963
|
+
heartbeatTimer = null;
|
|
964
|
+
}
|
|
965
|
+
// Finalize any active inbound contexts
|
|
966
|
+
for (const [, inbound] of inboundContexts) {
|
|
967
|
+
finalizeInbound(inbound, 'Instance shutting down', 'failed', _logger);
|
|
968
|
+
}
|
|
969
|
+
outboundTasks.clear();
|
|
970
|
+
_logger.info(`[fleet-agent] Stopped`);
|
|
971
|
+
},
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openclaw-fleet-agent",
|
|
3
|
+
"kind": "tools",
|
|
4
|
+
"name": "Fleet Agent",
|
|
5
|
+
"description": "Fleet agent plugin — managed team communication with ACL, status reporting, and maintenance",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"configSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": false,
|
|
10
|
+
"properties": {
|
|
11
|
+
"org": { "type": "string", "description": "Organisation identifier" },
|
|
12
|
+
"instanceName": { "type": "string", "description": "This instance's name" },
|
|
13
|
+
"role": { "type": "string", "description": "This instance's role (e.g. development, research, project-manager)" },
|
|
14
|
+
"hooksToken": { "type": "string", "description": "Shared org-level hooks token" },
|
|
15
|
+
"contacts": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"name": { "type": "string" },
|
|
21
|
+
"url": { "type": "string" },
|
|
22
|
+
"role": { "type": "string" }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"description": "Allowed contacts — ACL-enforced list of instances this agent can communicate with"
|
|
26
|
+
},
|
|
27
|
+
"idleTimeoutMs": { "type": "number", "description": "Idle timeout in ms before task is abandoned (default 180000)" },
|
|
28
|
+
"hardTimeoutMs": { "type": "number", "description": "Hard timeout in ms before task is force-completed (default 1800000)" },
|
|
29
|
+
"fleetApiUrl": { "type": "string", "description": "Fleet control plane API URL for task reporting" },
|
|
30
|
+
"fleetApiToken": { "type": "string", "description": "Fleet control plane API auth token" },
|
|
31
|
+
"projects": { "type": "array", "items": { "type": "string" }, "description": "Project names this agent belongs to" }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openclaw-fleet-agent",
|
|
3
|
+
"kind": "tools",
|
|
4
|
+
"name": "Fleet Agent",
|
|
5
|
+
"description": "Fleet agent plugin — managed team communication with ACL, status reporting, and maintenance",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"configSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": false,
|
|
10
|
+
"properties": {
|
|
11
|
+
"org": { "type": "string", "description": "Organisation identifier" },
|
|
12
|
+
"instanceName": { "type": "string", "description": "This instance's name" },
|
|
13
|
+
"role": { "type": "string", "description": "This instance's role (e.g. development, research, project-manager)" },
|
|
14
|
+
"hooksToken": { "type": "string", "description": "Shared org-level hooks token" },
|
|
15
|
+
"contacts": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"name": { "type": "string" },
|
|
21
|
+
"url": { "type": "string" },
|
|
22
|
+
"role": { "type": "string" }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"description": "Allowed contacts — ACL-enforced list of instances this agent can communicate with"
|
|
26
|
+
},
|
|
27
|
+
"idleTimeoutMs": { "type": "number", "description": "Idle timeout in ms before task is abandoned (default 180000)" },
|
|
28
|
+
"hardTimeoutMs": { "type": "number", "description": "Hard timeout in ms before task is force-completed (default 1800000)" },
|
|
29
|
+
"fleetApiUrl": { "type": "string", "description": "Fleet control plane API URL for task reporting" },
|
|
30
|
+
"fleetApiToken": { "type": "string", "description": "Fleet control plane API auth token" },
|
|
31
|
+
"projects": { "type": "array", "items": { "type": "string" }, "description": "Project names this agent belongs to" }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coderage-labs/openclaw-fleet-agent",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "Fleet agent plugin for OpenClaw \u2014 managed team communication with ACL, status reporting, and maintenance support",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "node --test dist/**/*.test.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"openclaw",
|
|
14
|
+
"openclaw-plugin",
|
|
15
|
+
"fleet",
|
|
16
|
+
"agent",
|
|
17
|
+
"team-communication"
|
|
18
|
+
],
|
|
19
|
+
"author": "Chris Kitch",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@coderage-labs/openclaw-fleet-plugin-shared": "^1.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^25.3.2"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"registry": "https://registry.npmjs.org/",
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/coderage-labs/openclaw-fleet.git",
|
|
34
|
+
"directory": "plugins/fleet-agent"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/",
|
|
38
|
+
"openclaw.plugin.json",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"package.json"
|
|
42
|
+
],
|
|
43
|
+
"openclaw": {
|
|
44
|
+
"extensions": [
|
|
45
|
+
"./dist/index.js"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|