clawmatrix 0.1.14 → 0.1.16
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/BOOTSTRAP.md +55 -8
- package/package.json +4 -2
- package/src/auth.ts +42 -12
- package/src/cluster-service.ts +35 -7
- package/src/compat.ts +3 -0
- package/src/config.ts +57 -6
- package/src/connection.ts +34 -8
- package/src/device-info.ts +48 -0
- package/src/handoff.ts +330 -21
- package/src/http-utils.ts +35 -0
- package/src/index.ts +47 -19
- package/src/model-proxy.ts +546 -242
- package/src/peer-manager.ts +65 -6
- package/src/router.ts +89 -47
- package/src/tool-proxy.ts +22 -7
- package/src/tools/cluster-events.ts +119 -0
- package/src/tools/cluster-exec.ts +4 -0
- package/src/tools/cluster-handoff-reply.ts +77 -0
- package/src/tools/cluster-handoff.ts +12 -0
- package/src/tools/cluster-peers.ts +17 -1
- package/src/tools/cluster-send.ts +1 -3
- package/src/tools/cluster-tool.ts +2 -5
- package/src/types.ts +117 -0
- package/src/web-ui.ts +694 -342
- package/src/web.ts +726 -50
|
@@ -37,6 +37,18 @@ export function createClusterHandoffTool(): AnyAgentTool {
|
|
|
37
37
|
const runtime = getClusterRuntime();
|
|
38
38
|
const result = await runtime.handoffManager.handoff(target, task, context);
|
|
39
39
|
|
|
40
|
+
if (result.inputRequired) {
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: "text" as const,
|
|
45
|
+
text: `Remote agent needs more information before continuing.\n\nHandoff ID: ${result.handoffId}\nQuestion: ${result.result}\n\nUse cluster_handoff_reply tool to respond.`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
details: result,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
if (!result.success) {
|
|
41
53
|
return {
|
|
42
54
|
content: [
|
|
@@ -6,7 +6,7 @@ export function createClusterPeersTool(): AnyAgentTool {
|
|
|
6
6
|
name: "cluster_peers",
|
|
7
7
|
label: "Cluster Peers",
|
|
8
8
|
description:
|
|
9
|
-
"List all reachable peers in the cluster, their agents,
|
|
9
|
+
"List all reachable peers in the cluster, their agents, models, tools, and connection status.",
|
|
10
10
|
parameters: {
|
|
11
11
|
type: "object",
|
|
12
12
|
properties: {},
|
|
@@ -26,10 +26,26 @@ export function createClusterPeersTool(): AnyAgentTool {
|
|
|
26
26
|
provider: m.provider,
|
|
27
27
|
})),
|
|
28
28
|
tags: entry.tags,
|
|
29
|
+
tools: entry.toolProxy?.enabled ? (entry.toolProxy.allow ?? []) : [],
|
|
29
30
|
status: entry.connection?.isOpen ? "connected" : "unreachable",
|
|
30
31
|
latencyMs: entry.latencyMs,
|
|
31
32
|
}));
|
|
32
33
|
|
|
34
|
+
// Include satellite nodes
|
|
35
|
+
const satellites = runtime.webHandler?.getSatelliteContexts() ?? runtime.peerManager.satelliteContexts;
|
|
36
|
+
for (const sat of satellites) {
|
|
37
|
+
if (Date.now() - sat.ts >= 600_000) continue;
|
|
38
|
+
peers.push({
|
|
39
|
+
nodeId: sat.nodeId,
|
|
40
|
+
agents: [],
|
|
41
|
+
models: [],
|
|
42
|
+
tags: [],
|
|
43
|
+
tools: sat.tools ?? [],
|
|
44
|
+
status: "satellite",
|
|
45
|
+
latencyMs: undefined,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
33
49
|
return {
|
|
34
50
|
content: [
|
|
35
51
|
{
|
|
@@ -6,9 +6,7 @@ export function createClusterSendTool(): AnyAgentTool {
|
|
|
6
6
|
name: "cluster_send",
|
|
7
7
|
label: "Cluster Send",
|
|
8
8
|
description:
|
|
9
|
-
"Send a one-way message to
|
|
10
|
-
"The message is injected into the target agent's session as an inbound message. " +
|
|
11
|
-
"Does not wait for a response.",
|
|
9
|
+
"Send a one-way message to a remote agent. Does not wait for a response.",
|
|
12
10
|
parameters: {
|
|
13
11
|
type: "object",
|
|
14
12
|
properties: {
|
|
@@ -6,10 +6,7 @@ export function createClusterToolTool(): AnyAgentTool {
|
|
|
6
6
|
name: "cluster_tool",
|
|
7
7
|
label: "Cluster Tool",
|
|
8
8
|
description:
|
|
9
|
-
"Invoke any OpenClaw tool on a remote cluster node. "
|
|
10
|
-
"Supports all tools available on the remote node (exec, read, write, edit, " +
|
|
11
|
-
"web_search, web_fetch, browser, process, etc.). " +
|
|
12
|
-
"Use nodeId or 'tags:<tag>' to specify the target.",
|
|
9
|
+
"Invoke any OpenClaw tool on a remote cluster node. Use nodeId or 'tags:<tag>' to specify the target.",
|
|
13
10
|
parameters: {
|
|
14
11
|
type: "object",
|
|
15
12
|
properties: {
|
|
@@ -19,7 +16,7 @@ export function createClusterToolTool(): AnyAgentTool {
|
|
|
19
16
|
},
|
|
20
17
|
tool: {
|
|
21
18
|
type: "string",
|
|
22
|
-
description: "Tool name to invoke
|
|
19
|
+
description: "Tool name to invoke on the remote node",
|
|
23
20
|
},
|
|
24
21
|
args: {
|
|
25
22
|
type: "object",
|
package/src/types.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface AuthRequest extends ClusterFrame {
|
|
|
23
23
|
agents?: AgentInfo[];
|
|
24
24
|
models?: ModelInfo[];
|
|
25
25
|
tags?: string[];
|
|
26
|
+
deviceInfo?: DeviceInfo;
|
|
27
|
+
toolProxy?: ToolProxyInfo;
|
|
26
28
|
};
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -33,6 +35,8 @@ export interface AuthOk extends ClusterFrame {
|
|
|
33
35
|
agents: AgentInfo[];
|
|
34
36
|
models: ModelInfo[];
|
|
35
37
|
tags: string[];
|
|
38
|
+
deviceInfo?: DeviceInfo;
|
|
39
|
+
toolProxy?: ToolProxyInfo;
|
|
36
40
|
};
|
|
37
41
|
}
|
|
38
42
|
|
|
@@ -42,10 +46,27 @@ export interface AuthFail extends ClusterFrame {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
// ── Peer discovery ─────────────────────────────────────────────────
|
|
49
|
+
export interface SatelliteContext {
|
|
50
|
+
nodeId: string;
|
|
51
|
+
ssid?: string;
|
|
52
|
+
ip?: string;
|
|
53
|
+
router?: string;
|
|
54
|
+
cellular: boolean;
|
|
55
|
+
country?: string;
|
|
56
|
+
tools?: string[];
|
|
57
|
+
ts: number;
|
|
58
|
+
// Extended context
|
|
59
|
+
battery?: number; // 0-100
|
|
60
|
+
charging?: boolean;
|
|
61
|
+
platform?: string; // "ios" | "macos"
|
|
62
|
+
location?: string; // user-defined location name from WiFi mapping
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
export interface PeerSync extends ClusterFrame {
|
|
46
66
|
type: "peer_sync";
|
|
47
67
|
payload: {
|
|
48
68
|
peers: PeerInfo[];
|
|
69
|
+
satellites?: SatelliteContext[];
|
|
49
70
|
};
|
|
50
71
|
}
|
|
51
72
|
|
|
@@ -74,6 +95,8 @@ export interface ModelRequest extends ClusterFrame {
|
|
|
74
95
|
id: string;
|
|
75
96
|
payload: {
|
|
76
97
|
model: string;
|
|
98
|
+
provider?: string;
|
|
99
|
+
api?: string;
|
|
77
100
|
messages: unknown[];
|
|
78
101
|
temperature?: number;
|
|
79
102
|
maxTokens?: number;
|
|
@@ -87,6 +110,9 @@ export interface ModelResponse extends ClusterFrame {
|
|
|
87
110
|
payload: {
|
|
88
111
|
success: boolean;
|
|
89
112
|
content?: string;
|
|
113
|
+
/** Full message object from upstream (choices[0].message or responses output).
|
|
114
|
+
* Carries tool_calls, refusal, etc. that `content` alone cannot represent. */
|
|
115
|
+
message?: unknown;
|
|
90
116
|
usage?: { inputTokens: number; outputTokens: number };
|
|
91
117
|
error?: string;
|
|
92
118
|
};
|
|
@@ -97,12 +123,23 @@ export interface ModelStreamChunk extends ClusterFrame {
|
|
|
97
123
|
id: string;
|
|
98
124
|
payload: {
|
|
99
125
|
delta: string;
|
|
126
|
+
/** Full delta object from upstream (choices[0].delta).
|
|
127
|
+
* Carries tool_calls chunks that `delta` string cannot represent. */
|
|
128
|
+
deltaObj?: unknown;
|
|
100
129
|
done: boolean;
|
|
101
130
|
usage?: { inputTokens: number; outputTokens: number };
|
|
102
131
|
};
|
|
103
132
|
}
|
|
104
133
|
|
|
105
134
|
// ── Handoff ────────────────────────────────────────────────────────
|
|
135
|
+
export type HandoffStatus = "working" | "input_required" | "completed" | "failed" | "canceled";
|
|
136
|
+
|
|
137
|
+
export interface Artifact {
|
|
138
|
+
name: string;
|
|
139
|
+
mimeType: string;
|
|
140
|
+
data: string; // text content or base64-encoded binary
|
|
141
|
+
}
|
|
142
|
+
|
|
106
143
|
export interface HandoffRequest extends ClusterFrame {
|
|
107
144
|
type: "handoff_req";
|
|
108
145
|
id: string;
|
|
@@ -119,6 +156,7 @@ export interface HandoffStreamChunk extends ClusterFrame {
|
|
|
119
156
|
payload: {
|
|
120
157
|
delta: string;
|
|
121
158
|
done: boolean;
|
|
159
|
+
artifacts?: Artifact[];
|
|
122
160
|
};
|
|
123
161
|
}
|
|
124
162
|
|
|
@@ -131,6 +169,48 @@ export interface HandoffResponse extends ClusterFrame {
|
|
|
131
169
|
agent?: string;
|
|
132
170
|
result?: string;
|
|
133
171
|
error?: string;
|
|
172
|
+
artifacts?: Artifact[];
|
|
173
|
+
inputRequired?: boolean;
|
|
174
|
+
handoffId?: string;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface HandoffCancel extends ClusterFrame {
|
|
179
|
+
type: "handoff_cancel";
|
|
180
|
+
id: string;
|
|
181
|
+
payload?: unknown;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface HandoffStatusQuery extends ClusterFrame {
|
|
185
|
+
type: "handoff_status";
|
|
186
|
+
id: string;
|
|
187
|
+
payload?: unknown;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface HandoffStatusResponse extends ClusterFrame {
|
|
191
|
+
type: "handoff_status_res";
|
|
192
|
+
id: string;
|
|
193
|
+
payload: {
|
|
194
|
+
status: HandoffStatus;
|
|
195
|
+
nodeId: string;
|
|
196
|
+
agent: string;
|
|
197
|
+
elapsedMs: number;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface HandoffInputRequired extends ClusterFrame {
|
|
202
|
+
type: "handoff_input_required";
|
|
203
|
+
id: string;
|
|
204
|
+
payload: {
|
|
205
|
+
message: string;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface HandoffInput extends ClusterFrame {
|
|
210
|
+
type: "handoff_input";
|
|
211
|
+
id: string;
|
|
212
|
+
payload: {
|
|
213
|
+
message: string;
|
|
134
214
|
};
|
|
135
215
|
}
|
|
136
216
|
|
|
@@ -163,6 +243,17 @@ export interface ToolProxyResponse extends ClusterFrame {
|
|
|
163
243
|
};
|
|
164
244
|
}
|
|
165
245
|
|
|
246
|
+
// ── Device info ───────────────────────────────────────────────────
|
|
247
|
+
export interface DeviceInfo {
|
|
248
|
+
os: string; // e.g. "Darwin 24.6.0", "Linux 6.1.0"
|
|
249
|
+
arch: string; // e.g. "arm64", "x64"
|
|
250
|
+
cpuModel: string; // e.g. "Apple M1 Pro"
|
|
251
|
+
cpuCores: number; // logical CPU cores
|
|
252
|
+
totalMemoryMB: number; // total system memory in MB
|
|
253
|
+
hostname: string; // machine hostname
|
|
254
|
+
openclawVersion?: string; // e.g. "2026.3.7"
|
|
255
|
+
}
|
|
256
|
+
|
|
166
257
|
// ── Shared info types ──────────────────────────────────────────────
|
|
167
258
|
export interface AgentInfo {
|
|
168
259
|
id: string;
|
|
@@ -192,12 +283,21 @@ export interface ModelInfo {
|
|
|
192
283
|
compat?: ModelCompatInfo;
|
|
193
284
|
}
|
|
194
285
|
|
|
286
|
+
export interface ToolProxyInfo {
|
|
287
|
+
enabled: boolean;
|
|
288
|
+
allow: string[];
|
|
289
|
+
deny: string[];
|
|
290
|
+
}
|
|
291
|
+
|
|
195
292
|
export interface PeerInfo {
|
|
196
293
|
nodeId: string;
|
|
197
294
|
agents: AgentInfo[];
|
|
198
295
|
models: ModelInfo[];
|
|
199
296
|
tags: string[];
|
|
200
297
|
reachableVia?: string; // nodeId of the relay node
|
|
298
|
+
directPeers?: string[]; // nodeIds this node has direct connections to
|
|
299
|
+
deviceInfo?: DeviceInfo; // system/hardware info
|
|
300
|
+
toolProxy?: ToolProxyInfo;
|
|
201
301
|
}
|
|
202
302
|
|
|
203
303
|
export interface NodeCapabilities {
|
|
@@ -205,6 +305,18 @@ export interface NodeCapabilities {
|
|
|
205
305
|
agents: AgentInfo[];
|
|
206
306
|
models: ModelInfo[];
|
|
207
307
|
tags: string[];
|
|
308
|
+
deviceInfo?: DeviceInfo;
|
|
309
|
+
toolProxy?: ToolProxyInfo;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ── Ingested events (from Shortcuts automations, etc.) ────────────
|
|
313
|
+
export interface IngestedEvent {
|
|
314
|
+
id: string;
|
|
315
|
+
source: string; // e.g. "shortcuts", "iphone-14", "surge"
|
|
316
|
+
type: string; // e.g. "message_received", "call_missed", "location_changed"
|
|
317
|
+
data: Record<string, unknown>;
|
|
318
|
+
ts: number; // ingestion timestamp
|
|
319
|
+
consumed: boolean; // whether an agent has consumed this event
|
|
208
320
|
}
|
|
209
321
|
|
|
210
322
|
// ── Union of all frame types ───────────────────────────────────────
|
|
@@ -224,6 +336,11 @@ export type AnyClusterFrame =
|
|
|
224
336
|
| HandoffRequest
|
|
225
337
|
| HandoffStreamChunk
|
|
226
338
|
| HandoffResponse
|
|
339
|
+
| HandoffCancel
|
|
340
|
+
| HandoffStatusQuery
|
|
341
|
+
| HandoffStatusResponse
|
|
227
342
|
| SendMessage
|
|
343
|
+
| HandoffInputRequired
|
|
344
|
+
| HandoffInput
|
|
228
345
|
| ToolProxyRequest
|
|
229
346
|
| ToolProxyResponse;
|