gopherhole_openclaw_a2a 0.4.7 → 0.4.8
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/channel.js
CHANGED
|
@@ -261,7 +261,20 @@ export const a2aPlugin = {
|
|
|
261
261
|
a2aLog.messageProcessing(message.taskId, sessionKey);
|
|
262
262
|
// Add A2A context so the agent knows to relay its full response
|
|
263
263
|
const a2aContext = `[A2A Request from agent "${message.from}"]\n\n${text}\n\n[Note: Your complete response will be sent back to the requesting agent. Include all relevant information in your reply.]`;
|
|
264
|
-
|
|
264
|
+
// A2A status updates are task-level keepalives. Publish one now and
|
|
265
|
+
// periodically while OpenClaw is working so callers do not mistake
|
|
266
|
+
// a long tool run for a dead connection.
|
|
267
|
+
connectionManager?.sendTaskStatusViaGopherHole(message.taskId, 'OpenClaw is working');
|
|
268
|
+
const keepalive = setInterval(() => {
|
|
269
|
+
connectionManager?.sendTaskStatusViaGopherHole(message.taskId, 'OpenClaw is still working');
|
|
270
|
+
}, 30_000);
|
|
271
|
+
let response;
|
|
272
|
+
try {
|
|
273
|
+
response = await sendChatMessage(sessionKey, a2aContext);
|
|
274
|
+
}
|
|
275
|
+
finally {
|
|
276
|
+
clearInterval(keepalive);
|
|
277
|
+
}
|
|
265
278
|
// Log captured response
|
|
266
279
|
if (response?.text) {
|
|
267
280
|
a2aLog.responseCaptured(message.taskId, response.text);
|
package/dist/src/connection.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export declare class A2AConnectionManager {
|
|
|
44
44
|
* Uses SDK's respond() method to complete the original task
|
|
45
45
|
*/
|
|
46
46
|
sendResponseViaGopherHole(_targetAgentId: string, taskId: string, text: string, _contextId?: string): void;
|
|
47
|
+
sendTaskStatusViaGopherHole(taskId: string, message?: string): void;
|
|
47
48
|
/**
|
|
48
49
|
* Legacy alias for sendPartsViaGopherHole with text-only
|
|
49
50
|
*/
|
package/dist/src/connection.js
CHANGED
|
@@ -271,6 +271,17 @@ export class A2AConnectionManager {
|
|
|
271
271
|
console.error('[a2a] Error details:', err);
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
|
+
sendTaskStatusViaGopherHole(taskId, message) {
|
|
275
|
+
if (!this.gopherhole || !this.connected || !taskId || taskId.startsWith('gph-')) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
this.gopherhole.updateTaskStatus(taskId, 'working', message);
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
console.error('[a2a] Failed to publish task status:', err.message);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
274
285
|
/**
|
|
275
286
|
* Legacy alias for sendPartsViaGopherHole with text-only
|
|
276
287
|
*/
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* resolve when we get state: "final".
|
|
8
8
|
*/
|
|
9
9
|
export declare const GATEWAY_PROTOCOL_VERSION = 4;
|
|
10
|
+
export declare const CHAT_INACTIVITY_TIMEOUT_MS: number;
|
|
10
11
|
export declare function connectToGateway(port?: number): Promise<void>;
|
|
11
12
|
export declare function callGateway(method: string, params: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
|
|
12
13
|
/**
|
|
@@ -20,6 +20,14 @@ let handshakeComplete = false;
|
|
|
20
20
|
// protocol bump fails a focused compatibility test instead of silently
|
|
21
21
|
// breaking inbound A2A replies at runtime.
|
|
22
22
|
export const GATEWAY_PROTOCOL_VERSION = 4;
|
|
23
|
+
export const CHAT_INACTIVITY_TIMEOUT_MS = 30 * 60 * 1000;
|
|
24
|
+
function refreshChatTimeout(runId, pending) {
|
|
25
|
+
clearTimeout(pending.timeout);
|
|
26
|
+
pending.timeout = setTimeout(() => {
|
|
27
|
+
pendingChats.delete(runId);
|
|
28
|
+
pending.reject(new Error('Chat response inactivity timeout'));
|
|
29
|
+
}, pending.timeoutMs);
|
|
30
|
+
}
|
|
23
31
|
function getGatewayToken() {
|
|
24
32
|
// Try the current OpenClaw config location first, then the legacy
|
|
25
33
|
// Clawdbot path as a fallback for users still on older installs.
|
|
@@ -65,7 +73,7 @@ export async function connectToGateway(port = 18789) {
|
|
|
65
73
|
client: {
|
|
66
74
|
id: 'gateway-client',
|
|
67
75
|
displayName: 'A2A Channel Plugin',
|
|
68
|
-
version: '0.4.
|
|
76
|
+
version: '0.4.8',
|
|
69
77
|
platform: process.platform,
|
|
70
78
|
mode: 'backend',
|
|
71
79
|
},
|
|
@@ -174,6 +182,9 @@ function handleChatEvent(payload) {
|
|
|
174
182
|
// Not a chat we're tracking
|
|
175
183
|
return;
|
|
176
184
|
}
|
|
185
|
+
// Any chat event proves the OpenClaw run is alive. Treat the timeout as an
|
|
186
|
+
// inactivity deadline rather than a fixed whole-task deadline.
|
|
187
|
+
refreshChatTimeout(payload.runId, pending);
|
|
177
188
|
// Detailed logging for debugging relay issues
|
|
178
189
|
console.log(`[a2a] Chat event: runId=${payload.runId}, state=${payload.state}, seq=${payload.seq}, role=${payload.message?.role}`);
|
|
179
190
|
if (payload.state === 'delta' || payload.state === 'final') {
|
|
@@ -238,7 +249,7 @@ export async function callGateway(method, params, timeoutMs = 300000) {
|
|
|
238
249
|
* Send a chat message and wait for the full response.
|
|
239
250
|
* chat.send is non-blocking - returns runId immediately, response streams via events.
|
|
240
251
|
*/
|
|
241
|
-
export async function sendChatMessage(sessionKey, message, timeoutMs =
|
|
252
|
+
export async function sendChatMessage(sessionKey, message, timeoutMs = CHAT_INACTIVITY_TIMEOUT_MS) {
|
|
242
253
|
if (!ws || !connected || !handshakeComplete) {
|
|
243
254
|
await connectToGateway();
|
|
244
255
|
}
|
|
@@ -256,16 +267,15 @@ export async function sendChatMessage(sessionKey, message, timeoutMs = 300000) {
|
|
|
256
267
|
}
|
|
257
268
|
// Now wait for chat events to complete
|
|
258
269
|
return new Promise((resolve, reject) => {
|
|
259
|
-
const
|
|
260
|
-
pendingChats.delete(result.runId);
|
|
261
|
-
reject(new Error('Chat response timeout'));
|
|
262
|
-
}, timeoutMs);
|
|
263
|
-
pendingChats.set(result.runId, {
|
|
270
|
+
const pending = {
|
|
264
271
|
resolve,
|
|
265
272
|
reject,
|
|
266
|
-
timeout,
|
|
273
|
+
timeout: undefined,
|
|
267
274
|
latestText: '',
|
|
268
|
-
|
|
275
|
+
timeoutMs,
|
|
276
|
+
};
|
|
277
|
+
pendingChats.set(result.runId, pending);
|
|
278
|
+
refreshChatTimeout(result.runId, pending);
|
|
269
279
|
});
|
|
270
280
|
}
|
|
271
281
|
export function disconnectFromGateway() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gopherhole_openclaw_a2a",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
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,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@gopherhole/sdk": "^0.
|
|
38
|
+
"@gopherhole/sdk": "^0.9.1",
|
|
39
39
|
"uuid": "^10.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|