@loopingai/core 0.3.1 → 0.4.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 (100) hide show
  1. package/README.md +83 -28
  2. package/dist/a2a/caller.d.ts +24 -0
  3. package/dist/a2a/caller.d.ts.map +1 -0
  4. package/dist/a2a/caller.js +34 -0
  5. package/dist/a2a/caller.js.map +1 -0
  6. package/dist/a2a/card.d.ts +7 -2
  7. package/dist/a2a/card.d.ts.map +1 -1
  8. package/dist/a2a/card.js +16 -7
  9. package/dist/a2a/card.js.map +1 -1
  10. package/dist/a2a/index.d.ts +15 -0
  11. package/dist/a2a/index.d.ts.map +1 -1
  12. package/dist/a2a/index.js +15 -0
  13. package/dist/a2a/index.js.map +1 -1
  14. package/dist/a2a/notify.d.ts +27 -5
  15. package/dist/a2a/notify.d.ts.map +1 -1
  16. package/dist/a2a/notify.js +18 -8
  17. package/dist/a2a/notify.js.map +1 -1
  18. package/dist/a2a/push.d.ts +71 -0
  19. package/dist/a2a/push.d.ts.map +1 -0
  20. package/dist/a2a/push.js +54 -0
  21. package/dist/a2a/push.js.map +1 -0
  22. package/dist/a2a/verify.d.ts +28 -36
  23. package/dist/a2a/verify.d.ts.map +1 -1
  24. package/dist/a2a/verify.js +20 -25
  25. package/dist/a2a/verify.js.map +1 -1
  26. package/dist/agent/index.d.ts +16 -5
  27. package/dist/agent/index.d.ts.map +1 -1
  28. package/dist/agent/index.js +16 -5
  29. package/dist/agent/index.js.map +1 -1
  30. package/dist/config.d.ts +49 -7
  31. package/dist/config.d.ts.map +1 -1
  32. package/dist/config.js +25 -3
  33. package/dist/config.js.map +1 -1
  34. package/dist/db/models/tasks.d.ts +19 -5
  35. package/dist/db/models/tasks.d.ts.map +1 -1
  36. package/dist/db/models/tasks.js +38 -8
  37. package/dist/db/models/tasks.js.map +1 -1
  38. package/dist/host/agent.d.ts +217 -0
  39. package/dist/host/agent.d.ts.map +1 -0
  40. package/dist/host/agent.js +306 -0
  41. package/dist/host/agent.js.map +1 -0
  42. package/dist/host/index.d.ts +21 -0
  43. package/dist/host/index.d.ts.map +1 -0
  44. package/dist/host/index.js +20 -0
  45. package/dist/host/index.js.map +1 -0
  46. package/dist/host/plugin-host.d.ts +47 -0
  47. package/dist/host/plugin-host.d.ts.map +1 -0
  48. package/dist/host/plugin-host.js +2 -0
  49. package/dist/host/plugin-host.js.map +1 -0
  50. package/dist/round/agent.d.ts +267 -0
  51. package/dist/round/agent.d.ts.map +1 -0
  52. package/dist/round/agent.js +691 -0
  53. package/dist/round/agent.js.map +1 -0
  54. package/dist/round/index.d.ts +25 -0
  55. package/dist/round/index.d.ts.map +1 -0
  56. package/dist/round/index.js +24 -0
  57. package/dist/round/index.js.map +1 -0
  58. package/dist/round/policy.d.ts +99 -0
  59. package/dist/round/policy.d.ts.map +1 -0
  60. package/dist/round/policy.js +2 -0
  61. package/dist/round/policy.js.map +1 -0
  62. package/dist/round/subagent.d.ts +67 -0
  63. package/dist/round/subagent.d.ts.map +1 -0
  64. package/dist/round/subagent.js +91 -0
  65. package/dist/round/subagent.js.map +1 -0
  66. package/dist/round/turn.d.ts +231 -0
  67. package/dist/round/turn.d.ts.map +1 -0
  68. package/dist/round/turn.js +497 -0
  69. package/dist/round/turn.js.map +1 -0
  70. package/dist/round/workflow.d.ts +109 -0
  71. package/dist/round/workflow.d.ts.map +1 -0
  72. package/dist/round/workflow.js +316 -0
  73. package/dist/round/workflow.js.map +1 -0
  74. package/dist/runtime/index.d.ts +5 -1
  75. package/dist/runtime/index.d.ts.map +1 -1
  76. package/dist/runtime/index.js.map +1 -1
  77. package/dist/testing/auth.d.ts.map +1 -1
  78. package/dist/testing/auth.js +10 -7
  79. package/dist/testing/auth.js.map +1 -1
  80. package/dist/testing/fixtures.d.ts +17 -0
  81. package/dist/testing/fixtures.d.ts.map +1 -1
  82. package/dist/testing/fixtures.js +17 -0
  83. package/dist/testing/fixtures.js.map +1 -1
  84. package/dist/testing/harness.d.ts +98 -0
  85. package/dist/testing/harness.d.ts.map +1 -0
  86. package/dist/testing/harness.js +139 -0
  87. package/dist/testing/harness.js.map +1 -0
  88. package/dist/testing/index.d.ts +2 -1
  89. package/dist/testing/index.d.ts.map +1 -1
  90. package/dist/testing/index.js +2 -1
  91. package/dist/testing/index.js.map +1 -1
  92. package/dist/worker/define-agent.d.ts +124 -0
  93. package/dist/worker/define-agent.d.ts.map +1 -0
  94. package/dist/worker/define-agent.js +21 -0
  95. package/dist/worker/define-agent.js.map +1 -0
  96. package/dist/worker/index.d.ts +29 -4
  97. package/dist/worker/index.d.ts.map +1 -1
  98. package/dist/worker/index.js +70 -12
  99. package/dist/worker/index.js.map +1 -1
  100. package/package.json +12 -3
package/README.md CHANGED
@@ -147,39 +147,71 @@ wildcard.
147
147
  > interoperate across this change in either direction, so they deploy together and
148
148
  > registered agents are re-registered.
149
149
 
150
- ### 3. Build the runtime in your Durable Object
150
+ ### 3. Write your Durable Object
151
151
 
152
- Everything that would otherwise be a module-level constant is resolved once per DO
153
- instance, from your config and your installed plugins:
152
+ `LoopingAgent` is the DO body every agent has: the runtime and database built once
153
+ per instance, one continuous Session per verified caller, the gateway callback
154
+ channel, and the task lifecycle a Workflow drives. Three seams are yours.
154
155
 
155
156
  ```ts
156
- import { Agent } from "agents";
157
- import { createAgentRuntime } from "@loopingai/core";
158
- import { AgentDB } from "@loopingai/core/db";
159
-
160
- export class MyAgent extends Agent<Env> {
161
- runtime!: ReturnType<typeof createAgentRuntime>;
162
- db!: AgentDB;
163
-
164
- async onStart() {
165
- this.runtime = createAgentRuntime({
166
- config: { model: { chatModelId: "@cf/zai-org/glm-5.2" } },
167
- plugins: [scraper({ apiKey: this.env.SCRAPER_API_KEY })],
168
- env: this.env // opt in to verifying every plugin's declared bindings exist
169
- });
170
-
171
- this.db = new AgentDB(this.ctx.storage, {
172
- maxSubtasks: this.runtime.config.maxSubtasks,
173
- stores: this.runtime.stores
174
- });
175
- await this.db.ensureReady();
157
+ import { LoopingAgent, type PluginHost } from "@loopingai/core/host";
158
+
159
+ export class MyAgent extends LoopingAgent<Env> {
160
+ protected agentConfig() {
161
+ return {
162
+ model: {
163
+ chatModelId: "@cf/zai-org/glm-5.2",
164
+ fallbackChatModelId: "@cf/meta/llama-4-scout-17b-16e-instruct"
165
+ }
166
+ };
167
+ }
168
+ protected agentPlugins(host: PluginHost<Env>) {
169
+ return [scraper({ apiKey: host.env.SCRAPER_API_KEY })];
170
+ }
171
+ protected agentSoul(capabilities: string) {
172
+ return soulPrompt(capabilities);
173
+ }
174
+ }
175
+ ```
176
+
177
+ Everything that would otherwise be a module-level constant is resolved from those,
178
+ once per instance. Resolving a registry at _import_ time is the one thing this
179
+ package exists to prevent: it freezes the registry before `env` exists (which on
180
+ Workers is always), defeats tree-shaking, and makes runtime plugin selection
181
+ impossible.
182
+
183
+ `createAgentRuntime` and `AgentDB` are still exported and still work on a bare
184
+ `Agent<Env>` — but everything the base class does is lifecycle with an ordering
185
+ that is load-bearing and invisible (migrations awaited before the first RPC, the
186
+ guarded terminal write, the cancellation verdict that must be read and not
187
+ probed for), and hand-rolling it is how two agents in one repo drift apart.
188
+
189
+ ### 4. Delegate, if your agent delegates
190
+
191
+ `@loopingai/core/round` adds the other half: a durable Subtask DAG, wave
192
+ scheduling, isolated subagent execution, and the round loop over them.
193
+
194
+ ```ts
195
+ import { RoundAgentBase, type RoundPolicy } from "@loopingai/core/round";
196
+
197
+ export class MyAgent extends RoundAgentBase<Env> {
198
+ // …the three seams above, plus:
199
+ protected roundPolicy(): RoundPolicy {
200
+ return policy;
201
+ }
202
+ protected subagentClass() {
203
+ return MySubagent;
176
204
  }
177
205
  }
178
206
  ```
179
207
 
180
- Resolving a registry at _import_ time is the one thing this package exists to
181
- prevent: it freezes the registry before `env` exists (which on Workers is always),
182
- defeats tree-shaking, and makes runtime plugin selection impossible.
208
+ #### The round policy
209
+
210
+ Core ships the machine and none of the words. `RoundPolicy` is every string the
211
+ loop emits — the round contract the model is held to, the note appended when the
212
+ budget is spent, and the three user-facing messages. Nothing has a default: a
213
+ lent-out round contract is exactly the house prompt copy this package refuses to
214
+ have.
183
215
 
184
216
  ---
185
217
 
@@ -194,6 +226,8 @@ not drag in the A2A adapter, and the test harness cannot reach a production bund
194
226
  | `@loopingai/core/a2a` | card signing, JWKS, gateway-JWT verify, push notify, task store, executor |
195
227
  | `@loopingai/core/worker` | `createA2AWorker()` — the whole zero-trust edge |
196
228
  | `@loopingai/core/agent` | session, history, model runtime, inference, budget, control tools |
229
+ | `@loopingai/core/host` | `LoopingAgent` — the Durable Object body — and `PluginHost` |
230
+ | `@loopingai/core/round` | the delegating round loop: `RoundAgentBase`, `runHandleTask`, `runTurn` |
197
231
  | `@loopingai/core/subtasks` | delegation types, decomposition, the `delegate` tool, wave scheduler |
198
232
  | `@loopingai/core/subagent` | `RecipeSubagentBase`, resumable runs, fingerprinting, workspace |
199
233
  | `@loopingai/core/db` | `AgentDB`, `notify_tasks` + `subtasks` schema, migrations, `PluginStore` |
@@ -388,13 +422,34 @@ await withDb("accepts a turn once", async (db) => {
388
422
  (a scripted `LanguageModel`), so a loop can be driven with no model call at all.
389
423
  - **Fixtures** — Ed25519 keypairs and a gateway-JWT signer, so the zero-trust path is
390
424
  exercisable end to end without a real gateway.
425
+ - **`createAgentHarness`** — the assembly of all of the above: send one A2A turn the
426
+ way a gateway does, and capture what comes back.
427
+
428
+ ```ts
429
+ const harness = createAgentHarness({ worker, env, tenant: "reactive" });
430
+ using _ = harness.interceptGateway();
431
+
432
+ const accepted = await harness.send("what's the weather?");
433
+ expect(accepted.status.state).toBe(TaskState.TASK_STATE_SUBMITTED);
434
+ ```
435
+
436
+ It exists because the pieces above were never the hard part. The audience is the
437
+ **endpoint**, not the origin; the tenant claim has to match the tenant in the
438
+ body; `SendMessage` is refused without a push config; and the gateway's JWKS has
439
+ to be reachable or every spec below it reports a 401 about something else. Four
440
+ facts, wrong the first time in every consumer that wrote this by hand.
391
441
 
392
442
  ---
393
443
 
394
444
  ## What core deliberately does _not_ contain
395
445
 
396
- - The turn loop, triage, and the DO / Workflow class bodies. Core ships the argument
397
- and budget types; you write the loop.
446
+ - **Prompt copy of any kind.** Not a soul, not a round contract, not a user-facing
447
+ failure message. `@loopingai/core/round` ships the whole delegating loop but takes
448
+ every word it says from a [`RoundPolicy`](#the-round-policy) you write, because a
449
+ run must never execute under an identity nobody chose.
450
+ - **A loop you cannot replace.** `/round` is opt-in and its own subpath. An agent
451
+ whose turn is a single inference extends `LoopingAgent` directly, writes its own
452
+ loop, and carries none of the delegation machinery in its bundle.
398
453
  - The main agent's soul. Core ships no prompt copy.
399
454
  - Config _values_ — model ids, budgets, limits. Core ships the shapes and safe
400
455
  defaults, and `resolveConfig` validates your overrides.
@@ -0,0 +1,24 @@
1
+ import type { GatewayIdentity } from "./verify.js";
2
+ /**
3
+ * Per-request system-prompt suffix describing the verified calling gateway-agent
4
+ * instance, from the gateway identity JWT.
5
+ *
6
+ * Core ships this and not a soul, and the line between them is the point: a soul
7
+ * is prompt copy expressing who an agent *is*, which nobody else can write for
8
+ * you. This is a **rendering of a protocol fact** — who the gateway proved it was
9
+ * — and that fact has one correct rendering. Two agents disagreeing about how to
10
+ * describe their caller would be a bug, not a personality. It is the same
11
+ * category as `renderSubagentPrompt`'s budget section, which core also owns.
12
+ *
13
+ * **Advisory context only.** This is the calling *agent instance*, not the human
14
+ * on the other end of it, so an agent's soul must never let the model read it as
15
+ * "who you're talking to" — point the model at whatever speaker wrapper the
16
+ * gateway applies instead.
17
+ *
18
+ * Deliberately neutral about what a workspace is: `GatewayIdentity.workspaceId`
19
+ * is whatever the calling gateway partitions by, and core does not know that it
20
+ * is a Slack team. Override `LoopingAgent.callerContext` for a deployment that
21
+ * wants to name it.
22
+ */
23
+ export declare function callerContext(identity: GatewayIdentity): string;
24
+ //# sourceMappingURL=caller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller.d.ts","sourceRoot":"","sources":["../../src/a2a/caller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAW/D"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Per-request system-prompt suffix describing the verified calling gateway-agent
3
+ * instance, from the gateway identity JWT.
4
+ *
5
+ * Core ships this and not a soul, and the line between them is the point: a soul
6
+ * is prompt copy expressing who an agent *is*, which nobody else can write for
7
+ * you. This is a **rendering of a protocol fact** — who the gateway proved it was
8
+ * — and that fact has one correct rendering. Two agents disagreeing about how to
9
+ * describe their caller would be a bug, not a personality. It is the same
10
+ * category as `renderSubagentPrompt`'s budget section, which core also owns.
11
+ *
12
+ * **Advisory context only.** This is the calling *agent instance*, not the human
13
+ * on the other end of it, so an agent's soul must never let the model read it as
14
+ * "who you're talking to" — point the model at whatever speaker wrapper the
15
+ * gateway applies instead.
16
+ *
17
+ * Deliberately neutral about what a workspace is: `GatewayIdentity.workspaceId`
18
+ * is whatever the calling gateway partitions by, and core does not know that it
19
+ * is a Slack team. Override `LoopingAgent.callerContext` for a deployment that
20
+ * wants to name it.
21
+ */
22
+ export function callerContext(identity) {
23
+ const label = identity.name ?? identity.key;
24
+ if (!label) {
25
+ return "\n\nCalling agent instance: unknown (the gateway did not include an agent identity).";
26
+ }
27
+ const withKind = identity.kind ? `${label} (${identity.kind})` : label;
28
+ const lines = ["", "", `Calling agent instance: ${withKind}.`];
29
+ if (identity.workspaceId != null) {
30
+ lines.push(`Calling workspace: ${identity.workspaceId}.`);
31
+ }
32
+ return lines.join("\n");
33
+ }
34
+ //# sourceMappingURL=caller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller.js","sourceRoot":"","sources":["../../src/a2a/caller.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,aAAa,CAAC,QAAyB;IACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,sFAAsF,CAAC;IAChG,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;IACvE,MAAM,KAAK,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,2BAA2B,QAAQ,GAAG,CAAC,CAAC;IAC/D,IAAI,QAAQ,CAAC,WAAW,IAAI,IAAI,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,sBAAsB,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -1,7 +1,12 @@
1
1
  import type { JWK } from "jose";
2
2
  import { AgentCard } from "@a2a-js/sdk";
3
- /** The default JSON-RPC path an agent answers on (the card's only interface). */
4
- export declare const A2A_RPC_PATH = "/a2a";
3
+ /**
4
+ * The card signature uses the one algorithm every Looping A2A signature uses,
5
+ * and the default RPC path is the one the gateway also knows. Both come from
6
+ * `@loopingai/a2a-protocol` — see {@link file://./verify.ts} for why that is a
7
+ * separate package rather than a constant declared on each side.
8
+ */
9
+ export { A2A_RPC_PATH } from "@loopingai/a2a-protocol";
5
10
  /**
6
11
  * The transport-independent half of an {@link AgentCard} — everything that does
7
12
  * not depend on the request origin. {@link buildBaseCard} adds
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/a2a/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAEL,SAAS,EAEV,MAAM,aAAa,CAAC;AAKrB,iFAAiF;AACjF,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,CAC9B,SAAS,EACP,MAAM,GACN,aAAa,GACb,SAAS,GACT,cAAc,GACd,mBAAmB,GACnB,oBAAoB,GACpB,QAAQ,CACX,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,UAAU,EAAE,GAAG,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAUD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,gBAAgB,GACrB,SAAS,CA6CX;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,aAAa,CAAC,CASxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,SAAS,CAAC,CAGpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAI5E;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,UAAU,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IACjE,IAAI,EAAE,GAAG,EAAE,CAAC;CACb,CAIA"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/a2a/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAEL,SAAS,EAEV,MAAM,aAAa,CAAC;AAOrB;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,CAC9B,SAAS,EACP,MAAM,GACN,aAAa,GACb,SAAS,GACT,cAAc,GACd,mBAAmB,GACnB,oBAAoB,GACpB,QAAQ,CACX,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,UAAU,EAAE,GAAG,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAUD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,gBAAgB,GACrB,SAAS,CAkDX;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,aAAa,CAAC,CASxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,SAAS,CAAC,CAGpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAI5E;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,UAAU,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IACjE,IAAI,EAAE,GAAG,EAAE,CAAC;CACb,CAIA"}
package/dist/a2a/card.js CHANGED
@@ -1,8 +1,12 @@
1
1
  import { A2A_PROTOCOL_VERSION, AgentCard, generateAgentCardSignature } from "@a2a-js/sdk";
2
- /** JWS algorithm for the card signature — must match the gateway (`EdDSA`). */
3
- const ALG = "EdDSA";
4
- /** The default JSON-RPC path an agent answers on (the card's only interface). */
5
- export const A2A_RPC_PATH = "/a2a";
2
+ import { A2A_JWS_ALG, A2A_RPC_PATH, endpointUrl } from "@loopingai/a2a-protocol";
3
+ /**
4
+ * The card signature uses the one algorithm every Looping A2A signature uses,
5
+ * and the default RPC path is the one the gateway also knows. Both come from
6
+ * `@loopingai/a2a-protocol` — see {@link file://./verify.ts} for why that is a
7
+ * separate package rather than a constant declared on each side.
8
+ */
9
+ export { A2A_RPC_PATH } from "@loopingai/a2a-protocol";
6
10
  /**
7
11
  * The `httpAuthSecurityScheme` describing the gateway's Bearer JWT, and the
8
12
  * requirement that references it. Split out so the requirement can be advertised
@@ -40,7 +44,12 @@ export function buildBaseCard(manifest, opts) {
40
44
  },
41
45
  supportedInterfaces: [
42
46
  {
43
- url: `${opts.origin}${rpcPath}`,
47
+ // The gateway reads this URL off the card and mints `aud` from it with
48
+ // `audienceFor`; this Worker derives its expected audience the same
49
+ // way. `endpointUrl` is what makes those provably equal — the protocol
50
+ // package pins `audienceFor(endpointUrl(o, p)) === endpointUrl(o, p)`
51
+ // for every path, rather than leaving both sides to concatenate.
52
+ url: endpointUrl(opts.origin, rpcPath),
44
53
  protocolBinding: "JSONRPC",
45
54
  protocolVersion: A2A_PROTOCOL_VERSION,
46
55
  tenant: opts.tenant ?? ""
@@ -86,7 +95,7 @@ export function buildBaseCard(manifest, opts) {
86
95
  */
87
96
  export async function signCard(card, cfg) {
88
97
  const sign = generateAgentCardSignature(cfg.privateJwk, {
89
- alg: ALG,
98
+ alg: A2A_JWS_ALG,
90
99
  kid: cfg.privateJwk.kid,
91
100
  typ: "JOSE",
92
101
  jku: cfg.jku
@@ -148,6 +157,6 @@ export function parsePrivateJwk(raw) {
148
157
  export function publicCardJwks(privateJwk) {
149
158
  const { d: _d, ...pub } = privateJwk;
150
159
  void _d;
151
- return { keys: [{ ...pub, use: "sig", alg: ALG }] };
160
+ return { keys: [{ ...pub, use: "sig", alg: A2A_JWS_ALG }] };
152
161
  }
153
162
  //# sourceMappingURL=card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","sourceRoot":"","sources":["../../src/a2a/card.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../../src/a2a/card.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,25 @@
5
5
  * JWKS, prove ourselves with ours), the accept-and-notify task lifecycle, and the
6
6
  * narrowed task types that survive Durable Object RPC. Nothing here knows what an
7
7
  * agent *does* — past {@link A2AExecutor} everything is plain strings.
8
+ *
9
+ * ## The wire values come from `@loopingai/a2a-protocol`
10
+ *
11
+ * Claim names, the algorithm, the well-known paths and the audience rule are a
12
+ * two-sided contract with a token issuer, and the issuer — looping-gateway — is
13
+ * not an agent and must not import this package. They live in a zero-dependency
14
+ * leaf both sides depend on, and are re-exported here so an agent's imports are
15
+ * unchanged: `IDENTITY_CLAIM`, `TENANT_CLAIM`, `A2A_RPC_PATH` and
16
+ * `GatewayIdentity` still come from `@loopingai/core/a2a`.
17
+ *
18
+ * The pure helpers are re-exported too, because an agent that builds a URL by
19
+ * hand is an agent that can disagree with the gateway about it.
8
20
  */
21
+ export { A2A_JWS_ALG, audienceFor, endpointUrl, jwksUrl } from "@loopingai/a2a-protocol";
9
22
  export { IDENTITY_CLAIM, TENANT_CLAIM, GatewayAuthError, bearerToken, normalizeGatewayOrigins, verifyGatewayToken, type GatewayIdentity, type VerifyOptions } from "./verify.js";
10
23
  export { A2A_RPC_PATH, buildBaseCard, signCard, wireCard, parsePrivateJwk, publicCardJwks, type AgentManifest, type BuildCardOptions, type CardSigningConfig, type WireAgentCard } from "./card.js";
11
24
  export { NOTIFICATION_TOKEN_HEADER, buildSubmittedTask, buildWorkingTask, buildCompletedTask, buildFailedTask, buildNoReplyCompletedTask, signCallbackJwt, postNotification } from "./notify.js";
25
+ export { callerContext } from "./caller.js";
26
+ export { createPushChannel, type PushChannel, type TurnPushContext } from "./push.js";
12
27
  export { taskStateLabel, type PlainArtifact, type PlainMessage, type PlainPart, type PlainStatus, type PlainTask } from "./task.js";
13
28
  export { textPart, partsText, textOf, agentTextMessage, inboundText, InboundPartError, MAX_INBOUND_TEXT_BYTES } from "./parts.js";
14
29
  export { buildCallContext, extensionHeaders } from "./context.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/a2a/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,aAAa,EACd,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/a2a/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,OAAO,EACR,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,aAAa,EACd,MAAM,iBAAiB,CAAC"}
package/dist/a2a/index.js CHANGED
@@ -5,10 +5,25 @@
5
5
  * JWKS, prove ourselves with ours), the accept-and-notify task lifecycle, and the
6
6
  * narrowed task types that survive Durable Object RPC. Nothing here knows what an
7
7
  * agent *does* — past {@link A2AExecutor} everything is plain strings.
8
+ *
9
+ * ## The wire values come from `@loopingai/a2a-protocol`
10
+ *
11
+ * Claim names, the algorithm, the well-known paths and the audience rule are a
12
+ * two-sided contract with a token issuer, and the issuer — looping-gateway — is
13
+ * not an agent and must not import this package. They live in a zero-dependency
14
+ * leaf both sides depend on, and are re-exported here so an agent's imports are
15
+ * unchanged: `IDENTITY_CLAIM`, `TENANT_CLAIM`, `A2A_RPC_PATH` and
16
+ * `GatewayIdentity` still come from `@loopingai/core/a2a`.
17
+ *
18
+ * The pure helpers are re-exported too, because an agent that builds a URL by
19
+ * hand is an agent that can disagree with the gateway about it.
8
20
  */
21
+ export { A2A_JWS_ALG, audienceFor, endpointUrl, jwksUrl } from "@loopingai/a2a-protocol";
9
22
  export { IDENTITY_CLAIM, TENANT_CLAIM, GatewayAuthError, bearerToken, normalizeGatewayOrigins, verifyGatewayToken } from "./verify.js";
10
23
  export { A2A_RPC_PATH, buildBaseCard, signCard, wireCard, parsePrivateJwk, publicCardJwks } from "./card.js";
11
24
  export { NOTIFICATION_TOKEN_HEADER, buildSubmittedTask, buildWorkingTask, buildCompletedTask, buildFailedTask, buildNoReplyCompletedTask, signCallbackJwt, postNotification } from "./notify.js";
25
+ export { callerContext } from "./caller.js";
26
+ export { createPushChannel } from "./push.js";
12
27
  export { taskStateLabel } from "./task.js";
13
28
  export { textPart, partsText, textOf, agentTextMessage, inboundText, InboundPartError, MAX_INBOUND_TEXT_BYTES } from "./parts.js";
14
29
  export { buildCallContext, extensionHeaders } from "./context.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/a2a/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,kBAAkB,EAGnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EAKf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,cAAc,EAMf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EAIpB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/a2a/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,OAAO,EACR,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,kBAAkB,EAGnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,cAAc,EAKf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,iBAAiB,EAGlB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EAMf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EAIpB,MAAM,eAAe,CAAC"}
@@ -2,12 +2,34 @@ import { type JWK } from "jose";
2
2
  import { type Task } from "@a2a-js/sdk";
3
3
  import type { PlainTask } from "./task.js";
4
4
  /**
5
- * Header carrying the per-task validation `token` the gateway set in the
6
- * `taskPushNotificationConfig`. Echoed verbatim so the gateway can correlate the
7
- * callback to its pending task row. Must match looping-gateway's
8
- * `NOTIFICATION_TOKEN_HEADER` (`src/a2a/notifications/remote.ts`).
5
+ * Outbound push-notification (accept + notify) helpers the "notify" half of the
6
+ * async A2A contract. The gateway dispatches `SendMessage` with a
7
+ * `taskPushNotificationConfig` (webhook `url` + validation `token`), we accept
8
+ * immediately with a `submitted` Task, and later POST the terminal Task back to
9
+ * that webhook. This module builds the Task shapes and signs + sends that
10
+ * callback.
11
+ *
12
+ * The callback is authenticated exactly like the AgentCard: a short-lived EdDSA
13
+ * JWT signed by `A2A_SIGNING_KEY`, whose protected header `kid`+`jku` must equal
14
+ * the card's signing `kid`+`jku` (see {@link file://./card.ts} `signCard`) — the
15
+ * gateway pinned those at registration (Trust-On-First-Use) and verifies the
16
+ * callback token against that same public JWKS. No shared secret crosses the
17
+ * boundary; only our public key is ever used to verify.
18
+ */
19
+ /**
20
+ * The two shared values on this hop — the signature algorithm and the header
21
+ * carrying the per-task validation `token` — come from
22
+ * `@loopingai/a2a-protocol`, the same package the gateway reads them from.
23
+ *
24
+ * The header used to be declared here and again in looping-gateway, each with a
25
+ * comment naming the other file. It is a slightly different case from the claim
26
+ * names: the value is `@a2a-js/sdk`'s own default for `tokenHeaderName`, not
27
+ * Looping's choice, but the SDK never *exports* it — it exists only as an
28
+ * inline fallback — so neither side could import it and both wrote it down.
29
+ *
30
+ * Re-exported so `@loopingai/core/a2a` keeps being where an agent finds it.
9
31
  */
10
- export declare const NOTIFICATION_TOKEN_HEADER = "x-a2a-notification-token";
32
+ export { NOTIFICATION_TOKEN_HEADER } from "@loopingai/a2a-protocol";
11
33
  /**
12
34
  * The `submitted` Task we return synchronously to accept a turn (A2A §7.2). The
13
35
  * gateway only requires a non-empty `id`; the actual reply follows later via the
@@ -1 +1 @@
1
- {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/a2a/notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,EAAa,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAqB3C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,6BAA6B,CAAC;AAqCpE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,SAAS,CAEX;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,SAAS,CAEX;AAwBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,SAAS,CAQX;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,SAAS,CAQX;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,SAAS,CAQX;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EACjC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,QAAQ,CAAC,CAanB"}
1
+ {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/a2a/notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,EAAa,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAOnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAqCpE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,SAAS,CAEX;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,SAAS,CAEX;AAwBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,SAAS,CAQX;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,SAAS,CAQX;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,SAAS,CAQX;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EACjC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,QAAQ,CAAC,CAanB"}
@@ -1,6 +1,7 @@
1
1
  import { SignJWT } from "jose";
2
2
  import { TaskState } from "@a2a-js/sdk";
3
3
  import { V1PushNotificationSerializer } from "@a2a-js/sdk/server";
4
+ import { A2A_JWS_ALG, NOTIFICATION_TOKEN_HEADER } from "@loopingai/a2a-protocol";
4
5
  import { agentTextMessage } from "./parts.js";
5
6
  /**
6
7
  * Outbound push-notification (accept + notify) helpers — the "notify" half of the
@@ -17,15 +18,20 @@ import { agentTextMessage } from "./parts.js";
17
18
  * callback token against that same public JWKS. No shared secret crosses the
18
19
  * boundary; only our public key is ever used to verify.
19
20
  */
20
- /** JWS algorithm — must match the card + gateway (`EdDSA`). */
21
- const ALG = "EdDSA";
22
21
  /**
23
- * Header carrying the per-task validation `token` the gateway set in the
24
- * `taskPushNotificationConfig`. Echoed verbatim so the gateway can correlate the
25
- * callback to its pending task row. Must match looping-gateway's
26
- * `NOTIFICATION_TOKEN_HEADER` (`src/a2a/notifications/remote.ts`).
22
+ * The two shared values on this hop — the signature algorithm and the header
23
+ * carrying the per-task validation `token` come from
24
+ * `@loopingai/a2a-protocol`, the same package the gateway reads them from.
25
+ *
26
+ * The header used to be declared here and again in looping-gateway, each with a
27
+ * comment naming the other file. It is a slightly different case from the claim
28
+ * names: the value is `@a2a-js/sdk`'s own default for `tokenHeaderName`, not
29
+ * Looping's choice, but the SDK never *exports* it — it exists only as an
30
+ * inline fallback — so neither side could import it and both wrote it down.
31
+ *
32
+ * Re-exported so `@loopingai/core/a2a` keeps being where an agent finds it.
27
33
  */
28
- export const NOTIFICATION_TOKEN_HEADER = "x-a2a-notification-token";
34
+ export { NOTIFICATION_TOKEN_HEADER } from "@loopingai/a2a-protocol";
29
35
  /**
30
36
  * Callback-JWT lifetime. The gateway enforces `maxTokenAge: 10m` with a 60s clock
31
37
  * tolerance, so keep this comfortably under that.
@@ -142,7 +148,11 @@ export function buildFailedTask(taskId, contextId, text) {
142
148
  */
143
149
  export async function signCallbackJwt(privateJwk, opts) {
144
150
  return new SignJWT({})
145
- .setProtectedHeader({ alg: ALG, kid: privateJwk.kid, jku: opts.jku })
151
+ .setProtectedHeader({
152
+ alg: A2A_JWS_ALG,
153
+ kid: privateJwk.kid,
154
+ jku: opts.jku
155
+ })
146
156
  .setAudience(opts.aud)
147
157
  .setIssuedAt()
148
158
  .setExpirationTime(CALLBACK_TOKEN_TTL)
@@ -1 +1 @@
1
- {"version":3,"file":"notify.js","sourceRoot":"","sources":["../../src/a2a/notify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"notify.js","sourceRoot":"","sources":["../../src/a2a/notify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { Task } from "@a2a-js/sdk";
2
+ import type { OnContent } from "../agent/inference.js";
3
+ /**
4
+ * The gateway callback channel for one accepted turn.
5
+ *
6
+ * Every agent that accepts asynchronously has to do the same four things with
7
+ * the push config the gateway handed it: sign a callback JWT against the
8
+ * deployment's card key, POST `working` snapshots as the model reasons, POST the
9
+ * terminal Task, and never let a failed progress post take down a turn. That was
10
+ * written out longhand in four places across two agents in the starter — twice as
11
+ * a `streamWorking` closure inside a Durable Object, twice as a `notify` step
12
+ * inside a Workflow — with the signing, the header names and the swallow-and-log
13
+ * discipline duplicated each time.
14
+ *
15
+ * It is one object here because none of it is per-agent. What *is* per-agent is
16
+ * the notification **key**, and that is the one thing a caller supplies.
17
+ */
18
+ /**
19
+ * Everything needed to call a gateway back about one task.
20
+ *
21
+ * RPC-serializable by construction: it crosses the Workflow → Durable Object
22
+ * boundary on every turn, so it holds only strings.
23
+ */
24
+ export interface TurnPushContext {
25
+ /** The accepted task id (echoed on every callback of this turn). */
26
+ taskId: string;
27
+ /** A2A context id, echoed on every callback. */
28
+ contextId: string;
29
+ /** Gateway push-notification webhook (also the callback JWT `aud`). */
30
+ pushUrl: string;
31
+ /** Per-task validation token the gateway set; echoed in the callback header. */
32
+ pushToken: string;
33
+ /** This agent's card-signing JWKS URL — the callback JWT `jku` (pinned key). */
34
+ jku: string;
35
+ }
36
+ export interface PushChannel {
37
+ /**
38
+ * POST one `working` Task snapshot, keyed by a stable semantic `key`.
39
+ *
40
+ * **Best-effort**: every failure is logged and swallowed, so a progress post
41
+ * can never abort generation or fail a durable step. The key is what lets the
42
+ * gateway dedupe a re-posted event on replay, so it must be derived from
43
+ * position (`r2:step:3`), never from content or a clock.
44
+ */
45
+ working(text: string, key: string): Promise<void>;
46
+ /**
47
+ * An {@link OnContent} sink that posts each intermediate message as a
48
+ * `working` snapshot, signing the JWT once and reusing it across the turn.
49
+ *
50
+ * `key` maps a 0-based step ordinal to its notification key. An agent running
51
+ * one turn per task can use the bare index; an agent with rounds **must**
52
+ * include the round, or two rounds of one task collide on the gateway.
53
+ */
54
+ stream(key: (stepIndex: number) => string): OnContent;
55
+ /**
56
+ * POST the terminal Task. **Throws on a non-2xx** so the calling Workflow step
57
+ * retries — the opposite of {@link working}, because this is the delivery the
58
+ * whole turn exists for.
59
+ */
60
+ deliver(task: Task): Promise<void>;
61
+ }
62
+ /**
63
+ * Build the callback channel for one turn.
64
+ *
65
+ * `signingKey` is the deployment's Ed25519 private JWK as JSON — `A2A_SIGNING_KEY`
66
+ * by default. There is one per origin, not one per agent: the card sits at a
67
+ * well-known URI, which RFC 8615 defines per-authority, so this origin publishes
68
+ * one card and the gateway pins one key for every agent on it.
69
+ */
70
+ export declare function createPushChannel(signingKey: string, push: TurnPushContext): PushChannel;
71
+ //# sourceMappingURL=push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/a2a/push.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAQvD;;;;;;;;;;;;;;GAcG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD;;;;;;;OAOG;IACH,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACtD;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,eAAe,GACpB,WAAW,CAkDb"}
@@ -0,0 +1,54 @@
1
+ import { parsePrivateJwk } from "./card.js";
2
+ import { buildWorkingTask, postNotification, signCallbackJwt } from "./notify.js";
3
+ /**
4
+ * Build the callback channel for one turn.
5
+ *
6
+ * `signingKey` is the deployment's Ed25519 private JWK as JSON — `A2A_SIGNING_KEY`
7
+ * by default. There is one per origin, not one per agent: the card sits at a
8
+ * well-known URI, which RFC 8615 defines per-authority, so this origin publishes
9
+ * one card and the gateway pins one key for every agent on it.
10
+ */
11
+ export function createPushChannel(signingKey, push) {
12
+ // Signed lazily and reused: one turn can post many progress snapshots, and
13
+ // re-signing per message costs a key import each time for no benefit.
14
+ let jwt;
15
+ const sign = () => (jwt ??= signCallbackJwt(parsePrivateJwk(signingKey), {
16
+ jku: push.jku,
17
+ aud: push.pushUrl
18
+ }));
19
+ const post = async (task) => postNotification(push.pushUrl, push.pushToken, await sign(), task);
20
+ const working = async (text, key) => {
21
+ try {
22
+ const res = await post(buildWorkingTask(push.taskId, push.contextId, text, key));
23
+ if (!res.ok) {
24
+ console.warn("[push] working notification non-2xx", {
25
+ taskId: push.taskId,
26
+ key,
27
+ status: res.status
28
+ });
29
+ }
30
+ }
31
+ catch (err) {
32
+ // Swallowed on purpose, including a signing failure: a turn that cannot
33
+ // report its progress is still a turn that should deliver its answer.
34
+ console.warn("[push] working notification failed", {
35
+ taskId: push.taskId,
36
+ key,
37
+ err: String(err)
38
+ });
39
+ }
40
+ };
41
+ return {
42
+ working,
43
+ stream(key) {
44
+ return (text, stepIndex) => working(text, key(stepIndex));
45
+ },
46
+ async deliver(task) {
47
+ const res = await post(task);
48
+ if (!res.ok) {
49
+ throw new Error(`gateway notification failed: HTTP ${res.status}`);
50
+ }
51
+ }
52
+ };
53
+ }
54
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/a2a/push.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAgErB;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,IAAqB;IAErB,2EAA2E;IAC3E,sEAAsE;IACtE,IAAI,GAAgC,CAAC;IACrC,MAAM,IAAI,GAAG,GAAoB,EAAE,CACjC,CAAC,GAAG,KAAK,eAAe,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE;QACpD,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,GAAG,EAAE,IAAI,CAAC,OAAO;KAClB,CAAC,CAAC,CAAC;IAEN,MAAM,IAAI,GAAG,KAAK,EAAE,IAAU,EAAqB,EAAE,CACnD,gBAAgB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAErE,MAAM,OAAO,GAAG,KAAK,EAAE,IAAY,EAAE,GAAW,EAAiB,EAAE;QACjE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CACpB,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,CACzD,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE;oBAClD,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,GAAG;oBACH,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,wEAAwE;YACxE,sEAAsE;YACtE,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBACjD,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG;gBACH,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;aACjB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,OAAO;QAEP,MAAM,CAAC,GAAG;YACR,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QAC5D,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}