@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.
- package/README.md +83 -28
- package/dist/a2a/caller.d.ts +24 -0
- package/dist/a2a/caller.d.ts.map +1 -0
- package/dist/a2a/caller.js +34 -0
- package/dist/a2a/caller.js.map +1 -0
- package/dist/a2a/card.d.ts +7 -2
- package/dist/a2a/card.d.ts.map +1 -1
- package/dist/a2a/card.js +16 -7
- package/dist/a2a/card.js.map +1 -1
- package/dist/a2a/index.d.ts +15 -0
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +15 -0
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/notify.d.ts +27 -5
- package/dist/a2a/notify.d.ts.map +1 -1
- package/dist/a2a/notify.js +18 -8
- package/dist/a2a/notify.js.map +1 -1
- package/dist/a2a/push.d.ts +71 -0
- package/dist/a2a/push.d.ts.map +1 -0
- package/dist/a2a/push.js +54 -0
- package/dist/a2a/push.js.map +1 -0
- package/dist/a2a/verify.d.ts +28 -36
- package/dist/a2a/verify.d.ts.map +1 -1
- package/dist/a2a/verify.js +20 -25
- package/dist/a2a/verify.js.map +1 -1
- package/dist/agent/index.d.ts +16 -5
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +16 -5
- package/dist/agent/index.js.map +1 -1
- package/dist/config.d.ts +49 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -3
- package/dist/config.js.map +1 -1
- package/dist/db/models/tasks.d.ts +19 -5
- package/dist/db/models/tasks.d.ts.map +1 -1
- package/dist/db/models/tasks.js +38 -8
- package/dist/db/models/tasks.js.map +1 -1
- package/dist/host/agent.d.ts +217 -0
- package/dist/host/agent.d.ts.map +1 -0
- package/dist/host/agent.js +306 -0
- package/dist/host/agent.js.map +1 -0
- package/dist/host/index.d.ts +21 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +20 -0
- package/dist/host/index.js.map +1 -0
- package/dist/host/plugin-host.d.ts +47 -0
- package/dist/host/plugin-host.d.ts.map +1 -0
- package/dist/host/plugin-host.js +2 -0
- package/dist/host/plugin-host.js.map +1 -0
- package/dist/round/agent.d.ts +267 -0
- package/dist/round/agent.d.ts.map +1 -0
- package/dist/round/agent.js +691 -0
- package/dist/round/agent.js.map +1 -0
- package/dist/round/index.d.ts +25 -0
- package/dist/round/index.d.ts.map +1 -0
- package/dist/round/index.js +24 -0
- package/dist/round/index.js.map +1 -0
- package/dist/round/policy.d.ts +99 -0
- package/dist/round/policy.d.ts.map +1 -0
- package/dist/round/policy.js +2 -0
- package/dist/round/policy.js.map +1 -0
- package/dist/round/subagent.d.ts +67 -0
- package/dist/round/subagent.d.ts.map +1 -0
- package/dist/round/subagent.js +91 -0
- package/dist/round/subagent.js.map +1 -0
- package/dist/round/turn.d.ts +231 -0
- package/dist/round/turn.d.ts.map +1 -0
- package/dist/round/turn.js +497 -0
- package/dist/round/turn.js.map +1 -0
- package/dist/round/workflow.d.ts +109 -0
- package/dist/round/workflow.d.ts.map +1 -0
- package/dist/round/workflow.js +316 -0
- package/dist/round/workflow.js.map +1 -0
- package/dist/runtime/index.d.ts +5 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/testing/auth.d.ts.map +1 -1
- package/dist/testing/auth.js +10 -7
- package/dist/testing/auth.js.map +1 -1
- package/dist/testing/fixtures.d.ts +17 -0
- package/dist/testing/fixtures.d.ts.map +1 -1
- package/dist/testing/fixtures.js +17 -0
- package/dist/testing/fixtures.js.map +1 -1
- package/dist/testing/harness.d.ts +98 -0
- package/dist/testing/harness.d.ts.map +1 -0
- package/dist/testing/harness.js +139 -0
- package/dist/testing/harness.js.map +1 -0
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/worker/define-agent.d.ts +124 -0
- package/dist/worker/define-agent.d.ts.map +1 -0
- package/dist/worker/define-agent.js +21 -0
- package/dist/worker/define-agent.js.map +1 -0
- package/dist/worker/index.d.ts +29 -4
- package/dist/worker/index.d.ts.map +1 -1
- package/dist/worker/index.js +70 -12
- package/dist/worker/index.js.map +1 -1
- package/package.json +12 -3
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { A2A_PROTOCOL_VERSION } from "@a2a-js/sdk";
|
|
2
|
+
import { A2A_RPC_PATH, NOTIFICATION_TOKEN_HEADER, endpointUrl, jwksUrl } from "@loopingai/a2a-protocol";
|
|
3
|
+
import { makeGatewayToken, TEST_TENANT } from "./auth.js";
|
|
4
|
+
import { AGENT_ORIGIN, GATEWAY_ORIGIN, gatewayPublicJwks } from "./fixtures.js";
|
|
5
|
+
/**
|
|
6
|
+
* Project the push envelope onto the three fields a spec usually asserts.
|
|
7
|
+
*
|
|
8
|
+
* Reads `status.message.parts` — the key the wire form actually uses. It read
|
|
9
|
+
* `content` until `harness.spec.ts` drove a real callback through it, which
|
|
10
|
+
* made `text` the empty string on every capture: silently, since a harness
|
|
11
|
+
* reporting `""` for what an agent said looks exactly like an agent that said
|
|
12
|
+
* nothing, and the no-reply completion is a legitimate outcome.
|
|
13
|
+
*/
|
|
14
|
+
function projectCallback(body, token) {
|
|
15
|
+
const task = body.task ?? body;
|
|
16
|
+
const t = task;
|
|
17
|
+
const parts = t.status?.message?.parts ?? [];
|
|
18
|
+
return {
|
|
19
|
+
taskId: t.id ?? "",
|
|
20
|
+
state: t.status?.state ?? "",
|
|
21
|
+
text: parts
|
|
22
|
+
.map((p) => p.text ?? "")
|
|
23
|
+
.join("")
|
|
24
|
+
.trim(),
|
|
25
|
+
token,
|
|
26
|
+
body
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function createAgentHarness(options) {
|
|
30
|
+
const origin = options.origin ?? AGENT_ORIGIN;
|
|
31
|
+
const rpcPath = options.rpcPath ?? A2A_RPC_PATH;
|
|
32
|
+
// The audience a gateway actually mints: the endpoint this deployment serves,
|
|
33
|
+
// which is also exactly what its card advertises as its interface. Composed
|
|
34
|
+
// with the protocol package's own helper, so a harness cannot agree with the
|
|
35
|
+
// verifier while disagreeing with what a real gateway would send.
|
|
36
|
+
const endpoint = endpointUrl(origin, rpcPath);
|
|
37
|
+
const tenant = options.tenant ?? TEST_TENANT;
|
|
38
|
+
const pushUrl = `${GATEWAY_ORIGIN}/a2a/push`;
|
|
39
|
+
const pushToken = "harness-push-token";
|
|
40
|
+
const callbacks = [];
|
|
41
|
+
const token = (overrides = {}) => makeGatewayToken({
|
|
42
|
+
audience: endpoint,
|
|
43
|
+
tenant: overrides.tenant ?? tenant
|
|
44
|
+
});
|
|
45
|
+
const rpc = async (body, init = {}) => options.worker.fetch(new Request(endpoint, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"content-type": "application/json",
|
|
49
|
+
"A2A-Version": A2A_PROTOCOL_VERSION,
|
|
50
|
+
authorization: `Bearer ${init.token ?? (await token())}`
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify(body)
|
|
53
|
+
}), options.env);
|
|
54
|
+
return {
|
|
55
|
+
endpoint,
|
|
56
|
+
pushUrl,
|
|
57
|
+
callbacks,
|
|
58
|
+
token,
|
|
59
|
+
rpc,
|
|
60
|
+
async send(text, sendOptions = {}) {
|
|
61
|
+
const messageId = crypto.randomUUID();
|
|
62
|
+
const res = await rpc({
|
|
63
|
+
jsonrpc: "2.0",
|
|
64
|
+
id: 1,
|
|
65
|
+
method: "SendMessage",
|
|
66
|
+
// `SendMessageRequest` is **flat**: `tenant`, `message`, `configuration`,
|
|
67
|
+
// `metadata`. There is no `request` wrapper, and wrapping is silent when
|
|
68
|
+
// you do it — `fromJSON` drops unknown keys rather than rejecting them,
|
|
69
|
+
// so the whole turn decodes to an empty message with no push config and
|
|
70
|
+
// the agent refuses it for "missing" fields the caller did send.
|
|
71
|
+
//
|
|
72
|
+
// This harness shipped with exactly that envelope. Nothing caught it,
|
|
73
|
+
// because nothing in this package drove the harness against a real
|
|
74
|
+
// Worker until `harness.spec.ts` — which is the argument for that spec
|
|
75
|
+
// existing, made by the code it tests.
|
|
76
|
+
params: {
|
|
77
|
+
tenant,
|
|
78
|
+
message: {
|
|
79
|
+
messageId,
|
|
80
|
+
role: "ROLE_USER",
|
|
81
|
+
// `parts`, not `content`. The decoded `Message` exposes `parts`, and
|
|
82
|
+
// `fromJSON` silently yields an empty list for anything else — so a
|
|
83
|
+
// turn sent under the wrong key arrives as a message with no text
|
|
84
|
+
// and the agent answers a blank prompt.
|
|
85
|
+
parts: [{ text }],
|
|
86
|
+
...(sendOptions.taskId ? { taskId: sendOptions.taskId } : {})
|
|
87
|
+
},
|
|
88
|
+
configuration: {
|
|
89
|
+
// Required by the accept-and-notify contract: an agent that replies
|
|
90
|
+
// out of band and is given nowhere to call back has accepted a turn
|
|
91
|
+
// it can never answer.
|
|
92
|
+
taskPushNotificationConfig: { url: pushUrl, token: pushToken }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const envelope = await res.json();
|
|
97
|
+
if (envelope.error) {
|
|
98
|
+
throw new Error(`SendMessage was refused (${envelope.error.code}): ${envelope.error.message}`);
|
|
99
|
+
}
|
|
100
|
+
const result = envelope.result;
|
|
101
|
+
const task = (result?.task ?? result);
|
|
102
|
+
if (!task) {
|
|
103
|
+
throw new Error(`SendMessage returned no task: ${JSON.stringify(envelope)}`);
|
|
104
|
+
}
|
|
105
|
+
return task;
|
|
106
|
+
},
|
|
107
|
+
interceptGateway() {
|
|
108
|
+
const original = globalThis.fetch;
|
|
109
|
+
globalThis.fetch = (async (input, init) => {
|
|
110
|
+
const url = typeof input === "string" ? input : String(input);
|
|
111
|
+
// The gateway's public JWKS — without it every token fails to verify and
|
|
112
|
+
// every spec below it reports a 401 that has nothing to do with its subject.
|
|
113
|
+
if (url === jwksUrl(GATEWAY_ORIGIN)) {
|
|
114
|
+
return new Response(gatewayPublicJwks(), {
|
|
115
|
+
headers: { "content-type": "application/json" }
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (url === pushUrl) {
|
|
119
|
+
const request = new Request(input, init);
|
|
120
|
+
const body = await request.json().catch(() => null);
|
|
121
|
+
callbacks.push(projectCallback(body, request.headers.get(NOTIFICATION_TOKEN_HEADER)));
|
|
122
|
+
return new Response(null, { status: 202 });
|
|
123
|
+
}
|
|
124
|
+
// Anything else is a call this harness did not expect. 404 rather than
|
|
125
|
+
// pass through: a spec that silently reaches the real network is a spec
|
|
126
|
+
// that passes for the wrong reason.
|
|
127
|
+
return new Response(`unexpected outbound fetch: ${url}`, {
|
|
128
|
+
status: 404
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
[Symbol.dispose]() {
|
|
133
|
+
globalThis.fetch = original;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=harness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/testing/harness.ts"],"names":[],"mappings":"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"}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export { VCR_CONTROL_ORIGIN, VCR_MARKER_HEADER, CASSETTE_NAME_RE, type VcrReleas
|
|
|
26
26
|
export { FakeSession } from "./fake-session.js";
|
|
27
27
|
export { mockModel, finalReply, type MockStep } from "./mock-model.js";
|
|
28
28
|
export { makeGatewayToken, type GatewayTokenOptions } from "./auth.js";
|
|
29
|
-
export { AGENT_ORIGIN, GATEWAY_ORIGIN, TEST_AGENT_PRIVATE_JWK, TEST_GATEWAY_PRIVATE_JWK, gatewayPublicJwks, testAgentMessage, testStatus, testTask } from "./fixtures.js";
|
|
29
|
+
export { AGENT_ORIGIN, GATEWAY_ORIGIN, TEST_AGENT_PRIVATE_JWK, TEST_GATEWAY_PRIVATE_JWK, TEST_MODELS, gatewayPublicJwks, testAgentMessage, testStatus, testTask } from "./fixtures.js";
|
|
30
30
|
export { doStorage, makeDoHelpers, type DoTestHelpers } from "./do.js";
|
|
31
|
+
export { createAgentHarness, type AgentHarness, type AgentHarnessOptions, type CapturedCallback, type HarnessWorker } from "./harness.js";
|
|
31
32
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvE,OAAO,EACL,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC"}
|
package/dist/testing/index.js
CHANGED
|
@@ -26,6 +26,7 @@ export { VCR_CONTROL_ORIGIN, VCR_MARKER_HEADER, CASSETTE_NAME_RE } from "./vcr-s
|
|
|
26
26
|
export { FakeSession } from "./fake-session.js";
|
|
27
27
|
export { mockModel, finalReply } from "./mock-model.js";
|
|
28
28
|
export { makeGatewayToken } from "./auth.js";
|
|
29
|
-
export { AGENT_ORIGIN, GATEWAY_ORIGIN, TEST_AGENT_PRIVATE_JWK, TEST_GATEWAY_PRIVATE_JWK, gatewayPublicJwks, testAgentMessage, testStatus, testTask } from "./fixtures.js";
|
|
29
|
+
export { AGENT_ORIGIN, GATEWAY_ORIGIN, TEST_AGENT_PRIVATE_JWK, TEST_GATEWAY_PRIVATE_JWK, TEST_MODELS, gatewayPublicJwks, testAgentMessage, testStatus, testTask } from "./fixtures.js";
|
|
30
30
|
export { doStorage, makeDoHelpers } from "./do.js";
|
|
31
|
+
export { createAgentHarness } from "./harness.js";
|
|
31
32
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,cAAc,EACd,eAAe,EAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAA4B,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAsB,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,cAAc,EACd,eAAe,EAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAA4B,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAsB,MAAM,SAAS,CAAC;AAEvE,OAAO,EACL,kBAAkB,EAKnB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { AgentManifest } from "../a2a/card.js";
|
|
2
|
+
import type { GatewayIdentity } from "../a2a/verify.js";
|
|
3
|
+
import type { TaskAgent } from "../a2a/agent-stub.js";
|
|
4
|
+
import { type AcceptedTurn } from "../a2a/executor.js";
|
|
5
|
+
/**
|
|
6
|
+
* One agent's wiring, declared once.
|
|
7
|
+
*
|
|
8
|
+
* ## What this replaces
|
|
9
|
+
*
|
|
10
|
+
* Mounting an agent used to mean writing the same four things by hand and keeping
|
|
11
|
+
* them in agreement: a `getAgent(identity)` that guards `identity.key` and reads a
|
|
12
|
+
* Durable Object binding, a `startTurn` that derives an idempotent workflow id and
|
|
13
|
+
* swallows the already-exists race, an entry in the `tenants` map, and — in the
|
|
14
|
+
* agent's own Workflow entrypoint — a second reference to the same DO binding.
|
|
15
|
+
*
|
|
16
|
+
* Four copies of one fact, and only the first two were even adjacent. The wiring
|
|
17
|
+
* also type-checked when it was **wrong**: naming a sibling's workflow binding on
|
|
18
|
+
* a tenant compiles perfectly and fails at runtime, after auth, after the turn was
|
|
19
|
+
* accepted, as a task that simply never calls back.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* export const reactive = defineAgent({
|
|
23
|
+
* tenant: "reactive",
|
|
24
|
+
* manifest,
|
|
25
|
+
* agent: (env: Env) => env.ReactiveAgent,
|
|
26
|
+
* workflow: (env: Env) => env.HANDLE_TASK_WORKFLOW
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // the Worker entry
|
|
30
|
+
* export default {
|
|
31
|
+
* fetch: createA2AWorker<Env>({ manifest: hostManifest, agents: [reactive] })
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* // the agent's Workflow entrypoint
|
|
35
|
+
* await runHandleTask(event.payload, step, {
|
|
36
|
+
* resolveAgent: (identity) => reactive.resolveAgent(this.env, identity),
|
|
37
|
+
* …
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* ## Why accessors rather than binding names
|
|
42
|
+
*
|
|
43
|
+
* `agent` and `workflow` are functions of `env`, not strings. A string would have
|
|
44
|
+
* to be checked against `keyof Env` and then widened back to a namespace, which
|
|
45
|
+
* loses the Durable Object's own class — so the Workflow could not see the very
|
|
46
|
+
* methods it exists to drive. An accessor infers both: the tenant is mounted and
|
|
47
|
+
* the Workflow is driven from one declaration, `env.RactiveAgent` is a compile
|
|
48
|
+
* error, and `resolveAgent` comes back typed as the agent itself.
|
|
49
|
+
*
|
|
50
|
+
* `env` stays a parameter throughout, for the reason `src/env.ts` gives: core
|
|
51
|
+
* never reaches for a consumer's ambient bindings, and on Workers `env` does not
|
|
52
|
+
* exist at module scope anyway.
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* What `createA2AWorker` needs in order to mount an agent. The Durable Object's
|
|
56
|
+
* own class is irrelevant to routing, so this shape forgets it —
|
|
57
|
+
* {@link AgentDefinition} keeps it for the agent's Workflow.
|
|
58
|
+
*/
|
|
59
|
+
export interface MountedAgent<TEnv> {
|
|
60
|
+
/** The tenant id a caller addresses this agent with. */
|
|
61
|
+
tenant: string;
|
|
62
|
+
/** The transport-independent half of this agent's card. */
|
|
63
|
+
manifest: AgentManifest;
|
|
64
|
+
resolveAgent(env: TEnv, identity: GatewayIdentity): TaskAgent;
|
|
65
|
+
startTurn(env: TEnv, turn: AcceptedTurn): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* {@link AgentDefinition} deliberately does **not** declare `extends
|
|
69
|
+
* MountedAgent`, even though every one satisfies it.
|
|
70
|
+
*
|
|
71
|
+
* A generic `DurableObjectStub<TAgent>` cannot be proven assignable to
|
|
72
|
+
* {@link TaskAgent} while `TAgent` is unresolved: the RPC stub type widens an
|
|
73
|
+
* *optional* method (`listTasks?`) to `Promise<undefined> | (…) => …`, and
|
|
74
|
+
* forcing the comparison also trips TypeScript's instantiation-depth limit — the
|
|
75
|
+
* same wall that made `PlainTask` necessary. At a concrete call site, where
|
|
76
|
+
* `TAgent` is a real agent class, the assignment resolves normally. So the check
|
|
77
|
+
* happens where it can actually succeed: passing `agents: [reactive]` to
|
|
78
|
+
* `createA2AWorker`.
|
|
79
|
+
*/
|
|
80
|
+
export interface DefineAgentOptions<TEnv, TAgent extends Rpc.DurableObjectBranded> {
|
|
81
|
+
/**
|
|
82
|
+
* The tenant id a caller addresses this agent with, and what a gateway
|
|
83
|
+
* registers against. Renaming one is a re-registration, not a refactor.
|
|
84
|
+
*/
|
|
85
|
+
tenant: string;
|
|
86
|
+
/** The transport-independent half of this agent's card. */
|
|
87
|
+
manifest: AgentManifest;
|
|
88
|
+
/**
|
|
89
|
+
* This agent's Durable Object namespace. One instance per verified caller —
|
|
90
|
+
* the tenant picks the agent, `identity.key` picks which instance of it.
|
|
91
|
+
*/
|
|
92
|
+
agent: (env: TEnv) => DurableObjectNamespace<TAgent>;
|
|
93
|
+
/** The Workflow this agent's turns run on. */
|
|
94
|
+
workflow: (env: TEnv) => Workflow<AcceptedTurn>;
|
|
95
|
+
}
|
|
96
|
+
export interface AgentDefinition<TEnv, TAgent extends Rpc.DurableObjectBranded> {
|
|
97
|
+
/** The tenant id a caller addresses this agent with. */
|
|
98
|
+
tenant: string;
|
|
99
|
+
/** The transport-independent half of this agent's card. */
|
|
100
|
+
manifest: AgentManifest;
|
|
101
|
+
/**
|
|
102
|
+
* Resolve the per-caller agent DO stub, keyed by the verified `identity.key`.
|
|
103
|
+
*
|
|
104
|
+
* Typed as the agent's **own** class, so the Workflow that drives its round
|
|
105
|
+
* methods reaches them through the same declaration the tenant is mounted with
|
|
106
|
+
* — the two cannot address different Durable Objects.
|
|
107
|
+
*
|
|
108
|
+
* Refuses a caller with no key rather than falling back to a shared instance:
|
|
109
|
+
* that key is what makes one caller's tasks unreachable from another's, so a
|
|
110
|
+
* missing one is a routing failure, not a default.
|
|
111
|
+
*/
|
|
112
|
+
resolveAgent(env: TEnv, identity: GatewayIdentity): DurableObjectStub<TAgent>;
|
|
113
|
+
/**
|
|
114
|
+
* Start this agent's durable turn, idempotently.
|
|
115
|
+
*
|
|
116
|
+
* The instance id is derived from the gateway's `messageId`, which is stable
|
|
117
|
+
* across dispatch retries — so a retry finding its instance already running is
|
|
118
|
+
* the idempotency working, not a failure. {@link ignoreAlreadyExists} swallows
|
|
119
|
+
* exactly that race and rethrows everything else.
|
|
120
|
+
*/
|
|
121
|
+
startTurn(env: TEnv, turn: AcceptedTurn): Promise<void>;
|
|
122
|
+
}
|
|
123
|
+
export declare function defineAgent<TEnv, TAgent extends Rpc.DurableObjectBranded>(options: DefineAgentOptions<TEnv, TAgent>): AgentDefinition<TEnv, TAgent>;
|
|
124
|
+
//# sourceMappingURL=define-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-agent.d.ts","sourceRoot":"","sources":["../../src/worker/define-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,IAAI;IAChC,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,GAAG,SAAS,CAAC;IAC9D,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,kBAAkB,CACjC,IAAI,EACJ,MAAM,SAAS,GAAG,CAAC,oBAAoB;IAEvC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,EAAE,aAAa,CAAC;IACxB;;;OAGG;IACH,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACrD,8CAA8C;IAC9C,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,QAAQ,CAAC,YAAY,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,eAAe,CAC9B,IAAI,EACJ,MAAM,SAAS,GAAG,CAAC,oBAAoB;IAEvC,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,EAAE,aAAa,CAAC;IACxB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC9E;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,SAAS,GAAG,CAAC,oBAAoB,EACvE,OAAO,EAAE,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,GACxC,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAsB/B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ignoreAlreadyExists, workflowIdForMessage } from "../a2a/executor.js";
|
|
2
|
+
export function defineAgent(options) {
|
|
3
|
+
return {
|
|
4
|
+
tenant: options.tenant,
|
|
5
|
+
manifest: options.manifest,
|
|
6
|
+
resolveAgent(env, identity) {
|
|
7
|
+
if (!identity.key) {
|
|
8
|
+
throw new Error("identity.key is required to route to the agent DO");
|
|
9
|
+
}
|
|
10
|
+
const ns = options.agent(env);
|
|
11
|
+
return ns.get(ns.idFromName(identity.key));
|
|
12
|
+
},
|
|
13
|
+
startTurn(env, turn) {
|
|
14
|
+
return ignoreAlreadyExists(() => options.workflow(env).create({
|
|
15
|
+
id: workflowIdForMessage(turn.messageId),
|
|
16
|
+
params: { ...turn }
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=define-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-agent.js","sourceRoot":"","sources":["../../src/worker/define-agent.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EAErB,MAAM,oBAAoB,CAAC;AAmI5B,MAAM,UAAU,WAAW,CACzB,OAAyC;IAEzC,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAE1B,YAAY,CAAC,GAAG,EAAE,QAAQ;YACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;YACvE,CAAC;YACD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC9B,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,CAAC;QAED,SAAS,CAAC,GAAG,EAAE,IAAI;YACjB,OAAO,mBAAmB,CAAC,GAAG,EAAE,CAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;gBAC3B,EAAE,EAAE,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC;gBACxC,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE;aACpB,CAAC,CACH,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/worker/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type AgentManifest } from "../a2a/card.js";
|
|
|
2
2
|
import { type TurnStarter } from "../a2a/executor.js";
|
|
3
3
|
import type { AgentResolver } from "../a2a/agent-stub.js";
|
|
4
4
|
import { type A2ASecretsEnv } from "../env.js";
|
|
5
|
+
import type { MountedAgent } from "./define-agent.js";
|
|
5
6
|
/**
|
|
6
7
|
* The A2A Worker: the zero-trust, no-shared-secrets edge every Looping agent
|
|
7
8
|
* puts in front of its Durable Object.
|
|
@@ -53,8 +54,17 @@ import { type A2ASecretsEnv } from "../env.js";
|
|
|
53
54
|
* agent on it*. The second is what makes `tenant` more than an unauthenticated
|
|
54
55
|
* routing hint in the request body.
|
|
55
56
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
export { defineAgent, type AgentDefinition, type DefineAgentOptions, type MountedAgent } from "./define-agent.js";
|
|
58
|
+
/**
|
|
59
|
+
* Default path serving the card-signing public JWKS (the card's `jku`).
|
|
60
|
+
*
|
|
61
|
+
* From `@loopingai/a2a-protocol`, because the gateway serves its own JWKS at
|
|
62
|
+
* the same path and fetches ours from whatever `jku` says — see
|
|
63
|
+
* {@link file://../a2a/verify.ts} for why the two sides share a package rather
|
|
64
|
+
* than a comment. Re-exported so this stays importable from
|
|
65
|
+
* `@loopingai/core/worker`, where it has always lived.
|
|
66
|
+
*/
|
|
67
|
+
export { JWKS_PATH } from "@loopingai/a2a-protocol";
|
|
58
68
|
/** The two secrets a mount signs and verifies with, already read off `env`. */
|
|
59
69
|
export interface A2ASecrets {
|
|
60
70
|
/** Ed25519 private JWK, as JSON. See {@link A2ASecretsEnv.A2A_SIGNING_KEY}. */
|
|
@@ -88,7 +98,7 @@ export interface A2AWorkerOptions<TEnv = A2ASecretsEnv> {
|
|
|
88
98
|
*/
|
|
89
99
|
manifest: AgentManifest;
|
|
90
100
|
/**
|
|
91
|
-
* The agents on this origin, keyed by tenant id.
|
|
101
|
+
* The agents on this origin, keyed by tenant id.
|
|
92
102
|
*
|
|
93
103
|
* The id is opaque to the protocol — "an opaque string used for routing
|
|
94
104
|
* requests to a specific agent or tenant when multiple agents are served
|
|
@@ -98,8 +108,23 @@ export interface A2AWorkerOptions<TEnv = A2ASecretsEnv> {
|
|
|
98
108
|
* The tenant chooses *which agent*; the verified `identity.key` still chooses
|
|
99
109
|
* *which instance of it*, so two callers of one tenant stay in separate
|
|
100
110
|
* Durable Objects exactly as before.
|
|
111
|
+
*
|
|
112
|
+
* The escape hatch, and still fully supported: use it for an agent whose
|
|
113
|
+
* routing or turn-start is genuinely its own. {@link A2AWorkerOptions.agents}
|
|
114
|
+
* is the shorter form for the ordinary case. Supply at least one of the two.
|
|
115
|
+
*/
|
|
116
|
+
tenants?: Record<string, TenantAgent>;
|
|
117
|
+
/**
|
|
118
|
+
* The agents on this origin, each declared once with
|
|
119
|
+
* {@link file://./define-agent.ts defineAgent}.
|
|
120
|
+
*
|
|
121
|
+
* Prefer this to {@link A2AWorkerOptions.tenants}: one declaration produces the
|
|
122
|
+
* tenant entry here *and* the resolver the agent's Workflow entrypoint uses, so
|
|
123
|
+
* the two cannot drift, and the binding names are type-constrained to bindings
|
|
124
|
+
* of the right kind. Merged over `tenants`, which is checked for duplicate
|
|
125
|
+
* tenant ids rather than silently overriding.
|
|
101
126
|
*/
|
|
102
|
-
|
|
127
|
+
agents?: readonly MountedAgent<TEnv>[];
|
|
103
128
|
/** Path serving the public JWKS. Defaults to {@link JWKS_PATH}. */
|
|
104
129
|
jwksPath?: string;
|
|
105
130
|
/** Path this agent answers JSON-RPC on. Defaults to `/a2a`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAQxB,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,EACL,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;GAQG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAKpD,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,QAAQ,EAAE,aAAa,CAAC;IACxB,uDAAuD;IACvD,YAAY,EAAE,aAAa,CAAC;IAC5B,4EAA4E;IAC5E,SAAS,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,aAAa;IACpD;;;;;;;;;;;;;OAaG;IACH,QAAQ,EAAE,aAAa,CAAC;IACxB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,SAAS,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;IACvC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,UAAU,CAAC;IACpC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,CAAC;IAC3C;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AA2ED;;;;;;;;;;;;;;;;;;GAkBG;AAEH,wBAAgB,eAAe,CAAC,IAAI,SAAS,aAAa,EACxD,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAC9B,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEtD,wBAAgB,eAAe,CAAC,IAAI,SAAS,MAAM,EACjD,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG;IAChC,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,UAAU,CAAC;CACpC,GACA,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC"}
|
package/dist/worker/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AGENT_CARD_PATH, SendMessageRequest } from "@a2a-js/sdk";
|
|
2
2
|
import { DefaultRequestHandler, JsonRpcTransportHandler, validateVersion } from "@a2a-js/sdk/server";
|
|
3
3
|
import { RequestMalformedError, toJsonRpcError } from "@a2a-js/sdk/errors";
|
|
4
|
+
import { JWKS_PATH, endpointUrl } from "@loopingai/a2a-protocol";
|
|
4
5
|
import { A2A_RPC_PATH, buildBaseCard, parsePrivateJwk, publicCardJwks, signCard, signCardInPlace } from "../a2a/card.js";
|
|
5
6
|
import { buildCallContext, extensionHeaders } from "../a2a/context.js";
|
|
6
7
|
import { GatewayAuthError, bearerToken, verifyGatewayToken } from "../a2a/verify.js";
|
|
@@ -58,8 +59,17 @@ import { parseGatewayOrigins } from "../env.js";
|
|
|
58
59
|
* agent on it*. The second is what makes `tenant` more than an unauthenticated
|
|
59
60
|
* routing hint in the request body.
|
|
60
61
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
export { defineAgent } from "./define-agent.js";
|
|
63
|
+
/**
|
|
64
|
+
* Default path serving the card-signing public JWKS (the card's `jku`).
|
|
65
|
+
*
|
|
66
|
+
* From `@loopingai/a2a-protocol`, because the gateway serves its own JWKS at
|
|
67
|
+
* the same path and fetches ours from whatever `jku` says — see
|
|
68
|
+
* {@link file://../a2a/verify.ts} for why the two sides share a package rather
|
|
69
|
+
* than a comment. Re-exported so this stays importable from
|
|
70
|
+
* `@loopingai/core/worker`, where it has always lived.
|
|
71
|
+
*/
|
|
72
|
+
export { JWKS_PATH } from "@loopingai/a2a-protocol";
|
|
63
73
|
/** The JSON-RPC method carrying a turn (v1.0 renamed v0.3's `message/send`). */
|
|
64
74
|
const SEND_MESSAGE_METHOD = "SendMessage";
|
|
65
75
|
function unauthorized(reason) {
|
|
@@ -124,14 +134,45 @@ function pushConfigError(rpcBody) {
|
|
|
124
134
|
return undefined;
|
|
125
135
|
}
|
|
126
136
|
export function createA2AWorker(options) {
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
// Normalized once, here, because each of these is used for two things that
|
|
138
|
+
// must agree: routing compares it against `url.pathname`, and `endpointUrl`
|
|
139
|
+
// composes it into the card's interface URL and the expected audience. A
|
|
140
|
+
// configured path written without its leading slash used to satisfy neither —
|
|
141
|
+
// `url.pathname` always has one, so the route simply never matched, and the
|
|
142
|
+
// audience came out as `https://hostpath`. Normalizing at the split keeps the
|
|
143
|
+
// two derivations from disagreeing whichever way it is written.
|
|
144
|
+
const withSlash = (path) => path.startsWith("/") ? path : `/${path}`;
|
|
145
|
+
const jwksPath = withSlash(options.jwksPath ?? JWKS_PATH);
|
|
146
|
+
const rpcPath = withSlash(options.rpcPath ?? A2A_RPC_PATH);
|
|
129
147
|
const requirePushConfig = options.requirePushConfig ?? true;
|
|
148
|
+
const declared = options.tenants ?? {};
|
|
149
|
+
const defined = options.agents ?? [];
|
|
150
|
+
// A tenant declared both ways is ambiguous, and silently letting one win is how
|
|
151
|
+
// a deployment serves an agent nobody meant to mount. Caught at startup.
|
|
152
|
+
const duplicate = defined.find((a) => Object.hasOwn(declared, a.tenant));
|
|
153
|
+
if (duplicate) {
|
|
154
|
+
throw new Error(`createA2AWorker got tenant '${duplicate.tenant}' from both \`agents\` and ` +
|
|
155
|
+
"`tenants` — declare each agent once");
|
|
156
|
+
}
|
|
157
|
+
// …and the same ambiguity within `agents` alone, which the check above cannot
|
|
158
|
+
// see. `definedByTenant` below is a `Map`, so a repeated id silently keeps the
|
|
159
|
+
// *last* entry: two `defineAgent` calls sharing a tenant would mount one and
|
|
160
|
+
// discard the other with no signal anywhere. That is the identical failure the
|
|
161
|
+
// cross-check exists to prevent, reached by copy-pasting a declaration rather
|
|
162
|
+
// than by mixing the two forms — which is the likelier mistake of the two.
|
|
163
|
+
const seen = new Set();
|
|
164
|
+
for (const agent of defined) {
|
|
165
|
+
if (seen.has(agent.tenant)) {
|
|
166
|
+
throw new Error(`createA2AWorker got tenant '${agent.tenant}' twice in \`agents\` — ` +
|
|
167
|
+
"declare each agent once");
|
|
168
|
+
}
|
|
169
|
+
seen.add(agent.tenant);
|
|
170
|
+
}
|
|
130
171
|
// Nothing can be served without at least one agent, and a deployment that
|
|
131
172
|
// configured none is a startup mistake rather than a per-request one.
|
|
132
|
-
const tenantIds = Object.keys(
|
|
173
|
+
const tenantIds = [...Object.keys(declared), ...defined.map((a) => a.tenant)];
|
|
133
174
|
if (tenantIds.length === 0) {
|
|
134
|
-
throw new Error("createA2AWorker requires at least one
|
|
175
|
+
throw new Error("createA2AWorker requires at least one agent — pass `agents` or `tenants`");
|
|
135
176
|
}
|
|
136
177
|
// …and one registered under `""` is the same mistake wearing a disguise. A
|
|
137
178
|
// request must name a tenant, and the empty string is how "named none" is
|
|
@@ -143,13 +184,30 @@ export function createA2AWorker(options) {
|
|
|
143
184
|
throw new Error("createA2AWorker requires every tenant id to be non-empty: a request " +
|
|
144
185
|
"names its tenant, so an agent registered under '' can never be reached");
|
|
145
186
|
}
|
|
187
|
+
const definedByTenant = new Map(defined.map((a) => [a.tenant, a]));
|
|
146
188
|
// The tenant id is caller-controlled, so the lookup is by *own* property.
|
|
147
189
|
// Plain indexing reaches `Object.prototype`, and every inherited name —
|
|
148
190
|
// `toString`, `constructor`, `__proto__` — comes back truthy, so a tenant
|
|
149
191
|
// called one of those slips past an `if (!agent)` guard and only fails later
|
|
150
192
|
// when a function is read off it. That is a 500 where the whole point of the
|
|
151
|
-
// guard is a 400 naming the unknown tenant.
|
|
152
|
-
|
|
193
|
+
// guard is a 400 naming the unknown tenant. (A `Map` has no such inheritance,
|
|
194
|
+
// so the `agents` half needs no equivalent guard.)
|
|
195
|
+
//
|
|
196
|
+
// Takes `env` because a `defineAgent` entry resolves its bindings from it —
|
|
197
|
+
// there is no `env` at module scope on Workers, so the closure is built per
|
|
198
|
+
// request rather than at construction.
|
|
199
|
+
const tenantAgent = (env, id) => {
|
|
200
|
+
if (Object.hasOwn(declared, id))
|
|
201
|
+
return declared[id];
|
|
202
|
+
const agent = definedByTenant.get(id);
|
|
203
|
+
if (!agent)
|
|
204
|
+
return undefined;
|
|
205
|
+
return {
|
|
206
|
+
manifest: agent.manifest,
|
|
207
|
+
resolveAgent: (identity) => agent.resolveAgent(env, identity),
|
|
208
|
+
startTurn: (turn) => agent.startTurn(env, turn)
|
|
209
|
+
};
|
|
210
|
+
};
|
|
153
211
|
// Only reachable through the first overload, which has already established
|
|
154
212
|
// that `TEnv` carries the two documented names.
|
|
155
213
|
const readSecrets = options.secrets ??
|
|
@@ -166,9 +224,9 @@ export function createA2AWorker(options) {
|
|
|
166
224
|
// value checked here are the same string by construction.
|
|
167
225
|
const audience = typeof options.audience === "function"
|
|
168
226
|
? options.audience(url)
|
|
169
|
-
: (options.audience ??
|
|
227
|
+
: (options.audience ?? endpointUrl(origin, rpcPath));
|
|
170
228
|
const privateJwk = parsePrivateJwk(secrets.signingKey);
|
|
171
|
-
const signing = { privateJwk, jku:
|
|
229
|
+
const signing = { privateJwk, jku: endpointUrl(origin, jwksPath) };
|
|
172
230
|
const cardFor = (manifest, tenant) => buildBaseCard(manifest, {
|
|
173
231
|
origin,
|
|
174
232
|
rpcPath: options.rpcPath,
|
|
@@ -252,7 +310,7 @@ export function createA2AWorker(options) {
|
|
|
252
310
|
return unauthorized(`gateway token authorizes tenant '${authorizedTenant || "<none>"}', ` +
|
|
253
311
|
`but the request addressed '${requestedTenant}'`);
|
|
254
312
|
}
|
|
255
|
-
const agent = tenantAgent(requestedTenant);
|
|
313
|
+
const agent = tenantAgent(env, requestedTenant);
|
|
256
314
|
if (!agent) {
|
|
257
315
|
return jsonRpcErrorResponse(body, toJsonRpcError(new RequestMalformedError(`unknown tenant '${requestedTenant}'`)));
|
|
258
316
|
}
|
|
@@ -297,7 +355,7 @@ export function createA2AWorker(options) {
|
|
|
297
355
|
// already authorized and routed on.
|
|
298
356
|
async (ctx) => {
|
|
299
357
|
const requested = ctx.tenant ?? "";
|
|
300
|
-
const target = tenantAgent(requested);
|
|
358
|
+
const target = tenantAgent(env, requested);
|
|
301
359
|
if (!target) {
|
|
302
360
|
throw new RequestMalformedError(`unknown tenant '${requested}'`);
|
|
303
361
|
}
|
package/dist/worker/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACL,YAAY,EACZ,aAAa,EACb,eAAe,EACf,cAAc,EACd,QAAQ,EACR,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,mBAAmB,EAAsB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"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"}
|