@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 +5 -2
- package/dist/client.d.ts +9 -8
- package/dist/client.js +41 -28
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/server.d.ts +13 -10
- package/dist/server.js +14 -20
- package/dist/types.d.ts +97 -26
- package/dist/utils.d.ts +14 -0
- package/dist/utils.js +84 -0
- package/package.json +22 -21
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
|
-
##
|
|
14
|
+
## Examples
|
|
15
15
|
|
|
16
|
-
|
|
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 = {
|
|
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
|
|
3
|
+
export { Server } from "./server";
|
|
4
4
|
export type { ServerHandler, ServerOptions } from "./server";
|
|
5
|
-
export
|
|
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.
|
|
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
|
-
|
|
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 {
|
|
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
|
-
/**
|
|
18
|
-
|
|
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
|
-
//
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
17
|
-
|
|
17
|
+
/** Supports `https://` URLs and `data:` URIs (base64). */
|
|
18
|
+
url: string;
|
|
18
19
|
};
|
|
19
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
183
|
+
/** Application-side tools declared for this session. */
|
|
184
|
+
tools?: ToolSpec[];
|
|
123
185
|
history?: {
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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[];
|
package/dist/utils.d.ts
ADDED
|
@@ -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
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "TypeScript SDK for the Agent Application Protocol (AAP)",
|
|
5
|
-
"
|
|
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
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
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
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"hono": "^4.12.8"
|
|
34
|
+
"lint-staged": {
|
|
35
|
+
"*.{ts,json,md}": "oxfmt"
|
|
35
36
|
}
|
|
36
37
|
}
|