gopherhole_openclaw_a2a 0.1.3 → 0.2.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/dist/index.js +46 -9
- package/dist/src/connection.d.ts +27 -22
- package/dist/src/connection.js +140 -444
- package/dist/src/types.d.ts +3 -8
- package/dist/src/types.js +1 -1
- package/index.ts +47 -9
- package/package.json +3 -4
- package/src/connection.ts +157 -491
- package/src/types.ts +6 -15
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Enables Clawdbot to communicate with other AI agents via A2A protocol
|
|
4
4
|
*/
|
|
5
5
|
import { a2aPlugin, setA2ARuntime, getA2AConnectionManager } from './src/channel.js';
|
|
6
|
+
import { readFileSync } from 'fs';
|
|
7
|
+
import { extname } from 'path';
|
|
6
8
|
const plugin = {
|
|
7
9
|
id: 'gopherhole_openclaw_a2a',
|
|
8
10
|
name: 'A2A Protocol',
|
|
@@ -29,7 +31,11 @@ const plugin = {
|
|
|
29
31
|
},
|
|
30
32
|
message: {
|
|
31
33
|
type: 'string',
|
|
32
|
-
description: '
|
|
34
|
+
description: 'Text message to send (for send action)',
|
|
35
|
+
},
|
|
36
|
+
image: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'Path to image file to send (for send action)',
|
|
33
39
|
},
|
|
34
40
|
},
|
|
35
41
|
required: ['action'],
|
|
@@ -38,6 +44,7 @@ const plugin = {
|
|
|
38
44
|
const action = params.action;
|
|
39
45
|
const agentId = params.agentId;
|
|
40
46
|
const message = params.message;
|
|
47
|
+
const imagePath = params.image;
|
|
41
48
|
const manager = getA2AConnectionManager();
|
|
42
49
|
if (!manager) {
|
|
43
50
|
return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: 'A2A channel not running' }) }] };
|
|
@@ -47,22 +54,52 @@ const plugin = {
|
|
|
47
54
|
return { content: [{ type: 'text', text: JSON.stringify({ status: 'ok', agents }) }] };
|
|
48
55
|
}
|
|
49
56
|
if (action === 'send') {
|
|
50
|
-
if (!agentId || !message) {
|
|
51
|
-
return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: 'agentId and message required for send action' }) }] };
|
|
57
|
+
if (!agentId || (!message && !imagePath)) {
|
|
58
|
+
return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: 'agentId and (message or image) required for send action' }) }] };
|
|
52
59
|
}
|
|
53
60
|
try {
|
|
54
|
-
// Use sendViaGopherHole for remote agents (routes through the hub)
|
|
55
|
-
// Use sendMessage for direct connections
|
|
56
61
|
const isGopherHoleConnected = manager.isGopherHoleConnected();
|
|
57
62
|
const isDirectConnection = manager.isConnected(agentId) && agentId !== 'gopherhole';
|
|
63
|
+
// Build parts array
|
|
64
|
+
const parts = [];
|
|
65
|
+
// Add text part if message provided
|
|
66
|
+
if (message) {
|
|
67
|
+
parts.push({ kind: 'text', text: message });
|
|
68
|
+
}
|
|
69
|
+
// Add image part if image path provided
|
|
70
|
+
if (imagePath) {
|
|
71
|
+
try {
|
|
72
|
+
const imageData = readFileSync(imagePath);
|
|
73
|
+
const base64Data = imageData.toString('base64');
|
|
74
|
+
const ext = extname(imagePath).toLowerCase();
|
|
75
|
+
const mimeTypes = {
|
|
76
|
+
'.png': 'image/png',
|
|
77
|
+
'.jpg': 'image/jpeg',
|
|
78
|
+
'.jpeg': 'image/jpeg',
|
|
79
|
+
'.gif': 'image/gif',
|
|
80
|
+
'.webp': 'image/webp',
|
|
81
|
+
'.svg': 'image/svg+xml',
|
|
82
|
+
};
|
|
83
|
+
const mimeType = mimeTypes[ext] || 'application/octet-stream';
|
|
84
|
+
parts.push({ kind: 'image', data: base64Data, mimeType });
|
|
85
|
+
}
|
|
86
|
+
catch (imgErr) {
|
|
87
|
+
return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: `Failed to read image: ${imgErr.message}` }) }] };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
58
90
|
let response;
|
|
59
91
|
if (isDirectConnection) {
|
|
60
|
-
// Direct WebSocket
|
|
61
|
-
|
|
92
|
+
// Direct WebSocket - only supports text for now
|
|
93
|
+
if (message) {
|
|
94
|
+
response = await manager.sendMessage(agentId, message);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: 'Direct connections only support text messages' }) }] };
|
|
98
|
+
}
|
|
62
99
|
}
|
|
63
100
|
else if (isGopherHoleConnected) {
|
|
64
|
-
// Route through GopherHole hub
|
|
65
|
-
response = await manager.
|
|
101
|
+
// Route through GopherHole hub with multi-part support
|
|
102
|
+
response = await manager.sendPartsViaGopherHole(agentId, parts);
|
|
66
103
|
}
|
|
67
104
|
else {
|
|
68
105
|
return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: `Cannot reach agent ${agentId} - no direct connection or GopherHole` }) }] };
|
package/dist/src/connection.d.ts
CHANGED
|
@@ -1,54 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A2A Connection Manager
|
|
3
|
-
*
|
|
3
|
+
* Uses @gopherhole/sdk for GopherHole hub connectivity
|
|
4
4
|
*/
|
|
5
|
+
import { GopherHole } from '@gopherhole/sdk';
|
|
5
6
|
import type { A2AMessage, A2AResponse, A2AChannelConfig } from './types.js';
|
|
6
7
|
export type MessageHandler = (agentId: string, message: A2AMessage) => Promise<void>;
|
|
7
8
|
export declare class A2AConnectionManager {
|
|
8
|
-
private
|
|
9
|
-
private pendingRequests;
|
|
10
|
-
private reconnectTimers;
|
|
9
|
+
private gopherhole;
|
|
11
10
|
private messageHandler;
|
|
12
11
|
private config;
|
|
13
12
|
private agentId;
|
|
13
|
+
private connected;
|
|
14
14
|
constructor(config: A2AChannelConfig);
|
|
15
15
|
setMessageHandler(handler: MessageHandler): void;
|
|
16
16
|
start(): Promise<void>;
|
|
17
17
|
private connectToGopherHole;
|
|
18
|
-
private
|
|
18
|
+
private handleIncomingMessage;
|
|
19
19
|
stop(): Promise<void>;
|
|
20
|
-
private connectToAgent;
|
|
21
|
-
private establishConnection;
|
|
22
|
-
private sendAgentAnnounce;
|
|
23
|
-
private scheduleReconnect;
|
|
24
|
-
private handleMessage;
|
|
25
20
|
/**
|
|
26
|
-
*
|
|
21
|
+
* Send a message to another agent via GopherHole and wait for response
|
|
27
22
|
*/
|
|
28
|
-
|
|
23
|
+
sendMessage(targetAgentId: string, text: string, _contextId?: string): Promise<A2AResponse>;
|
|
29
24
|
/**
|
|
30
|
-
* Send a message
|
|
25
|
+
* Send a multi-part message via GopherHole hub
|
|
26
|
+
* Supports text, images, and other MIME types
|
|
31
27
|
*/
|
|
32
|
-
|
|
28
|
+
sendPartsViaGopherHole(targetAgentId: string, parts: Array<{
|
|
29
|
+
kind: string;
|
|
30
|
+
text?: string;
|
|
31
|
+
data?: string;
|
|
32
|
+
mimeType?: string;
|
|
33
|
+
}>, contextId?: string): Promise<A2AResponse>;
|
|
33
34
|
/**
|
|
34
|
-
* Send a response to an incoming message
|
|
35
|
+
* Send a response to an incoming message via GopherHole
|
|
36
|
+
* Uses SDK's respond() method to complete the original task
|
|
35
37
|
*/
|
|
36
|
-
|
|
38
|
+
sendResponseViaGopherHole(_targetAgentId: string, taskId: string, text: string, _contextId?: string): void;
|
|
37
39
|
/**
|
|
38
|
-
*
|
|
40
|
+
* Legacy alias for sendPartsViaGopherHole with text-only
|
|
39
41
|
*/
|
|
40
|
-
|
|
42
|
+
sendViaGopherHole(targetAgentId: string, text: string, contextId?: string): Promise<A2AResponse>;
|
|
41
43
|
/**
|
|
42
|
-
*
|
|
43
|
-
* Note: targetAgentId must be the actual agent ID (e.g., "agent-70153299")
|
|
44
|
+
* Legacy sendResponse (routes to GopherHole)
|
|
44
45
|
*/
|
|
45
|
-
|
|
46
|
+
sendResponse(agentId: string, taskId: string, text: string, contextId?: string): void;
|
|
46
47
|
/**
|
|
47
48
|
* Check if GopherHole is connected
|
|
48
49
|
*/
|
|
49
50
|
isGopherHoleConnected(): boolean;
|
|
50
51
|
/**
|
|
51
|
-
* List connected agents
|
|
52
|
+
* List connected agents (just GopherHole for now)
|
|
52
53
|
*/
|
|
53
54
|
listAgents(): Array<{
|
|
54
55
|
id: string;
|
|
@@ -59,4 +60,8 @@ export declare class A2AConnectionManager {
|
|
|
59
60
|
* Check if an agent is connected
|
|
60
61
|
*/
|
|
61
62
|
isConnected(agentId: string): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Get the underlying GopherHole SDK instance (for advanced usage)
|
|
65
|
+
*/
|
|
66
|
+
getSDK(): GopherHole | null;
|
|
62
67
|
}
|