@agentapplicationprotocol/server 0.5.0 → 0.6.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.
|
@@ -54,7 +54,7 @@ const agent = new agent_js_1.Agent("basic-agent", {
|
|
|
54
54
|
});
|
|
55
55
|
const handler = {
|
|
56
56
|
getMeta() {
|
|
57
|
-
return {
|
|
57
|
+
return { agents: [agent.info] };
|
|
58
58
|
},
|
|
59
59
|
createSession(req) {
|
|
60
60
|
const sessionId = `sess_${(0, node_crypto_1.randomUUID)()}`;
|
|
@@ -74,16 +74,21 @@ const handler = {
|
|
|
74
74
|
throw new Error(`Session not found: ${sessionId}`);
|
|
75
75
|
return session.runTurn(req);
|
|
76
76
|
},
|
|
77
|
-
async getSession(sessionId
|
|
77
|
+
async getSession(sessionId) {
|
|
78
|
+
const session = sessions.get(sessionId);
|
|
79
|
+
if (!session)
|
|
80
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
81
|
+
return session.toSessionResponse();
|
|
82
|
+
},
|
|
83
|
+
async getSessionHistory(sessionId, type) {
|
|
78
84
|
const session = sessions.get(sessionId);
|
|
79
85
|
if (!session)
|
|
80
86
|
throw new Error(`Session not found: ${sessionId}`);
|
|
81
87
|
// history is never compacted, so compacted and full are the same
|
|
82
|
-
|
|
83
|
-
return { ...session.toSessionResponse(), history: historyData };
|
|
88
|
+
return session.history;
|
|
84
89
|
},
|
|
85
90
|
async listSessions() {
|
|
86
|
-
return { sessions: [...sessions.
|
|
91
|
+
return { sessions: [...sessions.values()].map((s) => s.toSessionResponse()) };
|
|
87
92
|
},
|
|
88
93
|
async deleteSession(sessionId) {
|
|
89
94
|
sessions.delete(sessionId);
|
|
@@ -52,7 +52,7 @@ const agent = new agent_js_1.Agent("compact-history-agent", {
|
|
|
52
52
|
});
|
|
53
53
|
const handler = {
|
|
54
54
|
getMeta() {
|
|
55
|
-
return {
|
|
55
|
+
return { agents: [agent.info] };
|
|
56
56
|
},
|
|
57
57
|
createSession(req) {
|
|
58
58
|
const sessionId = `sess_${(0, node_crypto_1.randomUUID)()}`;
|
|
@@ -72,20 +72,20 @@ const handler = {
|
|
|
72
72
|
throw new Error(`Session not found: ${sessionId}`);
|
|
73
73
|
return session.runTurn(req);
|
|
74
74
|
},
|
|
75
|
-
async getSession(sessionId
|
|
75
|
+
async getSession(sessionId) {
|
|
76
76
|
const session = session_js_1.sessions.get(sessionId);
|
|
77
77
|
if (!session)
|
|
78
78
|
throw new Error(`Session not found: ${sessionId}`);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return
|
|
79
|
+
return session.toSessionResponse();
|
|
80
|
+
},
|
|
81
|
+
async getSessionHistory(sessionId, type) {
|
|
82
|
+
const session = session_js_1.sessions.get(sessionId);
|
|
83
|
+
if (!session)
|
|
84
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
85
|
+
return type === "compacted" ? session.history : session.fullHistory;
|
|
86
86
|
},
|
|
87
87
|
async listSessions() {
|
|
88
|
-
return { sessions: [...session_js_1.sessions.
|
|
88
|
+
return { sessions: [...session_js_1.sessions.values()].map((s) => s.toSessionResponse()) };
|
|
89
89
|
},
|
|
90
90
|
async deleteSession(sessionId) {
|
|
91
91
|
session_js_1.sessions.delete(sessionId);
|
package/dist/src/server.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { AgentResponse, CreateSessionRequest, CreateSessionResponse, MetaResponse, SessionListResponse, SessionResponse, SessionTurnRequest, SSEEvent } from "@agentapplicationprotocol/core";
|
|
2
|
+
import { AgentResponse, CreateSessionRequest, CreateSessionResponse, HistoryMessage, MetaResponse, SessionListResponse, SessionResponse, SessionTurnRequest, SSEEvent } from "@agentapplicationprotocol/core";
|
|
3
3
|
export interface Handler {
|
|
4
|
-
getMeta(): MetaResponse
|
|
4
|
+
getMeta(): Omit<MetaResponse, "version">;
|
|
5
5
|
listSessions(params: {
|
|
6
6
|
after?: string;
|
|
7
7
|
}): Promise<SessionListResponse>;
|
|
8
|
-
getSession(sessionId: string
|
|
8
|
+
getSession(sessionId: string): Promise<SessionResponse>;
|
|
9
|
+
getSessionHistory(sessionId: string, type: "compacted" | "full"): Promise<HistoryMessage[]>;
|
|
9
10
|
/** The last message in `req.messages` is guaranteed to be a user message. */
|
|
10
11
|
createSession(req: CreateSessionRequest): Promise<CreateSessionResponse> | AsyncIterable<SSEEvent>;
|
|
11
12
|
sendTurn(sessionId: string, req: SessionTurnRequest): Promise<AgentResponse> | AsyncIterable<SSEEvent>;
|
package/dist/src/server.js
CHANGED
|
@@ -41,7 +41,7 @@ function redactSecretOptions(session, agents) {
|
|
|
41
41
|
*/
|
|
42
42
|
function aap(handler) {
|
|
43
43
|
const router = new hono_1.Hono();
|
|
44
|
-
router.get("/meta", (c) => c.json(handler.getMeta()));
|
|
44
|
+
router.get("/meta", (c) => c.json({ version: 2, ...handler.getMeta() }));
|
|
45
45
|
router.put("/session", async (c) => {
|
|
46
46
|
const req = await c.req.json();
|
|
47
47
|
if (req.messages.at(-1)?.role !== "user")
|
|
@@ -61,24 +61,25 @@ function aap(handler) {
|
|
|
61
61
|
return c.json(result);
|
|
62
62
|
});
|
|
63
63
|
router.get("/session/:id", async (c) => {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
session.history = undefined;
|
|
75
|
-
}
|
|
76
|
-
const meta = handler.getMeta();
|
|
77
|
-
return c.json(redactSecretOptions(session, meta.agents));
|
|
64
|
+
const session = await handler.getSession(c.req.param("id"));
|
|
65
|
+
const { agents } = handler.getMeta();
|
|
66
|
+
return c.json(redactSecretOptions(session, agents));
|
|
67
|
+
});
|
|
68
|
+
router.get("/session/:id/history", async (c) => {
|
|
69
|
+
const typeParam = c.req.query("type");
|
|
70
|
+
if (typeParam !== "compacted" && typeParam !== "full")
|
|
71
|
+
return c.json({ error: 'type must be "compacted" or "full"' }, 400);
|
|
72
|
+
const messages = await handler.getSessionHistory(c.req.param("id"), typeParam);
|
|
73
|
+
return c.json({ history: { [typeParam]: messages } });
|
|
78
74
|
});
|
|
79
75
|
router.get("/sessions", async (c) => {
|
|
80
76
|
const after = c.req.query("after");
|
|
81
|
-
|
|
77
|
+
const result = await handler.listSessions({ after });
|
|
78
|
+
const { agents } = handler.getMeta();
|
|
79
|
+
return c.json({
|
|
80
|
+
...result,
|
|
81
|
+
sessions: result.sessions.map((s) => redactSecretOptions(s, agents)),
|
|
82
|
+
});
|
|
82
83
|
});
|
|
83
84
|
router.delete("/session/:id", async (c) => {
|
|
84
85
|
await handler.deleteSession(c.req.param("id"));
|
package/dist/src/server.test.js
CHANGED
|
@@ -5,11 +5,11 @@ const hono_1 = require("hono");
|
|
|
5
5
|
const bearer_auth_1 = require("hono/bearer-auth");
|
|
6
6
|
const cors_1 = require("hono/cors");
|
|
7
7
|
const server_1 = require("./server");
|
|
8
|
-
const meta = { version:
|
|
8
|
+
const meta = { version: 2, agents: [] };
|
|
9
9
|
const session = { sessionId: "s1", agent: { name: "a" } };
|
|
10
10
|
const agentResponse = { stopReason: "end_turn", messages: [] };
|
|
11
11
|
const createSessionResponse = { ...agentResponse, sessionId: "s1" };
|
|
12
|
-
const sessionList = { sessions: [
|
|
12
|
+
const sessionList = { sessions: [session] };
|
|
13
13
|
async function* sseEvents() {
|
|
14
14
|
yield { event: "turn_start" };
|
|
15
15
|
yield { event: "text", text: "hi" };
|
|
@@ -17,9 +17,10 @@ async function* sseEvents() {
|
|
|
17
17
|
}
|
|
18
18
|
function makeHandler(overrides = {}) {
|
|
19
19
|
return {
|
|
20
|
-
getMeta: vitest_1.vi.fn().mockReturnValue(
|
|
20
|
+
getMeta: vitest_1.vi.fn().mockReturnValue({ agents: [] }),
|
|
21
21
|
listSessions: vitest_1.vi.fn().mockResolvedValue(sessionList),
|
|
22
22
|
getSession: vitest_1.vi.fn().mockResolvedValue(session),
|
|
23
|
+
getSessionHistory: vitest_1.vi.fn().mockResolvedValue([]),
|
|
23
24
|
createSession: vitest_1.vi.fn().mockResolvedValue(createSessionResponse),
|
|
24
25
|
sendTurn: vitest_1.vi.fn().mockResolvedValue(agentResponse),
|
|
25
26
|
deleteSession: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
@@ -57,22 +58,20 @@ function req(method, path, body, headers) {
|
|
|
57
58
|
sessionId: "s1",
|
|
58
59
|
agent: { name: "a", options: { key: "mysecret", model: "gpt-4" } },
|
|
59
60
|
};
|
|
60
|
-
const secretMeta = {
|
|
61
|
-
version: 1,
|
|
62
|
-
agents: [
|
|
63
|
-
{
|
|
64
|
-
name: "a",
|
|
65
|
-
version: "1.0.0",
|
|
66
|
-
options: [
|
|
67
|
-
{ type: "secret", name: "key", default: "" },
|
|
68
|
-
{ type: "text", name: "model", default: "" },
|
|
69
|
-
],
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
};
|
|
73
61
|
const app = makeApp(makeHandler({
|
|
74
62
|
getSession: vitest_1.vi.fn().mockResolvedValue(secretSession),
|
|
75
|
-
getMeta: vitest_1.vi.fn().mockReturnValue(
|
|
63
|
+
getMeta: vitest_1.vi.fn().mockReturnValue({
|
|
64
|
+
agents: [
|
|
65
|
+
{
|
|
66
|
+
name: "a",
|
|
67
|
+
version: "1.0.0",
|
|
68
|
+
options: [
|
|
69
|
+
{ type: "secret", name: "key", default: "" },
|
|
70
|
+
{ type: "text", name: "model", default: "" },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
}),
|
|
76
75
|
}));
|
|
77
76
|
const res = await app.fetch(req("GET", "/session/s1"));
|
|
78
77
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
@@ -89,6 +88,37 @@ function req(method, path, body, headers) {
|
|
|
89
88
|
(0, vitest_1.expect)(await res.json()).toEqual(sessionList);
|
|
90
89
|
(0, vitest_1.expect)(handler.listSessions).toHaveBeenCalledWith({ after: "cursor1" });
|
|
91
90
|
});
|
|
91
|
+
(0, vitest_1.it)("GET /sessions redacts secret options in each session", async () => {
|
|
92
|
+
const secretSession = {
|
|
93
|
+
sessionId: "s1",
|
|
94
|
+
agent: { name: "a", options: { key: "mysecret", model: "gpt-4" } },
|
|
95
|
+
};
|
|
96
|
+
const app = makeApp(makeHandler({
|
|
97
|
+
listSessions: vitest_1.vi.fn().mockResolvedValue({ sessions: [secretSession] }),
|
|
98
|
+
getMeta: vitest_1.vi.fn().mockReturnValue({
|
|
99
|
+
agents: [
|
|
100
|
+
{
|
|
101
|
+
name: "a",
|
|
102
|
+
version: "1.0.0",
|
|
103
|
+
options: [
|
|
104
|
+
{ type: "secret", name: "key", default: "" },
|
|
105
|
+
{ type: "text", name: "model", default: "" },
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
}),
|
|
110
|
+
}));
|
|
111
|
+
const res = await app.fetch(req("GET", "/sessions"));
|
|
112
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
113
|
+
(0, vitest_1.expect)(await res.json()).toEqual({
|
|
114
|
+
sessions: [
|
|
115
|
+
{
|
|
116
|
+
...secretSession,
|
|
117
|
+
agent: { ...secretSession.agent, options: { key: "***", model: "gpt-4" } },
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
});
|
|
92
122
|
(0, vitest_1.it)("PUT /session returns 400 if last message is not a user message", async () => {
|
|
93
123
|
const app = makeApp(makeHandler());
|
|
94
124
|
const res = await app.fetch(req("PUT", "/session", {
|
|
@@ -158,7 +188,7 @@ function req(method, path, body, headers) {
|
|
|
158
188
|
};
|
|
159
189
|
const app = makeApp(makeHandler({
|
|
160
190
|
getSession: vitest_1.vi.fn().mockResolvedValue(sessionWithOptions),
|
|
161
|
-
getMeta: vitest_1.vi.fn().mockReturnValue({
|
|
191
|
+
getMeta: vitest_1.vi.fn().mockReturnValue({ agents: [] }),
|
|
162
192
|
}));
|
|
163
193
|
const res = await app.fetch(req("GET", "/session/s1"));
|
|
164
194
|
(0, vitest_1.expect)(await res.json()).toEqual(sessionWithOptions);
|
|
@@ -171,7 +201,6 @@ function req(method, path, body, headers) {
|
|
|
171
201
|
const app = makeApp(makeHandler({
|
|
172
202
|
getSession: vitest_1.vi.fn().mockResolvedValue(sessionWithOptions),
|
|
173
203
|
getMeta: vitest_1.vi.fn().mockReturnValue({
|
|
174
|
-
version: 1,
|
|
175
204
|
agents: [
|
|
176
205
|
{
|
|
177
206
|
name: "a",
|
|
@@ -184,46 +213,27 @@ function req(method, path, body, headers) {
|
|
|
184
213
|
const res = await app.fetch(req("GET", "/session/s1"));
|
|
185
214
|
(0, vitest_1.expect)(await res.json()).toEqual(sessionWithOptions);
|
|
186
215
|
});
|
|
187
|
-
(0, vitest_1.it)("GET /session/:id?
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
...session,
|
|
191
|
-
history: { compacted: [], full: [] },
|
|
192
|
-
}),
|
|
193
|
-
});
|
|
194
|
-
const app = makeApp(handler);
|
|
195
|
-
const res = await app.fetch(req("GET", "/session/s1?history=compacted"));
|
|
196
|
-
(0, vitest_1.expect)(handler.getSession).toHaveBeenCalledWith("s1", "compacted");
|
|
197
|
-
(0, vitest_1.expect)(await res.json()).toEqual({ ...session, history: { compacted: [] } });
|
|
198
|
-
});
|
|
199
|
-
(0, vitest_1.it)("GET /session/:id?history=full passes param and strips compacted", async () => {
|
|
200
|
-
const handler = makeHandler({
|
|
201
|
-
getSession: vitest_1.vi.fn().mockResolvedValue({
|
|
202
|
-
...session,
|
|
203
|
-
history: { compacted: [], full: [] },
|
|
204
|
-
}),
|
|
205
|
-
});
|
|
206
|
-
const app = makeApp(handler);
|
|
207
|
-
const res = await app.fetch(req("GET", "/session/s1?history=full"));
|
|
208
|
-
(0, vitest_1.expect)(handler.getSession).toHaveBeenCalledWith("s1", "full");
|
|
209
|
-
(0, vitest_1.expect)(await res.json()).toEqual({ ...session, history: { full: [] } });
|
|
210
|
-
});
|
|
211
|
-
(0, vitest_1.it)("GET /session/:id without ?history passes undefined and strips history from response", async () => {
|
|
212
|
-
const handler = makeHandler({
|
|
213
|
-
getSession: vitest_1.vi.fn().mockResolvedValue({
|
|
214
|
-
...session,
|
|
215
|
-
history: { compacted: [], full: [] },
|
|
216
|
-
}),
|
|
217
|
-
});
|
|
216
|
+
(0, vitest_1.it)("GET /session/:id/history?type=compacted calls getSessionHistory", async () => {
|
|
217
|
+
const messages = [{ role: "user", content: "hi" }];
|
|
218
|
+
const handler = makeHandler({ getSessionHistory: vitest_1.vi.fn().mockResolvedValue(messages) });
|
|
218
219
|
const app = makeApp(handler);
|
|
219
|
-
const res = await app.fetch(req("GET", "/session/s1"));
|
|
220
|
-
(0, vitest_1.expect)(
|
|
221
|
-
(0, vitest_1.expect)(
|
|
220
|
+
const res = await app.fetch(req("GET", "/session/s1/history?type=compacted"));
|
|
221
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
222
|
+
(0, vitest_1.expect)(handler.getSessionHistory).toHaveBeenCalledWith("s1", "compacted");
|
|
223
|
+
(0, vitest_1.expect)(await res.json()).toEqual({ history: { compacted: messages } });
|
|
222
224
|
});
|
|
223
|
-
(0, vitest_1.it)("GET /session/:id
|
|
224
|
-
const
|
|
225
|
+
(0, vitest_1.it)("GET /session/:id/history?type=full calls getSessionHistory", async () => {
|
|
226
|
+
const messages = [{ role: "user", content: "hi" }];
|
|
227
|
+
const handler = makeHandler({ getSessionHistory: vitest_1.vi.fn().mockResolvedValue(messages) });
|
|
225
228
|
const app = makeApp(handler);
|
|
226
|
-
await app.fetch(req("GET", "/session/s1?
|
|
227
|
-
(0, vitest_1.expect)(
|
|
229
|
+
const res = await app.fetch(req("GET", "/session/s1/history?type=full"));
|
|
230
|
+
(0, vitest_1.expect)(res.status).toBe(200);
|
|
231
|
+
(0, vitest_1.expect)(handler.getSessionHistory).toHaveBeenCalledWith("s1", "full");
|
|
232
|
+
(0, vitest_1.expect)(await res.json()).toEqual({ history: { full: messages } });
|
|
233
|
+
});
|
|
234
|
+
(0, vitest_1.it)("GET /session/:id/history without valid ?type returns 400", async () => {
|
|
235
|
+
const app = makeApp(makeHandler());
|
|
236
|
+
const res = await app.fetch(req("GET", "/session/s1/history"));
|
|
237
|
+
(0, vitest_1.expect)(res.status).toBe(400);
|
|
228
238
|
});
|
|
229
239
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentapplicationprotocol/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "AAP server",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aap",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"ai": "^6.0.141",
|
|
32
32
|
"hono": "^4.12.8",
|
|
33
33
|
"zod": "^4.3.6",
|
|
34
|
-
"@agentapplicationprotocol/core": "0.
|
|
34
|
+
"@agentapplicationprotocol/core": "0.6.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@ai-sdk/openai": "^3.0.48",
|