@clawcrony/claw-crony 1.0.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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/dist/index.d.ts +17 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +720 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/agent-card.d.ts +4 -0
  8. package/dist/src/agent-card.d.ts.map +1 -0
  9. package/dist/src/agent-card.js +61 -0
  10. package/dist/src/agent-card.js.map +1 -0
  11. package/dist/src/audit.d.ts +36 -0
  12. package/dist/src/audit.d.ts.map +1 -0
  13. package/dist/src/audit.js +88 -0
  14. package/dist/src/audit.js.map +1 -0
  15. package/dist/src/client.d.ts +53 -0
  16. package/dist/src/client.d.ts.map +1 -0
  17. package/dist/src/client.js +322 -0
  18. package/dist/src/client.js.map +1 -0
  19. package/dist/src/executor.d.ts +34 -0
  20. package/dist/src/executor.d.ts.map +1 -0
  21. package/dist/src/executor.js +994 -0
  22. package/dist/src/executor.js.map +1 -0
  23. package/dist/src/file-security.d.ts +63 -0
  24. package/dist/src/file-security.d.ts.map +1 -0
  25. package/dist/src/file-security.js +350 -0
  26. package/dist/src/file-security.js.map +1 -0
  27. package/dist/src/hub-match.d.ts +73 -0
  28. package/dist/src/hub-match.d.ts.map +1 -0
  29. package/dist/src/hub-match.js +120 -0
  30. package/dist/src/hub-match.js.map +1 -0
  31. package/dist/src/hub-registration.d.ts +24 -0
  32. package/dist/src/hub-registration.d.ts.map +1 -0
  33. package/dist/src/hub-registration.js +242 -0
  34. package/dist/src/hub-registration.js.map +1 -0
  35. package/dist/src/internal/envelope.d.ts +33 -0
  36. package/dist/src/internal/envelope.d.ts.map +1 -0
  37. package/dist/src/internal/envelope.js +152 -0
  38. package/dist/src/internal/envelope.js.map +1 -0
  39. package/dist/src/internal/idempotency.d.ts +48 -0
  40. package/dist/src/internal/idempotency.d.ts.map +1 -0
  41. package/dist/src/internal/idempotency.js +82 -0
  42. package/dist/src/internal/idempotency.js.map +1 -0
  43. package/dist/src/internal/metrics.d.ts +38 -0
  44. package/dist/src/internal/metrics.d.ts.map +1 -0
  45. package/dist/src/internal/metrics.js +83 -0
  46. package/dist/src/internal/metrics.js.map +1 -0
  47. package/dist/src/internal/outbox.d.ts +49 -0
  48. package/dist/src/internal/outbox.d.ts.map +1 -0
  49. package/dist/src/internal/outbox.js +149 -0
  50. package/dist/src/internal/outbox.js.map +1 -0
  51. package/dist/src/internal/routing.d.ts +28 -0
  52. package/dist/src/internal/routing.d.ts.map +1 -0
  53. package/dist/src/internal/routing.js +57 -0
  54. package/dist/src/internal/routing.js.map +1 -0
  55. package/dist/src/internal/security.d.ts +53 -0
  56. package/dist/src/internal/security.d.ts.map +1 -0
  57. package/dist/src/internal/security.js +122 -0
  58. package/dist/src/internal/security.js.map +1 -0
  59. package/dist/src/internal/transport.d.ts +49 -0
  60. package/dist/src/internal/transport.d.ts.map +1 -0
  61. package/dist/src/internal/transport.js +207 -0
  62. package/dist/src/internal/transport.js.map +1 -0
  63. package/dist/src/internal/types-internal.d.ts +95 -0
  64. package/dist/src/internal/types-internal.d.ts.map +1 -0
  65. package/dist/src/internal/types-internal.js +9 -0
  66. package/dist/src/internal/types-internal.js.map +1 -0
  67. package/dist/src/peer-health.d.ts +47 -0
  68. package/dist/src/peer-health.d.ts.map +1 -0
  69. package/dist/src/peer-health.js +169 -0
  70. package/dist/src/peer-health.js.map +1 -0
  71. package/dist/src/peer-retry.d.ts +16 -0
  72. package/dist/src/peer-retry.d.ts.map +1 -0
  73. package/dist/src/peer-retry.js +75 -0
  74. package/dist/src/peer-retry.js.map +1 -0
  75. package/dist/src/queueing-executor.d.ts +23 -0
  76. package/dist/src/queueing-executor.d.ts.map +1 -0
  77. package/dist/src/queueing-executor.js +179 -0
  78. package/dist/src/queueing-executor.js.map +1 -0
  79. package/dist/src/routing-rules.d.ts +53 -0
  80. package/dist/src/routing-rules.d.ts.map +1 -0
  81. package/dist/src/routing-rules.js +130 -0
  82. package/dist/src/routing-rules.js.map +1 -0
  83. package/dist/src/task-cleanup.d.ts +21 -0
  84. package/dist/src/task-cleanup.d.ts.map +1 -0
  85. package/dist/src/task-cleanup.js +77 -0
  86. package/dist/src/task-cleanup.js.map +1 -0
  87. package/dist/src/task-store.d.ts +16 -0
  88. package/dist/src/task-store.d.ts.map +1 -0
  89. package/dist/src/task-store.js +80 -0
  90. package/dist/src/task-store.js.map +1 -0
  91. package/dist/src/telemetry.d.ts +88 -0
  92. package/dist/src/telemetry.d.ts.map +1 -0
  93. package/dist/src/telemetry.js +235 -0
  94. package/dist/src/telemetry.js.map +1 -0
  95. package/dist/src/transport-fallback.d.ts +29 -0
  96. package/dist/src/transport-fallback.d.ts.map +1 -0
  97. package/dist/src/transport-fallback.js +81 -0
  98. package/dist/src/transport-fallback.js.map +1 -0
  99. package/dist/src/types.d.ts +160 -0
  100. package/dist/src/types.d.ts.map +1 -0
  101. package/dist/src/types.js +7 -0
  102. package/dist/src/types.js.map +1 -0
  103. package/openclaw.plugin.json +272 -0
  104. package/package.json +56 -0
  105. package/skill/SKILL.md +230 -0
  106. package/skill/references/tools-md-template.md +57 -0
  107. package/skill/scripts/a2a-send.mjs +357 -0
@@ -0,0 +1,272 @@
1
+ {
2
+ "id": "claw-crony",
3
+ "name": "Claw Crony",
4
+ "description": "OpenClaw A2A v0.3.0 gateway with Agent Card, JSON-RPC, REST, routing rules, transport fallback, and Hub matchmaking",
5
+ "version": "1.0.1",
6
+ "defaultConfig": {
7
+ "agentCard": {
8
+ "name": "OpenClaw A2A Gateway",
9
+ "description": "A2A bridge for OpenClaw agents",
10
+ "skills": [{ "id": "chat", "name": "chat", "description": "Chat bridge" }]
11
+ },
12
+ "hub": {
13
+ "url": "https://www.factormining.cn",
14
+ "enabled": true,
15
+ "registrationEnabled": true
16
+ }
17
+ },
18
+ "configSchema": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "properties": {
22
+ "agentCard": {
23
+ "type": "object",
24
+ "additionalProperties": false,
25
+ "properties": {
26
+ "name": { "type": "string" },
27
+ "description": { "type": "string" },
28
+ "url": { "type": "string" },
29
+ "skills": {
30
+ "type": "array",
31
+ "items": {
32
+ "oneOf": [
33
+ { "type": "string" },
34
+ {
35
+ "type": "object",
36
+ "properties": {
37
+ "id": { "type": "string" },
38
+ "name": { "type": "string" },
39
+ "description": { "type": "string" }
40
+ },
41
+ "required": ["name"]
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ }
47
+ },
48
+ "hub": {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "properties": {
52
+ "url": { "type": "string" },
53
+ "enabled": { "type": "boolean", "default": true },
54
+ "registrationEnabled": { "type": "boolean", "default": true }
55
+ }
56
+ },
57
+ "registration": {
58
+ "type": "object",
59
+ "additionalProperties": false,
60
+ "properties": {
61
+ "username": { "type": "string" },
62
+ "email": { "type": "string" }
63
+ }
64
+ },
65
+ "server": {
66
+ "type": "object",
67
+ "additionalProperties": false,
68
+ "properties": {
69
+ "host": { "type": "string", "default": "0.0.0.0" },
70
+ "port": { "type": "number", "default": 18800 }
71
+ }
72
+ },
73
+ "storage": {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "properties": {
77
+ "tasksDir": { "type": "string", "default": "~/.openclaw/a2a-tasks" },
78
+ "taskTtlHours": {
79
+ "type": "number",
80
+ "default": 72,
81
+ "minimum": 1,
82
+ "description": "Hours before completed/failed/canceled tasks are automatically deleted (default 72h)"
83
+ },
84
+ "cleanupIntervalMinutes": {
85
+ "type": "number",
86
+ "default": 60,
87
+ "minimum": 1,
88
+ "description": "Minutes between automatic task cleanup runs (default 60min)"
89
+ }
90
+ }
91
+ },
92
+ "peers": {
93
+ "type": "array",
94
+ "items": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "properties": {
98
+ "name": { "type": "string" },
99
+ "agentCardUrl": { "type": "string" },
100
+ "auth": {
101
+ "type": "object",
102
+ "additionalProperties": false,
103
+ "properties": {
104
+ "type": {
105
+ "type": "string",
106
+ "enum": ["bearer", "apiKey"]
107
+ },
108
+ "token": { "type": "string" }
109
+ },
110
+ "required": ["type", "token"]
111
+ }
112
+ },
113
+ "required": ["name", "agentCardUrl"]
114
+ }
115
+ },
116
+ "security": {
117
+ "type": "object",
118
+ "additionalProperties": false,
119
+ "properties": {
120
+ "inboundAuth": {
121
+ "type": "string",
122
+ "enum": ["none", "bearer"],
123
+ "default": "none"
124
+ },
125
+ "token": { "type": "string" },
126
+ "tokens": {
127
+ "type": "array",
128
+ "items": { "type": "string" },
129
+ "description": "Multiple tokens for zero-downtime rotation. Used alongside or instead of 'token'."
130
+ },
131
+ "allowedMimeTypes": {
132
+ "type": "array",
133
+ "items": { "type": "string" },
134
+ "description": "Allowed MIME type patterns for file transfer (e.g. \"image/*\", \"application/pdf\")"
135
+ },
136
+ "maxFileSizeBytes": {
137
+ "type": "number",
138
+ "default": 52428800,
139
+ "minimum": 0,
140
+ "description": "Max file size in bytes for URI-based files (default 50MB)"
141
+ },
142
+ "maxInlineFileSizeBytes": {
143
+ "type": "number",
144
+ "default": 10485760,
145
+ "minimum": 0,
146
+ "description": "Max file size in bytes for inline base64 files (default 10MB)"
147
+ },
148
+ "fileUriAllowlist": {
149
+ "type": "array",
150
+ "items": { "type": "string" },
151
+ "description": "URI hostname allowlist patterns (e.g. \"*.example.com\"). Empty allows all public hosts."
152
+ }
153
+ }
154
+ },
155
+ "routing": {
156
+ "type": "object",
157
+ "additionalProperties": false,
158
+ "properties": {
159
+ "defaultAgentId": {
160
+ "type": "string",
161
+ "default": "default"
162
+ },
163
+ "rules": {
164
+ "type": "array",
165
+ "description": "Rule-based routing: auto-select peer by message text regex, tags, or required skills"
166
+ }
167
+ }
168
+ },
169
+ "limits": {
170
+ "type": "object",
171
+ "additionalProperties": false,
172
+ "properties": {
173
+ "maxConcurrentTasks": {
174
+ "type": "number",
175
+ "default": 4,
176
+ "minimum": 1
177
+ },
178
+ "maxQueuedTasks": {
179
+ "type": "number",
180
+ "default": 100,
181
+ "minimum": 0
182
+ }
183
+ }
184
+ },
185
+ "observability": {
186
+ "type": "object",
187
+ "additionalProperties": false,
188
+ "properties": {
189
+ "structuredLogs": {
190
+ "type": "boolean",
191
+ "default": true
192
+ },
193
+ "exposeMetricsEndpoint": {
194
+ "type": "boolean",
195
+ "default": true
196
+ },
197
+ "metricsPath": {
198
+ "type": "string",
199
+ "default": "/a2a/metrics"
200
+ },
201
+ "metricsAuth": {
202
+ "type": "string",
203
+ "enum": ["none", "bearer"],
204
+ "default": "none",
205
+ "description": "Authentication for the metrics endpoint. When set to 'bearer', reuses security.token/tokens."
206
+ },
207
+ "auditLogPath": {
208
+ "type": "string",
209
+ "default": "~/.openclaw/a2a-audit.jsonl",
210
+ "description": "Path for the JSONL audit log file (separate from structured logs)."
211
+ }
212
+ }
213
+ },
214
+ "timeouts": {
215
+ "type": "object",
216
+ "additionalProperties": false,
217
+ "properties": {
218
+ "agentResponseTimeoutMs": {
219
+ "type": "number",
220
+ "default": 300000,
221
+ "minimum": 1000
222
+ }
223
+ }
224
+ },
225
+ "resilience": {
226
+ "type": "object",
227
+ "additionalProperties": false,
228
+ "properties": {
229
+ "healthCheck": {
230
+ "type": "object",
231
+ "additionalProperties": false,
232
+ "properties": {
233
+ "enabled": { "type": "boolean", "default": true },
234
+ "intervalMs": { "type": "number", "default": 30000, "minimum": 1000 },
235
+ "timeoutMs": { "type": "number", "default": 5000, "minimum": 500 }
236
+ }
237
+ },
238
+ "retry": {
239
+ "type": "object",
240
+ "additionalProperties": false,
241
+ "properties": {
242
+ "maxRetries": { "type": "number", "default": 3, "minimum": 0 },
243
+ "baseDelayMs": { "type": "number", "default": 1000, "minimum": 100 },
244
+ "maxDelayMs": { "type": "number", "default": 10000, "minimum": 100 }
245
+ }
246
+ },
247
+ "circuitBreaker": {
248
+ "type": "object",
249
+ "additionalProperties": false,
250
+ "properties": {
251
+ "failureThreshold": { "type": "number", "default": 5, "minimum": 1 },
252
+ "resetTimeoutMs": { "type": "number", "default": 30000, "minimum": 1000 }
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+ },
259
+ "uiHints": {
260
+ "peers": {
261
+ "items": {
262
+ "auth": {
263
+ "token": { "sensitive": true }
264
+ }
265
+ }
266
+ },
267
+ "security": {
268
+ "token": { "sensitive": true },
269
+ "tokens": { "items": { "sensitive": true } }
270
+ }
271
+ }
272
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@clawcrony/claw-crony",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "description": "OpenClaw A2A gateway plugin implementing the A2A v0.3.0 protocol surface",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "openclaw.plugin.json",
17
+ "skill"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "test": "node --import tsx --test tests/*.test.ts"
22
+ },
23
+ "keywords": [
24
+ "openclaw",
25
+ "a2a",
26
+ "agent-to-agent",
27
+ "gateway",
28
+ "plugin"
29
+ ],
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "@types/express": "^5.0.6",
33
+ "@types/node": "^22.0.0",
34
+ "@types/supertest": "^2.0.16",
35
+ "@types/uuid": "^10.0.0",
36
+ "openclaw": "^2026.3.2",
37
+ "supertest": "^7.1.4",
38
+ "tsx": "^4.19.0",
39
+ "typescript": "^5.9.3"
40
+ },
41
+ "dependencies": {
42
+ "@a2a-js/sdk": "^0.3.0",
43
+ "@bufbuild/protobuf": "^2.11.0",
44
+ "@grpc/grpc-js": "^1.14.3",
45
+ "express": "^4.21.2",
46
+ "uuid": "^9.0.1"
47
+ },
48
+ "openclaw": {
49
+ "extensions": [
50
+ "./index.ts"
51
+ ]
52
+ },
53
+ "engines": {
54
+ "node": ">=22"
55
+ }
56
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,230 @@
1
+ ---
2
+ name: a2a-setup
3
+ description: "Install and configure the OpenClaw A2A Gateway plugin for cross-server agent communication. Use when: (1) setting up A2A between two or more OpenClaw instances, (2) user says 'configure A2A', 'set up A2A gateway', 'connect two OpenClaw servers', 'agent-to-agent communication', (3) adding a new A2A peer to an existing setup. Covers: plugin installation, Agent Card configuration, security tokens, peer registration, network setup (Tailscale/LAN), TOOLS.md template for agent awareness, and end-to-end verification."
4
+ ---
5
+
6
+ # A2A Gateway Setup
7
+
8
+ Configure the OpenClaw A2A Gateway plugin for cross-server agent-to-agent communication using the A2A v0.3.0 protocol.
9
+
10
+ ## Prerequisites
11
+
12
+ - OpenClaw ≥ 2026.3.0 installed and running on each server
13
+ - Network connectivity between servers (Tailscale recommended, LAN or public IP also work)
14
+ - Node.js ≥ 22
15
+
16
+ ## Step 1: Install the Plugin
17
+
18
+ ```bash
19
+ mkdir -p <WORKSPACE>/plugins
20
+ cd <WORKSPACE>/plugins
21
+ git clone https://github.com/win4r/openclaw-a2a-gateway.git a2a-gateway
22
+ cd a2a-gateway
23
+ npm install --production
24
+ ```
25
+
26
+ Replace `<WORKSPACE>` with the agent workspace path. Find it with:
27
+
28
+ ```bash
29
+ openclaw config get agents.defaults.workspace
30
+ ```
31
+
32
+ ## Step 2: Register Plugin in OpenClaw
33
+
34
+ Get current allowed plugins first to avoid overwriting:
35
+
36
+ ```bash
37
+ openclaw config get plugins.allow
38
+ ```
39
+
40
+ Then add `a2a-gateway` to the existing array (do NOT drop existing plugin ids):
41
+
42
+ ```bash
43
+ # Example only — include your existing plugins too
44
+ openclaw config set plugins.allow '["<existing...>", "a2a-gateway"]'
45
+ openclaw config set plugins.load.paths '["<ABSOLUTE_PATH>/plugins/a2a-gateway"]'
46
+ openclaw config set plugins.entries.a2a-gateway.enabled true
47
+ ```
48
+
49
+ **Critical:** Use the absolute path in `plugins.load.paths`. Relative paths will fail.
50
+
51
+ ## Step 3: Configure Agent Card
52
+
53
+ ```bash
54
+ openclaw config set plugins.entries.a2a-gateway.config.agentCard.name '<AGENT_NAME>'
55
+ openclaw config set plugins.entries.a2a-gateway.config.agentCard.description '<DESCRIPTION>'
56
+ openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://<REACHABLE_IP>:18800/a2a/jsonrpc'
57
+ openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Bridge chat/messages to OpenClaw agents"}]'
58
+ ```
59
+
60
+ ### URL field rules
61
+
62
+ | Field | Points to | Example |
63
+ |-------|-----------|---------|
64
+ | `agentCard.url` | JSON-RPC endpoint (default) | `http://100.x.x.x:18800/a2a/jsonrpc` |
65
+ | `peers[].agentCardUrl` | Agent Card discovery (preferred) | `http://100.x.x.x:18800/.well-known/agent-card.json` |
66
+
67
+ **Do NOT confuse these two.** `agentCard.url` tells peers where to send messages. `agentCardUrl` tells you where to discover the peer.
68
+
69
+ Note: this plugin also serves the legacy alias `/.well-known/agent.json`, but the official SDK default is `/.well-known/agent-card.json`.
70
+
71
+ ## Step 4: Configure Server
72
+
73
+ ```bash
74
+ openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
75
+ openclaw config set plugins.entries.a2a-gateway.config.server.port 18800
76
+ ```
77
+
78
+ ## Step 5: Configure Security
79
+
80
+ ```bash
81
+ TOKEN=$(openssl rand -hex 24)
82
+ echo "Save this token: $TOKEN"
83
+
84
+ openclaw config set plugins.entries.a2a-gateway.config.security.inboundAuth 'bearer'
85
+ openclaw config set plugins.entries.a2a-gateway.config.security.token "$TOKEN"
86
+ ```
87
+
88
+ Share this token with peers who need to send you messages.
89
+
90
+ ## Step 6: Configure Routing
91
+
92
+ ```bash
93
+ openclaw config set plugins.entries.a2a-gateway.config.routing.defaultAgentId 'main'
94
+ ```
95
+
96
+ ## Step 7: Add Peers
97
+
98
+ ```bash
99
+ openclaw config set plugins.entries.a2a-gateway.config.peers '[
100
+ {
101
+ "name": "<PEER_NAME>",
102
+ "agentCardUrl": "http://<PEER_IP>:18800/.well-known/agent-card.json",
103
+ "auth": {
104
+ "type": "bearer",
105
+ "token": "<PEER_INBOUND_TOKEN>"
106
+ }
107
+ }
108
+ ]'
109
+ ```
110
+
111
+ For multiple peers, include all in one JSON array.
112
+
113
+ ## Step 8: Restart and Verify
114
+
115
+ ```bash
116
+ openclaw gateway restart
117
+
118
+ # Verify Agent Card
119
+ curl -s http://localhost:18800/.well-known/agent-card.json | python3 -m json.tool
120
+
121
+ # Verify peer connectivity
122
+ curl -s http://<PEER_IP>:18800/.well-known/agent-card.json | python3 -m json.tool
123
+ ```
124
+
125
+ ## Step 9: Configure TOOLS.md
126
+
127
+ **This step is critical.** Without it, the agent won't know how to use A2A.
128
+
129
+ Read `references/tools-md-template.md` and append the A2A section to the agent's `TOOLS.md`, replacing placeholders with actual peer info.
130
+
131
+ For outbound messaging, use the SDK script (`scripts/a2a-send.mjs`).
132
+
133
+ To use the SDK script, ensure `@a2a-js/sdk` is installed in the plugin directory:
134
+
135
+ ```bash
136
+ cd <WORKSPACE>/plugins/a2a-gateway && npm ls @a2a-js/sdk
137
+ ```
138
+
139
+ ## Step 10: End-to-End Test
140
+
141
+ ```bash
142
+ node <WORKSPACE>/plugins/a2a-gateway/skill/scripts/a2a-send.mjs \
143
+ --peer-url http://<PEER_IP>:18800 \
144
+ --token <PEER_TOKEN> \
145
+ --message "Hello, what is your name?"
146
+ ```
147
+
148
+ The script uses `@a2a-js/sdk` ClientFactory to auto-discover the Agent Card, handle authentication, and print the peer agent's response.
149
+
150
+ ### Async task mode (recommended for long-running prompts)
151
+
152
+ For prompts that may take longer than a typical request timeout (e.g., multi-round discussions, long summaries), use non-blocking mode + polling:
153
+
154
+ ```bash
155
+ node <WORKSPACE>/plugins/a2a-gateway/skill/scripts/a2a-send.mjs \
156
+ --peer-url http://<PEER_IP>:18800 \
157
+ --token <PEER_TOKEN> \
158
+ --non-blocking \
159
+ --wait \
160
+ --timeout-ms 600000 \
161
+ --poll-ms 1000 \
162
+ --message "Discuss A2A advantages in 3 rounds and provide final conclusion"
163
+ ```
164
+
165
+ This sends `configuration.blocking=false` and then polls `tasks/get` until the task reaches a terminal state.
166
+
167
+ ### Server-side timeout configuration (OpenClaw dispatch)
168
+
169
+ If you still see `Request accepted (no agent dispatch available)`, the underlying OpenClaw agent run may be timing out. Increase:
170
+
171
+ - `plugins.entries.a2a-gateway.config.timeouts.agentResponseTimeoutMs` (default: 300000)
172
+
173
+ ### Optional: Route to a specific OpenClaw agentId (OpenClaw extension)
174
+
175
+ By default, the peer will route inbound A2A messages to `routing.defaultAgentId`.
176
+
177
+ To route a single request to a specific agentId (e.g., `coder`) on the peer, pass `--agent-id`:
178
+
179
+ ```bash
180
+ node <WORKSPACE>/plugins/a2a-gateway/skill/scripts/a2a-send.mjs \
181
+ --peer-url http://<PEER_IP>:18800 \
182
+ --token <PEER_TOKEN> \
183
+ --agent-id coder \
184
+ --message "Run tests and summarize failures"
185
+ ```
186
+
187
+ Note: this uses a non-standard `message.agentId` field understood by the OpenClaw A2A Gateway plugin. It is most reliable over JSON-RPC/REST. gRPC transport may drop unknown Message fields.
188
+
189
+ ## Network: Tailscale Setup (if needed)
190
+
191
+ When servers are on different networks, use Tailscale:
192
+
193
+ ```bash
194
+ curl -fsSL https://tailscale.com/install.sh | sh
195
+ sudo tailscale up
196
+ # Authenticate via the printed URL (use same account on all servers)
197
+ tailscale ip -4 # Get the 100.x.x.x IP
198
+ ```
199
+
200
+ Use Tailscale IPs in all A2A configuration. Verify with:
201
+
202
+ ```bash
203
+ ping <OTHER_SERVER_TAILSCALE_IP>
204
+ ```
205
+
206
+ ## Mutual Peering Checklist
207
+
208
+ For two-way communication, repeat Steps 1-9 on BOTH servers:
209
+
210
+ - [ ] Server A: plugin installed, Agent Card configured, token generated
211
+ - [ ] Server B: plugin installed, Agent Card configured, token generated
212
+ - [ ] Server A: has Server B in peers (with B's token)
213
+ - [ ] Server B: has Server A in peers (with A's token)
214
+ - [ ] Server A: TOOLS.md updated with Server B peer info
215
+ - [ ] Server B: TOOLS.md updated with Server A peer info
216
+ - [ ] Both: `openclaw gateway restart` done
217
+ - [ ] Both: Agent Cards accessible (`curl /.well-known/agent-card.json`)
218
+ - [ ] Test: A → B message/send works
219
+ - [ ] Test: B → A message/send works
220
+
221
+ ## Troubleshooting
222
+
223
+ | Symptom | Cause | Fix |
224
+ |---------|-------|-----|
225
+ | "no agent dispatch available" | (1) No AI provider configured, or (2) OpenClaw agent dispatch timed out | Check `openclaw config get auth.profiles`; for long prompts use async mode (`--non-blocking --wait`) or increase `config.timeouts.agentResponseTimeoutMs` |
226
+ | "plugin not found: a2a-gateway" | Load path missing or wrong | Verify `plugins.load.paths` uses absolute path |
227
+ | Agent Card 404 | Plugin not loaded | Check `plugins.allow` includes `a2a-gateway` |
228
+ | Port 18800 connection refused | Gateway not restarted | Run `openclaw gateway restart` |
229
+ | Peer auth fails | Token mismatch | Verify peer config token matches target's `security.token` |
230
+ | Agent doesn't know about A2A | TOOLS.md not configured | Add A2A section from the template (Step 9) |
@@ -0,0 +1,57 @@
1
+ # TOOLS.md A2A Section Template
2
+
3
+ Append this section to the agent's `TOOLS.md` file, replacing all `<PLACEHOLDERS>` with actual values.
4
+
5
+ ---
6
+
7
+ ```markdown
8
+ ## A2A Gateway (Agent-to-Agent Communication)
9
+
10
+ You have an A2A Gateway plugin running on port 18800. You can communicate with peer agents on other servers.
11
+
12
+ ### Peers
13
+
14
+ | Peer | IP | Auth Token |
15
+ |------|-----|------------|
16
+ | <PEER_NAME> | <PEER_IP> | <PEER_TOKEN> |
17
+
18
+ ### How to send a message to a peer
19
+
20
+ When the user says "通过 A2A 让 <PEER_NAME> 做 xxx" / "Send to <PEER_NAME>: xxx" / "Ask <PEER_NAME> to ..." or similar, use the exec tool to run:
21
+
22
+ ```bash
23
+ node <WORKSPACE>/plugins/a2a-gateway/skill/scripts/a2a-send.mjs \
24
+ --peer-url http://<PEER_IP>:18800 \
25
+ --token <PEER_TOKEN> \
26
+ --message "YOUR MESSAGE HERE"
27
+
28
+ # Optional (OpenClaw extension): route to a specific peer OpenClaw agentId
29
+ # --agent-id coder
30
+ ```
31
+
32
+ The script uses `@a2a-js/sdk` ClientFactory to:
33
+ - Auto-discover the peer's Agent Card
34
+ - Handle bearer token authentication
35
+ - Select the best transport (JSON-RPC by default; REST or GRPC if preferred/available)
36
+ - Print the peer agent's response text directly
37
+
38
+ ### Notes
39
+
40
+ - For long-running prompts (multi-round discussions, long summaries), use async task mode:
41
+ - add: `--non-blocking --wait --timeout-ms 600000 --poll-ms 1000`
42
+ - If the peer returns an error, check the token and network connectivity
43
+ - The script handles messageId generation and response parsing automatically
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Placeholder Reference
49
+
50
+ | Placeholder | Description | Example |
51
+ |-------------|-------------|---------|
52
+ | `<PEER_NAME>` | Display name of the peer agent | `Server-A` |
53
+ | `<PEER_IP>` | IP address reachable from this server | `100.76.43.74` |
54
+ | `<PEER_TOKEN>` | The peer's inbound security token | `9489c2c7ce10...` |
55
+ | `<WORKSPACE>` | Agent workspace absolute path | `/home/ubuntu/.openclaw/workspace` |
56
+
57
+ For multiple peers, add one row per peer to the table.