@ap3x/a2a 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +27 -0
  3. package/dist/backend.d.ts +89 -0
  4. package/dist/backend.d.ts.map +1 -0
  5. package/dist/bindings/grpc.d.ts +121 -0
  6. package/dist/bindings/grpc.d.ts.map +1 -0
  7. package/dist/bindings/jsonrpc.d.ts +135 -0
  8. package/dist/bindings/jsonrpc.d.ts.map +1 -0
  9. package/dist/bindings/rest.d.ts +75 -0
  10. package/dist/bindings/rest.d.ts.map +1 -0
  11. package/dist/chunk-PYM7LV6R.js +1590 -0
  12. package/dist/client.d.ts +116 -0
  13. package/dist/client.d.ts.map +1 -0
  14. package/dist/executor.d.ts +91 -0
  15. package/dist/executor.d.ts.map +1 -0
  16. package/dist/grpc-5DAU6EYQ.js +591 -0
  17. package/dist/index.d.ts +9 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +454 -0
  20. package/dist/model.d.ts +480 -0
  21. package/dist/model.d.ts.map +1 -0
  22. package/dist/server.d.ts +60 -0
  23. package/dist/server.d.ts.map +1 -0
  24. package/dist/task-store.d.ts +61 -0
  25. package/dist/task-store.d.ts.map +1 -0
  26. package/package.json +26 -15
  27. package/proto/a2a.proto +813 -0
  28. package/proto/google/api/annotations.proto +6 -0
  29. package/proto/google/api/client.proto +4 -0
  30. package/proto/google/api/field_behavior.proto +4 -0
  31. package/src/__tests__/a2a-auth-expired.test.ts +0 -84
  32. package/src/__tests__/a2a.test.ts +0 -87
  33. package/src/__tests__/handler-sendsubscribe-error.test.ts +0 -32
  34. package/src/__tests__/sendsubscribe-rejected-promise.test.ts +0 -89
  35. package/src/__tests__/server-apikey-warning.test.ts +0 -71
  36. package/src/__tests__/server-body-limit.test.ts +0 -54
  37. package/src/__tests__/server-security-headers.test.ts +0 -112
  38. package/src/__tests__/server-timing-safe-auth.test.ts +0 -45
  39. package/src/__tests__/sse-handler-error-propagation.test.ts +0 -69
  40. package/src/card/generator.ts +0 -18
  41. package/src/client/index.ts +0 -172
  42. package/src/errors.ts +0 -21
  43. package/src/index.ts +0 -15
  44. package/src/server/handler.ts +0 -90
  45. package/src/server/index.ts +0 -208
  46. package/src/server/sse.ts +0 -49
  47. package/src/swarm/a2a-agent.ts +0 -34
  48. package/src/types.ts +0 -50
  49. package/tsconfig.json +0 -20
  50. package/vitest.config.ts +0 -4
@@ -0,0 +1,116 @@
1
+ import { type AgentCard, type Message, type RemoteAgentCard, type Task, type TaskArtifactUpdateEvent, type TaskStatusUpdateEvent } from "./model";
2
+ import type { ListTasksFilter } from "./task-store";
3
+ /** Header carrying the protocol version on every client request. */
4
+ export declare const A2A_VERSION_HEADER = "A2A-Version";
5
+ /** Default per-request timeout: remote agents can be whole orchestrators. */
6
+ export declare const DEFAULT_TIMEOUT_MS: number;
7
+ /** Any client-side protocol failure: HTTP, envelope, validation, RPC error. */
8
+ export declare class A2aClientError extends Error {
9
+ /** JSON-RPC error code when the server answered with an error object. */
10
+ readonly code?: number;
11
+ constructor(message: string, code?: number);
12
+ }
13
+ export interface A2aClientOptions {
14
+ /** Sent as `Authorization: Bearer <token>` on every request. */
15
+ bearerToken?: string;
16
+ /** Injectable fetch (tests); defaults to the global. */
17
+ fetch?: typeof globalThis.fetch;
18
+ /** Per-request timeout in milliseconds. Default {@link DEFAULT_TIMEOUT_MS}. */
19
+ timeoutMs?: number;
20
+ }
21
+ export interface SendMessageConfig {
22
+ /**
23
+ * When true, ask the server to return the Task snapshot immediately instead
24
+ * of waiting for the terminal state. Default false — `SendMessage` is
25
+ * blocking by default per the v1.0.0 spec.
26
+ */
27
+ returnImmediately?: boolean;
28
+ }
29
+ export type A2aStreamFrame = Task | TaskStatusUpdateEvent | TaskArtifactUpdateEvent | Message;
30
+ /**
31
+ * Whether a stream frame is the Task object. Discriminates structurally: our
32
+ * Task model carries no `kind`, but a peer that tags Tasks with `kind: "task"`
33
+ * (0.2.x style) is accepted too — a residual v1.0 doubt, see the binding.
34
+ * A kindless frame is a Task unless it carries a Message's `messageId`.
35
+ */
36
+ export declare function isTaskFrame(frame: A2aStreamFrame): frame is Task;
37
+ /**
38
+ * Whether a stream frame is a bare Message (a peer answering directly with no
39
+ * task). Only Message frames carry a top-level `messageId`, so the check also
40
+ * accepts a peer that omits `kind: "message"`.
41
+ */
42
+ export declare function isMessageFrame(frame: A2aStreamFrame): frame is Message;
43
+ /** Whether a stream frame is a TaskStatusUpdateEvent. */
44
+ export declare function isStatusUpdateFrame(frame: A2aStreamFrame): frame is TaskStatusUpdateEvent;
45
+ /** The transports this client can negotiate, in preference order. */
46
+ export type A2aClientTransport = "JSONRPC" | "HTTP+JSON" | "GRPC";
47
+ /**
48
+ * Normalize a LIBERALLY-parsed remote card into the canonical
49
+ * {@link AgentCard}. The reference SDK (0.3.x) exposes the endpoint via
50
+ * top-level `url` + `preferredTransport` (plus `additionalInterfaces`); AP3X
51
+ * cards use `interfaces`. Both collapse into one deduplicated `interfaces`
52
+ * list (top-level endpoint first — it is the peer's declared preference);
53
+ * transports this client cannot speak are dropped. Fields we model loosely
54
+ * (skills, securitySchemes, provider) are carried over only when they match
55
+ * our schemas — a peer's exotic security scheme must not sink the connect.
56
+ */
57
+ export declare function normalizeRemoteCard(card: RemoteAgentCard): AgentCard;
58
+ export declare class A2aClient {
59
+ /** The Agent Card fetched (once) at connect time. */
60
+ readonly card: AgentCard;
61
+ /** The transport negotiated from the card (JSONRPC preferred). */
62
+ readonly transport: A2aClientTransport;
63
+ private readonly endpoint;
64
+ private readonly fetchImpl;
65
+ private readonly timeoutMs;
66
+ private readonly bearerToken?;
67
+ private nextId;
68
+ /** Present exactly when `transport` is GRPC (lazy-loaded at connect time). */
69
+ private grpcTransport?;
70
+ private constructor();
71
+ /**
72
+ * Fetch + validate the Agent Card from the well-known path, negotiate the
73
+ * transport (JSONRPC preferred, then HTTP+JSON, then GRPC as a last resort),
74
+ * and return a connected client.
75
+ */
76
+ static connect(baseUrl: string, options?: A2aClientOptions): Promise<A2aClient>;
77
+ /** Release transport resources (the gRPC channel; HTTP needs nothing). */
78
+ close(): void;
79
+ /**
80
+ * `SendMessage` — blocking by default; returns the (validated) Task
81
+ * snapshot, or a bare Message when the peer's executor answered directly
82
+ * without creating a task (a Task has `status`, a Message does not).
83
+ *
84
+ * `signal` cancels the in-flight HTTP request (combined with the per-request
85
+ * timeout). The gRPC transport relies on its own deadline — best-effort.
86
+ */
87
+ sendMessage(message: Message, config?: SendMessageConfig, signal?: AbortSignal): Promise<Task | Message>;
88
+ /** `SendStreamingMessage` — SSE: the Task object first, then update events. */
89
+ sendStreamingMessage(message: Message, signal?: AbortSignal): AsyncGenerator<A2aStreamFrame>;
90
+ /** `GetTask`. */
91
+ getTask(id: string, signal?: AbortSignal): Promise<Task>;
92
+ /** `ListTasks`. */
93
+ listTasks(filter?: ListTasksFilter): Promise<Task[]>;
94
+ /** `CancelTask`. */
95
+ cancelTask(id: string): Promise<Task>;
96
+ /** `SubscribeToTask` — SSE: the Task snapshot first, then update events. */
97
+ subscribeToTask(id: string): AsyncGenerator<A2aStreamFrame>;
98
+ private headers;
99
+ /** Per-request timeout signal, optionally combined with a caller's signal. */
100
+ private requestSignal;
101
+ private post;
102
+ private rpc;
103
+ /** Validate a JSON-RPC response envelope; throw the server's error typed. */
104
+ private unwrap;
105
+ private expect;
106
+ private rpcSse;
107
+ private parseSseFrame;
108
+ /** The raw `data:` payloads of an SSE response — shared by both transports. */
109
+ private sseData;
110
+ private restRequest;
111
+ /** Map a non-2xx REST answer to a typed error carrying the A2A code. */
112
+ private restErrorFrom;
113
+ private restJson;
114
+ private restSse;
115
+ }
116
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * A2aExecutor: fulfills A2A tasks by running ANY {@link AgentBackend}.
3
+ *
4
+ * The executor is the SOLE WRITER of TaskStore tasks — every public read
5
+ * returns a deep copy so callers (HTTP bindings, tests) can never mutate
6
+ * around the state machine. All runs route through the shared agent-core
7
+ * limiter, so a request flood cannot fan out unbounded. Deterministic: the
8
+ * clock is injected and threaded into the store.
9
+ */
10
+ import { type AgentBackend, type AgentMessage } from "@ap3x/agent-core";
11
+ import { type Message, type Task } from "./model";
12
+ import { type ListTasksFilter, type TaskSubscriber } from "./task-store";
13
+ export interface A2aExecutorOptions {
14
+ /** Injected clock (epoch millis). */
15
+ now: () => number;
16
+ /** Cap on concurrently running backend tasks. Default: max(4, availableParallelism()). */
17
+ maxConcurrentTasks?: number;
18
+ /** Retain at most this many TERMINAL tasks (see {@link TaskStore}). Default: unbounded. */
19
+ maxRetainedTasks?: number;
20
+ /**
21
+ * Retain at most this many contextId transcripts, evicting the
22
+ * LEAST-RECENTLY-USED context beyond the cap (an active multi-turn thread is
23
+ * never evicted just for being old). An evicted context loses only its prior
24
+ * conversational transcript — the next message on it starts fresh; no error,
25
+ * no task loss. Default: unbounded — long-lived servers should set it.
26
+ */
27
+ maxRetainedContexts?: number;
28
+ }
29
+ export interface SendMessageOptions {
30
+ /** When true, resolve only once the task reaches a terminal state. Default false. */
31
+ blocking?: boolean;
32
+ /**
33
+ * Fired with the Task snapshot BEFORE the run starts — the spec-mandated
34
+ * first frame of a stream (the stream MUST begin with the Task object).
35
+ */
36
+ onTask?: (task: Task) => void;
37
+ /**
38
+ * Status subscriber attached BEFORE the run starts, so a streaming consumer
39
+ * can never miss an event.
40
+ */
41
+ onEvent?: TaskSubscriber;
42
+ }
43
+ /** Concatenated text rendering of an A2A message's parts. */
44
+ export declare function messageText(message: Message): string;
45
+ /** Concatenated text of an agent-core transcript message. */
46
+ export declare function agentMessageText(message: AgentMessage): string;
47
+ export declare class A2aExecutor {
48
+ private readonly backend;
49
+ private readonly store;
50
+ private readonly now;
51
+ private readonly limit;
52
+ /**
53
+ * contextId -> transcript so a follow-up message keeps its conversational
54
+ * thread. Access-ordered (delete + re-set on touch) so Map insertion order
55
+ * doubles as LRU order for {@link maxRetainedContexts} eviction.
56
+ */
57
+ private readonly transcripts;
58
+ private readonly maxRetainedContexts?;
59
+ private readonly aborts;
60
+ constructor(backend: AgentBackend, options: A2aExecutorOptions);
61
+ /** Whether the wrapped backend supports incremental streaming. */
62
+ get streaming(): boolean;
63
+ /** Accept an inbound message: create a task and run the backend against it. */
64
+ sendMessage(message: Message, options?: SendMessageOptions): Promise<Task>;
65
+ /** Deep-copied task lookup (undefined when unknown). */
66
+ getTask(id: string): Task | undefined;
67
+ /** Deep-copied task listing. */
68
+ listTasks(filter?: ListTasksFilter): Task[];
69
+ /**
70
+ * Cancel a task: best-effort abort of the underlying run + store cancel.
71
+ * A backend without `abort` still cancels — the guarded terminal write in
72
+ * {@link execute} discards the late result. Throws TaskNotFoundError /
73
+ * IllegalTaskTransitionError for unknown / already-terminal tasks.
74
+ */
75
+ cancel(taskId: string): Task;
76
+ /** Subscribe to a task's status updates; returns an unsubscribe function. */
77
+ subscribe(taskId: string, fn: TaskSubscriber): () => void;
78
+ /** LRU read: touching a context moves it to the back of the eviction order. */
79
+ private recallTranscript;
80
+ /** LRU write: (re-)insert at the back, then evict the oldest beyond the cap. */
81
+ private retainTranscript;
82
+ private snapshot;
83
+ private agentMessage;
84
+ /**
85
+ * Terminal write, guarded: a task canceled mid-run stays canceled — the
86
+ * store's terminal-state rejection is caught and the late result discarded.
87
+ */
88
+ private finish;
89
+ private execute;
90
+ }
91
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EAMlB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,OAAO,EAAa,KAAK,IAAI,EAA8B,MAAM,SAAS,CAAC;AACzF,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,0FAA0F;IAC1F,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CASpD;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAe9D;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAChE;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;IACjE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;gBAEjD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,kBAAkB;IAe9D,kEAAkE;IAClE,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,+EAA+E;IACzE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBpF,wDAAwD;IACxD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIrC,gCAAgC;IAChC,SAAS,CAAC,MAAM,GAAE,eAAoB,GAAG,IAAI,EAAE;IAI/C;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO5B,6EAA6E;IAC7E,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc,GAAG,MAAM,IAAI;IAIzD,+EAA+E;IAC/E,OAAO,CAAC,gBAAgB;IASxB,gFAAgF;IAChF,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,YAAY;IAKpB;;;OAGG;IACH,OAAO,CAAC,MAAM;YAYA,OAAO;CAyFtB"}