@mcpmesh/sdk 1.3.4 → 2.0.0-beta.1
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/dist/__tests__/a2a/a2a-bearer.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-bearer.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-bearer.spec.js +58 -0
- package/dist/__tests__/a2a/a2a-bearer.spec.js.map +1 -0
- package/dist/__tests__/a2a/a2a-client.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-client.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-client.spec.js +334 -0
- package/dist/__tests__/a2a/a2a-client.spec.js.map +1 -0
- package/dist/__tests__/a2a/a2a-job.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-job.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-job.spec.js +255 -0
- package/dist/__tests__/a2a/a2a-job.spec.js.map +1 -0
- package/dist/__tests__/a2a/a2a-stream.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-stream.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-stream.spec.js +278 -0
- package/dist/__tests__/a2a/a2a-stream.spec.js.map +1 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.d.ts +2 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.js +262 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.js +127 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.js +113 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.js +850 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.js +164 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/mount.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/mount.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/mount.spec.js +433 -0
- package/dist/__tests__/a2a/producer/mount.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.js +116 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.js +754 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.js +124 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/task-store.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/task-store.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/task-store.spec.js +180 -0
- package/dist/__tests__/a2a/producer/task-store.spec.js.map +1 -0
- package/dist/__tests__/agent-add-tool.spec.d.ts +2 -0
- package/dist/__tests__/agent-add-tool.spec.d.ts.map +1 -0
- package/dist/__tests__/agent-add-tool.spec.js +483 -0
- package/dist/__tests__/agent-add-tool.spec.js.map +1 -0
- package/dist/__tests__/api-runtime-race.spec.d.ts +2 -0
- package/dist/__tests__/api-runtime-race.spec.d.ts.map +1 -0
- package/dist/__tests__/api-runtime-race.spec.js +193 -0
- package/dist/__tests__/api-runtime-race.spec.js.map +1 -0
- package/dist/__tests__/claim-dispatcher.spec.d.ts +2 -0
- package/dist/__tests__/claim-dispatcher.spec.d.ts.map +1 -0
- package/dist/__tests__/claim-dispatcher.spec.js +408 -0
- package/dist/__tests__/claim-dispatcher.spec.js.map +1 -0
- package/dist/__tests__/inbound-job-dispatch.spec.d.ts +2 -0
- package/dist/__tests__/inbound-job-dispatch.spec.d.ts.map +1 -0
- package/dist/__tests__/inbound-job-dispatch.spec.js +185 -0
- package/dist/__tests__/inbound-job-dispatch.spec.js.map +1 -0
- package/dist/__tests__/job-controller-progress.spec.d.ts +2 -0
- package/dist/__tests__/job-controller-progress.spec.d.ts.map +1 -0
- package/dist/__tests__/job-controller-progress.spec.js +85 -0
- package/dist/__tests__/job-controller-progress.spec.js.map +1 -0
- package/dist/__tests__/jobs-cancel-route.spec.d.ts +2 -0
- package/dist/__tests__/jobs-cancel-route.spec.d.ts.map +1 -0
- package/dist/__tests__/jobs-cancel-route.spec.js +88 -0
- package/dist/__tests__/jobs-cancel-route.spec.js.map +1 -0
- package/dist/__tests__/llm-agent-stream.test.d.ts +14 -0
- package/dist/__tests__/llm-agent-stream.test.d.ts.map +1 -0
- package/dist/__tests__/llm-agent-stream.test.js +341 -0
- package/dist/__tests__/llm-agent-stream.test.js.map +1 -0
- package/dist/__tests__/llm-provider.test.js +22 -1
- package/dist/__tests__/llm-provider.test.js.map +1 -1
- package/dist/__tests__/media-resolver.test.js +40 -0
- package/dist/__tests__/media-resolver.test.js.map +1 -1
- package/dist/__tests__/mesh-job-submitter.spec.d.ts +2 -0
- package/dist/__tests__/mesh-job-submitter.spec.d.ts.map +1 -0
- package/dist/__tests__/mesh-job-submitter.spec.js +110 -0
- package/dist/__tests__/mesh-job-submitter.spec.js.map +1 -0
- package/dist/__tests__/proxy-stream.test.d.ts +9 -0
- package/dist/__tests__/proxy-stream.test.d.ts.map +1 -0
- package/dist/__tests__/proxy-stream.test.js +347 -0
- package/dist/__tests__/proxy-stream.test.js.map +1 -0
- package/dist/__tests__/resolver-meshjob.spec.d.ts +26 -0
- package/dist/__tests__/resolver-meshjob.spec.d.ts.map +1 -0
- package/dist/__tests__/resolver-meshjob.spec.js +201 -0
- package/dist/__tests__/resolver-meshjob.spec.js.map +1 -0
- package/dist/__tests__/schema-verdict-policy.test.d.ts +6 -0
- package/dist/__tests__/schema-verdict-policy.test.d.ts.map +1 -0
- package/dist/__tests__/schema-verdict-policy.test.js +126 -0
- package/dist/__tests__/schema-verdict-policy.test.js.map +1 -0
- package/dist/__tests__/sse-stream.test.d.ts +12 -0
- package/dist/__tests__/sse-stream.test.d.ts.map +1 -0
- package/dist/__tests__/sse-stream.test.js +170 -0
- package/dist/__tests__/sse-stream.test.js.map +1 -0
- package/dist/a2a/a2a-bearer.d.ts +27 -0
- package/dist/a2a/a2a-bearer.d.ts.map +1 -0
- package/dist/a2a/a2a-bearer.js +63 -0
- package/dist/a2a/a2a-bearer.js.map +1 -0
- package/dist/a2a/a2a-client.d.ts +114 -0
- package/dist/a2a/a2a-client.d.ts.map +1 -0
- package/dist/a2a/a2a-client.js +405 -0
- package/dist/a2a/a2a-client.js.map +1 -0
- package/dist/a2a/a2a-event.d.ts +25 -0
- package/dist/a2a/a2a-event.d.ts.map +1 -0
- package/dist/a2a/a2a-event.js +9 -0
- package/dist/a2a/a2a-event.js.map +1 -0
- package/dist/a2a/a2a-job.d.ts +58 -0
- package/dist/a2a/a2a-job.d.ts.map +1 -0
- package/dist/a2a/a2a-job.js +264 -0
- package/dist/a2a/a2a-job.js.map +1 -0
- package/dist/a2a/a2a-stream.d.ts +39 -0
- package/dist/a2a/a2a-stream.d.ts.map +1 -0
- package/dist/a2a/a2a-stream.js +290 -0
- package/dist/a2a/a2a-stream.js.map +1 -0
- package/dist/a2a/errors.d.ts +29 -0
- package/dist/a2a/errors.d.ts.map +1 -0
- package/dist/a2a/errors.js +48 -0
- package/dist/a2a/errors.js.map +1 -0
- package/dist/a2a/index.d.ts +12 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +11 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/a2a/producer/auth-filter.d.ts +34 -0
- package/dist/a2a/producer/auth-filter.d.ts.map +1 -0
- package/dist/a2a/producer/auth-filter.js +39 -0
- package/dist/a2a/producer/auth-filter.js.map +1 -0
- package/dist/a2a/producer/card-builder.d.ts +59 -0
- package/dist/a2a/producer/card-builder.d.ts.map +1 -0
- package/dist/a2a/producer/card-builder.js +59 -0
- package/dist/a2a/producer/card-builder.js.map +1 -0
- package/dist/a2a/producer/dispatcher.d.ts +276 -0
- package/dist/a2a/producer/dispatcher.d.ts.map +1 -0
- package/dist/a2a/producer/dispatcher.js +896 -0
- package/dist/a2a/producer/dispatcher.js.map +1 -0
- package/dist/a2a/producer/index.d.ts +26 -0
- package/dist/a2a/producer/index.d.ts.map +1 -0
- package/dist/a2a/producer/index.js +23 -0
- package/dist/a2a/producer/index.js.map +1 -0
- package/dist/a2a/producer/mount.d.ts +75 -0
- package/dist/a2a/producer/mount.d.ts.map +1 -0
- package/dist/a2a/producer/mount.js +422 -0
- package/dist/a2a/producer/mount.js.map +1 -0
- package/dist/a2a/producer/public-url-cache.d.ts +73 -0
- package/dist/a2a/producer/public-url-cache.d.ts.map +1 -0
- package/dist/a2a/producer/public-url-cache.js +0 -0
- package/dist/a2a/producer/public-url-cache.js.map +1 -0
- package/dist/a2a/producer/registry.d.ts +138 -0
- package/dist/a2a/producer/registry.d.ts.map +1 -0
- package/dist/a2a/producer/registry.js +117 -0
- package/dist/a2a/producer/registry.js.map +1 -0
- package/dist/a2a/producer/sse-emitter.d.ts +85 -0
- package/dist/a2a/producer/sse-emitter.d.ts.map +1 -0
- package/dist/a2a/producer/sse-emitter.js +405 -0
- package/dist/a2a/producer/sse-emitter.js.map +1 -0
- package/dist/a2a/producer/state-translator.d.ts +63 -0
- package/dist/a2a/producer/state-translator.d.ts.map +1 -0
- package/dist/a2a/producer/state-translator.js +108 -0
- package/dist/a2a/producer/state-translator.js.map +1 -0
- package/dist/a2a/producer/task-store.d.ts +128 -0
- package/dist/a2a/producer/task-store.d.ts.map +1 -0
- package/dist/a2a/producer/task-store.js +128 -0
- package/dist/a2a/producer/task-store.js.map +1 -0
- package/dist/agent.d.ts +99 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +754 -19
- package/dist/agent.js.map +1 -1
- package/dist/api-runtime.d.ts +25 -0
- package/dist/api-runtime.d.ts.map +1 -1
- package/dist/api-runtime.js +75 -2
- package/dist/api-runtime.js.map +1 -1
- package/dist/claim-dispatcher.d.ts +126 -0
- package/dist/claim-dispatcher.d.ts.map +1 -0
- package/dist/claim-dispatcher.js +478 -0
- package/dist/claim-dispatcher.js.map +1 -0
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +33 -6
- package/dist/express.js.map +1 -1
- package/dist/inbound-job-dispatch.d.ts +105 -0
- package/dist/inbound-job-dispatch.d.ts.map +1 -0
- package/dist/inbound-job-dispatch.js +335 -0
- package/dist/inbound-job-dispatch.js.map +1 -0
- package/dist/index.d.ts +40 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -3
- package/dist/index.js.map +1 -1
- package/dist/job-context.d.ts +107 -0
- package/dist/job-context.d.ts.map +1 -0
- package/dist/job-context.js +95 -0
- package/dist/job-context.js.map +1 -0
- package/dist/jobs-cancel-route.d.ts +36 -0
- package/dist/jobs-cancel-route.d.ts.map +1 -0
- package/dist/jobs-cancel-route.js +60 -0
- package/dist/jobs-cancel-route.js.map +1 -0
- package/dist/jobs-helper-tools.d.ts +48 -0
- package/dist/jobs-helper-tools.d.ts.map +1 -0
- package/dist/jobs-helper-tools.js +133 -0
- package/dist/jobs-helper-tools.js.map +1 -0
- package/dist/llm-agent.d.ts +62 -53
- package/dist/llm-agent.d.ts.map +1 -1
- package/dist/llm-agent.js +211 -292
- package/dist/llm-agent.js.map +1 -1
- package/dist/llm-provider.d.ts +11 -4
- package/dist/llm-provider.d.ts.map +1 -1
- package/dist/llm-provider.js +57 -4
- package/dist/llm-provider.js.map +1 -1
- package/dist/llm.d.ts +4 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +7 -17
- package/dist/llm.js.map +1 -1
- package/dist/media/resolver.d.ts.map +1 -1
- package/dist/media/resolver.js +3 -2
- package/dist/media/resolver.js.map +1 -1
- package/dist/mesh-job-submitter.d.ts +83 -0
- package/dist/mesh-job-submitter.d.ts.map +1 -0
- package/dist/mesh-job-submitter.js +143 -0
- package/dist/mesh-job-submitter.js.map +1 -0
- package/dist/provider-handlers/gemini-handler.js +5 -0
- package/dist/provider-handlers/gemini-handler.js.map +1 -1
- package/dist/proxy.d.ts +40 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +375 -2
- package/dist/proxy.js.map +1 -1
- package/dist/resolver-meshjob.d.ts +170 -0
- package/dist/resolver-meshjob.d.ts.map +1 -0
- package/dist/resolver-meshjob.js +159 -0
- package/dist/resolver-meshjob.js.map +1 -0
- package/dist/route.d.ts +4 -0
- package/dist/route.d.ts.map +1 -1
- package/dist/route.js.map +1 -1
- package/dist/schema-normalize.d.ts +62 -0
- package/dist/schema-normalize.d.ts.map +1 -0
- package/dist/schema-normalize.js +128 -0
- package/dist/schema-normalize.js.map +1 -0
- package/dist/sse-stream.d.ts +44 -0
- package/dist/sse-stream.d.ts.map +1 -0
- package/dist/sse-stream.js +173 -0
- package/dist/sse-stream.js.map +1 -0
- package/dist/tool-worker-entry.d.ts +21 -0
- package/dist/tool-worker-entry.d.ts.map +1 -0
- package/dist/tool-worker-entry.js +162 -0
- package/dist/tool-worker-entry.js.map +1 -0
- package/dist/tool-worker-pool.d.ts +49 -0
- package/dist/tool-worker-pool.d.ts.map +1 -0
- package/dist/tool-worker-pool.js +272 -0
- package/dist/tool-worker-pool.js.map +1 -0
- package/dist/types.d.ts +351 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local cache of registry-stamped public URLs for each
|
|
3
|
+
* `mesh.a2a.mount(...)` surface (spec §8.2).
|
|
4
|
+
*
|
|
5
|
+
* Populated from the registry's heartbeat-response handler when it returns
|
|
6
|
+
* a `surfaces[].public_url` entry for each surface. Read by the agent-card
|
|
7
|
+
* endpoint at request time.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors Python's module-level `_PUBLIC_URL_CACHE` in
|
|
10
|
+
* `mesh/a2a.py:202-228` and Java's `MeshA2APublicUrlCache`. Process-local,
|
|
11
|
+
* not persisted across restarts — the registry re-stamps on the next
|
|
12
|
+
* heartbeat.
|
|
13
|
+
*
|
|
14
|
+
* When the cache has no entry for a given `(path, skillId)`, the agent
|
|
15
|
+
* card falls back to building a local-form URL from the agent's
|
|
16
|
+
* configured host:port. Returning an externally-reachable FQDN matters
|
|
17
|
+
* once the producer is deployed behind a load balancer or ingress.
|
|
18
|
+
*
|
|
19
|
+
* ## Cross-runtime parity status
|
|
20
|
+
*
|
|
21
|
+
* The Rust core does NOT currently emit a `surface_updated` mesh event
|
|
22
|
+
* back to TypeScript (or Java) consumers — `JsMeshEvent` covers only
|
|
23
|
+
* dependency / LLM / lifecycle signals today. When the registry adds
|
|
24
|
+
* surface URL stamping events (separate follow-up issue), the
|
|
25
|
+
* api-runtime event loop populates this cache via {@link put}. Until then
|
|
26
|
+
* the cache stays empty and the agent card uses the local-fallback URL
|
|
27
|
+
* (which is what Python does today when the registry hasn't stamped a
|
|
28
|
+
* URL yet).
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Process-wide singleton cache of registry-stamped public URLs.
|
|
32
|
+
*
|
|
33
|
+
* Mirrors Java's `MeshA2APublicUrlCache` API.
|
|
34
|
+
*/
|
|
35
|
+
export declare class A2APublicUrlCache {
|
|
36
|
+
private static instance;
|
|
37
|
+
private readonly cache;
|
|
38
|
+
private constructor();
|
|
39
|
+
static getInstance(): A2APublicUrlCache;
|
|
40
|
+
/** Reset the cache (mainly for testing). */
|
|
41
|
+
static reset(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Cache (or clear) the registry-stamped public URL for one surface.
|
|
44
|
+
* Pass `null` / empty `publicUrl` to clear the cached entry — matches
|
|
45
|
+
* Python's `update_public_url_cache` behavior (drops the entry when
|
|
46
|
+
* the registry stops stamping it).
|
|
47
|
+
*/
|
|
48
|
+
put(path: string, skillId: string, publicUrl: string | null | undefined): void;
|
|
49
|
+
/**
|
|
50
|
+
* @returns the cached public URL for `(path, skillId)`, or `undefined`
|
|
51
|
+
* when no entry exists. Callers MUST fall back to a locally-built
|
|
52
|
+
* URL form when this returns `undefined`.
|
|
53
|
+
*/
|
|
54
|
+
get(path: string, skillId: string): string | undefined;
|
|
55
|
+
/** @returns current cache size. For diagnostics + tests. */
|
|
56
|
+
size(): number;
|
|
57
|
+
/** Drop every cached entry. For tests and shutdown cleanup. */
|
|
58
|
+
clear(): void;
|
|
59
|
+
private makeKey;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the local-form fallback URL for one surface. Used when the
|
|
63
|
+
* registry hasn't stamped a public URL yet (spec §2.4).
|
|
64
|
+
*
|
|
65
|
+
* Format: `http://{host}:{port}{path}` — not addressable from outside
|
|
66
|
+
* the local network, but appropriate for dev/CI.
|
|
67
|
+
*
|
|
68
|
+
* IPv6 hosts are bracketed per RFC 3986 §3.2.2 (parity with Java's
|
|
69
|
+
* `MeshA2ACardBuilder.localFallbackUrl` #934 A6 fix). Hosts that already
|
|
70
|
+
* arrive bracketed (e.g. `[::1]`) are not re-bracketed.
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildLocalFallbackUrl(host: string | undefined, port: number | undefined, path: string): string;
|
|
73
|
+
//# sourceMappingURL=public-url-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-url-cache.d.ts","sourceRoot":"","sources":["../../../src/a2a/producer/public-url-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IAEnD,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,iBAAiB;IAOvC,4CAA4C;IAC5C,MAAM,CAAC,KAAK,IAAI,IAAI;IAIpB;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAS9E;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAItD,4DAA4D;IAC5D,IAAI,IAAI,MAAM;IAId,+DAA+D;IAC/D,KAAK,IAAI,IAAI;IAMb,OAAO,CAAC,OAAO;CAGhB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,GACX,MAAM,CAaR"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-url-cache.js","sourceRoot":"","sources":["../../../src/a2a/producer/public-url-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACpB,MAAM,CAAC,QAAQ,GAA6B,IAAI,CAAC;IACxC,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEnD,gBAAuB,CAAC;IAExB,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YAChC,iBAAiB,CAAC,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACvD,CAAC;QACD,OAAO,iBAAiB,CAAC,QAAQ,CAAC;IACpC,CAAC;IAED,4CAA4C;IAC5C,MAAM,CAAC,KAAK;QACV,iBAAiB,CAAC,QAAQ,GAAG,IAAI,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,IAAY,EAAE,OAAe,EAAE,SAAoC;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAY,EAAE,OAAe;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,4DAA4D;IAC5D,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,+DAA+D;IAC/D,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,uEAAuE;IACvE,iEAAiE;IACzD,OAAO,CAAC,IAAY,EAAE,OAAe;QAC3C,OAAO,GAAG,IAAI,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;IACpC,CAAC;;AAGH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAwB,EACxB,IAAwB,EACxB,IAAY;IAEZ,MAAM,QAAQ,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;IAC9D,0EAA0E;IAC1E,uEAAuE;IACvE,uEAAuE;IACvE,MAAM,QAAQ,GACZ,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;QACjD,CAAC,CAAC,IAAI,QAAQ,GAAG;QACjB,CAAC,CAAC,QAAQ,CAAC;IACf,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,UAAU,QAAQ,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,UAAU,QAAQ,GAAG,IAAI,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry for `mesh.a2a.mount(...)` producer surfaces (issue #933).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the role of `RouteRegistry` on the `mesh.route()` side: built at
|
|
5
|
+
* mount time, queried during request dispatch (for path-to-surface lookup),
|
|
6
|
+
* card render, auth gating, and heartbeat envelope construction.
|
|
7
|
+
*
|
|
8
|
+
* Single process-wide singleton (matches `RouteRegistry`). Each mount call
|
|
9
|
+
* registers a unique path; duplicate paths throw at mount time so wiring
|
|
10
|
+
* mistakes surface synchronously instead of as silent overrides.
|
|
11
|
+
*
|
|
12
|
+
* Cross-cuts with `RouteRegistry`: A2A surfaces declare mesh dependencies
|
|
13
|
+
* just like routes, and the producer reuses `RouteRegistry` for dependency
|
|
14
|
+
* resolution so the same DDDI plumbing powers both surfaces. Each mount
|
|
15
|
+
* registers its dependencies as a synthetic route in `RouteRegistry`; the
|
|
16
|
+
* surface keeps a back-reference to that route's `routeId` so dispatch can
|
|
17
|
+
* resolve injected `McpMeshTool` proxies.
|
|
18
|
+
*/
|
|
19
|
+
import type { DependencySpec, NormalizedDependency } from "../../types.js";
|
|
20
|
+
/**
|
|
21
|
+
* Captured metadata for a single `mesh.a2a.mount(...)` call.
|
|
22
|
+
*
|
|
23
|
+
* Constructed once at mount time and immutable thereafter — the dispatcher
|
|
24
|
+
* reads these fields on every request.
|
|
25
|
+
*/
|
|
26
|
+
export interface A2ASurfaceMetadata {
|
|
27
|
+
/** URL path prefix for this surface; must start with `/` and not end with `/`. */
|
|
28
|
+
readonly path: string;
|
|
29
|
+
/** A2A skill identifier, kebab-case canonical (e.g., `"get-date"`). */
|
|
30
|
+
readonly skillId: string;
|
|
31
|
+
/** Human-readable skill name (defaults to `skillId` when unset). */
|
|
32
|
+
readonly skillName: string;
|
|
33
|
+
/** Free-form skill description (`""` when unset). */
|
|
34
|
+
readonly description: string;
|
|
35
|
+
/** Skill tags surfaced on the agent card. */
|
|
36
|
+
readonly tags: readonly string[];
|
|
37
|
+
/** Normalized dependencies (matches `RouteMetadata.dependencies`). */
|
|
38
|
+
readonly dependencies: readonly NormalizedDependency[];
|
|
39
|
+
/**
|
|
40
|
+
* Auth scheme — `"bearer"` enables the presence-check gate (spec §6.2),
|
|
41
|
+
* `""` leaves the path open. Phase 1 supports only `"bearer"`.
|
|
42
|
+
*/
|
|
43
|
+
readonly auth: "" | "bearer";
|
|
44
|
+
/**
|
|
45
|
+
* The `routeId` returned by `RouteRegistry.registerRoute` for this surface's
|
|
46
|
+
* dependencies — used by the dispatcher to look up resolved `McpMeshTool`
|
|
47
|
+
* proxies by position via `RouteRegistry.getDependenciesForRoute(routeId)`.
|
|
48
|
+
*/
|
|
49
|
+
readonly routeId: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Configuration object passed to `mesh.a2a.mount(...)`.
|
|
53
|
+
*/
|
|
54
|
+
export interface A2AMountConfig {
|
|
55
|
+
/** URL path prefix for this surface. MUST start with `/`. */
|
|
56
|
+
path: string;
|
|
57
|
+
/** A2A skill identifier (kebab-case). MUST be non-empty. */
|
|
58
|
+
skillId: string;
|
|
59
|
+
/** Human-readable skill name. Defaults to `skillId` when unset. */
|
|
60
|
+
skillName?: string;
|
|
61
|
+
/** Free-form skill description. */
|
|
62
|
+
description?: string;
|
|
63
|
+
/** Skill tags surfaced on the agent card. */
|
|
64
|
+
tags?: string[];
|
|
65
|
+
/** Mesh dependencies to inject into the handler (DDDI). */
|
|
66
|
+
dependencies?: DependencySpec[];
|
|
67
|
+
/**
|
|
68
|
+
* Auth scheme — `"bearer"` enables the presence-check gate (spec §6.2).
|
|
69
|
+
* Default: no auth gate.
|
|
70
|
+
*/
|
|
71
|
+
auth?: "bearer";
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Singleton registry for `mesh.a2a.mount(...)` producer surfaces.
|
|
75
|
+
*
|
|
76
|
+
* Insertion order is preserved (mirrors Java's `MeshA2ARegistry`) so the
|
|
77
|
+
* heartbeat envelope's `surfaces[]` array order stays stable across
|
|
78
|
+
* restarts.
|
|
79
|
+
*/
|
|
80
|
+
export declare class A2AProducerRegistry {
|
|
81
|
+
private static instance;
|
|
82
|
+
private readonly surfacesByPath;
|
|
83
|
+
private constructor();
|
|
84
|
+
static getInstance(): A2AProducerRegistry;
|
|
85
|
+
/** Reset the registry (mainly for testing). */
|
|
86
|
+
static reset(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Register an A2A surface. Throws on duplicate path so wiring mistakes
|
|
89
|
+
* fail loudly instead of silently overriding (matches Java's
|
|
90
|
+
* `MeshA2ARegistry.register`).
|
|
91
|
+
*/
|
|
92
|
+
register(metadata: A2ASurfaceMetadata): void;
|
|
93
|
+
/** Look up a surface by path. Returns `undefined` when no surface owns it. */
|
|
94
|
+
getByPath(path: string): A2ASurfaceMetadata | undefined;
|
|
95
|
+
/** @returns insertion-ordered list of every registered surface. */
|
|
96
|
+
getAll(): A2ASurfaceMetadata[];
|
|
97
|
+
/** @returns `true` when at least one surface is registered. */
|
|
98
|
+
hasSurfaces(): boolean;
|
|
99
|
+
/** @returns number of registered surfaces. */
|
|
100
|
+
size(): number;
|
|
101
|
+
/**
|
|
102
|
+
* Build the `(agentType, surfacesJson)` pair the napi binding expects on
|
|
103
|
+
* `JsAgentSpec.surfaces` and on `JsAgentHandle.updateSurfaces(...)` (issue
|
|
104
|
+
* #938). Centralizes the {@link buildHeartbeatSurfaces} → JSON.stringify
|
|
105
|
+
* → flip-agentType logic so the three callers — `ApiRuntime.start`,
|
|
106
|
+
* `MeshAgent.startHeartbeat`, and `mesh.a2a.mount` — emit identical
|
|
107
|
+
* payloads.
|
|
108
|
+
*
|
|
109
|
+
* `nonA2aType` is the agent_type to use when no A2A surfaces are
|
|
110
|
+
* registered ({@code "api"} for consumer-only Express apps, {@code "mcp_agent"}
|
|
111
|
+
* for full MCP agents). When at least one surface is registered the
|
|
112
|
+
* agent_type flips to {@code "a2a"} (matches Python's
|
|
113
|
+
* `heartbeat_preparation.py:371-389`).
|
|
114
|
+
*
|
|
115
|
+
* Empty surfaces arrays are encoded as `undefined` so the wire stays
|
|
116
|
+
* clean — the napi binding's `surfaces?: string` field is omitted by
|
|
117
|
+
* `skip_serializing_if` in Rust when None.
|
|
118
|
+
*/
|
|
119
|
+
buildAgentSpecContribution(nonA2aType?: "api" | "mcp_agent"): {
|
|
120
|
+
agentType: "a2a" | "api" | "mcp_agent";
|
|
121
|
+
surfacesJson: string | undefined;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Build the heartbeat `a2a_surfaces[]` array (spec §2.1).
|
|
125
|
+
*
|
|
126
|
+
* Required fields (`path`, `skill_id`) are always emitted. `name` is
|
|
127
|
+
* always emitted because mount-time defaults `skillName` to `skillId`
|
|
128
|
+
* (see mount.ts), so it is never empty at this point. The remaining
|
|
129
|
+
* optional fields (`description`, `tags`) are emitted ONLY when set —
|
|
130
|
+
* never as empty strings or empty arrays — so the registry's OpenAPI
|
|
131
|
+
* defaults (`input_modes: ["application/json"]`, etc.) aren't overridden
|
|
132
|
+
* with empty values. Spec §2.1 is explicit about this.
|
|
133
|
+
*
|
|
134
|
+
* @returns list of plain-object surface entries ready for JSON serialization
|
|
135
|
+
*/
|
|
136
|
+
buildHeartbeatSurfaces(): Array<Record<string, unknown>>;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/a2a/producer/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3E;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACvD;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,EAAE,GAAG,QAAQ,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyC;IAExE,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,mBAAmB;IAOzC,+CAA+C;IAC/C,MAAM,CAAC,KAAK,IAAI,IAAI;IAIpB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAW5C,8EAA8E;IAC9E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIvD,mEAAmE;IACnE,MAAM,IAAI,kBAAkB,EAAE;IAI9B,+DAA+D;IAC/D,WAAW,IAAI,OAAO;IAItB,8CAA8C;IAC9C,IAAI,IAAI,MAAM;IAId;;;;;;;;;;;;;;;;;OAiBG;IACH,0BAA0B,CACxB,UAAU,GAAE,KAAK,GAAG,WAAmB,GACtC;QAAE,SAAS,EAAE,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE;IAW/E;;;;;;;;;;;;OAYG;IACH,sBAAsB,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAwBzD"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singleton registry for `mesh.a2a.mount(...)` producer surfaces.
|
|
3
|
+
*
|
|
4
|
+
* Insertion order is preserved (mirrors Java's `MeshA2ARegistry`) so the
|
|
5
|
+
* heartbeat envelope's `surfaces[]` array order stays stable across
|
|
6
|
+
* restarts.
|
|
7
|
+
*/
|
|
8
|
+
export class A2AProducerRegistry {
|
|
9
|
+
static instance = null;
|
|
10
|
+
surfacesByPath = new Map();
|
|
11
|
+
constructor() { }
|
|
12
|
+
static getInstance() {
|
|
13
|
+
if (!A2AProducerRegistry.instance) {
|
|
14
|
+
A2AProducerRegistry.instance = new A2AProducerRegistry();
|
|
15
|
+
}
|
|
16
|
+
return A2AProducerRegistry.instance;
|
|
17
|
+
}
|
|
18
|
+
/** Reset the registry (mainly for testing). */
|
|
19
|
+
static reset() {
|
|
20
|
+
A2AProducerRegistry.instance = null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Register an A2A surface. Throws on duplicate path so wiring mistakes
|
|
24
|
+
* fail loudly instead of silently overriding (matches Java's
|
|
25
|
+
* `MeshA2ARegistry.register`).
|
|
26
|
+
*/
|
|
27
|
+
register(metadata) {
|
|
28
|
+
if (this.surfacesByPath.has(metadata.path)) {
|
|
29
|
+
const existing = this.surfacesByPath.get(metadata.path);
|
|
30
|
+
throw new Error(`mesh.a2a.mount: path collision: '${metadata.path}' is already registered ` +
|
|
31
|
+
`(existing skillId=${existing.skillId}). Each producer path must be unique.`);
|
|
32
|
+
}
|
|
33
|
+
this.surfacesByPath.set(metadata.path, metadata);
|
|
34
|
+
}
|
|
35
|
+
/** Look up a surface by path. Returns `undefined` when no surface owns it. */
|
|
36
|
+
getByPath(path) {
|
|
37
|
+
return this.surfacesByPath.get(path);
|
|
38
|
+
}
|
|
39
|
+
/** @returns insertion-ordered list of every registered surface. */
|
|
40
|
+
getAll() {
|
|
41
|
+
return Array.from(this.surfacesByPath.values());
|
|
42
|
+
}
|
|
43
|
+
/** @returns `true` when at least one surface is registered. */
|
|
44
|
+
hasSurfaces() {
|
|
45
|
+
return this.surfacesByPath.size > 0;
|
|
46
|
+
}
|
|
47
|
+
/** @returns number of registered surfaces. */
|
|
48
|
+
size() {
|
|
49
|
+
return this.surfacesByPath.size;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the `(agentType, surfacesJson)` pair the napi binding expects on
|
|
53
|
+
* `JsAgentSpec.surfaces` and on `JsAgentHandle.updateSurfaces(...)` (issue
|
|
54
|
+
* #938). Centralizes the {@link buildHeartbeatSurfaces} → JSON.stringify
|
|
55
|
+
* → flip-agentType logic so the three callers — `ApiRuntime.start`,
|
|
56
|
+
* `MeshAgent.startHeartbeat`, and `mesh.a2a.mount` — emit identical
|
|
57
|
+
* payloads.
|
|
58
|
+
*
|
|
59
|
+
* `nonA2aType` is the agent_type to use when no A2A surfaces are
|
|
60
|
+
* registered ({@code "api"} for consumer-only Express apps, {@code "mcp_agent"}
|
|
61
|
+
* for full MCP agents). When at least one surface is registered the
|
|
62
|
+
* agent_type flips to {@code "a2a"} (matches Python's
|
|
63
|
+
* `heartbeat_preparation.py:371-389`).
|
|
64
|
+
*
|
|
65
|
+
* Empty surfaces arrays are encoded as `undefined` so the wire stays
|
|
66
|
+
* clean — the napi binding's `surfaces?: string` field is omitted by
|
|
67
|
+
* `skip_serializing_if` in Rust when None.
|
|
68
|
+
*/
|
|
69
|
+
buildAgentSpecContribution(nonA2aType = "api") {
|
|
70
|
+
if (!this.hasSurfaces()) {
|
|
71
|
+
return { agentType: nonA2aType, surfacesJson: undefined };
|
|
72
|
+
}
|
|
73
|
+
const surfaces = this.buildHeartbeatSurfaces();
|
|
74
|
+
return {
|
|
75
|
+
agentType: "a2a",
|
|
76
|
+
surfacesJson: JSON.stringify(surfaces),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Build the heartbeat `a2a_surfaces[]` array (spec §2.1).
|
|
81
|
+
*
|
|
82
|
+
* Required fields (`path`, `skill_id`) are always emitted. `name` is
|
|
83
|
+
* always emitted because mount-time defaults `skillName` to `skillId`
|
|
84
|
+
* (see mount.ts), so it is never empty at this point. The remaining
|
|
85
|
+
* optional fields (`description`, `tags`) are emitted ONLY when set —
|
|
86
|
+
* never as empty strings or empty arrays — so the registry's OpenAPI
|
|
87
|
+
* defaults (`input_modes: ["application/json"]`, etc.) aren't overridden
|
|
88
|
+
* with empty values. Spec §2.1 is explicit about this.
|
|
89
|
+
*
|
|
90
|
+
* @returns list of plain-object surface entries ready for JSON serialization
|
|
91
|
+
*/
|
|
92
|
+
buildHeartbeatSurfaces() {
|
|
93
|
+
const out = [];
|
|
94
|
+
for (const md of this.surfacesByPath.values()) {
|
|
95
|
+
const entry = {
|
|
96
|
+
path: md.path,
|
|
97
|
+
skill_id: md.skillId,
|
|
98
|
+
};
|
|
99
|
+
// skill_name is always present (defaulted to skillId at mount time) —
|
|
100
|
+
// emit it as `name` so the registry can use it for human-readable
|
|
101
|
+
// discovery. Mirrors Java's MeshA2ARegistry.buildHeartbeatSurfaces.
|
|
102
|
+
entry.name = md.skillName;
|
|
103
|
+
if (md.description && md.description.length > 0) {
|
|
104
|
+
entry.description = md.description;
|
|
105
|
+
}
|
|
106
|
+
if (md.tags.length > 0) {
|
|
107
|
+
entry.tags = [...md.tags];
|
|
108
|
+
}
|
|
109
|
+
// input_modes / output_modes default at card-render time, not at
|
|
110
|
+
// heartbeat-emit time (spec §2.1). The mount config doesn't expose
|
|
111
|
+
// them yet — omit so the registry's defaults apply.
|
|
112
|
+
out.push(entry);
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/a2a/producer/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express SSE adapter for the framework-agnostic
|
|
3
|
+
* {@link SseStreamPlan} produced by {@link buildSendSubscribeStream} /
|
|
4
|
+
* {@link buildResubscribeStream} (spec §4.6 / §4.7 / §5).
|
|
5
|
+
*
|
|
6
|
+
* The dispatcher returns a stream-plan value object describing one of
|
|
7
|
+
* four SSE shapes. This adapter materialises that plan as `data: <json>\n\n`
|
|
8
|
+
* frames on an Express {@link Response} plus `: keepalive\n\n` comment
|
|
9
|
+
* lines every {@link KEEPALIVE_MILLIS} milliseconds of inactivity.
|
|
10
|
+
*
|
|
11
|
+
* ## Why a separate file?
|
|
12
|
+
*
|
|
13
|
+
* Keeping the dispatcher framework-agnostic makes it unit-testable
|
|
14
|
+
* without an HTTP server. This adapter contains the only dependency on
|
|
15
|
+
* Express's `Response` streaming API. Mirrors Java's
|
|
16
|
+
* `MeshA2ASseDispatcher` → `MeshA2ADispatcher` split.
|
|
17
|
+
*
|
|
18
|
+
* ## Client-disconnect handling
|
|
19
|
+
*
|
|
20
|
+
* Per spec §7.3 / §5.4: a client-side SSE disconnect MUST NOT cancel the
|
|
21
|
+
* underlying job — the client may rejoin via `tasks/resubscribe`. We
|
|
22
|
+
* detect disconnect via:
|
|
23
|
+
* 1. `res.writableEnded` / `res.destroyed` (Node http.ServerResponse).
|
|
24
|
+
* 2. `res.write(...)` returning `false` on an already-closed socket.
|
|
25
|
+
* 3. `req.on("close", ...)` firing while the poll loop is sleeping.
|
|
26
|
+
* In all three cases we exit the loop cleanly without calling
|
|
27
|
+
* `JobProxy.cancel()` — the job continues running and the task store is
|
|
28
|
+
* preserved.
|
|
29
|
+
*
|
|
30
|
+
* ## BLOCKER-fix invariants (Java #934 carry-over)
|
|
31
|
+
*
|
|
32
|
+
* 1. Transient `proxy.status()` failures during the poll loop emit a
|
|
33
|
+
* `state=working` (NOT terminal `state=failed`) frame and continue
|
|
34
|
+
* polling. Spec §4.4 conformance: transient unreachability is NOT
|
|
35
|
+
* authoritative evidence the job is dead.
|
|
36
|
+
*
|
|
37
|
+
* 2. After {@link MAX_CONSECUTIVE_STATUS_FAILURES} consecutive status()
|
|
38
|
+
* exceptions the adapter closes the SSE stream WITHOUT marking the
|
|
39
|
+
* task store record terminal — subsequent `tasks/get` resumes
|
|
40
|
+
* polling normally.
|
|
41
|
+
*
|
|
42
|
+
* 3. The {@link MAX_STREAM_MILLIS} cap emits a `state=working, final=false`
|
|
43
|
+
* frame (NOT `final=true`) so the client knows to reconnect via
|
|
44
|
+
* `tasks/resubscribe` — the task is still running, only the SSE
|
|
45
|
+
* transport is closed.
|
|
46
|
+
*/
|
|
47
|
+
import type { Request, RequestHandler, Response } from "express";
|
|
48
|
+
import { A2ATaskStore } from "./task-store.js";
|
|
49
|
+
import { type DispatcherDeps, type SseStreamPlan } from "./dispatcher.js";
|
|
50
|
+
/** Poll cadence for the long-running stream (spec §4.6 sequence diagram: 1s). */
|
|
51
|
+
export declare const POLL_INTERVAL_MILLIS = 1000;
|
|
52
|
+
/** Keepalive interval — SSE comment frame after this much inactivity (spec §5.1: 15s). */
|
|
53
|
+
export declare const KEEPALIVE_MILLIS = 15000;
|
|
54
|
+
/** Maximum total stream duration as a defensive cap (1 hour, matches Java). */
|
|
55
|
+
export declare const MAX_STREAM_MILLIS: number;
|
|
56
|
+
/**
|
|
57
|
+
* Consecutive `proxy.status()` failures to tolerate during the SSE poll
|
|
58
|
+
* loop before giving up. Spec §4.4: transient unreachability is NOT
|
|
59
|
+
* authoritative evidence the job is dead, so we keep emitting
|
|
60
|
+
* `state=working` status frames and continue polling until this cap.
|
|
61
|
+
* Once reached we close the SSE stream WITHOUT marking the task store
|
|
62
|
+
* record terminal — subsequent `tasks/get` resumes polling normally.
|
|
63
|
+
*
|
|
64
|
+
* Matches Java's `MAX_CONSECUTIVE_STATUS_FAILURES`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const MAX_CONSECUTIVE_STATUS_FAILURES = 5;
|
|
67
|
+
/**
|
|
68
|
+
* Build the SSE dispatcher middleware. Mounted in front of the JSON-RPC
|
|
69
|
+
* dispatcher: when the request body's `method` is `tasks/sendSubscribe`
|
|
70
|
+
* or `tasks/resubscribe`, this middleware consumes the request and
|
|
71
|
+
* streams an SSE response. Otherwise it calls `next()` and execution
|
|
72
|
+
* falls through to the JSON-RPC dispatcher.
|
|
73
|
+
*
|
|
74
|
+
* The middleware peeks at the parsed body (`req.body.method`) rather
|
|
75
|
+
* than `Accept` header — even when the client sends both, we want to
|
|
76
|
+
* route by JSON-RPC method to keep the dispatch deterministic.
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildSseDispatcherMiddleware(deps: DispatcherDeps): RequestHandler;
|
|
79
|
+
/**
|
|
80
|
+
* Materialise an SSE stream-plan as an Express response. Exposed for
|
|
81
|
+
* advanced wiring / tests; the public mount API calls this via the
|
|
82
|
+
* middleware above.
|
|
83
|
+
*/
|
|
84
|
+
export declare function renderSsePlan(req: Request, res: Response, plan: SseStreamPlan, taskStore: A2ATaskStore): Promise<void>;
|
|
85
|
+
//# sourceMappingURL=sse-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-emitter.d.ts","sourceRoot":"","sources":["../../../src/a2a/producer/sse-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGjE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAWzB,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,OAAO,CAAC;AACzC,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,QAAc,CAAC;AAC7C;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,CA4CjF;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,YAAY,GACtB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|