@nylorun/runtime 0.12.0-beta → 0.14.0-beta

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 (223) hide show
  1. package/CHANGELOG.md +361 -0
  2. package/README.md +69 -15
  3. package/dist/adapters/execution/restate.d.ts +7 -2
  4. package/dist/adapters/execution/restate.js +38 -8
  5. package/dist/adapters/replication/pgoutput.d.ts +16 -0
  6. package/dist/adapters/replication/pgoutput.js +169 -0
  7. package/dist/adapters/streams/s2.js +37 -20
  8. package/dist/admin-openapi.json +1071 -0
  9. package/dist/api/a2a/card.d.ts +15 -0
  10. package/dist/api/a2a/card.js +24 -0
  11. package/dist/api/a2a/endpoint.d.ts +8 -0
  12. package/dist/api/a2a/endpoint.js +81 -0
  13. package/dist/api/a2a/protocol.d.ts +144 -0
  14. package/dist/api/a2a/protocol.js +188 -0
  15. package/dist/api/a2a/routes.d.ts +19 -0
  16. package/dist/api/a2a/routes.js +289 -0
  17. package/dist/api/a2a/tasks.d.ts +50 -0
  18. package/dist/api/a2a/tasks.js +186 -0
  19. package/dist/api/ag-ui/endpoint.d.ts +8 -0
  20. package/dist/api/ag-ui/endpoint.js +126 -0
  21. package/dist/api/ag-ui/history.d.ts +7 -0
  22. package/dist/api/ag-ui/history.js +60 -0
  23. package/dist/api/ag-ui/routes.d.ts +32 -0
  24. package/dist/api/ag-ui/routes.js +305 -0
  25. package/dist/api/ag-ui/session-id.d.ts +1 -0
  26. package/dist/api/ag-ui/session-id.js +12 -0
  27. package/dist/api/ag-ui/sse.d.ts +9 -0
  28. package/dist/api/ag-ui/sse.js +7 -0
  29. package/dist/api/ag-ui/translate.d.ts +38 -0
  30. package/dist/api/ag-ui/translate.js +222 -0
  31. package/dist/api/components.d.ts +7825 -0
  32. package/dist/api/components.js +83 -0
  33. package/dist/api/http/app.d.ts +18 -0
  34. package/dist/api/http/app.js +58 -0
  35. package/dist/api/http/body.d.ts +4 -0
  36. package/dist/api/http/body.js +37 -0
  37. package/dist/api/http/define.d.ts +39 -0
  38. package/dist/api/http/define.js +130 -0
  39. package/dist/api/http/respond.d.ts +9 -0
  40. package/dist/api/http/respond.js +44 -0
  41. package/dist/api/http/routes/access.d.ts +24 -0
  42. package/dist/api/http/routes/access.js +259 -0
  43. package/dist/api/http/routes/actions.d.ts +8 -0
  44. package/dist/api/http/routes/actions.js +76 -0
  45. package/dist/api/http/routes/endpoints.d.ts +7 -0
  46. package/dist/api/http/routes/endpoints.js +100 -0
  47. package/dist/api/http/routes/sessions.d.ts +3 -0
  48. package/dist/api/http/routes/sessions.js +205 -0
  49. package/dist/api/http/routes/tenant.d.ts +10 -0
  50. package/dist/api/http/routes/tenant.js +172 -0
  51. package/dist/api/http/routes/vaults.d.ts +8 -0
  52. package/dist/api/http/routes/vaults.js +167 -0
  53. package/dist/api/openapi.d.ts +19 -0
  54. package/dist/api/openapi.js +138 -0
  55. package/dist/api/route.d.ts +12 -0
  56. package/dist/api/route.js +4 -0
  57. package/dist/core/bearer.d.ts +8 -0
  58. package/dist/core/bearer.js +11 -0
  59. package/dist/core/flow-host.d.ts +7 -15
  60. package/dist/core/flow-host.js +19 -41
  61. package/dist/core/sandbox-routes.d.ts +12 -7
  62. package/dist/core/sandbox-routes.js +24 -25
  63. package/dist/execution/memory.d.ts +8 -5
  64. package/dist/execution/memory.js +33 -13
  65. package/dist/execution/types.d.ts +38 -6
  66. package/dist/execution/types.js +12 -3
  67. package/dist/host/admin-api.d.ts +22 -0
  68. package/dist/host/admin-api.js +178 -0
  69. package/dist/host/app.d.ts +34 -0
  70. package/dist/host/app.js +185 -0
  71. package/dist/host/config-for.d.ts +2 -0
  72. package/dist/host/config-for.js +1 -0
  73. package/dist/host/config.d.ts +11 -0
  74. package/dist/host/cors.d.ts +27 -0
  75. package/dist/host/cors.js +64 -0
  76. package/dist/host/create-host.d.ts +31 -3
  77. package/dist/host/create-host.js +168 -327
  78. package/dist/host/http.d.ts +14 -3
  79. package/dist/host/http.js +64 -23
  80. package/dist/host/main.js +55 -4
  81. package/dist/host/stack-config.d.ts +20 -0
  82. package/dist/host/stack-config.js +55 -0
  83. package/dist/mcp/pool.d.ts +19 -1
  84. package/dist/mcp/pool.js +60 -10
  85. package/dist/model/catalog.d.ts +2 -10
  86. package/dist/model/classify.d.ts +13 -0
  87. package/dist/model/classify.js +61 -0
  88. package/dist/model/models.d.ts +10 -1
  89. package/dist/model/models.js +14 -6
  90. package/dist/model/pi-model.d.ts +17 -2
  91. package/dist/model/pi-model.js +366 -222
  92. package/dist/openapi.json +25696 -0
  93. package/dist/sandbox/manager.d.ts +13 -1
  94. package/dist/sandbox/manager.js +8 -11
  95. package/dist/sandbox/resolve.d.ts +33 -0
  96. package/dist/sandbox/resolve.js +81 -0
  97. package/dist/sandbox/session-sandbox.d.ts +11 -0
  98. package/dist/sandbox/session-sandbox.js +51 -0
  99. package/dist/sandbox/share.d.ts +14 -2
  100. package/dist/sandbox/share.js +33 -3
  101. package/dist/sandbox/tenant-config.d.ts +37 -0
  102. package/dist/sandbox/tenant-config.js +51 -0
  103. package/dist/sandbox/tools.d.ts +7 -9
  104. package/dist/sandbox/tools.js +11 -3
  105. package/dist/sandbox/types.d.ts +8 -2
  106. package/dist/store/event.d.ts +19 -0
  107. package/dist/store/event.js +49 -0
  108. package/dist/store/memory.d.ts +20 -8
  109. package/dist/store/memory.js +265 -100
  110. package/dist/store/postgres/connect.d.ts +13 -0
  111. package/dist/store/postgres/connect.js +5 -0
  112. package/dist/store/postgres/migrations/003_subject_tokens.d.ts +8 -0
  113. package/dist/store/postgres/migrations/003_subject_tokens.js +42 -0
  114. package/dist/store/postgres/migrations/004_publishable_keys.d.ts +6 -0
  115. package/dist/store/postgres/migrations/004_publishable_keys.js +18 -0
  116. package/dist/store/postgres/migrations/005_action_endpoints.d.ts +6 -0
  117. package/dist/store/postgres/migrations/005_action_endpoints.js +32 -0
  118. package/dist/store/postgres/migrations/006_drop_executors.d.ts +11 -0
  119. package/dist/store/postgres/migrations/006_drop_executors.js +32 -0
  120. package/dist/store/postgres/migrations/007_event_time.d.ts +7 -0
  121. package/dist/store/postgres/migrations/007_event_time.js +14 -0
  122. package/dist/store/postgres/migrations/008_durable_streams.d.ts +13 -0
  123. package/dist/store/postgres/migrations/008_durable_streams.js +35 -0
  124. package/dist/store/postgres/migrations/index.d.ts +5 -1
  125. package/dist/store/postgres/migrations/index.js +22 -2
  126. package/dist/store/postgres/migrations/shared/index.d.ts +31 -0
  127. package/dist/store/postgres/migrations/shared/index.js +92 -0
  128. package/dist/store/postgres/record.d.ts +11 -0
  129. package/dist/store/postgres/record.js +64 -0
  130. package/dist/store/postgres/store.js +337 -95
  131. package/dist/store/postgres/tenants.js +14 -0
  132. package/dist/store/types.d.ts +176 -81
  133. package/dist/streams/basin.d.ts +18 -1
  134. package/dist/streams/basin.js +34 -2
  135. package/dist/streams/control.d.ts +18 -0
  136. package/dist/streams/control.js +29 -0
  137. package/dist/streams/memory.d.ts +3 -1
  138. package/dist/streams/memory.js +14 -8
  139. package/dist/streams/relay/core.d.ts +35 -0
  140. package/dist/streams/relay/core.js +366 -0
  141. package/dist/streams/relay/memory.d.ts +69 -0
  142. package/dist/streams/relay/memory.js +176 -0
  143. package/dist/streams/relay/types.d.ts +77 -0
  144. package/dist/streams/relay/types.js +7 -0
  145. package/dist/streams/types.d.ts +66 -36
  146. package/dist/streams/types.js +18 -53
  147. package/dist/tenant/access-policy.d.ts +30 -0
  148. package/dist/tenant/access-policy.js +52 -0
  149. package/dist/tenant/actions.d.ts +10 -149
  150. package/dist/tenant/actions.js +5 -167
  151. package/dist/tenant/advance.js +32 -0
  152. package/dist/tenant/auth.d.ts +19 -17
  153. package/dist/tenant/auth.js +90 -93
  154. package/dist/tenant/browser.d.ts +15 -0
  155. package/dist/tenant/browser.js +39 -0
  156. package/dist/tenant/commands.d.ts +18 -2
  157. package/dist/tenant/commands.js +121 -129
  158. package/dist/tenant/context.d.ts +75 -18
  159. package/dist/tenant/context.js +14 -10
  160. package/dist/tenant/delivery-token.d.ts +41 -0
  161. package/dist/tenant/delivery-token.js +105 -0
  162. package/dist/tenant/delivery.d.ts +62 -0
  163. package/dist/tenant/delivery.js +476 -0
  164. package/dist/tenant/effects.d.ts +5 -0
  165. package/dist/tenant/effects.js +138 -48
  166. package/dist/tenant/endpoints.d.ts +67 -0
  167. package/dist/tenant/endpoints.js +90 -0
  168. package/dist/tenant/ephemeral.d.ts +6 -0
  169. package/dist/tenant/ephemeral.js +60 -36
  170. package/dist/tenant/http.d.ts +8 -9
  171. package/dist/tenant/http.js +13 -27
  172. package/dist/tenant/jwt.d.ts +16 -0
  173. package/dist/tenant/jwt.js +50 -0
  174. package/dist/tenant/module.d.ts +3 -0
  175. package/dist/tenant/module.js +6 -12
  176. package/dist/tenant/outbound.d.ts +44 -0
  177. package/dist/tenant/outbound.js +127 -0
  178. package/dist/tenant/pool.d.ts +0 -2
  179. package/dist/tenant/pool.js +0 -18
  180. package/dist/tenant/reset.d.ts +0 -4
  181. package/dist/tenant/reset.js +0 -5
  182. package/dist/tenant/runtime.d.ts +10 -20
  183. package/dist/tenant/runtime.js +59 -42
  184. package/dist/tenant/scheduler.d.ts +7 -2
  185. package/dist/tenant/scheduler.js +7 -3
  186. package/dist/tenant/session-streams.d.ts +125 -0
  187. package/dist/tenant/session-streams.js +399 -0
  188. package/dist/tenant/sessions.d.ts +28 -4
  189. package/dist/tenant/sessions.js +118 -24
  190. package/dist/tenant/signing-keys.d.ts +55 -0
  191. package/dist/tenant/signing-keys.js +172 -0
  192. package/dist/tenant/slim.d.ts +8 -0
  193. package/dist/tenant/slim.js +21 -0
  194. package/dist/tenant/status.d.ts +0 -3
  195. package/dist/tenant/status.js +19 -12
  196. package/dist/tenant/streams.d.ts +60 -67
  197. package/dist/tenant/streams.js +140 -208
  198. package/dist/tenant/subject-limits.d.ts +16 -0
  199. package/dist/tenant/subject-limits.js +45 -0
  200. package/dist/tenant/sweep.d.ts +1 -10
  201. package/dist/tenant/sweep.js +29 -69
  202. package/dist/tenant/tokens.d.ts +14 -0
  203. package/dist/tenant/tokens.js +178 -0
  204. package/dist/tenant/transcript.d.ts +48 -5
  205. package/dist/tenant/transcript.js +58 -1
  206. package/dist/tenant/types.d.ts +29 -7
  207. package/dist/tenant/worker.d.ts +3 -1
  208. package/dist/tenant/worker.js +9 -3
  209. package/dist/vault/service.d.ts +18 -2
  210. package/dist/vault/service.js +57 -13
  211. package/dist/version.d.ts +1 -1
  212. package/dist/version.js +1 -1
  213. package/package.json +20 -8
  214. package/dist/core/executors.d.ts +0 -44
  215. package/dist/core/executors.js +0 -95
  216. package/dist/streams/relay.d.ts +0 -37
  217. package/dist/streams/relay.js +0 -254
  218. package/dist/tenant/live.d.ts +0 -92
  219. package/dist/tenant/live.js +0 -290
  220. package/dist/tenant/routes-tenant.d.ts +0 -12
  221. package/dist/tenant/routes-tenant.js +0 -137
  222. package/dist/tenant/routes.d.ts +0 -9
  223. package/dist/tenant/routes.js +0 -151
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The Agent Card of one agent, from its manifest: name, description and one skill, never its
3
+ * instructions, tools or MCP servers. The Runtime does not know where callers reach it, so
4
+ * `supportedInterfaces` is empty: whoever publishes the card (the gateway in v1) adds its own
5
+ * URL, provider and security schemes.
6
+ */
7
+ export interface CardDefinition {
8
+ readonly manifest: {
9
+ id?: unknown;
10
+ name?: unknown;
11
+ description?: unknown;
12
+ };
13
+ readonly implementationVersion: string;
14
+ }
15
+ export declare function agentCard(agentId: string, definition: CardDefinition): Record<string, unknown>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The Agent Card of one agent, from its manifest: name, description and one skill, never its
3
+ * instructions, tools or MCP servers. The Runtime does not know where callers reach it, so
4
+ * `supportedInterfaces` is empty: whoever publishes the card (the gateway in v1) adds its own
5
+ * URL, provider and security schemes.
6
+ */
7
+ const MODES = ["text/plain", "application/json"];
8
+ export function agentCard(agentId, definition) {
9
+ const { manifest } = definition;
10
+ const name = typeof manifest.name === "string" && manifest.name !== "" ? manifest.name : agentId;
11
+ const description = typeof manifest.description === "string" && manifest.description !== ""
12
+ ? manifest.description
13
+ : name;
14
+ return {
15
+ name,
16
+ description,
17
+ supportedInterfaces: [],
18
+ version: definition.implementationVersion,
19
+ capabilities: { streaming: false, pushNotifications: false, extendedAgentCard: false },
20
+ defaultInputModes: MODES,
21
+ defaultOutputModes: MODES,
22
+ skills: [{ id: agentId, name, description, tags: [] }],
23
+ };
24
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The A2A endpoint's routes (`/v1/a2a/agents/{agentId}[/card]`), declared for serving and for
3
+ * the Runtime's OpenAPI document. What each does is in `routes.ts`. The JSON-RPC operations are
4
+ * A2A's (specification 1.0); the document describes the envelope and links the specification.
5
+ */
6
+ import type { OpenAPIHono } from "@hono/zod-openapi";
7
+ import type { TenantEnv } from "../http/app.js";
8
+ export declare function a2aRoutes(api: OpenAPIHono<TenantEnv>): void;
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ import { readText } from "../http/body.js";
3
+ import { tenantRoute } from "../http/define.js";
4
+ import { jsonResponse } from "../http/respond.js";
5
+ import { a2aCall, a2aCard } from "./routes.js";
6
+ const A2A_SPECIFICATION = {
7
+ description: "The A2A specification",
8
+ url: "https://a2a-protocol.org/latest/specification/",
9
+ };
10
+ const agentId = z.object({ agentId: z.string() });
11
+ const TAGS = ["A2A"];
12
+ const JsonRpcRequest = z
13
+ .looseObject({
14
+ jsonrpc: z.literal("2.0"),
15
+ id: z.union([z.string(), z.number(), z.null()]).optional(),
16
+ method: z
17
+ .string()
18
+ .meta({ description: "`SendMessage`, `GetTask` or `CancelTask`; others answer their A2A error" }),
19
+ params: z.unknown().optional(),
20
+ })
21
+ .meta({ id: "A2aJsonRpcRequest" });
22
+ const JsonRpcResponse = z
23
+ .looseObject({
24
+ jsonrpc: z.literal("2.0"),
25
+ id: z.union([z.string(), z.number(), z.null()]),
26
+ result: z.unknown().optional(),
27
+ error: z
28
+ .object({ code: z.number().int(), message: z.string(), data: z.unknown().optional() })
29
+ .optional(),
30
+ })
31
+ .meta({ id: "A2aJsonRpcResponse" });
32
+ const AgentCard = z
33
+ .looseObject({ name: z.string(), description: z.string().optional(), skills: z.array(z.unknown()).optional() })
34
+ .meta({ id: "A2aAgentCard", description: "The agent's A2A card, without interfaces" });
35
+ export function a2aRoutes(api) {
36
+ tenantRoute(api, {
37
+ credentials: ["application", "subject", "token"],
38
+ scopes: ["agents:read", "sessions:own"],
39
+ }, {
40
+ method: "get",
41
+ path: "/v1/a2a/agents/{agentId}/card",
42
+ tags: TAGS,
43
+ summary: "Get an agent's A2A card",
44
+ externalDocs: A2A_SPECIFICATION,
45
+ request: { params: agentId },
46
+ responses: {
47
+ 200: { description: "The card", content: { "application/json": { schema: AgentCard } } },
48
+ },
49
+ }, async (c) => {
50
+ const scope = c.get("scope");
51
+ return jsonResponse(200, await a2aCard(c.env.tenant, scope, c.req.param("agentId")));
52
+ });
53
+ tenantRoute(api, { credentials: ["subject", "token"], scopes: ["sessions:own"] }, {
54
+ method: "post",
55
+ path: "/v1/a2a/agents/{agentId}",
56
+ tags: TAGS,
57
+ summary: "Call an agent over A2A",
58
+ description: "A2A 1.0 JSON-RPC, for a subject: `SendMessage` (blocking up to 5 minutes, or `returnImmediately`), `GetTask` and `CancelTask`. A context is one session per subject, agent and `contextId`; a task is one turn. JSON-RPC errors are answered with 200; limits, scopes and unavailable streams stay HTTP errors.",
59
+ externalDocs: A2A_SPECIFICATION,
60
+ request: {
61
+ params: agentId,
62
+ query: z.object({
63
+ "A2A-Version": z.string().optional().meta({ description: "Or the `A2A-Version` header: `1.0`" }),
64
+ }),
65
+ body: { required: true, content: { "application/json": { schema: JsonRpcRequest } } },
66
+ },
67
+ responses: {
68
+ 200: {
69
+ description: "The JSON-RPC answer: a result, or an A2A error",
70
+ content: { "application/json": { schema: JsonRpcResponse } },
71
+ },
72
+ },
73
+ }, async (c) => {
74
+ const scope = c.get("scope");
75
+ const version = c.env.incoming.headers["a2a-version"];
76
+ return jsonResponse(200, await a2aCall(c.env.tenant, scope, c.req.param("agentId"), {
77
+ body: () => readText(c.req.raw),
78
+ version: typeof version === "string" ? version : (c.req.query("A2A-Version") ?? null),
79
+ }, c.env.outgoing));
80
+ });
81
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * A2A 1.0 over JSON-RPC: the wire types the Runtime answers with, the envelope, the error
3
+ * codes and the parameter checks (Host feature `a2a-endpoint`). Only what v1 serves is typed:
4
+ * text and data parts, tasks, the card. Field names are the spec's ProtoJSON (camelCase,
5
+ * enum values such as `TASK_STATE_WORKING`). No Tenant state is read here.
6
+ */
7
+ /** The A2A version this endpoint speaks (`A2A-Version`, Major.Minor). */
8
+ export declare const A2A_VERSION = "1.0";
9
+ export type TaskState = "TASK_STATE_SUBMITTED" | "TASK_STATE_WORKING" | "TASK_STATE_INPUT_REQUIRED" | "TASK_STATE_AUTH_REQUIRED" | "TASK_STATE_COMPLETED" | "TASK_STATE_FAILED" | "TASK_STATE_CANCELED" | "TASK_STATE_REJECTED";
10
+ export declare const TERMINAL_STATES: ReadonlySet<TaskState>;
11
+ export type Part = {
12
+ text: string;
13
+ mediaType?: string;
14
+ metadata?: Record<string, unknown>;
15
+ } | {
16
+ data: unknown;
17
+ mediaType?: string;
18
+ metadata?: Record<string, unknown>;
19
+ };
20
+ export interface Message {
21
+ messageId: string;
22
+ role: "ROLE_USER" | "ROLE_AGENT";
23
+ parts: Part[];
24
+ contextId?: string;
25
+ taskId?: string;
26
+ metadata?: Record<string, unknown>;
27
+ }
28
+ export interface Artifact {
29
+ artifactId: string;
30
+ name?: string;
31
+ parts: Part[];
32
+ }
33
+ export interface TaskStatus {
34
+ state: TaskState;
35
+ message?: Message;
36
+ timestamp?: string;
37
+ }
38
+ export interface Task {
39
+ id: string;
40
+ contextId: string;
41
+ status: TaskStatus;
42
+ artifacts?: Artifact[];
43
+ history?: Message[];
44
+ }
45
+ /** The standard JSON-RPC codes and the A2A codes (spec §5.4, §9.5). */
46
+ export declare const A2A_ERRORS: {
47
+ readonly parse: {
48
+ readonly code: -32700;
49
+ readonly reason: "INVALID_JSON";
50
+ };
51
+ readonly invalidRequest: {
52
+ readonly code: -32600;
53
+ readonly reason: "INVALID_REQUEST";
54
+ };
55
+ readonly methodNotFound: {
56
+ readonly code: -32601;
57
+ readonly reason: "METHOD_NOT_FOUND";
58
+ };
59
+ readonly invalidParams: {
60
+ readonly code: -32602;
61
+ readonly reason: "INVALID_PARAMS";
62
+ };
63
+ readonly internal: {
64
+ readonly code: -32603;
65
+ readonly reason: "INTERNAL";
66
+ };
67
+ readonly taskNotFound: {
68
+ readonly code: -32001;
69
+ readonly reason: "TASK_NOT_FOUND";
70
+ };
71
+ readonly taskNotCancelable: {
72
+ readonly code: -32002;
73
+ readonly reason: "TASK_NOT_CANCELABLE";
74
+ };
75
+ readonly pushNotSupported: {
76
+ readonly code: -32003;
77
+ readonly reason: "PUSH_NOTIFICATION_NOT_SUPPORTED";
78
+ };
79
+ readonly unsupportedOperation: {
80
+ readonly code: -32004;
81
+ readonly reason: "UNSUPPORTED_OPERATION";
82
+ };
83
+ readonly contentTypeNotSupported: {
84
+ readonly code: -32005;
85
+ readonly reason: "CONTENT_TYPE_NOT_SUPPORTED";
86
+ };
87
+ readonly versionNotSupported: {
88
+ readonly code: -32009;
89
+ readonly reason: "VERSION_NOT_SUPPORTED";
90
+ };
91
+ };
92
+ export type A2aErrorKind = keyof typeof A2A_ERRORS;
93
+ /** An error answered in the JSON-RPC body, with `google.rpc.ErrorInfo` (and `BadRequest`). */
94
+ export declare class A2aError extends Error {
95
+ readonly kind: A2aErrorKind;
96
+ readonly metadata: Readonly<Record<string, string>>;
97
+ /** `google.rpc.BadRequest` field violations, for invalid parameters. */
98
+ readonly field?: string | undefined;
99
+ constructor(kind: A2aErrorKind, message: string, metadata?: Readonly<Record<string, string>>,
100
+ /** `google.rpc.BadRequest` field violations, for invalid parameters. */
101
+ field?: string | undefined);
102
+ }
103
+ export declare const a2aFail: (kind: A2aErrorKind, message: string, metadata?: Record<string, string>, field?: string) => never;
104
+ export type JsonRpcId = string | number | null;
105
+ export interface JsonRpcRequest {
106
+ id: JsonRpcId;
107
+ method: string;
108
+ params: Record<string, unknown>;
109
+ }
110
+ export declare function jsonRpcResult(id: JsonRpcId, result: unknown): unknown;
111
+ export declare function jsonRpcError(id: JsonRpcId, error: A2aError): unknown;
112
+ /** A JSON-RPC 2.0 request object, or an `A2aError` (`id` recovered when possible). */
113
+ export declare function parseEnvelope(text: string): {
114
+ ok: true;
115
+ request: JsonRpcRequest;
116
+ } | {
117
+ ok: false;
118
+ id: JsonRpcId;
119
+ error: A2aError;
120
+ };
121
+ /** `A2A-Version` as Major.Minor; empty means 0.3 (spec §3.6.2). */
122
+ export declare function checkVersion(value: string | null | undefined): void;
123
+ /** A client's message reduced to what the Runtime runs: text, or one JSON value. */
124
+ export type MessageInput = {
125
+ content: string;
126
+ } | {
127
+ data: unknown;
128
+ };
129
+ export interface SendParams {
130
+ messageId: string;
131
+ contextId?: string;
132
+ taskId?: string;
133
+ input: MessageInput;
134
+ returnImmediately: boolean;
135
+ historyLength?: number;
136
+ }
137
+ export declare function parseHistoryLength(value: unknown, field: string): number | undefined;
138
+ /** `SendMessage` params (spec §3.2.1), checked in the order a client can fix them. */
139
+ export declare function parseSendParams(params: Record<string, unknown>): SendParams;
140
+ /** `GetTask` and `CancelTask` params: the task id (and `historyLength` for `GetTask`). */
141
+ export declare function parseTaskParams(params: Record<string, unknown>): {
142
+ id: string;
143
+ historyLength?: number;
144
+ };
@@ -0,0 +1,188 @@
1
+ /**
2
+ * A2A 1.0 over JSON-RPC: the wire types the Runtime answers with, the envelope, the error
3
+ * codes and the parameter checks (Host feature `a2a-endpoint`). Only what v1 serves is typed:
4
+ * text and data parts, tasks, the card. Field names are the spec's ProtoJSON (camelCase,
5
+ * enum values such as `TASK_STATE_WORKING`). No Tenant state is read here.
6
+ */
7
+ /** The A2A version this endpoint speaks (`A2A-Version`, Major.Minor). */
8
+ export const A2A_VERSION = "1.0";
9
+ export const TERMINAL_STATES = new Set([
10
+ "TASK_STATE_COMPLETED",
11
+ "TASK_STATE_FAILED",
12
+ "TASK_STATE_CANCELED",
13
+ "TASK_STATE_REJECTED",
14
+ ]);
15
+ /** The standard JSON-RPC codes and the A2A codes (spec §5.4, §9.5). */
16
+ export const A2A_ERRORS = {
17
+ parse: { code: -32700, reason: "INVALID_JSON" },
18
+ invalidRequest: { code: -32600, reason: "INVALID_REQUEST" },
19
+ methodNotFound: { code: -32601, reason: "METHOD_NOT_FOUND" },
20
+ invalidParams: { code: -32602, reason: "INVALID_PARAMS" },
21
+ internal: { code: -32603, reason: "INTERNAL" },
22
+ taskNotFound: { code: -32001, reason: "TASK_NOT_FOUND" },
23
+ taskNotCancelable: { code: -32002, reason: "TASK_NOT_CANCELABLE" },
24
+ pushNotSupported: { code: -32003, reason: "PUSH_NOTIFICATION_NOT_SUPPORTED" },
25
+ unsupportedOperation: { code: -32004, reason: "UNSUPPORTED_OPERATION" },
26
+ contentTypeNotSupported: { code: -32005, reason: "CONTENT_TYPE_NOT_SUPPORTED" },
27
+ versionNotSupported: { code: -32009, reason: "VERSION_NOT_SUPPORTED" },
28
+ };
29
+ /** An error answered in the JSON-RPC body, with `google.rpc.ErrorInfo` (and `BadRequest`). */
30
+ export class A2aError extends Error {
31
+ kind;
32
+ metadata;
33
+ field;
34
+ constructor(kind, message, metadata = {},
35
+ /** `google.rpc.BadRequest` field violations, for invalid parameters. */
36
+ field) {
37
+ super(message);
38
+ this.kind = kind;
39
+ this.metadata = metadata;
40
+ this.field = field;
41
+ this.name = "A2aError";
42
+ }
43
+ }
44
+ export const a2aFail = (kind, message, metadata, field) => {
45
+ throw new A2aError(kind, message, metadata, field);
46
+ };
47
+ export function jsonRpcResult(id, result) {
48
+ return { jsonrpc: "2.0", id, result };
49
+ }
50
+ export function jsonRpcError(id, error) {
51
+ const { code, reason } = A2A_ERRORS[error.kind];
52
+ const data = [
53
+ {
54
+ "@type": "type.googleapis.com/google.rpc.ErrorInfo",
55
+ reason,
56
+ domain: "a2a-protocol.org",
57
+ metadata: { ...error.metadata },
58
+ },
59
+ ];
60
+ if (error.field !== undefined)
61
+ data.push({
62
+ "@type": "type.googleapis.com/google.rpc.BadRequest",
63
+ fieldViolations: [{ field: error.field, description: error.message }],
64
+ });
65
+ return { jsonrpc: "2.0", id, error: { code, message: error.message, data } };
66
+ }
67
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
68
+ /** A JSON-RPC 2.0 request object, or an `A2aError` (`id` recovered when possible). */
69
+ export function parseEnvelope(text) {
70
+ let body;
71
+ try {
72
+ body = JSON.parse(text);
73
+ }
74
+ catch {
75
+ return { ok: false, id: null, error: new A2aError("parse", "Invalid JSON payload") };
76
+ }
77
+ const invalid = (id, message) => ({
78
+ ok: false,
79
+ id,
80
+ error: new A2aError("invalidRequest", message),
81
+ });
82
+ if (!isObject(body))
83
+ return invalid(null, "The body must be one JSON-RPC request object");
84
+ const id = body.id;
85
+ const validId = typeof id === "string" || (typeof id === "number" && Number.isFinite(id)) || id === null;
86
+ const safeId = validId ? id : null;
87
+ if (body.jsonrpc !== "2.0")
88
+ return invalid(safeId, 'jsonrpc must be "2.0"');
89
+ // A2A has no notifications: every request is answered, so it needs an id.
90
+ if (!("id" in body) || !validId)
91
+ return invalid(null, "The request needs an id");
92
+ if (typeof body.method !== "string" || body.method === "")
93
+ return invalid(safeId, "The request needs a method");
94
+ if (body.params !== undefined && !isObject(body.params))
95
+ return invalid(safeId, "params must be an object");
96
+ return {
97
+ ok: true,
98
+ request: {
99
+ id: safeId,
100
+ method: body.method,
101
+ params: body.params ?? {},
102
+ },
103
+ };
104
+ }
105
+ /** `A2A-Version` as Major.Minor; empty means 0.3 (spec §3.6.2). */
106
+ export function checkVersion(value) {
107
+ const trimmed = (value ?? "").trim();
108
+ const [major, minor] = trimmed === "" ? ["0", "3"] : trimmed.split(".");
109
+ if (`${major}.${minor}` !== A2A_VERSION)
110
+ a2aFail("versionNotSupported", `A2A version ${trimmed === "" ? "0.3" : trimmed} is not supported; send A2A-Version: ${A2A_VERSION}`, { supportedVersions: A2A_VERSION });
111
+ }
112
+ const MAX_ID = 200;
113
+ const VISIBLE = /^[\x21-\x7e]+$/;
114
+ function checkId(value, field, required) {
115
+ if (value === undefined && !required)
116
+ return undefined;
117
+ if (typeof value !== "string" || value.length === 0)
118
+ return a2aFail("invalidParams", `${field} must be a non-empty string`, {}, field);
119
+ if (value.length > MAX_ID || !VISIBLE.test(value))
120
+ return a2aFail("invalidParams", `${field} must be 1 to ${MAX_ID} visible ASCII characters`, {}, field);
121
+ return value;
122
+ }
123
+ export function parseHistoryLength(value, field) {
124
+ if (value === undefined || value === null)
125
+ return undefined;
126
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0)
127
+ return a2aFail("invalidParams", `${field} must be a non-negative integer`, {}, field);
128
+ return value;
129
+ }
130
+ /** The input of one part: exactly one of `text`, `raw`, `url`, `data` (spec §4.1.6). */
131
+ function partKind(part, field) {
132
+ if (!isObject(part))
133
+ return a2aFail("invalidParams", `${field} must be an object`, {}, field);
134
+ const kinds = ["text", "raw", "url", "data"].filter((k) => part[k] !== undefined);
135
+ if (kinds.length !== 1)
136
+ return a2aFail("invalidParams", `${field} must contain exactly one of text, raw, url, data`, {}, field);
137
+ if (kinds[0] === "text" && typeof part.text !== "string")
138
+ return a2aFail("invalidParams", `${field}.text must be a string`, {}, `${field}.text`);
139
+ return kinds[0] === "raw" || kinds[0] === "url" ? "file" : kinds[0];
140
+ }
141
+ /** `SendMessage` params (spec §3.2.1), checked in the order a client can fix them. */
142
+ export function parseSendParams(params) {
143
+ const message = params.message;
144
+ if (!isObject(message))
145
+ return a2aFail("invalidParams", "message is required", {}, "message");
146
+ const messageId = checkId(message.messageId, "message.messageId", true);
147
+ if (message.role !== "ROLE_USER")
148
+ a2aFail("invalidParams", 'message.role must be "ROLE_USER"', {}, "message.role");
149
+ const contextId = checkId(message.contextId, "message.contextId", false);
150
+ const taskId = checkId(message.taskId, "message.taskId", false);
151
+ if (!Array.isArray(message.parts) || message.parts.length === 0)
152
+ a2aFail("invalidParams", "At least one part is required", {}, "message.parts");
153
+ const parts = message.parts;
154
+ const kinds = parts.map((part, index) => partKind(part, `message.parts[${index}]`));
155
+ const configuration = params.configuration;
156
+ if (configuration !== undefined && !isObject(configuration))
157
+ a2aFail("invalidParams", "configuration must be an object", {}, "configuration");
158
+ const config = (configuration ?? {});
159
+ if (config.taskPushNotificationConfig !== undefined && config.taskPushNotificationConfig !== null)
160
+ a2aFail("pushNotSupported", "Push notifications are not supported");
161
+ if (config.returnImmediately !== undefined && typeof config.returnImmediately !== "boolean")
162
+ a2aFail("invalidParams", "configuration.returnImmediately must be a boolean", {}, "configuration.returnImmediately");
163
+ const historyLength = parseHistoryLength(config.historyLength, "configuration.historyLength");
164
+ let input;
165
+ if (kinds.every((kind) => kind === "text"))
166
+ input = { content: parts.map((part) => part.text).join("\n") };
167
+ else if (kinds.length === 1 && kinds[0] === "data")
168
+ input = { data: parts[0].data };
169
+ else
170
+ return a2aFail("contentTypeNotSupported", "This agent accepts text parts, or a single data part; files are not supported", { accepted: "text/plain,application/json" });
171
+ if ("content" in input && input.content.trim() === "")
172
+ a2aFail("invalidParams", "The message has no text", {}, "message.parts");
173
+ return {
174
+ messageId,
175
+ ...(contextId !== undefined ? { contextId } : {}),
176
+ ...(taskId !== undefined ? { taskId } : {}),
177
+ input,
178
+ returnImmediately: config.returnImmediately === true,
179
+ ...(historyLength !== undefined ? { historyLength } : {}),
180
+ };
181
+ }
182
+ /** `GetTask` and `CancelTask` params: the task id (and `historyLength` for `GetTask`). */
183
+ export function parseTaskParams(params) {
184
+ if (typeof params.id !== "string" || params.id === "")
185
+ return a2aFail("invalidParams", "id is required", {}, "id");
186
+ const historyLength = parseHistoryLength(params.historyLength, "historyLength");
187
+ return { id: params.id, ...(historyLength !== undefined ? { historyLength } : {}) };
188
+ }
@@ -0,0 +1,19 @@
1
+ import type { ServerResponse } from "node:http";
2
+ import { type AuthScope, type TenantContext } from "../../tenant/context.js";
3
+ /**
4
+ * How long a blocking `SendMessage` waits for the task to end or ask for input. After it, the
5
+ * task is returned `WORKING` and keeps running; the caller polls `GetTask`.
6
+ */
7
+ export declare const A2A_BLOCKING_WAIT_MS: number;
8
+ /** `GET /v1/a2a/agents/:agent/card`: the agent's card, for a caller who may use the agent. */
9
+ export declare function a2aCard(ctx: TenantContext, scope: AuthScope, agentId: string): Promise<unknown>;
10
+ /**
11
+ * `POST /v1/a2a/agents/:agent`: one A2A JSON-RPC call, for a subject. JSON-RPC answers (errors
12
+ * included) are the body to send with 200; HTTP-level refusals (unknown agent, no subject,
13
+ * limits) are thrown as `HttpError` like any Tenant route. `body` is read once the agent is
14
+ * known to be the caller's; closing `response` stops a blocking wait, never the task.
15
+ */
16
+ export declare function a2aCall(ctx: TenantContext, scope: AuthScope, agentId: string, input: {
17
+ body: () => Promise<string>;
18
+ version: string | null;
19
+ }, response: ServerResponse): Promise<unknown>;