@agentapplicationprotocol/sdk 0.1.0 → 0.2.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/README.md CHANGED
@@ -11,6 +11,9 @@ TypeScript SDK for the [Agent Application Protocol (AAP)](https://github.com/age
11
11
  npm install @agentapplicationprotocol/sdk
12
12
  ```
13
13
 
14
- ## [Examples](./src/examples/)
14
+ ## Examples
15
15
 
16
- ## [CHANGELOG](./CHANGELOG.md)
16
+ - [Web playground](https://agentapplicationprotocol.github.io/playground/)
17
+ - [Example agents](https://github.com/agentapplicationprotocol/agents)
18
+
19
+ ## [CHANGELOG](./CHANGELOG.md)
package/dist/client.d.ts CHANGED
@@ -15,8 +15,17 @@ export declare class Client {
15
15
  constructor({ baseUrl, apiKey }: ClientOptions);
16
16
  private url;
17
17
  private request;
18
+ private streamRequest;
18
19
  /** GET /meta */
19
20
  getMeta(): Promise<MetaResponse>;
21
+ /** GET /sessions */
22
+ listSessions(params?: {
23
+ after?: string;
24
+ }): Promise<SessionListResponse>;
25
+ /** Fetches all session IDs across all pages. */
26
+ listAllSessions(): Promise<string[]>;
27
+ /** GET /session/:id */
28
+ getSession(sessionId: string): Promise<SessionResponse>;
20
29
  /** PUT /session — non-streaming */
21
30
  createSession(req: CreateSessionRequest & {
22
31
  stream?: "none";
@@ -33,14 +42,6 @@ export declare class Client {
33
42
  sendTurn(sessionId: string, req: SessionTurnRequest & {
34
43
  stream: "delta" | "message";
35
44
  }): Promise<AsyncIterable<SSEEvent>>;
36
- /** GET /session/:id */
37
- getSession(sessionId: string): Promise<SessionResponse>;
38
- /** GET /sessions */
39
- listSessions(params?: {
40
- limit?: number;
41
- after?: string;
42
- }): Promise<SessionListResponse>;
43
45
  /** DELETE /session/:id */
44
46
  deleteSession(sessionId: string): Promise<void>;
45
- private streamRequest;
46
47
  }
package/dist/client.js CHANGED
@@ -15,7 +15,10 @@ exports.ClientError = ClientError;
15
15
  class Client {
16
16
  constructor({ baseUrl, apiKey }) {
17
17
  this.baseUrl = baseUrl.replace(/\/$/, "");
18
- this.headers = { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` };
18
+ this.headers = {
19
+ "Content-Type": "application/json",
20
+ Authorization: `Bearer ${apiKey}`,
21
+ };
19
22
  }
20
23
  url(path) {
21
24
  return `${this.baseUrl}${path}`;
@@ -34,11 +37,48 @@ class Client {
34
37
  return undefined;
35
38
  return res.json();
36
39
  }
40
+ async streamRequest(method, path, body) {
41
+ const res = await fetch(this.url(path), {
42
+ method,
43
+ headers: { ...this.headers, Accept: "text/event-stream" },
44
+ body: JSON.stringify(body),
45
+ });
46
+ if (!res.ok || !res.body) {
47
+ const text = await res.text().catch(() => res.statusText);
48
+ throw new ClientError(method, path, res.status, text);
49
+ }
50
+ return parseSSE(res.body);
51
+ }
37
52
  /** GET /meta */
38
53
  getMeta() {
39
54
  return this.request("GET", "/meta");
40
55
  }
56
+ /** GET /sessions */
57
+ listSessions(params) {
58
+ let path = "/sessions";
59
+ if (params?.after) {
60
+ path += "?" + new URLSearchParams({ after: params.after }).toString();
61
+ }
62
+ return this.request("GET", path);
63
+ }
64
+ /** Fetches all session IDs across all pages. */
65
+ async listAllSessions() {
66
+ const sessions = [];
67
+ let after;
68
+ do {
69
+ const res = await this.listSessions({ after });
70
+ sessions.push(...res.sessions);
71
+ after = res.next;
72
+ } while (after);
73
+ return sessions;
74
+ }
75
+ /** GET /session/:id */
76
+ getSession(sessionId) {
77
+ return this.request("GET", `/session/${sessionId}`);
78
+ }
41
79
  createSession(req) {
80
+ if (req.messages.at(-1)?.role !== "user")
81
+ throw new Error("Last message must be a user message");
42
82
  if (req.stream === "delta" || req.stream === "message") {
43
83
  return this.streamRequest("PUT", "/session", req);
44
84
  }
@@ -50,37 +90,10 @@ class Client {
50
90
  }
51
91
  return this.request("POST", `/session/${sessionId}`, req);
52
92
  }
53
- /** GET /session/:id */
54
- getSession(sessionId) {
55
- return this.request("GET", `/session/${sessionId}`);
56
- }
57
- /** GET /sessions */
58
- listSessions(params) {
59
- let path = "/sessions";
60
- if (params) {
61
- const entries = Object.entries(params).filter((e) => e[1] !== undefined);
62
- if (entries.length > 0) {
63
- path += "?" + new URLSearchParams(entries.map(([k, v]) => [k, String(v)])).toString();
64
- }
65
- }
66
- return this.request("GET", path);
67
- }
68
93
  /** DELETE /session/:id */
69
94
  deleteSession(sessionId) {
70
95
  return this.request("DELETE", `/session/${sessionId}`);
71
96
  }
72
- async streamRequest(method, path, body) {
73
- const res = await fetch(this.url(path), {
74
- method,
75
- headers: { ...this.headers, Accept: "text/event-stream" },
76
- body: JSON.stringify(body),
77
- });
78
- if (!res.ok || !res.body) {
79
- const text = await res.text().catch(() => res.statusText);
80
- throw new ClientError(method, path, res.status, text);
81
- }
82
- return parseSSE(res.body);
83
- }
84
97
  }
85
98
  exports.Client = Client;
86
99
  async function* parseSSE(body) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { Client, ClientError } from "./client";
2
2
  export type { ClientOptions } from "./client";
3
- export { Server, writeSSEEvents } from "./server";
3
+ export { Server } from "./server";
4
4
  export type { ServerHandler, ServerOptions } from "./server";
5
- export type { Message, ToolPermissionMessage, ContentBlock, ToolSpec, ServerToolRef, AgentOption, StreamMode, StopReason, JSONSchema, AgentConfig, CreateSessionRequest, SessionTurnRequest, AgentResponse, SessionResponse, SessionListResponse, MetaResponse, AgentInfo, SSEEvent, } from "./types";
5
+ export { sseEventsToMessages, resolvePendingToolUse } from "./utils";
6
+ export type * from "./types";
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.writeSSEEvents = exports.Server = exports.ClientError = exports.Client = void 0;
3
+ exports.resolvePendingToolUse = exports.sseEventsToMessages = exports.Server = exports.ClientError = exports.Client = void 0;
4
4
  var client_1 = require("./client");
5
5
  Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_1.Client; } });
6
6
  Object.defineProperty(exports, "ClientError", { enumerable: true, get: function () { return client_1.ClientError; } });
7
7
  var server_1 = require("./server");
8
8
  Object.defineProperty(exports, "Server", { enumerable: true, get: function () { return server_1.Server; } });
9
- Object.defineProperty(exports, "writeSSEEvents", { enumerable: true, get: function () { return server_1.writeSSEEvents; } });
9
+ var utils_1 = require("./utils");
10
+ Object.defineProperty(exports, "sseEventsToMessages", { enumerable: true, get: function () { return utils_1.sseEventsToMessages; } });
11
+ Object.defineProperty(exports, "resolvePendingToolUse", { enumerable: true, get: function () { return utils_1.resolvePendingToolUse; } });
package/dist/server.d.ts CHANGED
@@ -1,21 +1,26 @@
1
1
  import { Hono } from "hono";
2
- import type { SSEStreamingApi } from "hono/streaming";
2
+ import type { Context } from "hono";
3
3
  import { AgentResponse, CreateSessionRequest, MetaResponse, SessionListResponse, SessionResponse, SessionTurnRequest, SSEEvent } from "./types";
4
4
  export interface ServerHandler {
5
5
  getMeta(): Promise<MetaResponse>;
6
- createSession(req: CreateSessionRequest): Promise<AgentResponse | AsyncIterable<SSEEvent>> | AsyncIterable<SSEEvent>;
7
- sendTurn(sessionId: string, req: SessionTurnRequest): Promise<AgentResponse | AsyncIterable<SSEEvent>> | AsyncIterable<SSEEvent>;
8
- getSession(sessionId: string): Promise<SessionResponse>;
9
6
  listSessions(params: {
10
7
  after?: string;
11
8
  }): Promise<SessionListResponse>;
9
+ getSession(sessionId: string): Promise<SessionResponse>;
10
+ /** The last message in `req.messages` is guaranteed to be a user message. */
11
+ createSession(req: CreateSessionRequest): Promise<AgentResponse | AsyncIterable<SSEEvent>>;
12
+ sendTurn(sessionId: string, req: SessionTurnRequest): Promise<AgentResponse | AsyncIterable<SSEEvent>>;
12
13
  deleteSession(sessionId: string): Promise<void>;
13
14
  }
14
- export type { SSEStreamingApi };
15
- export declare function writeSSEEvents(stream: SSEStreamingApi, events: AsyncIterable<SSEEvent>): Promise<void>;
16
15
  export interface ServerOptions {
17
- /** Called on every request (except GET /meta) to authenticate. Return false to reject. */
18
- authenticate?: (apiKey: string) => boolean | Promise<boolean>;
16
+ /**
17
+ * Called on every request to authenticate. Return false to reject.
18
+ * Use `c.req.path` to allow unauthenticated access to specific routes.
19
+ * @example
20
+ * // Allow unauthenticated access to GET /meta
21
+ * authenticate: (apiKey, c) => c.req.path === "/meta" || apiKey === "secret"
22
+ */
23
+ authenticate?: (apiKey: string, c: Context) => boolean | Promise<boolean>;
19
24
  /** CORS origin(s) to allow. Disabled by default. */
20
25
  cors?: string | string[];
21
26
  /** Base path to mount all routes under, e.g. "/api/v1". */
@@ -24,6 +29,4 @@ export interface ServerOptions {
24
29
  export declare class Server {
25
30
  readonly app: Hono;
26
31
  constructor(handler: ServerHandler, options?: ServerOptions);
27
- /** Returns the Hono fetch handler, ready to pass to any runtime (Node, Bun, Deno, etc.) */
28
- fetch: (req: Request) => Response | Promise<Response>;
29
32
  }
package/dist/server.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Server = void 0;
4
- exports.writeSSEEvents = writeSSEEvents;
5
4
  const hono_1 = require("hono");
6
5
  const cors_1 = require("hono/cors");
7
6
  const streaming_1 = require("hono/streaming");
7
+ // --- SSE helper ---
8
8
  async function writeSSEEvents(stream, events) {
9
9
  for await (const { event, ...data } of events) {
10
10
  await stream.writeSSE({ event, data: JSON.stringify(data) });
@@ -12,37 +12,34 @@ async function writeSSEEvents(stream, events) {
12
12
  }
13
13
  class Server {
14
14
  constructor(handler, options = {}) {
15
- /** Returns the Hono fetch handler, ready to pass to any runtime (Node, Bun, Deno, etc.) */
16
- this.fetch = (req) => this.app.fetch(req);
17
15
  this.app = new hono_1.Hono();
18
16
  const { authenticate } = options;
19
17
  const router = options.base ? this.app.basePath(options.base) : this.app;
20
18
  if (options.cors !== undefined) {
21
19
  router.use("*", (0, cors_1.cors)({ origin: options.cors }));
22
20
  }
23
- const auth = async (apiKey) => {
24
- if (!authenticate)
25
- return true;
26
- return authenticate(apiKey);
27
- };
28
21
  const getApiKey = (authHeader) => authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : "";
29
- // GET /meta auth optional
30
- router.get("/meta", async (c) => {
31
- const meta = await handler.getMeta();
32
- return c.json(meta);
33
- });
34
- // Auth middleware for all other routes
22
+ // Auth middleware for all routes
35
23
  router.use("*", async (c, next) => {
24
+ if (!authenticate)
25
+ return next();
36
26
  const apiKey = getApiKey(c.req.header("Authorization"));
37
- if (!(await auth(apiKey)))
27
+ if (!(await authenticate(apiKey, c)))
38
28
  return c.json({ error: "Unauthorized" }, 401);
39
29
  return next();
40
30
  });
31
+ // GET /meta
32
+ router.get("/meta", async (c) => {
33
+ const meta = await handler.getMeta();
34
+ return c.json(meta);
35
+ });
41
36
  // PUT /session
42
37
  router.put("/session", async (c) => {
43
38
  const req = await c.req.json();
39
+ if (req.messages.at(-1)?.role !== "user")
40
+ return c.json({ error: "Last message must be a user message" }, 400);
44
41
  const result = await handler.createSession(req);
45
- if (isAsyncIterable(result)) {
42
+ if (req.stream === "delta" || req.stream === "message") {
46
43
  return (0, streaming_1.streamSSE)(c, (stream) => writeSSEEvents(stream, result));
47
44
  }
48
45
  return c.json(result, 201);
@@ -51,7 +48,7 @@ class Server {
51
48
  router.post("/session/:id", async (c) => {
52
49
  const req = await c.req.json();
53
50
  const result = await handler.sendTurn(c.req.param("id"), req);
54
- if (isAsyncIterable(result)) {
51
+ if (req.stream === "delta" || req.stream === "message") {
55
52
  return (0, streaming_1.streamSSE)(c, (stream) => writeSSEEvents(stream, result));
56
53
  }
57
54
  return c.json(result);
@@ -75,6 +72,3 @@ class Server {
75
72
  }
76
73
  }
77
74
  exports.Server = Server;
78
- function isAsyncIterable(value) {
79
- return value != null && typeof value[Symbol.asyncIterator] === "function";
80
- }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { JSONSchema7 } from "json-schema";
2
2
  export type JSONSchema = JSONSchema7;
3
+ /** A single block of content within a message. */
3
4
  export type ContentBlock = {
4
5
  type: "text";
5
6
  text: string;
@@ -13,122 +14,195 @@ export type ContentBlock = {
13
14
  input: Record<string, unknown>;
14
15
  } | {
15
16
  type: "image";
16
- mimeType: string;
17
- data: string;
17
+ /** Supports `https://` URLs and `data:` URIs (base64). */
18
+ url: string;
18
19
  };
19
- export type Message = {
20
+ /** A system-role message providing instructions to the agent. */
21
+ export interface SystemMessage {
20
22
  role: "system";
21
23
  content: string;
22
- } | {
24
+ }
25
+ /** A user-role message. */
26
+ export interface UserMessage {
23
27
  role: "user";
24
28
  content: string | ContentBlock[];
25
- } | {
29
+ }
30
+ /** An assistant-role message. */
31
+ export interface AssistantMessage {
26
32
  role: "assistant";
27
33
  content: string | ContentBlock[];
28
- } | {
34
+ }
35
+ /** A tool result message returned by the application after a `tool_use` block. */
36
+ export interface ToolMessage {
29
37
  role: "tool";
30
38
  toolCallId: string;
31
39
  content: string | ContentBlock[];
32
- };
33
- export type ToolPermissionMessage = {
40
+ }
41
+ /** A message that can appear in conversation history. */
42
+ export type HistoryMessage = SystemMessage | UserMessage | AssistantMessage | ToolMessage;
43
+ /** Grants or denies permission for the server to invoke a tool on the client's behalf. */
44
+ export interface ToolPermissionMessage {
34
45
  role: "tool_permission";
35
46
  toolCallId: string;
47
+ /** Whether the client grants permission for the tool call. */
36
48
  granted: boolean;
49
+ /** Optional explanation, especially useful when `granted` is `false`. */
37
50
  reason?: string;
38
- };
51
+ }
52
+ /** Declares a tool (application-side in requests; server-side in `/meta`). */
39
53
  export interface ToolSpec {
40
54
  name: string;
41
55
  title?: string;
42
56
  description: string;
43
57
  inputSchema: JSONSchema;
44
58
  }
59
+ /** References a server-side tool to enable for a session. */
45
60
  export interface ServerToolRef {
61
+ /** Server tool name as declared in `/meta`. */
46
62
  name: string;
47
- trust: boolean;
63
+ /** If `true`, the server may invoke this tool without requesting client permission. Defaults to `false`. */
64
+ trust?: boolean;
48
65
  }
66
+ /** A configurable option the client may set per request. */
49
67
  export type AgentOption = {
68
+ type: "text";
50
69
  name: string;
51
70
  title?: string;
52
71
  description?: string;
53
- type: "text";
54
72
  default: string;
55
73
  } | {
74
+ type: "secret";
56
75
  name: string;
57
76
  title?: string;
58
77
  description?: string;
59
- type: "secret";
60
78
  default: string;
61
79
  } | {
80
+ type: "select";
62
81
  name: string;
63
82
  title?: string;
64
83
  description?: string;
65
- type: "select";
66
84
  options: string[];
67
85
  default: string;
68
86
  };
87
+ /** Describes an agent available on the server, as returned by `GET /meta`. */
69
88
  export interface AgentInfo {
89
+ /** Unique identifier for the agent on this server. */
70
90
  name: string;
91
+ /** Human-readable display name. */
71
92
  title?: string;
93
+ /** Semantic version of the agent. */
72
94
  version: string;
73
95
  description?: string;
96
+ /** Server-side tools the agent exposes to the client for configuration. */
74
97
  tools?: ToolSpec[];
98
+ /** Configurable options the client may set per request. */
75
99
  options?: AgentOption[];
100
+ /** Declares what the agent supports. Missing fields should be treated as unsupported. */
76
101
  capabilities?: {
102
+ /** Declares what history the agent can return in `GET /session/:id`. */
77
103
  history?: {
104
+ /** Server can return compacted history. */
78
105
  compacted?: Record<string, never>;
106
+ /** Server can return full uncompacted history. */
79
107
  full?: Record<string, never>;
80
108
  };
109
+ /** Declares which stream modes the agent supports. */
81
110
  stream?: {
111
+ /** Agent supports `"delta"` streaming. */
82
112
  delta?: Record<string, never>;
113
+ /** Agent supports `"message"` streaming. */
83
114
  message?: Record<string, never>;
115
+ /** Agent supports non-streaming (`"none"`) responses. */
84
116
  none?: Record<string, never>;
85
117
  };
118
+ /** Declares what application-provided inputs the agent supports. */
86
119
  application?: {
120
+ /** Agent accepts application-side tools in requests. */
87
121
  tools?: Record<string, never>;
88
122
  };
123
+ /** Declares what image input the agent supports. */
124
+ image?: {
125
+ /** Agent accepts `https://` image URLs. */
126
+ http?: Record<string, never>;
127
+ /** Agent accepts `data:` URI (base64) images. */
128
+ data?: Record<string, never>;
129
+ };
89
130
  };
90
131
  }
132
+ /** Response body for `GET /meta`. */
91
133
  export interface MetaResponse {
134
+ /** AAP protocol version. */
92
135
  version: number;
93
136
  agents: AgentInfo[];
94
137
  }
95
138
  export type StreamMode = "delta" | "message" | "none";
96
139
  export type StopReason = "end_turn" | "tool_use" | "max_tokens" | "refusal" | "error";
140
+ /** Agent configuration supplied with a request. */
97
141
  export interface AgentConfig {
142
+ /** Agent name to invoke. */
98
143
  name: string;
144
+ /** Server-side tools to enable. If omitted, all exposed agent tools are disabled. */
99
145
  tools?: ServerToolRef[];
146
+ /** Key-value pairs matching the agent's declared options. */
100
147
  options?: Record<string, string>;
101
148
  }
149
+ /** Request body for `PUT /session`. */
102
150
  export interface CreateSessionRequest {
151
+ /** Agent configuration. `name` is required at session creation. */
103
152
  agent: AgentConfig;
153
+ /** Response mode. Defaults to `"none"`. */
104
154
  stream?: StreamMode;
105
- messages: Message[];
155
+ /** Seed history. The last message must be a `user` message. */
156
+ messages: HistoryMessage[];
157
+ /** Application-side tools with full schema. */
106
158
  tools?: ToolSpec[];
107
159
  }
160
+ /** Request body for `POST /session/:id`. */
108
161
  export interface SessionTurnRequest {
162
+ /** Session-level agent overrides. Agent name cannot be changed. */
163
+ agent?: Omit<AgentConfig, "name">;
164
+ /** Response mode. Defaults to `"none"`. */
109
165
  stream?: StreamMode;
110
- messages: (Message | ToolPermissionMessage)[];
166
+ /** A single user message, or a mixed list of tool results and tool permissions. */
167
+ messages: (UserMessage | ToolMessage | ToolPermissionMessage)[];
168
+ /** Application-side tools. Overrides tools declared at session creation. */
111
169
  tools?: ToolSpec[];
112
- agent?: Omit<AgentConfig, "name">;
113
170
  }
171
+ /** JSON response body for non-streaming (`stream: "none"`) requests. */
114
172
  export interface AgentResponse {
173
+ /** Present in `PUT /session` response only. */
115
174
  sessionId?: string;
116
175
  stopReason: StopReason;
117
- messages: Message[];
176
+ messages: HistoryMessage[];
118
177
  }
178
+ /** Response body for `GET /session/:id`. */
119
179
  export interface SessionResponse {
120
180
  sessionId: string;
181
+ /** Secret option values in `agent.options` are redacted (e.g. `"***"`). */
121
182
  agent: AgentConfig;
122
- tools: ToolSpec[];
183
+ /** Application-side tools declared for this session. */
184
+ tools?: ToolSpec[];
123
185
  history?: {
124
- compacted?: Message[];
125
- full?: Message[];
186
+ /** Omitted if the server chooses not to expose. */
187
+ compacted?: HistoryMessage[];
188
+ /** Omitted if the server chooses not to expose. */
189
+ full?: HistoryMessage[];
126
190
  };
127
191
  }
192
+ /** Response body for `GET /sessions`. */
128
193
  export interface SessionListResponse {
194
+ /** Array of session IDs. */
129
195
  sessions: string[];
130
- nextCursor?: string;
196
+ /** Pagination cursor; absent when there are no more results. Pass as `after` to get the next page. */
197
+ next?: string;
198
+ }
199
+ /** A tool call emitted by the agent during a streaming turn. */
200
+ export interface ToolCallEvent {
201
+ toolCallId: string;
202
+ name: string;
203
+ input: Record<string, unknown>;
131
204
  }
205
+ /** SSE event data for `stream: "delta"` and `stream: "message"` responses. */
132
206
  export type SSEEvent = {
133
207
  event: "session_start";
134
208
  sessionId: string;
@@ -146,12 +220,9 @@ export type SSEEvent = {
146
220
  } | {
147
221
  event: "thinking";
148
222
  thinking: string;
149
- } | {
223
+ } | ({
150
224
  event: "tool_call";
151
- toolCallId: string;
152
- name: string;
153
- input: Record<string, unknown>;
154
- } | {
225
+ } & ToolCallEvent) | {
155
226
  event: "tool_result";
156
227
  toolCallId: string;
157
228
  content: string | ContentBlock[];
@@ -0,0 +1,14 @@
1
+ import type { HistoryMessage, SSEEvent, ToolCallEvent, ToolSpec } from "./types";
2
+ /**
3
+ * Converts a list of SSE events into `HistoryMessage[]`.
4
+ * Handles delta accumulation, tool call/result pairing, and assistant message finalization.
5
+ */
6
+ export declare function sseEventsToMessages(events: SSEEvent[]): HistoryMessage[];
7
+ /**
8
+ * Inspects the last assistant message in `messages` and classifies its unresolved `tool_use` blocks
9
+ * into client-side tools (matched against `clientTools`) and server-side tools (requiring permission).
10
+ */
11
+ export declare function resolvePendingToolUse(messages: HistoryMessage[], clientTools?: ToolSpec[]): {
12
+ client: ToolCallEvent[];
13
+ server: ToolCallEvent[];
14
+ };
package/dist/utils.js ADDED
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sseEventsToMessages = sseEventsToMessages;
4
+ exports.resolvePendingToolUse = resolvePendingToolUse;
5
+ /**
6
+ * Converts a list of SSE events into `HistoryMessage[]`.
7
+ * Handles delta accumulation, tool call/result pairing, and assistant message finalization.
8
+ */
9
+ function sseEventsToMessages(events) {
10
+ const history = [];
11
+ const blocks = [];
12
+ let textAcc = "";
13
+ let thinkingAcc = "";
14
+ for (const event of events) {
15
+ // flush delta accumulators when a non-delta event arrives
16
+ if (event.event !== "text_delta" && event.event !== "thinking_delta") {
17
+ if (textAcc) {
18
+ blocks.push({ type: "text", text: textAcc });
19
+ textAcc = "";
20
+ }
21
+ if (thinkingAcc) {
22
+ blocks.push({ type: "thinking", thinking: thinkingAcc });
23
+ thinkingAcc = "";
24
+ }
25
+ }
26
+ switch (event.event) {
27
+ case "text_delta":
28
+ textAcc += event.delta;
29
+ break;
30
+ case "thinking_delta":
31
+ thinkingAcc += event.delta;
32
+ break;
33
+ case "text":
34
+ blocks.push({ type: "text", text: event.text });
35
+ break;
36
+ case "thinking":
37
+ blocks.push({ type: "thinking", thinking: event.thinking });
38
+ break;
39
+ case "tool_call":
40
+ // accumulate tool_use blocks into the current assistant message
41
+ blocks.push({
42
+ type: "tool_use",
43
+ toolCallId: event.toolCallId,
44
+ name: event.name,
45
+ input: event.input,
46
+ });
47
+ break;
48
+ case "tool_result":
49
+ // flush accumulated assistant blocks before appending the tool result
50
+ if (blocks.length > 0) {
51
+ history.push({ role: "assistant", content: [...blocks] });
52
+ blocks.length = 0;
53
+ }
54
+ history.push({ role: "tool", toolCallId: event.toolCallId, content: event.content });
55
+ break;
56
+ case "turn_stop":
57
+ // finalize the assistant message
58
+ if (blocks.length > 0)
59
+ history.push({ role: "assistant", content: blocks });
60
+ break;
61
+ }
62
+ }
63
+ return history;
64
+ }
65
+ /**
66
+ * Inspects the last assistant message in `messages` and classifies its unresolved `tool_use` blocks
67
+ * into client-side tools (matched against `clientTools`) and server-side tools (requiring permission).
68
+ */
69
+ function resolvePendingToolUse(messages, clientTools) {
70
+ const last = [...messages].reverse().find((m) => m.role === "assistant");
71
+ if (!last || !Array.isArray(last.content))
72
+ return { client: [], server: [] };
73
+ const resolved = new Set(messages.filter((m) => m.role === "tool").map((m) => m.toolCallId));
74
+ const clientNames = new Set(clientTools?.map((t) => t.name) ?? []);
75
+ const client = [];
76
+ const server = [];
77
+ for (const block of last.content) {
78
+ if (block.type !== "tool_use" || resolved.has(block.toolCallId))
79
+ continue;
80
+ const { toolCallId, name, input } = block;
81
+ (clientNames.has(name) ? client : server).push({ toolCallId, name, input });
82
+ }
83
+ return { client, server };
84
+ }
package/package.json CHANGED
@@ -1,36 +1,37 @@
1
1
  {
2
2
  "name": "@agentapplicationprotocol/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "TypeScript SDK for the Agent Application Protocol (AAP)",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "license": "Apache-2.0",
7
6
  "files": [
8
- "dist"
7
+ "dist",
8
+ "!dist/**/*.test.js",
9
+ "!dist/**/*.test.d.ts"
9
10
  ],
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
10
13
  "scripts": {
11
14
  "build": "tsc",
12
- "dev": "tsc --watch",
13
- "example:basic:server": "tsx src/examples/01-basic/server.ts",
14
- "example:basic:client": "tsx src/examples/01-basic/client.ts",
15
- "example:streaming:server": "tsx src/examples/02-streaming/server.ts",
16
- "example:streaming:client": "tsx src/examples/02-streaming/client.ts",
17
- "example:client-tool:server": "tsx src/examples/03-client-tool/server.ts",
18
- "example:client-tool:client": "tsx src/examples/03-client-tool/client.ts",
19
- "example:server-tool-permission:server": "tsx src/examples/04-server-tool-permission/server.ts",
20
- "example:server-tool-permission:client": "tsx src/examples/04-server-tool-permission/client.ts",
21
- "example:server-tool-inline:server": "tsx src/examples/05-server-tool-inline/server.ts",
22
- "example:server-tool-inline:client": "tsx src/examples/05-server-tool-inline/client.ts"
15
+ "test": "vitest run --exclude 'dist/**'",
16
+ "prepare": "husky",
17
+ "dev": "tsc --watch"
18
+ },
19
+ "dependencies": {
20
+ "eventsource-parser": "^3.0.6",
21
+ "hono": "^4.12.8"
23
22
  },
24
- "license": "Apache-2.0",
25
23
  "devDependencies": {
26
- "@hono/node-server": "^1.19.11",
27
24
  "@types/json-schema": "^7.0.15",
28
25
  "@types/node": "^25.5.0",
26
+ "@vitest/coverage-v8": "^4.1.2",
27
+ "husky": "^9.1.7",
28
+ "lint-staged": "^16.4.0",
29
+ "oxfmt": "^0.42.0",
29
30
  "tsx": "^4.21.0",
30
- "typescript": "^5.0.0"
31
+ "typescript": "^5.0.0",
32
+ "vitest": "^4.1.2"
31
33
  },
32
- "dependencies": {
33
- "eventsource-parser": "^3.0.6",
34
- "hono": "^4.12.8"
34
+ "lint-staged": {
35
+ "*.{ts,json,md}": "oxfmt"
35
36
  }
36
37
  }