@aramisfa/openclaw-a2a-outbound 1.0.0 → 2.0.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.
Files changed (40) hide show
  1. package/README.md +355 -33
  2. package/dist/capability-diagnostics.d.ts +13 -0
  3. package/dist/capability-diagnostics.d.ts.map +1 -0
  4. package/dist/capability-diagnostics.js +131 -0
  5. package/dist/capability-diagnostics.js.map +1 -0
  6. package/dist/errors.d.ts +1 -0
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +1 -0
  9. package/dist/errors.js.map +1 -1
  10. package/dist/request-normalization.d.ts +4 -10
  11. package/dist/request-normalization.d.ts.map +1 -1
  12. package/dist/request-normalization.js +83 -47
  13. package/dist/request-normalization.js.map +1 -1
  14. package/dist/result-shape.d.ts +58 -15
  15. package/dist/result-shape.d.ts.map +1 -1
  16. package/dist/result-shape.js +324 -85
  17. package/dist/result-shape.js.map +1 -1
  18. package/dist/schemas.d.ts +28 -5
  19. package/dist/schemas.d.ts.map +1 -1
  20. package/dist/schemas.js +128 -21
  21. package/dist/schemas.js.map +1 -1
  22. package/dist/sdk-client-pool.d.ts +0 -2
  23. package/dist/sdk-client-pool.d.ts.map +1 -1
  24. package/dist/sdk-client-pool.js +2 -22
  25. package/dist/sdk-client-pool.js.map +1 -1
  26. package/dist/service.d.ts +4 -2
  27. package/dist/service.d.ts.map +1 -1
  28. package/dist/service.js +333 -80
  29. package/dist/service.js.map +1 -1
  30. package/dist/target-catalog.d.ts +27 -5
  31. package/dist/target-catalog.d.ts.map +1 -1
  32. package/dist/target-catalog.js +164 -58
  33. package/dist/target-catalog.js.map +1 -1
  34. package/dist/task-handle-registry.d.ts +3 -2
  35. package/dist/task-handle-registry.d.ts.map +1 -1
  36. package/dist/task-handle-registry.js +7 -0
  37. package/dist/task-handle-registry.js.map +1 -1
  38. package/openclaw.plugin.json +42 -12
  39. package/package.json +10 -11
  40. package/skills/remote-agent/SKILL.md +74 -8
package/README.md CHANGED
@@ -16,6 +16,14 @@ Pin the exact published version if you want reproducible installs:
16
16
  openclaw plugins install @aramisfa/openclaw-a2a-outbound --pin
17
17
  ```
18
18
 
19
+ Optional guided setup helper:
20
+
21
+ ```bash
22
+ clawhub install a2a-delegation-setup
23
+ ```
24
+
25
+ The ClawHub skill is an optional guided setup helper for installing, enabling, configuring, verifying, updating, and troubleshooting `@aramisfa/openclaw-a2a-outbound`. The plugin itself still installs through `openclaw plugins install @aramisfa/openclaw-a2a-outbound`.
26
+
19
27
  ## Requirements
20
28
 
21
29
  - Node.js `>=22.12.0`
@@ -57,7 +65,7 @@ The plugin installs through the OpenClaw CLI, but the tool stays disabled until
57
65
  }
58
66
  ```
59
67
 
60
- Call `list_targets` first to discover configured aliases and refreshed target-card metadata. Prefer `target_alias` over `target_url`; use `target_url` only when policy allows direct URL routing.
68
+ Call `list_targets` first to discover configured aliases and refreshed peer-card metadata. Prefer `target_alias` over `target_url`; use `target_url` only when policy allows direct URL routing.
61
69
 
62
70
  ## Unified Tool Contract
63
71
 
@@ -66,27 +74,74 @@ Call `list_targets` first to discover configured aliases and refreshed target-ca
66
74
  - `action`: required for every request.
67
75
  - `target_alias`: preferred routing key for `send`, `watch`, `status`, and `cancel`.
68
76
  - `target_url`: explicit remote base URL when policy allows it or when it matches a configured target.
69
- - `input`: required for `send`; becomes the single user text part sent to the peer.
70
- - `attachments`: optional file or data attachments for `send`.
71
- - `task_handle`: opaque follow-up handle returned after delegated tasks are created.
72
- - `task_id`: fallback follow-up key when no live `task_handle` is available.
73
- - `follow_updates`: stream live updates during `send`.
77
+ - `parts`: required non-empty array for `send`; each part is `text`, `file`, or `data`.
78
+ - `message_id`: optional client-supplied message id for `send`.
79
+ - `task_handle`: opaque delegated-task handle. `send`, `watch`, `status`, and `cancel` all accept it.
80
+ - `task_id`: for `send`, continue an existing remote task when no `task_handle` is available; for `watch`/`status`/`cancel`, fallback follow-up key when no live `task_handle` is available.
81
+ - `context_id`: optional remote conversation context id for `send`. Use it either with `task_id` or by itself to start a new task inside an existing conversation.
82
+ - `reference_task_ids`: optional related task ids for `send`. `task_id` continues an existing task; `reference_task_ids` references prior tasks without continuing them.
83
+ - `task_requirement`: optional `send` contract. Defaults to `"optional"`; set `task_requirement="required"` to require a real task.
84
+ - `follow_updates`: stream the initial `send`. `follow_updates=true` means “stream the initial send”; it does not guarantee task creation unless `task_requirement="required"`.
85
+ - `accepted_output_modes`: optional per-call output mode override for `send`.
86
+ - `blocking`: optional non-stream `send` knob. Rejected when `follow_updates=true`.
74
87
  - `history_length`: optional history window for `send` and `status`.
88
+ - `push_notification_config`: optional push callback config for `send`.
75
89
  - `timeout_ms`: per-request timeout override.
76
90
  - `service_parameters`: optional outbound service parameters.
77
91
  - `metadata`: optional metadata payload for `send`.
78
92
 
79
- Action-specific validation rejects unsupported fields for each action, so keep requests flat and action-focused.
93
+ Snake_case tool fields are translated internally to the A2A SDK camelCase request payload. Action-specific validation rejects unsupported fields for each action, so keep requests flat and action-focused.
80
94
 
81
95
  ## Actions
82
96
 
83
- - `list_targets`: discover configured targets, aliases, examples, and hydrated card metadata.
84
- - `send`: send user input to a remote agent selected by `target_alias`, `target_url`, or a configured default target.
97
+ - `list_targets`: discover configured targets, aliases, examples, and hydrated peer-card metadata.
98
+ - `send`: send one or more message parts to a remote agent, either as a new turn or as a follow-up turn on an existing task/conversation.
85
99
  - `watch`: resubscribe to a running delegated task and stream updates.
86
100
  - `status`: fetch the latest task snapshot.
87
101
  - `cancel`: request cancellation for a delegated task.
88
102
 
89
- For follow-up actions, prefer `task_handle` first. If the handle is expired or unavailable, fall back to `target_alias` + `task_id`.
103
+ Failed `send` and `sendStream` calls include `error.details.capability_diagnostics` so remote validation or content-type rejections can be compared against the stored peer card without blocking permissive runtime sends.
104
+
105
+ Supported `send` modes:
106
+
107
+ - new task: `send` with `target_alias`/`target_url` or a configured default target, and no continuation fields
108
+ - existing task continuation: `send` with `task_handle`, or `task_id` plus `target_alias`/`target_url` or a configured default target
109
+ - related new task: `send` with `reference_task_ids`, optionally plus `context_id`, plus `target_alias`/`target_url` or a configured default target
110
+ - new task in an existing conversation: `send` with `context_id` plus `target_alias`/`target_url` or a configured default target
111
+
112
+ When a delegated task pauses in `input-required` or an approval workflow, resume it with `send` again. Prefer `task_handle` first. If the handle is expired or unavailable, fall back to `target_alias` + `task_id`.
113
+
114
+ ## Reading Output Continuations
115
+
116
+ This package returns continuation metadata under `summary.continuation`.
117
+
118
+ - `summary.continuation.task`: the only machine-readable signal that a real remote task exists. Read `task_handle`, `task_id`, `status`, `can_resume_send`, `can_watch`, and the deprecated alias `can_send` from here, and use it for follow-up `send`, `watch`, `status`, and `cancel`.
119
+ - `summary.continuation.conversation`: send-only conversation continuity. Read `context_id` from here and use it only for follow-up `send`.
120
+ - `response_kind`: descriptive wire-shape classification only. `response_kind="message"` means the peer returned a `Message`; `response_kind="task"` means a task-bearing response or event appeared. `response_kind` does not replace `summary.continuation`.
121
+ - Do not poll from conversation continuity.
122
+ - Message-only follow-up uses `context_id`, not task actions.
123
+ - `task_handle` is returned only when the peer actually created a task.
124
+ - The old flat `summary.task_handle`, `summary.task_id`, `summary.context_id`, `summary.status`, and `summary.can_watch` fields are removed.
125
+
126
+ Branch on `summary.continuation.task` vs `summary.continuation.conversation` before choosing the next action:
127
+
128
+ ```ts
129
+ const task = result.summary.continuation?.task
130
+ const conversation = result.summary.continuation?.conversation
131
+
132
+ if (task) {
133
+ const followUp = task.task_handle
134
+ ? { action: "status", task_handle: task.task_handle }
135
+ : { action: "status", target_alias: "support", task_id: task.task_id }
136
+ } else if (conversation) {
137
+ const followUp = {
138
+ action: "send",
139
+ target_alias: "support",
140
+ context_id: conversation.context_id,
141
+ parts: [{ kind: "text", text: "Start a related task in the same conversation." }],
142
+ }
143
+ }
144
+ ```
90
145
 
91
146
  ## Examples
92
147
 
@@ -111,24 +166,89 @@ For follow-up actions, prefer `task_handle` first. If the handle is expired or u
111
166
  "examples": ["Summarize this incident and propose next steps."],
112
167
  "target_name": "Support Agent",
113
168
  "description": "Primary support lane",
114
- "streaming_supported": true,
169
+ "peer_card": {
170
+ "preferred_transport": "JSONRPC",
171
+ "additional_interfaces": [
172
+ {
173
+ "transport": "JSONRPC",
174
+ "url": "https://support.example/a2a/jsonrpc"
175
+ },
176
+ {
177
+ "transport": "HTTP+JSON",
178
+ "url": "https://support.example/a2a/rest"
179
+ }
180
+ ],
181
+ "capabilities": {
182
+ "streaming": true,
183
+ "push_notifications": true,
184
+ "state_transition_history": true
185
+ },
186
+ "default_input_modes": ["text/plain"],
187
+ "default_output_modes": ["text/plain"],
188
+ "skills": [
189
+ {
190
+ "id": "triage",
191
+ "name": "Incident Triage",
192
+ "description": "Summarize incidents and propose next actions.",
193
+ "tags": ["support"],
194
+ "examples": ["Summarize this incident and propose next steps."],
195
+ "input_modes": ["application/json"],
196
+ "output_modes": ["application/pdf"]
197
+ }
198
+ ]
199
+ }
200
+ }
201
+ ]
202
+ },
203
+ "raw": [
204
+ {
205
+ "target": {
206
+ "baseUrl": "https://support.example/",
207
+ "cardPath": "/.well-known/agent-card.json",
208
+ "preferredTransports": ["JSONRPC", "HTTP+JSON"],
209
+ "alias": "support",
210
+ "displayName": "Support Agent",
211
+ "description": "Primary support lane",
212
+ "streamingSupported": true
213
+ },
214
+ "configuredDescription": "Primary support lane",
215
+ "default": true,
216
+ "tags": ["support"],
217
+ "examples": ["Summarize this incident and propose next steps."],
218
+ "card": {
219
+ "displayName": "Support Agent",
220
+ "description": "Summarize incidents and propose next actions.",
221
+ "preferredTransport": "JSONRPC",
222
+ "additionalInterfaces": [
223
+ {
224
+ "transport": "JSONRPC",
225
+ "url": "https://support.example/a2a/jsonrpc"
226
+ },
227
+ {
228
+ "transport": "HTTP+JSON",
229
+ "url": "https://support.example/a2a/rest"
230
+ }
231
+ ],
232
+ "capabilities": {
233
+ "streaming": true,
234
+ "pushNotifications": true,
235
+ "stateTransitionHistory": true
236
+ },
237
+ "defaultInputModes": ["text/plain"],
238
+ "defaultOutputModes": ["text/plain"],
115
239
  "skills": [
116
240
  {
117
241
  "id": "triage",
118
242
  "name": "Incident Triage",
119
243
  "description": "Summarize incidents and propose next actions.",
120
244
  "tags": ["support"],
121
- "examples": ["Summarize this incident and propose next steps."]
245
+ "examples": ["Summarize this incident and propose next steps."],
246
+ "inputModes": ["application/json"],
247
+ "outputModes": ["application/pdf"]
122
248
  }
123
- ]
249
+ ],
250
+ "lastRefreshedAt": "2026-03-12T10:00:00.000Z"
124
251
  }
125
- ]
126
- },
127
- "raw": [
128
- {
129
- "default": true,
130
- "tags": ["support"],
131
- "examples": ["Summarize this incident and propose next steps."]
132
252
  }
133
253
  ]
134
254
  }
@@ -140,7 +260,12 @@ For follow-up actions, prefer `task_handle` first. If the handle is expired or u
140
260
  {
141
261
  "action": "send",
142
262
  "target_alias": "support",
143
- "input": "Summarize this bug report for triage.",
263
+ "parts": [
264
+ {
265
+ "kind": "text",
266
+ "text": "Summarize this bug report for triage."
267
+ }
268
+ ],
144
269
  "metadata": {
145
270
  "ticket_id": "INC-42"
146
271
  }
@@ -155,6 +280,7 @@ For follow-up actions, prefer `task_handle` first. If the handle is expired or u
155
280
  "summary": {
156
281
  "target_alias": "support",
157
282
  "target_url": "https://support.example/",
283
+ "response_kind": "message",
158
284
  "message_text": "Triage summary: reproduce, collect logs, and notify the on-call engineer."
159
285
  },
160
286
  "raw": {
@@ -163,6 +289,39 @@ For follow-up actions, prefer `task_handle` first. If the handle is expired or u
163
289
  }
164
290
  ```
165
291
 
292
+ ### Require A Durable Task
293
+
294
+ ```json
295
+ {
296
+ "action": "send",
297
+ "target_alias": "support",
298
+ "task_requirement": "required",
299
+ "parts": [
300
+ {
301
+ "kind": "text",
302
+ "text": "Start a trackable task and return immediately."
303
+ }
304
+ ]
305
+ }
306
+ ```
307
+
308
+ ### Start Related Work Without Continuing A Task
309
+
310
+ ```json
311
+ {
312
+ "action": "send",
313
+ "target_alias": "support",
314
+ "context_id": "ctx-123",
315
+ "reference_task_ids": ["task-101", "task-102"],
316
+ "parts": [
317
+ {
318
+ "kind": "text",
319
+ "text": "Start a related task in the same conversation."
320
+ }
321
+ ]
322
+ }
323
+ ```
324
+
166
325
  ### Send Using The Configured Default Target
167
326
 
168
327
  If one target is marked `"default": true`, `send` can omit `target_alias`:
@@ -170,7 +329,12 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
170
329
  ```json
171
330
  {
172
331
  "action": "send",
173
- "input": "Draft a reply to the customer update.",
332
+ "parts": [
333
+ {
334
+ "kind": "text",
335
+ "text": "Draft a reply to the customer update."
336
+ }
337
+ ],
174
338
  "follow_updates": true
175
339
  }
176
340
  ```
@@ -183,16 +347,30 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
183
347
  "summary": {
184
348
  "target_alias": "support",
185
349
  "target_url": "https://support.example/",
186
- "task_handle": "rah_0a3ff8c2-4a6d-48cb-a57d-4ae6f3c589d0",
187
- "task_id": "task-456",
188
- "status": "completed",
189
- "can_watch": true
350
+ "response_kind": "task",
351
+ "continuation": {
352
+ "task": {
353
+ "task_handle": "rah_0a3ff8c2-4a6d-48cb-a57d-4ae6f3c589d0",
354
+ "task_id": "task-456",
355
+ "status": "completed",
356
+ "can_resume_send": false,
357
+ "can_send": false,
358
+ "can_status": true,
359
+ "can_cancel": false,
360
+ "can_watch": false
361
+ },
362
+ "conversation": {
363
+ "context_id": "ctx-456",
364
+ "can_send": true
365
+ }
366
+ }
190
367
  },
191
368
  "raw": {
192
369
  "events": [
193
370
  {
194
371
  "kind": "task",
195
372
  "id": "task-456",
373
+ "contextId": "ctx-456",
196
374
  "status": {
197
375
  "state": "submitted"
198
376
  }
@@ -200,6 +378,7 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
200
378
  {
201
379
  "kind": "status-update",
202
380
  "taskId": "task-456",
381
+ "contextId": "ctx-456",
203
382
  "status": {
204
383
  "state": "completed"
205
384
  },
@@ -209,6 +388,7 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
209
388
  "finalEvent": {
210
389
  "kind": "status-update",
211
390
  "taskId": "task-456",
391
+ "contextId": "ctx-456",
212
392
  "status": {
213
393
  "state": "completed"
214
394
  },
@@ -218,6 +398,118 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
218
398
  }
219
399
  ```
220
400
 
401
+ ```ts
402
+ const task = result.summary.continuation?.task
403
+ const conversation = result.summary.continuation?.conversation
404
+
405
+ if (!task) {
406
+ throw new Error("expected a trackable delegated task")
407
+ }
408
+
409
+ if (task.can_watch) {
410
+ // `watch` is valid here.
411
+ }
412
+
413
+ const followUpContext = conversation?.context_id
414
+ ```
415
+
416
+ ### Continue An Existing Remote Task With `task_handle`
417
+
418
+ Use `summary.continuation.task.task_handle` from the prior result when a delegated task reaches `input-required` or asks for approval:
419
+
420
+ ```json
421
+ {
422
+ "action": "send",
423
+ "task_handle": "rah_0a3ff8c2-4a6d-48cb-a57d-4ae6f3c589d0",
424
+ "parts": [
425
+ {
426
+ "kind": "text",
427
+ "text": "Approved. Continue with the task and finish the reply."
428
+ }
429
+ ]
430
+ }
431
+ ```
432
+
433
+ ### Continue An Existing Remote Task With `task_id`
434
+
435
+ If `summary.continuation.task.task_handle` is unavailable, use `summary.continuation.task.task_id` plus target routing:
436
+
437
+ ```json
438
+ {
439
+ "action": "send",
440
+ "target_alias": "support",
441
+ "task_id": "task-456",
442
+ "context_id": "ctx-456",
443
+ "parts": [
444
+ {
445
+ "kind": "text",
446
+ "text": "Continue the prior conversation and draft the final reply."
447
+ }
448
+ ]
449
+ }
450
+ ```
451
+
452
+ ### Start A New Task In An Existing Conversation
453
+
454
+ Use `summary.continuation.conversation.context_id` when the prior result has conversation continuity without task continuity:
455
+
456
+ ```json
457
+ {
458
+ "action": "send",
459
+ "target_alias": "support",
460
+ "context_id": "ctx-456",
461
+ "parts": [
462
+ {
463
+ "kind": "text",
464
+ "text": "Start a new side task, but keep it in the same conversation."
465
+ }
466
+ ]
467
+ }
468
+ ```
469
+
470
+ ```json
471
+ {
472
+ "ok": true,
473
+ "operation": "remote_agent",
474
+ "action": "send",
475
+ "summary": {
476
+ "target_alias": "support",
477
+ "target_url": "https://support.example/",
478
+ "response_kind": "message",
479
+ "message_text": "Conversation continued. Start the next task when ready.",
480
+ "continuation": {
481
+ "conversation": {
482
+ "context_id": "ctx-456",
483
+ "can_send": true
484
+ }
485
+ }
486
+ },
487
+ "raw": {
488
+ "kind": "message"
489
+ }
490
+ }
491
+ ```
492
+
493
+ ```ts
494
+ const task = result.summary.continuation?.task
495
+ const conversation = result.summary.continuation?.conversation
496
+
497
+ if (task) {
498
+ throw new Error("expected a context-only continuation")
499
+ }
500
+
501
+ if (conversation) {
502
+ const followUp = {
503
+ action: "send",
504
+ target_alias: "support",
505
+ context_id: conversation.context_id,
506
+ parts: [{ kind: "text", text: "Start the next task in this conversation." }],
507
+ }
508
+ }
509
+ ```
510
+
511
+ Do not poll from conversation continuity.
512
+
221
513
  ### Check Task Status With `task_handle`
222
514
 
223
515
  ```json
@@ -236,10 +528,23 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
236
528
  "summary": {
237
529
  "target_alias": "support",
238
530
  "target_url": "https://support.example/",
239
- "task_handle": "rah_0a3ff8c2-4a6d-48cb-a57d-4ae6f3c589d0",
240
- "task_id": "task-456",
241
- "status": "completed",
242
- "can_watch": true
531
+ "response_kind": "task",
532
+ "continuation": {
533
+ "task": {
534
+ "task_handle": "rah_0a3ff8c2-4a6d-48cb-a57d-4ae6f3c589d0",
535
+ "task_id": "task-456",
536
+ "status": "completed",
537
+ "can_resume_send": false,
538
+ "can_send": false,
539
+ "can_status": true,
540
+ "can_cancel": false,
541
+ "can_watch": false
542
+ },
543
+ "conversation": {
544
+ "context_id": "ctx-456",
545
+ "can_send": true
546
+ }
547
+ }
243
548
  },
244
549
  "raw": {
245
550
  "kind": "task",
@@ -251,7 +556,24 @@ If one target is marked `"default": true`, `send` can omit `target_alias`:
251
556
  }
252
557
  ```
253
558
 
254
- When a handle is expired or unavailable, retry with `target_alias` + `task_id`:
559
+ ```ts
560
+ const task = result.summary.continuation?.task
561
+ const conversation = result.summary.continuation?.conversation
562
+
563
+ if (!task) {
564
+ throw new Error("status requires summary.continuation.task")
565
+ }
566
+
567
+ const nextStatus = task.task_handle
568
+ ? { action: "status", task_handle: task.task_handle }
569
+ : { action: "status", target_alias: "support", task_id: task.task_id }
570
+
571
+ const nextSend = conversation
572
+ ? { action: "send", target_alias: "support", context_id: conversation.context_id }
573
+ : undefined
574
+ ```
575
+
576
+ When `summary.continuation.task.task_handle` is expired or unavailable, retry with `target_alias` + `summary.continuation.task.task_id`:
255
577
 
256
578
  ```json
257
579
  {
@@ -261,7 +583,7 @@ When a handle is expired or unavailable, retry with `target_alias` + `task_id`:
261
583
  }
262
584
  ```
263
585
 
264
- `watch` and `cancel` use the same follow-up targeting rules:
586
+ `watch` and `cancel` use the same follow-up targeting rules, and both require `summary.continuation.task` from a prior result:
265
587
 
266
588
  ```json
267
589
  { "action": "watch", "task_handle": "rah_0a3ff8c2-4a6d-48cb-a57d-4ae6f3c589d0" }
@@ -290,7 +612,7 @@ Tool input validation uses Ajv in strict mode. Validation failures use `operatio
290
612
  {
291
613
  "keyword": "anyOf",
292
614
  "instancePath": "",
293
- "message": "send requires target_alias, target_url, or a configured default target"
615
+ "message": "send requires task_handle, target_alias, target_url, or a configured default target"
294
616
  }
295
617
  ]
296
618
  }
@@ -0,0 +1,13 @@
1
+ import type { SendActionInput } from "./schemas.js";
2
+ import type { TargetCardSnapshot } from "./target-catalog.js";
3
+ export interface CapabilityDiagnostics {
4
+ requested_input_modes: string[];
5
+ advertised_input_modes: string[];
6
+ unsupported_input_modes: string[];
7
+ requested_output_modes: string[];
8
+ advertised_output_modes: string[];
9
+ unsupported_output_modes: string[];
10
+ unknown_file_attachments: number[];
11
+ }
12
+ export declare function evaluateSendCompatibility(input: SendActionInput, acceptedOutputModes: readonly string[], card: TargetCardSnapshot | undefined): CapabilityDiagnostics;
13
+ //# sourceMappingURL=capability-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-diagnostics.d.ts","sourceRoot":"","sources":["../src/capability-diagnostics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAsB9D,MAAM,WAAW,qBAAqB;IACpC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,wBAAwB,EAAE,MAAM,EAAE,CAAC;CACpC;AAgID,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,eAAe,EACtB,mBAAmB,EAAE,SAAS,MAAM,EAAE,EACtC,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC,qBAAqB,CAoBvB"}
@@ -0,0 +1,131 @@
1
+ import { basename, extname } from "node:path";
2
+ const UNKNOWN_INPUT_MODE = "unknown";
3
+ const FILE_MIME_BY_EXTENSION = {
4
+ ".csv": "text/csv",
5
+ ".gif": "image/gif",
6
+ ".jpeg": "image/jpeg",
7
+ ".jpg": "image/jpeg",
8
+ ".json": "application/json",
9
+ ".md": "text/markdown",
10
+ ".mp3": "audio/mpeg",
11
+ ".mp4": "video/mp4",
12
+ ".ogg": "audio/ogg",
13
+ ".pdf": "application/pdf",
14
+ ".png": "image/png",
15
+ ".svg": "image/svg+xml",
16
+ ".txt": "text/plain",
17
+ ".wav": "audio/wav",
18
+ ".webm": "video/webm",
19
+ ".webp": "image/webp",
20
+ };
21
+ function isNonEmptyString(value) {
22
+ return typeof value === "string" && value.trim() !== "";
23
+ }
24
+ function normalizeMode(mode) {
25
+ return mode.trim().toLowerCase();
26
+ }
27
+ function normalizeModeList(modes) {
28
+ if (!modes) {
29
+ return [];
30
+ }
31
+ const normalized = new Set();
32
+ for (const mode of modes) {
33
+ if (!isNonEmptyString(mode)) {
34
+ continue;
35
+ }
36
+ normalized.add(normalizeMode(mode));
37
+ }
38
+ return [...normalized];
39
+ }
40
+ function readUriBasename(uri) {
41
+ try {
42
+ const parsed = new URL(uri);
43
+ const name = basename(parsed.pathname);
44
+ return name.length > 0 ? name : undefined;
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ function inferMimeTypeFromName(name) {
51
+ if (!isNonEmptyString(name)) {
52
+ return undefined;
53
+ }
54
+ const extension = extname(name.trim()).toLowerCase();
55
+ return extension.length > 0 ? FILE_MIME_BY_EXTENSION[extension] : undefined;
56
+ }
57
+ function inferMimeTypeFromUri(uri) {
58
+ if (!isNonEmptyString(uri)) {
59
+ return undefined;
60
+ }
61
+ return inferMimeTypeFromName(readUriBasename(uri));
62
+ }
63
+ function requestedInputModes(parts) {
64
+ const requested = new Set();
65
+ const unknownFileAttachments = [];
66
+ parts.forEach((part, index) => {
67
+ switch (part.kind) {
68
+ case "text":
69
+ requested.add("text/plain");
70
+ return;
71
+ case "data":
72
+ requested.add("application/json");
73
+ return;
74
+ case "file": {
75
+ const mode = isNonEmptyString(part.mime_type)
76
+ ? normalizeMode(part.mime_type)
77
+ : inferMimeTypeFromName(part.name) ?? inferMimeTypeFromUri(part.uri);
78
+ if (mode) {
79
+ requested.add(mode);
80
+ return;
81
+ }
82
+ requested.add(UNKNOWN_INPUT_MODE);
83
+ unknownFileAttachments.push(index);
84
+ return;
85
+ }
86
+ }
87
+ });
88
+ return {
89
+ requested_input_modes: [...requested],
90
+ unknown_file_attachments: unknownFileAttachments,
91
+ };
92
+ }
93
+ function advertisedInputModes(card) {
94
+ if (!card) {
95
+ return [];
96
+ }
97
+ return normalizeModeList([
98
+ ...card.defaultInputModes,
99
+ ...card.skills.flatMap((skill) => skill.inputModes ?? []),
100
+ ]);
101
+ }
102
+ function advertisedOutputModes(card) {
103
+ if (!card) {
104
+ return [];
105
+ }
106
+ return normalizeModeList([
107
+ ...card.defaultOutputModes,
108
+ ...card.skills.flatMap((skill) => skill.outputModes ?? []),
109
+ ]);
110
+ }
111
+ function unsupportedModes(requestedModes, advertisedModes) {
112
+ const supported = new Set(advertisedModes);
113
+ return requestedModes.filter((mode, index) => mode !== UNKNOWN_INPUT_MODE &&
114
+ !supported.has(mode) &&
115
+ requestedModes.indexOf(mode) === index);
116
+ }
117
+ export function evaluateSendCompatibility(input, acceptedOutputModes, card) {
118
+ const inputModes = requestedInputModes(input.parts);
119
+ const requestedOutputModes = normalizeModeList(acceptedOutputModes);
120
+ const advertisedInput = advertisedInputModes(card);
121
+ const advertisedOutput = advertisedOutputModes(card);
122
+ return {
123
+ ...inputModes,
124
+ advertised_input_modes: advertisedInput,
125
+ unsupported_input_modes: unsupportedModes(inputModes.requested_input_modes, advertisedInput),
126
+ requested_output_modes: requestedOutputModes,
127
+ advertised_output_modes: advertisedOutput,
128
+ unsupported_output_modes: unsupportedModes(requestedOutputModes, advertisedOutput),
129
+ };
130
+ }
131
+ //# sourceMappingURL=capability-diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-diagnostics.js","sourceRoot":"","sources":["../src/capability-diagnostics.ts"],"names":[],"mappings":"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"}