@plurnk/plurnk-a2a 1.17.0 → 1.19.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 (54) hide show
  1. package/.env.defaults +12 -8
  2. package/README.md +16 -13
  3. package/SPEC.md +155 -37
  4. package/dist/A2a.d.ts +19 -5
  5. package/dist/A2a.d.ts.map +1 -1
  6. package/dist/A2a.js +120 -33
  7. package/dist/A2a.js.map +1 -1
  8. package/dist/A2aMessage.d.ts +2 -1
  9. package/dist/A2aMessage.d.ts.map +1 -1
  10. package/dist/A2aMessage.js +11 -6
  11. package/dist/A2aMessage.js.map +1 -1
  12. package/dist/A2aProjection.d.ts +13 -4
  13. package/dist/A2aProjection.d.ts.map +1 -1
  14. package/dist/A2aProjection.js +94 -52
  15. package/dist/A2aProjection.js.map +1 -1
  16. package/dist/Functionality.d.ts +6 -4
  17. package/dist/Functionality.d.ts.map +1 -1
  18. package/dist/Functionality.js +18 -17
  19. package/dist/Functionality.js.map +1 -1
  20. package/dist/Module.d.ts +8 -15
  21. package/dist/Module.d.ts.map +1 -1
  22. package/dist/Module.js +75 -40
  23. package/dist/Module.js.map +1 -1
  24. package/dist/OutboundModule.d.ts +0 -1
  25. package/dist/OutboundModule.d.ts.map +1 -1
  26. package/dist/OutboundModule.js +4 -7
  27. package/dist/OutboundModule.js.map +1 -1
  28. package/dist/PlurnkAgentExecutor.d.ts +4 -1
  29. package/dist/PlurnkAgentExecutor.d.ts.map +1 -1
  30. package/dist/PlurnkAgentExecutor.js +51 -16
  31. package/dist/PlurnkAgentExecutor.js.map +1 -1
  32. package/dist/PlurnkRequestHandler.d.ts +11 -0
  33. package/dist/PlurnkRequestHandler.d.ts.map +1 -0
  34. package/dist/PlurnkRequestHandler.js +19 -0
  35. package/dist/PlurnkRequestHandler.js.map +1 -0
  36. package/dist/PlurnkTaskStore.d.ts +2 -1
  37. package/dist/PlurnkTaskStore.d.ts.map +1 -1
  38. package/dist/PlurnkTaskStore.js +88 -42
  39. package/dist/PlurnkTaskStore.js.map +1 -1
  40. package/dist/WorkspaceBinding.d.ts +1 -0
  41. package/dist/WorkspaceBinding.d.ts.map +1 -1
  42. package/dist/WorkspaceBinding.js +14 -5
  43. package/dist/WorkspaceBinding.js.map +1 -1
  44. package/dist/config.d.ts +5 -2
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +46 -20
  47. package/dist/config.js.map +1 -1
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +1 -1
  51. package/dist/index.js.map +1 -1
  52. package/docs/a2a.md +54 -15
  53. package/package.json +6 -6
  54. package/docs/agents.md +0 -42
package/.env.defaults CHANGED
@@ -1,7 +1,8 @@
1
1
  # @plurnk/plurnk-a2a — remote agents and optional hosted exposure.
2
2
 
3
3
  # --- Outbound agents ---
4
- # Initially enabled aliases, JSON array; [] = none. Workers manage their own agents Functionality.
4
+ # An empty alias target masks its definition, companions and ENABLED selection.
5
+ # Initially enabled workspace agent aliases, JSON array; [] = none.
5
6
  PLURNK_A2A_ENABLED=[]
6
7
  # Connection/discovery deadline, positive ms.
7
8
  PLURNK_A2A_CONNECT_TIMEOUT=30000
@@ -15,21 +16,24 @@ PLURNK_A2A_ERROR_DETAIL_LIMIT=512
15
16
  # PLURNK_A2A_research_BEARER=${A2A_RESEARCH_TOKEN}
16
17
  # PLURNK_A2A_research_HEADERS={"X-Tenant":"${A2A_RESEARCH_TENANT}"}
17
18
 
18
- # --- Inbound exposure (unauthenticated; protect nonlocal deployments externally) ---
19
- # 1 = expose a Plurnk agent; 0 = off. Protocol capabilities come from the implementation.
19
+ # --- Inbound exposure ---
20
+ # 1 = expose a Plurnk agent on the service listener (PLURNK_HOST:PLURNK_PORT); 0 = off. Protocol
21
+ # capabilities come from the implementation.
20
22
  PLURNK_A2A_EXPOSE=0
21
- # Listener bind address.
22
- PLURNK_A2A_HOST=127.0.0.1
23
- # Listener TCP port; 0 = choose an available port.
24
- PLURNK_A2A_PORT=4100
23
+ # Bearer required on the endpoint, declared by the card; empty = an unauthenticated exposure, so
24
+ # protect a nonlocal deployment externally. The card at /.well-known/agent-card.json is public.
25
+ PLURNK_A2A_TOKEN=
25
26
  # Absolute endpoint URL pathname, without query or fragment.
26
27
  PLURNK_A2A_ENDPOINT_PATH=/a2a
27
- # Public HTTP(S) endpoint advertised in the card; empty = derive from listener.
28
+ # Public HTTP(S) endpoint advertised in the card; empty = derive from the service listener.
28
29
  PLURNK_A2A_ENDPOINT_URL=
29
30
  # Workspace used for inbound tasks.
30
31
  PLURNK_A2A_WORKSPACE=a2a
31
32
  # Absolute project root for a new inbound workspace; empty = headless.
32
33
  PLURNK_A2A_PROJECT_ROOT=
34
+ # What an inbound task's loop does with a proposal: accept applies it, reject refuses it.
35
+ # A2A carries no review channel, so review is not a choice here.
36
+ PLURNK_A2A_PROPOSALS=reject
33
37
  # Agent card name; required when EXPOSE=1.
34
38
  PLURNK_A2A_NAME=
35
39
  # Agent card description; required when EXPOSE=1.
package/README.md CHANGED
@@ -10,7 +10,7 @@ HTTP+JSON v1 binding.
10
10
 
11
11
  The module is an exterior client of Core's `ApplicationPort`; it does not add
12
12
  an A2A scheduler or Task database. The installed service reads the ordinary
13
- Plurnk environment cascade. Enable one listener and describe its public
13
+ Plurnk environment cascade. Enable the exposure and describe its public
14
14
  identity in an operator or project `.env`:
15
15
 
16
16
  ```dotenv
@@ -22,11 +22,13 @@ PLURNK_A2A_VERSION=1.0.0
22
22
  PLURNK_A2A_SKILLS=[{"id":"research","name":"Research","description":"Researches a question and returns a sourced answer","tags":["research"]}]
23
23
  ```
24
24
 
25
- The module publishes the Agent Card at `/.well-known/agent-card.json` and the
26
- advertised HTTP+JSON interface at `/a2a`. It rejects security declarations
27
- until an authenticated exposure owns the corresponding enforcement path.
28
- Starting the listener or reading its card does not create or hydrate the named
29
- workspace; the first admitted Task does so.
25
+ The module mounts the Agent Card at `/.well-known/agent-card.json` and the
26
+ advertised HTTP+JSON interface at `/a2a` on the service listener
27
+ (`PLURNK_HOST:PLURNK_PORT`); it opens no socket of its own. With
28
+ `PLURNK_A2A_TOKEN` set, the card declares an HTTP bearer scheme and the
29
+ interface requires that bearer; the card itself stays public. Starting the
30
+ service or reading the card does not create or hydrate the named workspace;
31
+ the first admitted Task does so.
30
32
 
31
33
  ## Connect to an agent
32
34
 
@@ -45,23 +47,24 @@ PLURNK_A2A_RESEARCH_BEARER=${A2A_RESEARCH_TOKEN}
45
47
  PLURNK_A2A_ENABLED=["research"]
46
48
  ```
47
49
 
48
- In the service those definitions are the baseline of the workspace `agents`
50
+ In the service those definitions are the baseline of the workspace `a2a`
49
51
  Functionality family (`OutboundModule`): every Worker lists, discovers, adds,
50
52
  enables, disables, and removes outbound agents through the common
51
- `workspace.agents.*` actions or the generated ```` ```agents ```` manager, and the
53
+ `workspace.a2a.*` actions or the generated ```` ```a2a ```` manager, and the
52
54
  `a2a://<alias>` scheme resolves an alias against the workspace's enabled
53
- snapshot. Enabled agents appear in Turn 0 as one `worker:///_plurnk/agents/<alias>.md`
55
+ snapshot. Enabled agents appear in Turn 0 as one `worker:///_plurnk/a2a/<alias>.md`
54
56
  catalog row each; the exact Agent Card stays pullable with `READ a2a://<alias>`.
55
57
 
56
- The package also exports the outbound `a2a://` scheme handler for embedding.
57
- Its resolver maps each URI authority, in the operation's workspace, to
58
- one client while keeping alias and credential policy outside the
58
+ The package also exports the scheme's live face for embedding: a runtime named
59
+ `a2a` carries it as its `scheme`, and it claims every coordinate that opens
60
+ with an alias. Its resolver maps each URI authority, in the operation's
61
+ workspace, to one client while keeping alias and credential policy outside the
59
62
  protocol/resource owner:
60
63
 
61
64
  ```ts
62
65
  import { A2a, connectHttpJsonAgent } from "@plurnk/plurnk-a2a";
63
66
 
64
- const scheme = new A2a(async (alias, ctx) =>
67
+ const face = new A2a(async (alias, ctx) =>
65
68
  alias === "research" && ctx.workspaceId === 1 ? await connectHttpJsonAgent("https://agent.example") : null);
66
69
  ```
67
70
 
package/SPEC.md CHANGED
@@ -17,10 +17,10 @@ cards are protocol projections, not configuration files.
17
17
  | Family | Variables | Meaning |
18
18
  |---|---|---|
19
19
  | Outbound definition | `PLURNK_A2A_<ALIAS>=<absolute HTTP(S) URL>` plus optional `_CARD_PATH`, `_HEADERS`, and `_BEARER` companions | Defines one available remote agent without fetching or enabling it. `_BEARER` contains only a symbolic `${NAME}` reference; secrets remain environment-owned. |
20
- | Outbound defaults | `PLURNK_A2A_ENABLED` | JSON array selecting the exact aliases enabled by default for the workspace's `agents` family ({§a2a-agents-functionality}); workspace state may override enabledness. |
20
+ | Outbound defaults | `PLURNK_A2A_ENABLED` | JSON array selecting the exact aliases enabled by default for the workspace's `a2a` family ({§a2a-functionality}); workspace state may override enabledness. `[]` is the one spelling of none: an absent or empty key is refused by name. |
21
21
  | Timeouts | `PLURNK_A2A_CONNECT_TIMEOUT`, `PLURNK_A2A_REQUEST_TIMEOUT` | Positive integer milliseconds owned by the A2A package. |
22
22
  | Diagnostics | `PLURNK_A2A_ERROR_DETAIL_LIMIT` | Non-negative character bound for one caught upstream diagnostic admitted to a model-facing A2A Problem; complete causes remain internal. |
23
- | Inbound listener | `PLURNK_A2A_EXPOSE`, `_HOST`, `_PORT`, `_ENDPOINT_PATH`, `_ENDPOINT_URL` | `EXPOSE=1` admits one optional HTTP+JSON listener; `0` admits none. |
23
+ | Inbound exposure | `PLURNK_A2A_EXPOSE`, `_TOKEN`, `_ENDPOINT_PATH`, `_ENDPOINT_URL` | `EXPOSE=1` mounts one HTTP+JSON exposure on the service listener ({§http-host}); `0` mounts none. `_TOKEN` is the bearer the endpoint requires and the card declares ({§a2a-hosted-bearer}); empty is an unauthenticated exposure. |
24
24
  | Inbound workspace | `PLURNK_A2A_WORKSPACE`, `_PROJECT_ROOT` | Names the lazily resolved execution workspace and its creation root. |
25
25
  | Hosted identity | `PLURNK_A2A_NAME`, `_DESCRIPTION`, `_VERSION`, optional provider/docs/icon fields, and `_SKILLS` | Supplies identity content for one generated standard Agent Card. `_SKILLS` is a JSON array; omitted per-skill examples and media modes receive the exposure's factual defaults. |
26
26
 
@@ -30,6 +30,11 @@ environment references until connection admission. A remote Agent Card remains
30
30
  the authority for that remote agent; its discovered contents are never copied
31
31
  into this environment vocabulary.
32
32
 
33
+ An explicitly empty outbound target omits that definition, ignores its companion
34
+ values and drops its inherited `ENABLED` selection. It does not remove a
35
+ workspace-owned definition or prohibit adding one. Genuinely undeclared aliases
36
+ and case-fold collisions still fail validation.
37
+
33
38
  ## §a2a-protocol-witness Protocol witness
34
39
 
35
40
  The integration witness places a discovery-first client and an independent
@@ -44,8 +49,11 @@ architecture.
44
49
 
45
50
  ## §a2a-inbound-exposure Inbound exterior exposure
46
51
 
47
- The inbound HTTP+JSON listener is an exterior adapter over
48
- `ApplicationPort`. The official SDK owns A2A framing and request handling;
52
+ The inbound HTTP+JSON exposure is an exterior adapter over
53
+ `ApplicationPort`, mounted on the daemon's one listener ({§http-host}): the
54
+ public Agent Card at the standard well-known path and the interface at
55
+ `PLURNK_A2A_ENDPOINT_PATH`, both on the service address, and it opens no
56
+ socket of its own. The official SDK owns A2A framing and request handling;
49
57
  Plurnk Workers, Loops, logs, and terminal results remain the only execution
50
58
  state. The SDK `TaskStore` implementation is a projection of that durable
51
59
  state, not an independent Task database.
@@ -60,58 +68,94 @@ flowchart LR
60
68
  ```
61
69
 
62
70
  The SDK generates new Context and Task UUIDs before execution. Those UUIDs
63
- already satisfy Plurnk's worker-name contract, so their exact values name the
71
+ already satisfy Plurnk's worker-name contract ({§worker-name}), so their exact values name the
64
72
  root Context Worker and its Task child. No adapter binding table, synthetic
65
73
  actor, or second scheduler exists. Later Tasks fork the Context root and
66
74
  therefore receive the parent-visible prior Task evidence under Core's ordinary
67
75
  topology contract.
68
76
 
69
- Only a child Worker with a durable prompt source matching its exact A2A Context,
77
+ Only a child Worker with a durable message source matching its exact A2A Context,
70
78
  Task, and Message identities projects as a Task. A root is reusable as an A2A
71
79
  Context only after this adapter created it in the running exposure or one such
72
80
  Task proves its durable ownership after restart. Ordinary model Workers in the
73
- same workspace are neither discoverable nor adoptable through A2A. A request
74
- rejected before Worker admission may yield the official SDK's ephemeral failed
75
- Task response, but it creates no durable Task state.
81
+ same workspace are neither discoverable nor adoptable through A2A. Foreign
82
+ Task identities that cannot name a local Worker are unknown Tasks, not Core
83
+ validation failures. Unsupported Message content and invalid answers to a
84
+ pending interaction are rejected before execution with the standard protocol
85
+ error; they do not create Workers or alter an existing Task. Other executor
86
+ failures follow the SDK's failed-Task behavior.
76
87
 
77
88
  | Durable Plurnk state | A2A projection |
78
89
  |---|---|
79
90
  | Loop `100` | `SUBMITTED` |
80
91
  | Loop `102` or `202` | `WORKING`; parking alone does not claim user input is required |
81
92
  | Pending client interaction on the Task Loop | `INPUT_REQUIRED` |
82
- | Successful terminal result | `COMPLETED`; a non-empty final SEND is the `result` Artifact |
93
+ | Successful terminal result | `COMPLETED`; the current Loop's last non-empty delivered reply from message history is the `result` Artifact. The lifecycle result is not a message body. |
83
94
  | External cancellation / Loop `499` | `CANCELED` |
84
95
  | Other terminal failure | `FAILED` with the exact Problem detail as its status Message |
85
- | Prompt rows carrying the adapter's causal source | User Message history |
86
-
87
- The first exposure accepts only text Message Parts, advertises HTTP+JSON v1
88
- streaming without push notifications, tenants, extended cards, or security
89
- schemes, and rejects a card that claims unsupported security. Those omitted
90
- surfaces are not silently simulated. The adapter subscribes to live
96
+ | Inbox messages carrying the adapter's causal source | Complete admitted user Message history from {§message-envelope-evidence}, including accepted interaction answers; independent of log curation and publication. |
97
+ | Delivered replies answering this Task's A2A messages | Only replies whose `answers` name this Task's A2A messages contribute text or attachments. Native or other-protocol replies do not become A2A Artifacts. |
98
+ | Such replies' attachment receipts | Distinct standard Artifacts holding send-time bytes from {§send-resource-attachments}, independent of later source changes. |
99
+
100
+ The exposure accepts text, data, URL, and raw Message Parts, advertises HTTP+JSON v1
101
+ streaming without push notifications, tenants, or extended cards, declares no
102
+ security beyond the bearer it enforces ({§a2a-hosted-bearer}), and rejects a
103
+ card that claims any security of its own. Those omitted surfaces are not
104
+ silently simulated. The adapter subscribes to live
91
105
  application events for streaming and reads durable Worker/Loop/log projections
92
106
  for retrieval and restart truth.
93
107
 
94
108
  §a2a-hosted-card The service generates the hosted standard Agent Card from
95
109
  normalized environment identity plus actual adapter capabilities. The adapter,
96
110
  not configuration, fixes HTTP+JSON protocol `1.0`, streaming, no push
97
- notifications, no extended card, no tenant, no security, `text/plain` input,
98
- and `text/markdown` output. Unsupported security claims are structurally absent
111
+ notifications, no extended card, no tenant, the security it enforces
112
+ ({§a2a-hosted-bearer}), and `*/*` input/output.
113
+ Arbitrary media are resources; native model interpretation still depends on its route.
114
+ Unsupported security claims are structurally absent
99
115
  rather than configurable. The official SDK serializes the card served at the
100
116
  standard well-known path.
101
117
 
102
- §a2a-lazy-workspace Listener startup and Agent Card discovery perform no
103
- workspace creation, attachment, hydration, model selection, or inference. The
118
+ §a2a-hosted-bearer With `PLURNK_A2A_TOKEN` set, the card declares one `http`
119
+ bearer scheme as its whole security requirement, and the endpoint refuses any
120
+ request without that exact bearer — `401`, `UNAUTHENTICATED`,
121
+ `WWW-Authenticate: Bearer`, in the binding's own error shape — before the SDK
122
+ reads anything. The card at the well-known path is never behind the bearer, so a
123
+ caller can discover the scheme. Empty is an unauthenticated exposure: the panel
124
+ states it, the adapter never infers it.
125
+
126
+ §a2a-hosted-proposals A2A carries no review channel, so an inbound Task's loop
127
+ settles its own proposals: `PLURNK_A2A_PROPOSALS` states `accept` or `reject`,
128
+ and `review` is outside its vocabulary. That one field is all the adapter states
129
+ about the loop's policy; attendance is the daemon's to supply, because a remote
130
+ agent can answer an interaction through `input-required`.
131
+
132
+ §a2a-lazy-workspace Mounting the exposure, Agent Card discovery, Task observations,
133
+ and rejected Task lookups perform no workspace creation, attachment, hydration,
134
+ model selection, or inference. An absent workspace yields an empty Task list or
135
+ the standard Task-not-found result, not implicit creation. The
104
136
  first admitted Task resolves the configured workspace name, adopting the one
105
137
  existing match or creating it with the configured project root. A configured
106
138
  non-null root must match an existing workspace exactly. The resolution is
107
139
  shared across concurrent requests and a failed resolution remains retryable.
108
140
 
109
- ## §a2a-agents-functionality Outbound agents as workspace Functionality
141
+ ### §a2a-task-listing Task listing
110
142
 
111
- The package registers, through `OutboundModule`, the `a2a` resource scheme and
112
- one workspace Functionality family named `agents` ({§functionality-adapter} in
113
- core). The family is not tagged `a2a` because every executor tag is also a
114
- scheme face and would collide with the `a2a://` resource scheme. Its definition
143
+ `ListTasks` follows the [A2A listing contract](https://a2a-protocol.org/latest/specification/#314-list-tasks),
144
+ not the Worker directory's creation order.
145
+
146
+ | Concern | Projection |
147
+ |---|---|
148
+ | Ordering | Status timestamp descending; equal or absent timestamps use Task ID ascending. Absent timestamps sort last. |
149
+ | Pagination | Opaque cursor after the last returned timestamp/ID, not an offset. Newer Tasks do not shift subsequent pages. This is a live listing, not a frozen snapshot. |
150
+ | Filtering | Context, state, and inclusive status timestamp bound apply before paging; `totalSize` counts the filtered Tasks. |
151
+ | Content | Artifacts are omitted unless requested; the SDK applies the requested history limit. |
152
+ | Invalid cursor | Standard `RequestMalformedError`; never silently restart at the first page. |
153
+
154
+ ## §a2a-functionality Outbound agents as workspace Functionality
155
+
156
+ The package registers, through `OutboundModule`, one workspace Functionality
157
+ family named `a2a` ({§functionality-adapter} in core): the package, its keys,
158
+ the family and the scheme share one name. Its definition
115
159
  is the `A2aAgentDefinition` contract — local alias `name`, remote `url`,
116
160
  optional `cardPath`, `headers`, and symbolic bearer `authorization` —
117
161
  exactly the environment's `PLURNK_A2A_<ALIAS>*` projection.
@@ -132,9 +176,10 @@ Agent Card at the definition's URL (`card-unreachable`), and connects only
132
176
  through an advertised HTTP+JSON `1.0` interface (`interface-unsupported`),
133
177
  reusing an unchanged attachment across publications. The outcome detail carries
134
178
  the card's name, version, description, skill identifiers, and streaming
135
- capability. The family publishes no runtimes; its snapshot is the workspace's
136
- `alias → client` map, and the `a2a` scheme resolves an authority against the
137
- Functionality of the operation's workspace (`ctx.workspaceId`):
179
+ capability. The family publishes no runtimes of its own; its snapshot is the
180
+ workspace's `alias → client` map, and its scheme face ({§a2a-scheme-face})
181
+ resolves an authority against the Functionality of the operation's workspace
182
+ (`ctx.workspaceId`):
138
183
  an unknown or disabled alias is 404 `agent-not-configured`, an unavailable
139
184
  alias carries its one exact preparation Problem. Every worker in a workspace
140
185
  resolves the same alias definition; independent workspaces may differ.
@@ -145,12 +190,12 @@ prose. A decision-relevant caught configuration, discovery, or interface
145
190
  diagnostic is admitted only through `PLURNK_A2A_ERROR_DETAIL_LIMIT`; the exact
146
191
  cause remains attached for daemon diagnostics.
147
192
 
148
- §a2a-agents-catalog **Turn 0 shows enabled agents concisely.** Preparation
149
- publishes one `worker:///_plurnk/agents/<alias>.md` document per active
193
+ §a2a-catalog **Turn 0 shows enabled agents concisely.** Preparation
194
+ publishes one `worker:///_plurnk/a2a/<alias>.md` document per active
150
195
  alias — an H1 alias, an H2 `Summary` whose one line is
151
196
  `a2a://<alias> — <card name> v<version>: <description>`, and the invocation
152
197
  form — and nothing for disabled or unavailable aliases. Core's seventh turn-0
153
- survey (```` ```FIND (worker:///_plurnk/agents/*.md) <1,-1> ````,
198
+ survey (```` ```FIND (worker:///_plurnk/a2a/*.md) <1,-1> ````,
154
199
  {§actor-boundary-catalog-preview}) therefore presents every effective agent as
155
200
  one summary row. The document embeds neither the card nor its skills; both stay
156
201
  pullable exactly through `READ a2a://<alias>` ({§a2a-outbound-definition}).
@@ -163,8 +208,21 @@ and subscription contracts. Its URI authority is the configured remote-agent
163
208
  alias. The adapter is not a Worker producer, scheduler, Task store, or alternate
164
209
  operation runtime.
165
210
 
211
+ §a2a-scheme-face **The scheme is the live half of the family's own runtime.**
212
+ Every executor tag is a scheme of the same name, so the `a2a` manager and the
213
+ `a2a://` resources are one scheme with two halves ({§runtime-resource-binding}
214
+ in core). The manager's stored executions keep `a2a:///<loop>/<turn>/<sequence>`,
215
+ numeric throughout; the package's face claims every other coordinate — one that
216
+ opens with an agent alias, or with `contexts` for a hosted message — and owns
217
+ READ, FIND preparation and SEND there; KILL of a live Task is the ordinary
218
+ stream control. The face declares its own representation — resource authority,
219
+ `#body` and `#json` — so a resource keeps the one address `a2a://planner/tasks/7`
220
+ in what the model writes, in its log, and in the wake that concludes a Task.
221
+ The family states the `web` trait, so a capability policy that selects on it
222
+ covers the manager and every resource alike.
223
+
166
224
  §a2a-outbound-definition An enabled outbound alias resolves through its
167
- workspace's `agents` Functionality snapshot ({§a2a-agents-functionality}), whose
225
+ workspace's `a2a` Functionality snapshot ({§a2a-functionality}), whose
168
226
  preparation discovered and validated the remote standard Agent Card and
169
227
  selected only an advertised HTTP+JSON `1.0` interface. The local alias,
170
228
  target, optional card path, symbolic authentication, and provenance are local
@@ -180,11 +238,11 @@ interfaces remain remote protocol authority.
180
238
  | READ | Exact Task resource | Materialize the remote Task's current canonical snapshot. |
181
239
  | READ | Stored Artifact resource | Read the workspace's retained bytes without requiring an active agent connection. |
182
240
 
183
- §a2a-outbound-turn-rhythm SEND delivers a Message; TASK independently declares
184
- the local Loop's inventory under {§task-inventory-intent}. A Task-backed SEND
185
- creates an ordinary live obligation. An `in_progress` inventory continues work;
186
- a `waiting` inventory joins that obligation. Subscription settlement wakes the
187
- same Loop with its terminal READ, and a later terminal inventory concludes
241
+ §a2a-outbound-turn-rhythm SEND delivers a Message; lifecycle verbs independently
242
+ declare the local Loop's intent under {§turn-disposition}. A Task-backed SEND
243
+ creates an ordinary live obligation. Ordinary operations continue work;
244
+ WAIT joins that obligation. Subscription settlement wakes the
245
+ same Loop with its terminal READ, and an answered, observed and settled loop concludes
188
246
  under {§wait-obligation-matrix}. KILL cancels through that same subscription.
189
247
  No adapter-authored turn or alternate disposition path fills any step.
190
248
 
@@ -193,6 +251,14 @@ entry, opens one subscription, returns its exact address with `102`, and closes
193
251
  that subscription with the remote Task result. Core alone owns parking, waking,
194
252
  the terminal next-turn READ, and cancellation propagation.
195
253
 
254
+ Reaching a remote agent is a host effect, so the SEND proposes first
255
+ ({§http-outbound-proposes}) and the seeding above happens on the settlement. The
256
+ `102` is then what the applied operation returns to the settlement, not what the
257
+ model reads: an accepted proposal answers `200` ({§proposal-accept-applies}), so
258
+ the Task's first snapshot arrives by ordinary observation of the resource rather
259
+ than on the SEND row. The model sees the same canonical entry either way, one
260
+ turn later; a rejected proposal reaches no agent at all.
261
+
196
262
  §a2a-outbound-replay A card or resource READ and connection discovery are
197
263
  replay-safe observations. A SEND is not: once dispatch begins, a transport or
198
264
  stream-protocol failure cannot prove that the remote agent rejected the
@@ -202,6 +268,41 @@ automatic identical replay that could duplicate remote work.
202
268
 
203
269
  ## §a2a-resource-projection Resource projection
204
270
 
271
+ §a2a-hosted-message-resources Hosted input uses the ordinary inbox and
272
+ {§send-resource-attachments}, not the outbound alias resolver. An incoming
273
+ caller needs neither an Agent Card nor a configured remote alias.
274
+
275
+ | Input Part | Model-facing arrival |
276
+ |---|---|
277
+ | Text | Authored text. |
278
+ | Data | Pretty-printed JSON. |
279
+ | URL | Literal supplied URL; no arrival-time fetch. |
280
+ | Raw | Link to `worker://<task>/attachments/<eight-character-id>/<name>`, with ordinary typed bytes; unnamed/colliding names use {§resource-publication-names}. |
281
+
282
+ The complete admitted SDK SendMessageRequest envelope preserves configuration,
283
+ request metadata, and its inner Message's Part order, media types, filenames,
284
+ metadata, and assigned Task/Context identity. Accepted interaction
285
+ answers enter that same evidence path before the operation resumes; invalid
286
+ answers do not. Task history selects the envelope's inner Message, including
287
+ those awaiting log publication. Derived status Messages describe the current
288
+ pending interaction or terminal Problem; they are not additional inbox arrivals.
289
+ Task retrieval reconstructs these facts after adapter/daemon restart.
290
+
291
+ §a2a-response-preferences Nonempty `configuration.acceptedOutputModes` appears
292
+ as labeled response preferences beside the model-facing arrival, for normal
293
+ requests and accepted interaction answers. Omitted or empty preferences add
294
+ nothing. This projection neither edits the protocol Message nor changes
295
+ interaction validation. Other request configuration remains adapter-owned;
296
+ opaque request metadata is evidence, not additional instructions. Preferences
297
+ do not relabel source bytes or promise an unavailable output representation.
298
+
299
+ Explicit resource selections in a hosted worker's targetless SEND become
300
+ standard raw-Part Artifacts, one per selected resource in order. Artifact IDs
301
+ are stable within the Task. The ordinary final textual result retains its
302
+ `result` Artifact. A directed A2A SEND instead transmits its selected resources
303
+ as raw Parts of that user Message. Resource creation and READ never export;
304
+ the selected send-time snapshot survives both source mutation and log curation.
305
+
205
306
  Every retained Agent Card, Message, Task, and Artifact has a model-oriented
206
307
  Markdown `#body` and an exact protocol `#json` channel serialized by the pinned
207
308
  official SDK. A Task's Artifact identities remain distinct URI descendants and
@@ -209,3 +310,20 @@ materialize independently; the adapter never flattens multiple Artifacts into
209
310
  one fabricated result. Projection wording is presentation rather than protocol
210
311
  identity: tests assert lifecycle state, content, media type, and addressability,
211
312
  not a prose template.
313
+
314
+ §a2a-part-resources Received raw Parts are ordinary typed resources, not base64
315
+ placeholders. Their parent Message or Artifact links to them in Part order;
316
+ the exact protocol JSON remains independently readable.
317
+
318
+ | Part | Ordinary resource projection |
319
+ |---|---|
320
+ | Text / structured data | Text / pretty JSON in the parent body. |
321
+ | URL | The supplied URL; arrival does not fetch it or bypass its scheme's acquisition policy. |
322
+ | Raw bytes | `<parent>/resources/<name>` with exact bytes and media type (or `application/octet-stream` if absent). Supplied names and stable eight-character fallback names use {§resource-publication-names}. |
323
+
324
+ A received Task snapshot retains its Artifacts and Messages with their Part
325
+ resources before publishing links or settling its subscription. Retained
326
+ Message, Artifact, and Part READs need no active remote connection. READ alone
327
+ controls native attachment delivery through {§packet-attachment-parts}; listing
328
+ a resource does not inject its bytes into model context. Log curation does not
329
+ delete the retained source.
package/dist/A2a.d.ts CHANGED
@@ -1,12 +1,26 @@
1
1
  import type { Client } from "@a2a-js/sdk/client";
2
- import { type PassthroughResult, type RepresentationPreparationRequest, type RepresentationPreparationResult, type SchemeCtx, type SchemeHandler, type SchemeManifest, type SendStatement } from "@plurnk/plurnk-schemes";
2
+ import { type PassthroughResult, type ProposalResult, type ProposalApplyRequest, type ProposalApplyResult, type RepresentationPreparationRequest, type RepresentationPreparationResult, type SchemeCtx, type SchemeResult, type SendStatement, type FindStatement } from "@plurnk/plurnk-schemes";
3
3
  export type A2aClientResolver = (authority: string, ctx: SchemeCtx) => Client | null | Promise<Client | null>;
4
- /** Outbound A2A v1 resources and Task obligations over the ordinary scheme API. */
5
- export default class A2a implements SchemeHandler {
4
+ /**
5
+ * {§a2a-scheme-face} Outbound A2A v1 resources and Task obligations: the live half of the `a2a`
6
+ * runtime's scheme. The family manager's stored executions keep `a2a:///<loop>/<turn>/<sequence>`;
7
+ * every other coordinate opens with an agent alias, or with `contexts` for a hosted message.
8
+ */
9
+ export default class A2a {
6
10
  #private;
7
- static manifest: SchemeManifest;
11
+ readonly manifest: {
12
+ readonly authority: "resource";
13
+ readonly channels: {
14
+ readonly body: "text/markdown";
15
+ readonly json: "application/json";
16
+ };
17
+ readonly defaultChannel: "body";
18
+ };
19
+ claims(pathname: string): boolean;
20
+ prepareFind(_statement: FindStatement, ctx: SchemeCtx): Promise<SchemeResult>;
8
21
  constructor(resolveClient: A2aClientResolver);
9
22
  prepareRepresentation(request: RepresentationPreparationRequest, ctx: SchemeCtx): Promise<RepresentationPreparationResult>;
10
- send(statement: SendStatement, ctx: SchemeCtx): Promise<PassthroughResult>;
23
+ send(statement: SendStatement, ctx: SchemeCtx): Promise<PassthroughResult | ProposalResult>;
24
+ applyResolution(request: ProposalApplyRequest, ctx: SchemeCtx): Promise<ProposalApplyResult>;
11
25
  }
12
26
  //# sourceMappingURL=A2a.d.ts.map
package/dist/A2a.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"A2a.d.ts","sourceRoot":"","sources":["../src/A2a.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAIH,KAAK,iBAAiB,EACtB,KAAK,gCAAgC,EACrC,KAAK,+BAA+B,EACpC,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,KAAK,aAAa,EAErB,MAAM,wBAAwB,CAAC;AAShC,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAe9G,mFAAmF;AACnF,MAAM,CAAC,OAAO,OAAO,GAAI,YAAW,aAAa;;IAC7C,MAAM,CAAC,QAAQ,EAAE,cAAc,CAa7B;IAIF,YAAY,aAAa,EAAE,iBAAiB,EAE3C;IAEK,qBAAqB,CACvB,OAAO,EAAE,gCAAgC,EACzC,GAAG,EAAE,SAAS,GACf,OAAO,CAAC,+BAA+B,CAAC,CAsE1C;IAEK,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4G/E;CAyNJ"}
1
+ {"version":3,"file":"A2a.d.ts","sourceRoot":"","sources":["../src/A2a.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAMH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,gCAAgC,EACrC,KAAK,+BAA+B,EACpC,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAGlB,KAAK,aAAa,EACrB,MAAM,wBAAwB,CAAC;AAQhC,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAe9G;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,GAAG;;IAEpB,QAAQ,CAAC,QAAQ;iBACb,SAAS,EAAE,UAAU;iBACrB,QAAQ;qBAAI,IAAI,EAAE,eAAe;qBAAE,IAAI,EAAE,kBAAkB;;iBAC3D,cAAc,EAAE,MAAM;MACf;IASX,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEhC;IAEK,WAAW,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAElF;IAID,YAAY,aAAa,EAAE,iBAAiB,EAE3C;IAEK,qBAAqB,CACvB,OAAO,EAAE,gCAAgC,EACzC,GAAG,EAAE,SAAS,GACf,OAAO,CAAC,+BAA+B,CAAC,CA0E1C;IAMK,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,iBAAiB,GAAG,cAAc,CAAC,CA8BhG;IAEK,eAAe,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmBjG;CAuVJ"}