@probelabs/visor 0.1.169 → 0.1.170
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/README.md +64 -7
- package/defaults/assistant.yaml +1 -1
- package/defaults/code-talk.yaml +2 -2
- package/dist/defaults/assistant.yaml +1 -1
- package/dist/defaults/code-talk.yaml +2 -2
- package/dist/docs/a2a-provider.md +672 -0
- package/dist/docs/architecture.md +174 -12
- package/dist/docs/commands.md +36 -0
- package/dist/docs/configuration.md +1 -0
- package/dist/docs/index.md +9 -2
- package/dist/docs/pluggable.md +16 -1
- package/dist/index.js +4 -4
- package/dist/output/traces/{run-2026-03-07T13-37-21-566Z.ndjson → run-2026-03-07T15-43-18-430Z.ndjson} +84 -84
- package/dist/output/traces/{run-2026-03-07T13-37-59-420Z.ndjson → run-2026-03-07T15-43-56-196Z.ndjson} +1818 -1818
- package/dist/sdk/{a2a-frontend-XFCSNQR5.mjs → a2a-frontend-IPLHACI6.mjs} +2 -2
- package/dist/sdk/{check-provider-registry-XEU5BSRJ.mjs → check-provider-registry-STRAOYRJ.mjs} +5 -5
- package/dist/sdk/{chunk-VPPW2TFI.mjs → chunk-47WAHGHK.mjs} +3 -3
- package/dist/sdk/{chunk-ROMY3ZN3.mjs → chunk-NYQTQYGU.mjs} +15 -15
- package/dist/sdk/{chunk-WGZNS5IB.mjs → chunk-WNLCRRQO.mjs} +2 -2
- package/dist/sdk/{chunk-HBT572VG.mjs → chunk-ZM7ALGTE.mjs} +2 -2
- package/dist/sdk/{chunk-HBT572VG.mjs.map → chunk-ZM7ALGTE.mjs.map} +1 -1
- package/dist/sdk/{failure-condition-evaluator-WYDAZT3H.mjs → failure-condition-evaluator-T67YFO2Z.mjs} +3 -3
- package/dist/sdk/{github-frontend-BVM7MHBJ.mjs → github-frontend-BAPXDLBB.mjs} +3 -3
- package/dist/sdk/{host-MHYGIPDP.mjs → host-K6IZWJG3.mjs} +3 -3
- package/dist/sdk/{routing-K2U7U3OO.mjs → routing-SAGHEUOA.mjs} +4 -4
- package/dist/sdk/{schedule-tool-RYYNPLDH.mjs → schedule-tool-TGWPINHO.mjs} +5 -5
- package/dist/sdk/{schedule-tool-handler-NFNY6BVX.mjs → schedule-tool-handler-OEBLE5AB.mjs} +5 -5
- package/dist/sdk/sdk.js +1 -1
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +4 -4
- package/dist/sdk/{trace-helpers-DQYOGQT5.mjs → trace-helpers-M7RVAZQ2.mjs} +2 -2
- package/dist/sdk/{workflow-check-provider-OM5L5FJX.mjs → workflow-check-provider-VDSZR7Y5.mjs} +5 -5
- package/dist/traces/{run-2026-03-07T13-37-21-566Z.ndjson → run-2026-03-07T15-43-18-430Z.ndjson} +84 -84
- package/dist/traces/{run-2026-03-07T13-37-59-420Z.ndjson → run-2026-03-07T15-43-56-196Z.ndjson} +1818 -1818
- package/package.json +1 -1
- /package/dist/sdk/{a2a-frontend-XFCSNQR5.mjs.map → a2a-frontend-IPLHACI6.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-XEU5BSRJ.mjs.map → check-provider-registry-STRAOYRJ.mjs.map} +0 -0
- /package/dist/sdk/{chunk-VPPW2TFI.mjs.map → chunk-47WAHGHK.mjs.map} +0 -0
- /package/dist/sdk/{chunk-ROMY3ZN3.mjs.map → chunk-NYQTQYGU.mjs.map} +0 -0
- /package/dist/sdk/{chunk-WGZNS5IB.mjs.map → chunk-WNLCRRQO.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-WYDAZT3H.mjs.map → failure-condition-evaluator-T67YFO2Z.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-BVM7MHBJ.mjs.map → github-frontend-BAPXDLBB.mjs.map} +0 -0
- /package/dist/sdk/{host-MHYGIPDP.mjs.map → host-K6IZWJG3.mjs.map} +0 -0
- /package/dist/sdk/{routing-K2U7U3OO.mjs.map → routing-SAGHEUOA.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-RYYNPLDH.mjs.map → schedule-tool-TGWPINHO.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-NFNY6BVX.mjs.map → schedule-tool-handler-OEBLE5AB.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-DQYOGQT5.mjs.map → trace-helpers-M7RVAZQ2.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-OM5L5FJX.mjs.map → workflow-check-provider-VDSZR7Y5.mjs.map} +0 -0
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
# A2A Provider (Agent-to-Agent Protocol)
|
|
2
|
+
|
|
3
|
+
Visor implements the [A2A (Agent-to-Agent) protocol](https://github.com/google/A2A) for agent interoperability. This enables two modes of operation:
|
|
4
|
+
|
|
5
|
+
- **Server mode** — Visor exposes workflows as a discoverable A2A agent that external systems can call
|
|
6
|
+
- **Client mode** — Visor calls external A2A agents as workflow steps using `type: a2a`
|
|
7
|
+
|
|
8
|
+
### A2A vs MCP
|
|
9
|
+
|
|
10
|
+
| | A2A | MCP |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| **Pattern** | Agent-to-Agent task delegation | Agent-to-Tool function calls |
|
|
13
|
+
| **Communication** | Stateful tasks with lifecycle | Stateless function invocation |
|
|
14
|
+
| **Input** | Natural language + structured data | Typed JSON Schema parameters |
|
|
15
|
+
| **Discovery** | Agent Card at `/.well-known/agent-card.json` | Tool listing via `tools/list` |
|
|
16
|
+
| **Multi-turn** | Built-in (input_required state) | Not applicable |
|
|
17
|
+
|
|
18
|
+
Use MCP when you need deterministic tool calls with typed schemas. Use A2A when you need to delegate complex tasks to another agent that may require multiple turns or long-running execution.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Server: Expose a Workflow as an A2A Agent
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
# .visor.yaml
|
|
28
|
+
version: "1.0"
|
|
29
|
+
|
|
30
|
+
agent_protocol:
|
|
31
|
+
enabled: true
|
|
32
|
+
protocol: a2a
|
|
33
|
+
port: 9000
|
|
34
|
+
agent_card_inline:
|
|
35
|
+
name: "Review Agent"
|
|
36
|
+
description: "AI code review"
|
|
37
|
+
skills:
|
|
38
|
+
- id: review
|
|
39
|
+
name: Code Review
|
|
40
|
+
description: Review code for issues
|
|
41
|
+
default_workflow: review
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
review:
|
|
45
|
+
type: ai
|
|
46
|
+
prompt: "Review the submitted code for issues"
|
|
47
|
+
on: [manual]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Start the A2A server
|
|
52
|
+
visor --a2a --config .visor.yaml
|
|
53
|
+
|
|
54
|
+
# Test with curl
|
|
55
|
+
curl http://localhost:9000/.well-known/agent-card.json
|
|
56
|
+
curl -X POST http://localhost:9000/message:send \
|
|
57
|
+
-H "Content-Type: application/json" \
|
|
58
|
+
-d '{"message": {"message_id": "1", "role": "user", "parts": [{"text": "Review my code"}]}}'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Client: Call an External A2A Agent
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
steps:
|
|
65
|
+
scan:
|
|
66
|
+
type: a2a
|
|
67
|
+
agent_url: "http://compliance-agent:9000"
|
|
68
|
+
message: "Review PR #{{ pr.number }}: {{ pr.title }}"
|
|
69
|
+
blocking: true
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Server Mode: Visor as an A2A Agent
|
|
75
|
+
|
|
76
|
+
### Enabling the Server
|
|
77
|
+
|
|
78
|
+
Start with the `--a2a` CLI flag:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
visor --a2a --config .visor.yaml
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or enable in configuration:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
agent_protocol:
|
|
88
|
+
enabled: true
|
|
89
|
+
protocol: a2a
|
|
90
|
+
port: 9000 # default: 9000
|
|
91
|
+
host: "0.0.0.0" # default: 0.0.0.0
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
A2A can run alongside other modes:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
visor --a2a --slack --config .visor.yaml # A2A + Slack simultaneously
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Agent Card
|
|
101
|
+
|
|
102
|
+
The Agent Card describes your agent to external clients. Define it inline or load from a file:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
# Inline
|
|
106
|
+
agent_protocol:
|
|
107
|
+
agent_card_inline:
|
|
108
|
+
name: "Code Review Agent"
|
|
109
|
+
description: "AI-powered code review"
|
|
110
|
+
version: "1.0.0"
|
|
111
|
+
provider:
|
|
112
|
+
organization: "My Org"
|
|
113
|
+
url: "https://myorg.com"
|
|
114
|
+
skills:
|
|
115
|
+
- id: security
|
|
116
|
+
name: Security Review
|
|
117
|
+
description: OWASP Top 10 analysis
|
|
118
|
+
tags: [security, owasp]
|
|
119
|
+
- id: performance
|
|
120
|
+
name: Performance Review
|
|
121
|
+
description: Performance bottleneck detection
|
|
122
|
+
tags: [performance]
|
|
123
|
+
supported_interfaces:
|
|
124
|
+
- url: "http://localhost:9000"
|
|
125
|
+
protocol_binding: "a2a/v1"
|
|
126
|
+
capabilities:
|
|
127
|
+
streaming: false
|
|
128
|
+
push_notifications: false
|
|
129
|
+
|
|
130
|
+
# Or load from file
|
|
131
|
+
agent_protocol:
|
|
132
|
+
agent_card: "./agent-card.json"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The Agent Card is served publicly at `GET /.well-known/agent-card.json` (no authentication required).
|
|
136
|
+
|
|
137
|
+
### Skill Routing
|
|
138
|
+
|
|
139
|
+
Map incoming A2A skill IDs to internal Visor workflows:
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
agent_protocol:
|
|
143
|
+
skill_routing:
|
|
144
|
+
security: security-review # A2A skill "security" → workflow "security-review"
|
|
145
|
+
performance: performance-review
|
|
146
|
+
default_workflow: general-review # Fallback when skill not matched
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
When a client sends a message with `metadata.skill_id: "security"`, Visor routes it to the `security-review` workflow. Unmatched skills use `default_workflow`.
|
|
150
|
+
|
|
151
|
+
### Authentication
|
|
152
|
+
|
|
153
|
+
Configure authentication for inbound requests:
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
agent_protocol:
|
|
157
|
+
auth:
|
|
158
|
+
type: bearer # bearer | api_key | none
|
|
159
|
+
token_env: AGENT_AUTH_TOKEN # Environment variable containing the token
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Bearer token:**
|
|
163
|
+
```yaml
|
|
164
|
+
auth:
|
|
165
|
+
type: bearer
|
|
166
|
+
token_env: AGENT_AUTH_TOKEN # Checked via Authorization: Bearer <token>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**API key:**
|
|
170
|
+
```yaml
|
|
171
|
+
auth:
|
|
172
|
+
type: api_key
|
|
173
|
+
key_env: AGENT_API_KEY
|
|
174
|
+
header_name: X-API-Key # default: x-api-key
|
|
175
|
+
param_name: api_key # also checked as query parameter
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
> The Agent Card endpoint (`/.well-known/agent-card.json`) is always public regardless of auth configuration.
|
|
179
|
+
|
|
180
|
+
### HTTP Endpoints
|
|
181
|
+
|
|
182
|
+
| Method | Path | Auth | Description |
|
|
183
|
+
|--------|------|------|-------------|
|
|
184
|
+
| `GET` | `/.well-known/agent-card.json` | No | Agent Card for discovery |
|
|
185
|
+
| `POST` | `/message:send` | Yes | Submit a task / send a message |
|
|
186
|
+
| `GET` | `/tasks/{id}` | Yes | Get task by ID |
|
|
187
|
+
| `GET` | `/tasks` | Yes | List all tasks |
|
|
188
|
+
| `POST` | `/tasks/{id}:cancel` | Yes | Cancel a running task |
|
|
189
|
+
|
|
190
|
+
### Task Lifecycle
|
|
191
|
+
|
|
192
|
+
Tasks follow a state machine with these transitions:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
┌─────────────┐
|
|
196
|
+
│ submitted │
|
|
197
|
+
└──────┬──────┘
|
|
198
|
+
┌────────────┼────────────┐
|
|
199
|
+
v v v
|
|
200
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
201
|
+
│ working │ │ canceled │ │ rejected │
|
|
202
|
+
└────┬─────┘ └──────────┘ └──────────┘
|
|
203
|
+
┌─────┬───┼───┬─────────┐
|
|
204
|
+
v v v v v
|
|
205
|
+
┌─────────┐ │ ┌───┐ │ ┌────────────────┐
|
|
206
|
+
│completed│ │ │ │ │ │input_required │──→ working (resumed)
|
|
207
|
+
└─────────┘ │ │ │ │ └────────────────┘
|
|
208
|
+
┌─────┘ │ │ └──────────┐
|
|
209
|
+
v v v v
|
|
210
|
+
┌──────────┐ ┌──────────┐ ┌────────────────┐
|
|
211
|
+
│ failed │ │ canceled │ │ auth_required │──→ working (resumed)
|
|
212
|
+
└──────────┘ └──────────┘ └────────────────┘
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Terminal states:** `completed`, `failed`, `canceled`, `rejected`
|
|
216
|
+
|
|
217
|
+
| State | Description |
|
|
218
|
+
|-------|-------------|
|
|
219
|
+
| `submitted` | Task created, waiting to be picked up |
|
|
220
|
+
| `working` | Workflow engine is processing the task |
|
|
221
|
+
| `input_required` | Agent needs additional input from the client |
|
|
222
|
+
| `auth_required` | Agent needs authentication credentials |
|
|
223
|
+
| `completed` | Task finished successfully |
|
|
224
|
+
| `failed` | Task execution encountered an error |
|
|
225
|
+
| `canceled` | Task was canceled by the client |
|
|
226
|
+
| `rejected` | Task was rejected at submission |
|
|
227
|
+
|
|
228
|
+
### Task Queue
|
|
229
|
+
|
|
230
|
+
For async execution, configure the task queue:
|
|
231
|
+
|
|
232
|
+
```yaml
|
|
233
|
+
agent_protocol:
|
|
234
|
+
queue:
|
|
235
|
+
poll_interval: 1000 # Poll database every N ms (default: 1000)
|
|
236
|
+
max_concurrent: 5 # Max concurrent tasks (default: 5)
|
|
237
|
+
stale_claim_timeout: 300000 # Worker timeout in ms (default: 300000)
|
|
238
|
+
task_ttl: "7d" # Task retention period (default: 7d)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Blocking vs async:**
|
|
242
|
+
- **Blocking** (default): The `POST /message:send` request waits for the workflow to complete and returns the full task with artifacts.
|
|
243
|
+
- **Async**: Set `configuration.blocking: false` in the request. Returns the task ID immediately; the client polls `GET /tasks/{id}` for status updates.
|
|
244
|
+
|
|
245
|
+
### TLS
|
|
246
|
+
|
|
247
|
+
For production deployments:
|
|
248
|
+
|
|
249
|
+
```yaml
|
|
250
|
+
agent_protocol:
|
|
251
|
+
tls:
|
|
252
|
+
cert: "/path/to/cert.pem"
|
|
253
|
+
key: "/path/to/key.pem"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Client Mode: Calling External A2A Agents
|
|
259
|
+
|
|
260
|
+
Use `type: a2a` to call external A2A-compatible agents from your workflow.
|
|
261
|
+
|
|
262
|
+
### Basic Usage
|
|
263
|
+
|
|
264
|
+
```yaml
|
|
265
|
+
steps:
|
|
266
|
+
compliance-scan:
|
|
267
|
+
type: a2a
|
|
268
|
+
agent_url: "http://compliance-agent:9000"
|
|
269
|
+
message: |
|
|
270
|
+
Review PR #{{ pr.number }}: {{ pr.title }}
|
|
271
|
+
Files changed: {{ files | size }}
|
|
272
|
+
blocking: true
|
|
273
|
+
timeout: 60000
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Agent Discovery
|
|
277
|
+
|
|
278
|
+
Specify the agent endpoint in one of two ways (mutually exclusive):
|
|
279
|
+
|
|
280
|
+
```yaml
|
|
281
|
+
# Option 1: Direct URL to the agent
|
|
282
|
+
agent_url: "http://agent.example.com:9000"
|
|
283
|
+
|
|
284
|
+
# Option 2: URL to the Agent Card (endpoint resolved from card)
|
|
285
|
+
agent_card: "https://agent.example.com/.well-known/agent-card.json"
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
When using `agent_card`, Visor fetches the card, caches it for 5 minutes, and resolves the endpoint from `supported_interfaces`.
|
|
289
|
+
|
|
290
|
+
### Authentication
|
|
291
|
+
|
|
292
|
+
```yaml
|
|
293
|
+
steps:
|
|
294
|
+
scan:
|
|
295
|
+
type: a2a
|
|
296
|
+
agent_url: "http://agent:9000"
|
|
297
|
+
message: "Review this code"
|
|
298
|
+
auth:
|
|
299
|
+
scheme: bearer # bearer | api_key
|
|
300
|
+
token_env: AGENT_TOKEN # Environment variable with the token
|
|
301
|
+
# header_name: X-API-Key # For api_key scheme (default: x-api-key)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Message Construction
|
|
305
|
+
|
|
306
|
+
**Text message** (Liquid template):
|
|
307
|
+
```yaml
|
|
308
|
+
message: |
|
|
309
|
+
Review PR #{{ pr.number }}: {{ pr.title }}
|
|
310
|
+
Author: {{ pr.author }}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Structured data** (Liquid-templated key-value pairs sent as data parts):
|
|
314
|
+
```yaml
|
|
315
|
+
data:
|
|
316
|
+
repo_context: '{{ pr.repo | json }}'
|
|
317
|
+
file_list: '{{ files | json }}'
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**File attachments:**
|
|
321
|
+
```yaml
|
|
322
|
+
files:
|
|
323
|
+
- url: "https://example.com/requirements.txt"
|
|
324
|
+
media_type: "text/plain"
|
|
325
|
+
filename: "requirements.txt"
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Polling and Multi-Turn
|
|
329
|
+
|
|
330
|
+
```yaml
|
|
331
|
+
steps:
|
|
332
|
+
interactive-agent:
|
|
333
|
+
type: a2a
|
|
334
|
+
agent_url: "http://agent:9000"
|
|
335
|
+
message: "Analyze {{ pr.title }}"
|
|
336
|
+
|
|
337
|
+
blocking: true # Wait for completion (default: true)
|
|
338
|
+
timeout: 300000 # Max wait in ms (default: 300000)
|
|
339
|
+
poll_interval: 2000 # Poll frequency in ms (default: 2000)
|
|
340
|
+
|
|
341
|
+
# Multi-turn conversation
|
|
342
|
+
max_turns: 3 # Max conversation turns (default: 1)
|
|
343
|
+
on_input_required: | # Auto-reply when agent asks for more info
|
|
344
|
+
Here is additional context:
|
|
345
|
+
{{ pr.body }}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
When the agent enters `input_required` state, Visor automatically sends the `on_input_required` template as a follow-up message. This continues up to `max_turns`.
|
|
349
|
+
|
|
350
|
+
### Output Transformation
|
|
351
|
+
|
|
352
|
+
Transform agent responses into structured issues with JavaScript:
|
|
353
|
+
|
|
354
|
+
```yaml
|
|
355
|
+
steps:
|
|
356
|
+
scan:
|
|
357
|
+
type: a2a
|
|
358
|
+
agent_url: "http://agent:9000"
|
|
359
|
+
message: "Security scan"
|
|
360
|
+
transform_js: |
|
|
361
|
+
return {
|
|
362
|
+
issues: (output.issues || []).map(function(i) {
|
|
363
|
+
return {
|
|
364
|
+
file: i.file,
|
|
365
|
+
line: i.line || 0,
|
|
366
|
+
ruleId: 'a2a/' + (i.ruleId || 'issue'),
|
|
367
|
+
message: i.message,
|
|
368
|
+
severity: i.severity || 'warning'
|
|
369
|
+
};
|
|
370
|
+
})
|
|
371
|
+
};
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Error Handling
|
|
375
|
+
|
|
376
|
+
A2A errors are surfaced as issues with `ruleId: a2a/error`:
|
|
377
|
+
|
|
378
|
+
| Error | When |
|
|
379
|
+
|-------|------|
|
|
380
|
+
| `A2ATimeoutError` | Task didn't complete within `timeout` |
|
|
381
|
+
| `A2AMaxTurnsExceededError` | Conversation exceeded `max_turns` |
|
|
382
|
+
| `A2AInputRequiredError` | Agent needs input but `max_turns` exhausted |
|
|
383
|
+
| `A2AAuthRequiredError` | Agent requires authentication credentials |
|
|
384
|
+
| `A2ATaskFailedError` | Task execution failed on the remote agent |
|
|
385
|
+
| `A2ATaskRejectedError` | Task was rejected or canceled |
|
|
386
|
+
| `A2ARequestError` | HTTP request to the agent failed |
|
|
387
|
+
| `AgentCardFetchError` | Failed to fetch Agent Card |
|
|
388
|
+
| `InvalidAgentCardError` | Agent Card is malformed |
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Task Management CLI
|
|
393
|
+
|
|
394
|
+
Monitor and manage A2A tasks with `visor tasks`:
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
visor tasks # List all tasks (alias for list)
|
|
398
|
+
visor tasks list # List tasks
|
|
399
|
+
visor tasks list --state working # Filter by state
|
|
400
|
+
visor tasks list --agent security-review # Filter by workflow
|
|
401
|
+
visor tasks list --limit 50 # Show more results
|
|
402
|
+
visor tasks list --output json # JSON output
|
|
403
|
+
visor tasks list --watch # Live refresh every 2s
|
|
404
|
+
visor tasks stats # Queue summary statistics
|
|
405
|
+
visor tasks stats --output json # Stats as JSON
|
|
406
|
+
visor tasks cancel <task-id> # Cancel a running task
|
|
407
|
+
visor tasks help # Show usage
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Flags:**
|
|
411
|
+
|
|
412
|
+
| Flag | Description | Default |
|
|
413
|
+
|------|-------------|---------|
|
|
414
|
+
| `--state <state>` | Filter by task state | all |
|
|
415
|
+
| `--agent <workflow-id>` | Filter by workflow | all |
|
|
416
|
+
| `--limit <n>` | Number of tasks to show | 20 |
|
|
417
|
+
| `--output <format>` | Output format: `table`, `json`, `markdown` | table |
|
|
418
|
+
| `--watch` | Refresh every 2 seconds | off |
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Configuration Reference
|
|
423
|
+
|
|
424
|
+
### Server-Side: `agent_protocol`
|
|
425
|
+
|
|
426
|
+
| Key | Type | Default | Description |
|
|
427
|
+
|-----|------|---------|-------------|
|
|
428
|
+
| `enabled` | boolean | `false` | Enable the A2A server |
|
|
429
|
+
| `protocol` | string | `"a2a"` | Protocol binding |
|
|
430
|
+
| `port` | number | `9000` | HTTP listen port |
|
|
431
|
+
| `host` | string | `"0.0.0.0"` | HTTP bind address |
|
|
432
|
+
| `public_url` | string | auto | Public URL for Agent Card |
|
|
433
|
+
| `agent_card_inline` | object | - | Inline Agent Card definition |
|
|
434
|
+
| `agent_card` | string | - | Path to Agent Card JSON file |
|
|
435
|
+
| `auth` | object | - | Authentication config |
|
|
436
|
+
| `auth.type` | string | - | `bearer`, `api_key`, or `none` |
|
|
437
|
+
| `auth.token_env` | string | - | Env var for bearer token |
|
|
438
|
+
| `auth.key_env` | string | - | Env var for API key |
|
|
439
|
+
| `auth.header_name` | string | `"x-api-key"` | Custom header for API key |
|
|
440
|
+
| `auth.param_name` | string | `"api_key"` | Query parameter for API key |
|
|
441
|
+
| `skill_routing` | object | - | Map of skill_id to workflow name |
|
|
442
|
+
| `default_workflow` | string | - | Fallback workflow for unmatched skills |
|
|
443
|
+
| `task_ttl` | string | `"7d"` | Task retention period |
|
|
444
|
+
| `queue.poll_interval` | number | `1000` | Queue poll interval in ms |
|
|
445
|
+
| `queue.max_concurrent` | number | `5` | Max concurrent task executions |
|
|
446
|
+
| `queue.stale_claim_timeout` | number | `300000` | Worker stale claim timeout in ms |
|
|
447
|
+
| `tls.cert` | string | - | Path to TLS certificate |
|
|
448
|
+
| `tls.key` | string | - | Path to TLS private key |
|
|
449
|
+
|
|
450
|
+
### Client-Side: `type: a2a` Check Provider
|
|
451
|
+
|
|
452
|
+
| Key | Type | Default | Required | Description |
|
|
453
|
+
|-----|------|---------|----------|-------------|
|
|
454
|
+
| `agent_url` | string | - | one of | Direct agent endpoint URL |
|
|
455
|
+
| `agent_card` | string | - | one of | URL to Agent Card |
|
|
456
|
+
| `message` | string | - | yes | Liquid template for the message text |
|
|
457
|
+
| `data` | object | - | no | Liquid-templated structured data parts |
|
|
458
|
+
| `files` | array | - | no | File attachments (`url`, `media_type`, `filename`) |
|
|
459
|
+
| `auth.scheme` | string | - | no | `bearer` or `api_key` |
|
|
460
|
+
| `auth.token_env` | string | - | no | Env var containing auth token |
|
|
461
|
+
| `auth.header_name` | string | `"x-api-key"` | no | Custom header for API key |
|
|
462
|
+
| `blocking` | boolean | `true` | no | Wait for task completion |
|
|
463
|
+
| `timeout` | number | `300000` | no | Max wait time in ms |
|
|
464
|
+
| `poll_interval` | number | `2000` | no | Poll interval in ms |
|
|
465
|
+
| `max_turns` | number | `1` | no | Max conversation turns |
|
|
466
|
+
| `on_input_required` | string | - | no | Liquid template for auto-reply |
|
|
467
|
+
| `transform_js` | string | - | no | JavaScript output transformation |
|
|
468
|
+
| `accepted_output_modes` | string[] | `["text/plain", "application/json"]` | no | Accepted MIME types |
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## Examples
|
|
473
|
+
|
|
474
|
+
### Server: Code Review Agent
|
|
475
|
+
|
|
476
|
+
Full example from [examples/a2a-agent-example.yaml](../examples/a2a-agent-example.yaml):
|
|
477
|
+
|
|
478
|
+
```yaml
|
|
479
|
+
version: "1.0"
|
|
480
|
+
|
|
481
|
+
agent_protocol:
|
|
482
|
+
enabled: true
|
|
483
|
+
protocol: a2a
|
|
484
|
+
port: 9000
|
|
485
|
+
host: "0.0.0.0"
|
|
486
|
+
|
|
487
|
+
agent_card_inline:
|
|
488
|
+
name: "Code Review Agent"
|
|
489
|
+
description: "AI-powered code review agent built with Visor"
|
|
490
|
+
version: "1.0.0"
|
|
491
|
+
provider:
|
|
492
|
+
organization: "Visor"
|
|
493
|
+
skills:
|
|
494
|
+
- id: security
|
|
495
|
+
name: Security Review
|
|
496
|
+
description: Analyze code for security vulnerabilities (OWASP Top 10)
|
|
497
|
+
tags: [security, owasp]
|
|
498
|
+
- id: performance
|
|
499
|
+
name: Performance Review
|
|
500
|
+
description: Analyze code for performance issues and bottlenecks
|
|
501
|
+
tags: [performance]
|
|
502
|
+
supported_interfaces:
|
|
503
|
+
- url: "http://localhost:9000"
|
|
504
|
+
protocol_binding: "a2a/v1"
|
|
505
|
+
capabilities:
|
|
506
|
+
streaming: false
|
|
507
|
+
push_notifications: false
|
|
508
|
+
|
|
509
|
+
auth:
|
|
510
|
+
type: bearer
|
|
511
|
+
token_env: AGENT_AUTH_TOKEN
|
|
512
|
+
|
|
513
|
+
skill_routing:
|
|
514
|
+
security: security-review
|
|
515
|
+
performance: performance-review
|
|
516
|
+
default_workflow: general-review
|
|
517
|
+
|
|
518
|
+
task_ttl: "7d"
|
|
519
|
+
queue:
|
|
520
|
+
max_concurrent: 5
|
|
521
|
+
|
|
522
|
+
steps:
|
|
523
|
+
security-review:
|
|
524
|
+
type: ai
|
|
525
|
+
prompt: |
|
|
526
|
+
Perform a security review focusing on OWASP Top 10 vulnerabilities.
|
|
527
|
+
Check for SQL injection, XSS, CSRF, and authentication issues.
|
|
528
|
+
on: [manual]
|
|
529
|
+
|
|
530
|
+
performance-review:
|
|
531
|
+
type: ai
|
|
532
|
+
prompt: |
|
|
533
|
+
Review for performance issues: N+1 queries, memory leaks,
|
|
534
|
+
unnecessary allocations, and algorithmic complexity.
|
|
535
|
+
on: [manual]
|
|
536
|
+
|
|
537
|
+
general-review:
|
|
538
|
+
type: ai
|
|
539
|
+
prompt: |
|
|
540
|
+
General code quality review: naming, structure, error handling,
|
|
541
|
+
and adherence to project conventions.
|
|
542
|
+
on: [manual]
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
# Start
|
|
547
|
+
visor --a2a --config examples/a2a-agent-example.yaml
|
|
548
|
+
|
|
549
|
+
# Discover
|
|
550
|
+
curl http://localhost:9000/.well-known/agent-card.json | jq .
|
|
551
|
+
|
|
552
|
+
# Send a task targeting the security skill
|
|
553
|
+
curl -X POST http://localhost:9000/message:send \
|
|
554
|
+
-H "Content-Type: application/json" \
|
|
555
|
+
-H "Authorization: Bearer $AGENT_AUTH_TOKEN" \
|
|
556
|
+
-d '{
|
|
557
|
+
"message": {
|
|
558
|
+
"message_id": "msg-1",
|
|
559
|
+
"role": "user",
|
|
560
|
+
"parts": [{"text": "Review auth.py for security issues"}],
|
|
561
|
+
"metadata": {"skill_id": "security"}
|
|
562
|
+
}
|
|
563
|
+
}'
|
|
564
|
+
|
|
565
|
+
# Monitor tasks
|
|
566
|
+
visor tasks list --watch
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Client: Multi-Agent Composition
|
|
570
|
+
|
|
571
|
+
Chain multiple A2A agents and aggregate results:
|
|
572
|
+
|
|
573
|
+
```yaml
|
|
574
|
+
steps:
|
|
575
|
+
compliance-scan:
|
|
576
|
+
type: a2a
|
|
577
|
+
agent_url: "http://compliance-agent:9000"
|
|
578
|
+
message: "Check compliance for PR #{{ pr.number }}"
|
|
579
|
+
blocking: true
|
|
580
|
+
|
|
581
|
+
security-scan:
|
|
582
|
+
type: a2a
|
|
583
|
+
agent_url: "http://security-agent:9000"
|
|
584
|
+
message: "Security review for PR #{{ pr.number }}"
|
|
585
|
+
blocking: true
|
|
586
|
+
|
|
587
|
+
summarize:
|
|
588
|
+
type: ai
|
|
589
|
+
depends_on: [compliance-scan, security-scan]
|
|
590
|
+
prompt: |
|
|
591
|
+
Summarize findings from two agents:
|
|
592
|
+
Compliance: {{ outputs["compliance-scan"] | json }}
|
|
593
|
+
Security: {{ outputs["security-scan"] | json }}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Multi-Turn Conversation
|
|
597
|
+
|
|
598
|
+
Handle agents that ask follow-up questions:
|
|
599
|
+
|
|
600
|
+
```yaml
|
|
601
|
+
steps:
|
|
602
|
+
interactive-review:
|
|
603
|
+
type: a2a
|
|
604
|
+
agent_card: "https://agent.example.com/.well-known/agent-card.json"
|
|
605
|
+
message: "Analyze {{ pr.title }} for best practices"
|
|
606
|
+
max_turns: 3
|
|
607
|
+
on_input_required: |
|
|
608
|
+
Here is additional context:
|
|
609
|
+
{{ pr.body }}
|
|
610
|
+
transform_js: |
|
|
611
|
+
return {
|
|
612
|
+
issues: (output.issues || []).map(function(i) {
|
|
613
|
+
return {
|
|
614
|
+
file: i.file,
|
|
615
|
+
line: i.line || 0,
|
|
616
|
+
ruleId: 'a2a/' + (i.ruleId || 'issue'),
|
|
617
|
+
message: i.message,
|
|
618
|
+
severity: i.severity || 'warning'
|
|
619
|
+
};
|
|
620
|
+
})
|
|
621
|
+
};
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## Security Considerations
|
|
627
|
+
|
|
628
|
+
- **Always configure auth for production** — without it, anyone can submit tasks to your agent
|
|
629
|
+
- **Use `token_env` / `key_env`** — never hardcode tokens in config files
|
|
630
|
+
- **Enable TLS** for public-facing servers
|
|
631
|
+
- **Agent Card is public** — it's served without auth, so don't include sensitive information
|
|
632
|
+
- **Task TTL** — set appropriate retention to limit stored data (`task_ttl: "7d"`)
|
|
633
|
+
- **Token comparison** uses timing-safe comparison to prevent timing attacks
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
## Debugging
|
|
638
|
+
|
|
639
|
+
```bash
|
|
640
|
+
# Start with debug logging
|
|
641
|
+
visor --a2a --debug --config .visor.yaml
|
|
642
|
+
|
|
643
|
+
# Verify Agent Card is served correctly
|
|
644
|
+
curl http://localhost:9000/.well-known/agent-card.json | jq .
|
|
645
|
+
|
|
646
|
+
# Monitor live task queue
|
|
647
|
+
visor tasks list --watch
|
|
648
|
+
|
|
649
|
+
# Check queue statistics
|
|
650
|
+
visor tasks stats
|
|
651
|
+
|
|
652
|
+
# View specific task
|
|
653
|
+
visor tasks list --state failed # Find failed tasks
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
With OpenTelemetry enabled, A2A tasks emit spans with:
|
|
657
|
+
- `agent.task.id` — Task ID
|
|
658
|
+
- `agent.task.state` — Current state
|
|
659
|
+
- `agent.task.workflow_id` — Target workflow
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
## Related Documentation
|
|
664
|
+
|
|
665
|
+
- [MCP Provider](./mcp-provider.md) — MCP tool integration (complementary to A2A)
|
|
666
|
+
- [HTTP Integration](./http.md) — HTTP server and webhooks
|
|
667
|
+
- [Workflows](./workflows.md) — Reusable workflow definitions
|
|
668
|
+
- [Configuration](./configuration.md) — Configuration reference
|
|
669
|
+
- [Architecture](./architecture.md) — System architecture overview
|
|
670
|
+
- [Security](./security.md) — Security best practices
|
|
671
|
+
- [Debugging](./debugging.md) — Debugging techniques
|
|
672
|
+
- [RFC: A2A Protocol Support](../rfc/001-a2a-protocol-support.md) — Design document
|