gopherhole_openclaw_a2a 0.3.9 → 0.3.11
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/dist/src/connection.d.ts +31 -3
- package/dist/src/connection.js +80 -15
- package/package.json +2 -1
- package/src/connection.ts +126 -27
package/dist/src/connection.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export declare class A2AConnectionManager {
|
|
|
16
16
|
start(): Promise<void>;
|
|
17
17
|
private connectToGopherHole;
|
|
18
18
|
private handleIncomingMessage;
|
|
19
|
+
/**
|
|
20
|
+
* Handle system messages from GopherHole Hub
|
|
21
|
+
* These include spending alerts, account alerts, notices, maintenance, etc.
|
|
22
|
+
*/
|
|
23
|
+
private handleSystemMessage;
|
|
19
24
|
stop(): Promise<void>;
|
|
20
25
|
/**
|
|
21
26
|
* Send a message to another agent via GopherHole and wait for response
|
|
@@ -49,15 +54,38 @@ export declare class A2AConnectionManager {
|
|
|
49
54
|
*/
|
|
50
55
|
isGopherHoleConnected(): boolean;
|
|
51
56
|
/**
|
|
52
|
-
*
|
|
53
|
-
* Fetches same-tenant agents + agents with approved access + public agents
|
|
57
|
+
* Make an A2A JSON-RPC call
|
|
54
58
|
*/
|
|
55
|
-
|
|
59
|
+
private a2aRpc;
|
|
60
|
+
/**
|
|
61
|
+
* List available agents from GopherHole (agents you have access to)
|
|
62
|
+
*/
|
|
63
|
+
listAvailableAgents(options?: {
|
|
64
|
+
query?: string;
|
|
65
|
+
public?: boolean;
|
|
66
|
+
}): Promise<Array<{
|
|
56
67
|
id: string;
|
|
57
68
|
name: string;
|
|
58
69
|
description?: string;
|
|
70
|
+
verified?: boolean;
|
|
59
71
|
accessType: 'same-tenant' | 'public' | 'granted';
|
|
60
72
|
}>>;
|
|
73
|
+
/**
|
|
74
|
+
* Discover public agents in the marketplace
|
|
75
|
+
*/
|
|
76
|
+
discoverAgents(options?: {
|
|
77
|
+
query?: string;
|
|
78
|
+
category?: string;
|
|
79
|
+
verified?: boolean;
|
|
80
|
+
limit?: number;
|
|
81
|
+
}): Promise<Array<{
|
|
82
|
+
id: string;
|
|
83
|
+
name: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
verified?: boolean;
|
|
86
|
+
tenantName?: string;
|
|
87
|
+
avgRating?: number;
|
|
88
|
+
}>>;
|
|
61
89
|
/**
|
|
62
90
|
* List connection status (for backward compatibility)
|
|
63
91
|
*/
|
package/dist/src/connection.js
CHANGED
|
@@ -92,6 +92,10 @@ export class A2AConnectionManager {
|
|
|
92
92
|
this.gopherhole.on('message', (message) => {
|
|
93
93
|
this.handleIncomingMessage(message);
|
|
94
94
|
});
|
|
95
|
+
// Handle system messages (rate limits, budget alerts, announcements)
|
|
96
|
+
this.gopherhole.on('system', (message) => {
|
|
97
|
+
this.handleSystemMessage(message);
|
|
98
|
+
});
|
|
95
99
|
// Connect
|
|
96
100
|
try {
|
|
97
101
|
await this.gopherhole.connect();
|
|
@@ -131,6 +135,40 @@ export class A2AConnectionManager {
|
|
|
131
135
|
console.error('[a2a] Error handling incoming message:', err);
|
|
132
136
|
});
|
|
133
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Handle system messages from GopherHole Hub
|
|
140
|
+
* These include spending alerts, account alerts, notices, maintenance, etc.
|
|
141
|
+
*/
|
|
142
|
+
handleSystemMessage(message) {
|
|
143
|
+
const kind = message.metadata?.kind;
|
|
144
|
+
const text = message.payload.parts.find(p => p.kind === 'text')?.text || '';
|
|
145
|
+
const data = message.metadata?.data;
|
|
146
|
+
// Log all system messages
|
|
147
|
+
console.log(`[a2a] System message (${kind || 'unknown'}): ${text}`);
|
|
148
|
+
// Handle specific message kinds
|
|
149
|
+
switch (kind) {
|
|
150
|
+
case 'spending_alert':
|
|
151
|
+
console.warn(`[a2a] 💰 Spending alert: ${text}`);
|
|
152
|
+
if (data) {
|
|
153
|
+
console.warn(`[a2a] Spending data:`, JSON.stringify(data));
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
case 'account_alert':
|
|
157
|
+
console.warn(`[a2a] ⚠️ Account alert: ${text}`);
|
|
158
|
+
break;
|
|
159
|
+
case 'system_notice':
|
|
160
|
+
console.log(`[a2a] 📢 System notice: ${text}`);
|
|
161
|
+
break;
|
|
162
|
+
case 'maintenance':
|
|
163
|
+
console.warn(`[a2a] 🔧 Maintenance notice: ${text}`);
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
// Log but don't warn for unknown types
|
|
167
|
+
if (kind) {
|
|
168
|
+
console.log(`[a2a] System message "${kind}": ${text}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
134
172
|
async stop() {
|
|
135
173
|
if (this.gopherhole) {
|
|
136
174
|
this.gopherhole.disconnect();
|
|
@@ -234,39 +272,66 @@ export class A2AConnectionManager {
|
|
|
234
272
|
return this.connected && this.gopherhole?.connected === true;
|
|
235
273
|
}
|
|
236
274
|
/**
|
|
237
|
-
*
|
|
238
|
-
* Fetches same-tenant agents + agents with approved access + public agents
|
|
275
|
+
* Make an A2A JSON-RPC call
|
|
239
276
|
*/
|
|
240
|
-
async
|
|
277
|
+
async a2aRpc(method, params) {
|
|
241
278
|
if (!this.config.apiKey) {
|
|
242
|
-
return
|
|
279
|
+
return null;
|
|
243
280
|
}
|
|
244
281
|
const hubUrl = this.config.bridgeUrl || 'wss://hub.gopherhole.ai/ws';
|
|
245
|
-
// Convert wss:// to https:// for API calls
|
|
246
282
|
const apiBase = hubUrl.replace('wss://', 'https://').replace('/ws', '');
|
|
247
283
|
try {
|
|
248
|
-
const response = await fetch(`${apiBase}/
|
|
284
|
+
const response = await fetch(`${apiBase}/a2a`, {
|
|
285
|
+
method: 'POST',
|
|
249
286
|
headers: {
|
|
250
287
|
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
251
288
|
'Content-Type': 'application/json',
|
|
252
289
|
},
|
|
290
|
+
body: JSON.stringify({
|
|
291
|
+
jsonrpc: '2.0',
|
|
292
|
+
method,
|
|
293
|
+
params: params || {},
|
|
294
|
+
id: Date.now(),
|
|
295
|
+
}),
|
|
253
296
|
});
|
|
254
297
|
if (!response.ok) {
|
|
255
|
-
console.error(`[a2a]
|
|
256
|
-
return
|
|
298
|
+
console.error(`[a2a] RPC failed: ${response.status}`);
|
|
299
|
+
return null;
|
|
257
300
|
}
|
|
258
301
|
const data = await response.json();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}));
|
|
302
|
+
if (data.error) {
|
|
303
|
+
console.error(`[a2a] RPC error: ${data.error.message}`);
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
return data.result || null;
|
|
265
307
|
}
|
|
266
308
|
catch (err) {
|
|
267
|
-
console.error('[a2a]
|
|
309
|
+
console.error('[a2a] RPC error:', err.message);
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* List available agents from GopherHole (agents you have access to)
|
|
315
|
+
*/
|
|
316
|
+
async listAvailableAgents(options) {
|
|
317
|
+
const result = await this.a2aRpc('x-gopherhole/agents.available', options);
|
|
318
|
+
if (!result?.agents) {
|
|
268
319
|
return [];
|
|
269
320
|
}
|
|
321
|
+
return result.agents.map(a => ({
|
|
322
|
+
id: a.id,
|
|
323
|
+
name: a.name,
|
|
324
|
+
description: a.description,
|
|
325
|
+
verified: a.verified,
|
|
326
|
+
accessType: a.accessType,
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Discover public agents in the marketplace
|
|
331
|
+
*/
|
|
332
|
+
async discoverAgents(options) {
|
|
333
|
+
const result = await this.a2aRpc('x-gopherhole/agents.discover', options);
|
|
334
|
+
return result?.agents || [];
|
|
270
335
|
}
|
|
271
336
|
/**
|
|
272
337
|
* List connection status (for backward compatibility)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gopherhole_openclaw_a2a",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "GopherHole A2A plugin for OpenClaw - connect your AI agent to the GopherHole network",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"uuid": "^10.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
+
"@types/node": "^25.5.0",
|
|
38
39
|
"@types/uuid": "^10.0.0",
|
|
39
40
|
"typescript": "^5.9.3"
|
|
40
41
|
},
|
package/src/connection.ts
CHANGED
|
@@ -113,6 +113,11 @@ export class A2AConnectionManager {
|
|
|
113
113
|
this.handleIncomingMessage(message);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
+
// Handle system messages (rate limits, budget alerts, announcements)
|
|
117
|
+
this.gopherhole.on('system', (message) => {
|
|
118
|
+
this.handleSystemMessage(message);
|
|
119
|
+
});
|
|
120
|
+
|
|
116
121
|
// Connect
|
|
117
122
|
try {
|
|
118
123
|
await this.gopherhole.connect();
|
|
@@ -157,6 +162,47 @@ export class A2AConnectionManager {
|
|
|
157
162
|
});
|
|
158
163
|
}
|
|
159
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Handle system messages from GopherHole Hub
|
|
167
|
+
* These include spending alerts, account alerts, notices, maintenance, etc.
|
|
168
|
+
*/
|
|
169
|
+
private handleSystemMessage(message: Message): void {
|
|
170
|
+
const kind = message.metadata?.kind;
|
|
171
|
+
const text = message.payload.parts.find(p => p.kind === 'text')?.text || '';
|
|
172
|
+
const data = message.metadata?.data;
|
|
173
|
+
|
|
174
|
+
// Log all system messages
|
|
175
|
+
console.log(`[a2a] System message (${kind || 'unknown'}): ${text}`);
|
|
176
|
+
|
|
177
|
+
// Handle specific message kinds
|
|
178
|
+
switch (kind) {
|
|
179
|
+
case 'spending_alert':
|
|
180
|
+
console.warn(`[a2a] 💰 Spending alert: ${text}`);
|
|
181
|
+
if (data) {
|
|
182
|
+
console.warn(`[a2a] Spending data:`, JSON.stringify(data));
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
|
|
186
|
+
case 'account_alert':
|
|
187
|
+
console.warn(`[a2a] ⚠️ Account alert: ${text}`);
|
|
188
|
+
break;
|
|
189
|
+
|
|
190
|
+
case 'system_notice':
|
|
191
|
+
console.log(`[a2a] 📢 System notice: ${text}`);
|
|
192
|
+
break;
|
|
193
|
+
|
|
194
|
+
case 'maintenance':
|
|
195
|
+
console.warn(`[a2a] 🔧 Maintenance notice: ${text}`);
|
|
196
|
+
break;
|
|
197
|
+
|
|
198
|
+
default:
|
|
199
|
+
// Log but don't warn for unknown types
|
|
200
|
+
if (kind) {
|
|
201
|
+
console.log(`[a2a] System message "${kind}": ${text}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
160
206
|
async stop(): Promise<void> {
|
|
161
207
|
if (this.gopherhole) {
|
|
162
208
|
this.gopherhole.disconnect();
|
|
@@ -297,53 +343,106 @@ export class A2AConnectionManager {
|
|
|
297
343
|
}
|
|
298
344
|
|
|
299
345
|
/**
|
|
300
|
-
*
|
|
301
|
-
* Fetches same-tenant agents + agents with approved access + public agents
|
|
346
|
+
* Make an A2A JSON-RPC call
|
|
302
347
|
*/
|
|
303
|
-
async
|
|
304
|
-
id: string;
|
|
305
|
-
name: string;
|
|
306
|
-
description?: string;
|
|
307
|
-
accessType: 'same-tenant' | 'public' | 'granted';
|
|
308
|
-
}>> {
|
|
348
|
+
private async a2aRpc<T>(method: string, params?: Record<string, unknown>): Promise<T | null> {
|
|
309
349
|
if (!this.config.apiKey) {
|
|
310
|
-
return
|
|
350
|
+
return null;
|
|
311
351
|
}
|
|
312
352
|
|
|
313
353
|
const hubUrl = this.config.bridgeUrl || 'wss://hub.gopherhole.ai/ws';
|
|
314
|
-
// Convert wss:// to https:// for API calls
|
|
315
354
|
const apiBase = hubUrl.replace('wss://', 'https://').replace('/ws', '');
|
|
316
355
|
|
|
317
356
|
try {
|
|
318
|
-
const response = await fetch(`${apiBase}/
|
|
357
|
+
const response = await fetch(`${apiBase}/a2a`, {
|
|
358
|
+
method: 'POST',
|
|
319
359
|
headers: {
|
|
320
360
|
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
321
361
|
'Content-Type': 'application/json',
|
|
322
362
|
},
|
|
363
|
+
body: JSON.stringify({
|
|
364
|
+
jsonrpc: '2.0',
|
|
365
|
+
method,
|
|
366
|
+
params: params || {},
|
|
367
|
+
id: Date.now(),
|
|
368
|
+
}),
|
|
323
369
|
});
|
|
324
370
|
|
|
325
371
|
if (!response.ok) {
|
|
326
|
-
console.error(`[a2a]
|
|
327
|
-
return
|
|
372
|
+
console.error(`[a2a] RPC failed: ${response.status}`);
|
|
373
|
+
return null;
|
|
328
374
|
}
|
|
329
375
|
|
|
330
|
-
const data = await response.json() as {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return data.agents.map(a => ({
|
|
338
|
-
id: a.id,
|
|
339
|
-
name: a.name,
|
|
340
|
-
description: a.description,
|
|
341
|
-
accessType: a.access_type as 'same-tenant' | 'public' | 'granted',
|
|
342
|
-
}));
|
|
376
|
+
const data = await response.json() as { result?: T; error?: { message: string } };
|
|
377
|
+
if (data.error) {
|
|
378
|
+
console.error(`[a2a] RPC error: ${data.error.message}`);
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return data.result || null;
|
|
343
383
|
} catch (err) {
|
|
344
|
-
console.error('[a2a]
|
|
384
|
+
console.error('[a2a] RPC error:', (err as Error).message);
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* List available agents from GopherHole (agents you have access to)
|
|
391
|
+
*/
|
|
392
|
+
async listAvailableAgents(options?: { query?: string; public?: boolean }): Promise<Array<{
|
|
393
|
+
id: string;
|
|
394
|
+
name: string;
|
|
395
|
+
description?: string;
|
|
396
|
+
verified?: boolean;
|
|
397
|
+
accessType: 'same-tenant' | 'public' | 'granted';
|
|
398
|
+
}>> {
|
|
399
|
+
const result = await this.a2aRpc<{ agents: Array<{
|
|
400
|
+
id: string;
|
|
401
|
+
name: string;
|
|
402
|
+
description?: string;
|
|
403
|
+
verified?: boolean;
|
|
404
|
+
accessType: string;
|
|
405
|
+
}> }>('x-gopherhole/agents.available', options);
|
|
406
|
+
|
|
407
|
+
if (!result?.agents) {
|
|
345
408
|
return [];
|
|
346
409
|
}
|
|
410
|
+
|
|
411
|
+
return result.agents.map(a => ({
|
|
412
|
+
id: a.id,
|
|
413
|
+
name: a.name,
|
|
414
|
+
description: a.description,
|
|
415
|
+
verified: a.verified,
|
|
416
|
+
accessType: a.accessType as 'same-tenant' | 'public' | 'granted',
|
|
417
|
+
}));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Discover public agents in the marketplace
|
|
422
|
+
*/
|
|
423
|
+
async discoverAgents(options?: {
|
|
424
|
+
query?: string;
|
|
425
|
+
category?: string;
|
|
426
|
+
verified?: boolean;
|
|
427
|
+
limit?: number;
|
|
428
|
+
}): Promise<Array<{
|
|
429
|
+
id: string;
|
|
430
|
+
name: string;
|
|
431
|
+
description?: string;
|
|
432
|
+
verified?: boolean;
|
|
433
|
+
tenantName?: string;
|
|
434
|
+
avgRating?: number;
|
|
435
|
+
}>> {
|
|
436
|
+
const result = await this.a2aRpc<{ agents: Array<{
|
|
437
|
+
id: string;
|
|
438
|
+
name: string;
|
|
439
|
+
description?: string;
|
|
440
|
+
verified?: boolean;
|
|
441
|
+
tenantName?: string;
|
|
442
|
+
avgRating?: number;
|
|
443
|
+
}> }>('x-gopherhole/agents.discover', options);
|
|
444
|
+
|
|
445
|
+
return result?.agents || [];
|
|
347
446
|
}
|
|
348
447
|
|
|
349
448
|
/**
|