@agentapplicationprotocol/server 0.6.1 → 0.7.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.
- package/dist/src/agent.js +1 -1
- package/dist/src/examples/basic/index.js +2 -2
- package/dist/src/examples/compact-history/index.js +2 -2
- package/dist/src/model.js +1 -1
- package/dist/src/server.d.ts +1 -2
- package/dist/src/server.js +6 -11
- package/dist/src/server.test.js +19 -34
- package/dist/src/session.d.ts +3 -5
- package/dist/src/session.js +2 -14
- package/dist/src/session.test.js +88 -21
- package/package.json +2 -2
package/dist/src/agent.js
CHANGED
|
@@ -62,7 +62,7 @@ class Agent {
|
|
|
62
62
|
name,
|
|
63
63
|
title: options.title,
|
|
64
64
|
description: options.description ?? "",
|
|
65
|
-
|
|
65
|
+
parameters: zod_1.default.toJSONSchema(options.inputSchema),
|
|
66
66
|
});
|
|
67
67
|
this.tools.set(name, async (input) => {
|
|
68
68
|
const output = await exec(options.inputSchema.parse(JSON.parse(input)));
|
|
@@ -64,9 +64,9 @@ const handler = {
|
|
|
64
64
|
apiKey: req.agent.options?.apiKey || undefined,
|
|
65
65
|
});
|
|
66
66
|
const model = new model_js_1.AiModelProvider(openai.chat(req.agent.options?.model ?? "gpt-4o"));
|
|
67
|
-
const session = new session_js_1.Session(sessionId, agent, model, req.agent, req.tools);
|
|
67
|
+
const session = new session_js_1.Session(sessionId, agent, model, req.agent, req.tools ?? [], req.messages ?? []);
|
|
68
68
|
sessions.set(sessionId, session);
|
|
69
|
-
return
|
|
69
|
+
return Promise.resolve({ sessionId });
|
|
70
70
|
},
|
|
71
71
|
sendTurn(sessionId, req) {
|
|
72
72
|
const session = sessions.get(sessionId);
|
|
@@ -62,9 +62,9 @@ const handler = {
|
|
|
62
62
|
apiKey: req.agent.options?.apiKey || undefined,
|
|
63
63
|
});
|
|
64
64
|
const model = new model_js_1.AiModelProvider(openai.chat(req.agent.options?.model ?? "gpt-4o"));
|
|
65
|
-
const session = new session_js_1.TruncatedHistorySession(sessionId, agent, model, req.agent, req.tools);
|
|
65
|
+
const session = new session_js_1.TruncatedHistorySession(sessionId, agent, model, req.agent, req.tools ?? [], req.messages ?? []);
|
|
66
66
|
session_js_1.sessions.set(sessionId, session);
|
|
67
|
-
return
|
|
67
|
+
return Promise.resolve({ sessionId });
|
|
68
68
|
},
|
|
69
69
|
sendTurn(sessionId, req) {
|
|
70
70
|
const session = session_js_1.sessions.get(sessionId);
|
package/dist/src/model.js
CHANGED
|
@@ -168,7 +168,7 @@ function toToolSet(tools) {
|
|
|
168
168
|
for (const t of tools) {
|
|
169
169
|
res[t.name] = (0, ai_1.tool)({
|
|
170
170
|
description: t.description,
|
|
171
|
-
inputSchema: (0, ai_1.jsonSchema)(t.
|
|
171
|
+
inputSchema: (0, ai_1.jsonSchema)(t.parameters),
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
174
|
return res;
|
package/dist/src/server.d.ts
CHANGED
|
@@ -7,8 +7,7 @@ export interface Handler {
|
|
|
7
7
|
}): Promise<SessionListResponse>;
|
|
8
8
|
getSession(sessionId: string): Promise<SessionResponse>;
|
|
9
9
|
getSessionHistory(sessionId: string, type: "compacted" | "full"): Promise<HistoryMessage[]>;
|
|
10
|
-
|
|
11
|
-
createSession(req: CreateSessionRequest): Promise<CreateSessionResponse> | AsyncIterable<SSEEvent>;
|
|
10
|
+
createSession(req: CreateSessionRequest): Promise<CreateSessionResponse>;
|
|
12
11
|
sendTurn(sessionId: string, req: SessionTurnRequest): Promise<AgentResponse> | AsyncIterable<SSEEvent>;
|
|
13
12
|
deleteSession(sessionId: string): Promise<void>;
|
|
14
13
|
}
|
package/dist/src/server.js
CHANGED
|
@@ -41,18 +41,13 @@ 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({ version:
|
|
45
|
-
router.
|
|
44
|
+
router.get("/meta", (c) => c.json({ version: 3, ...handler.getMeta() }));
|
|
45
|
+
router.post("/sessions", async (c) => {
|
|
46
46
|
const req = await c.req.json();
|
|
47
|
-
if (req.messages.at(-1)?.role !== "user")
|
|
48
|
-
return c.json({ error: "Last message must be a user message" }, 400);
|
|
49
47
|
const result = await handler.createSession(req);
|
|
50
|
-
if (req.stream === "delta" || req.stream === "message") {
|
|
51
|
-
return (0, streaming_1.streamSSE)(c, (stream) => writeSSEEvents(stream, result));
|
|
52
|
-
}
|
|
53
48
|
return c.json(result, 201);
|
|
54
49
|
});
|
|
55
|
-
router.post("/
|
|
50
|
+
router.post("/sessions/:id/turns", async (c) => {
|
|
56
51
|
const req = await c.req.json();
|
|
57
52
|
const result = await handler.sendTurn(c.req.param("id"), req);
|
|
58
53
|
if (req.stream === "delta" || req.stream === "message") {
|
|
@@ -60,12 +55,12 @@ function aap(handler) {
|
|
|
60
55
|
}
|
|
61
56
|
return c.json(result);
|
|
62
57
|
});
|
|
63
|
-
router.get("/
|
|
58
|
+
router.get("/sessions/:id", async (c) => {
|
|
64
59
|
const session = await handler.getSession(c.req.param("id"));
|
|
65
60
|
const { agents } = handler.getMeta();
|
|
66
61
|
return c.json(redactSecretOptions(session, agents));
|
|
67
62
|
});
|
|
68
|
-
router.get("/
|
|
63
|
+
router.get("/sessions/:id/history", async (c) => {
|
|
69
64
|
const typeParam = c.req.query("type");
|
|
70
65
|
if (typeParam !== "compacted" && typeParam !== "full")
|
|
71
66
|
return c.json({ error: 'type must be "compacted" or "full"' }, 400);
|
|
@@ -81,7 +76,7 @@ function aap(handler) {
|
|
|
81
76
|
sessions: result.sessions.map((s) => redactSecretOptions(s, agents)),
|
|
82
77
|
});
|
|
83
78
|
});
|
|
84
|
-
router.delete("/
|
|
79
|
+
router.delete("/sessions/:id", async (c) => {
|
|
85
80
|
await handler.deleteSession(c.req.param("id"));
|
|
86
81
|
return new Response(null, { status: 204 });
|
|
87
82
|
});
|
package/dist/src/server.test.js
CHANGED
|
@@ -5,10 +5,10 @@ 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: 3, agents: [] };
|
|
9
9
|
const session = { sessionId: "s1", agent: { name: "a" } };
|
|
10
10
|
const agentResponse = { stopReason: "end_turn", messages: [] };
|
|
11
|
-
const createSessionResponse = {
|
|
11
|
+
const createSessionResponse = { sessionId: "s1" };
|
|
12
12
|
const sessionList = { sessions: [session] };
|
|
13
13
|
async function* sseEvents() {
|
|
14
14
|
yield { event: "turn_start" };
|
|
@@ -49,7 +49,7 @@ function req(method, path, body, headers) {
|
|
|
49
49
|
});
|
|
50
50
|
(0, vitest_1.it)("GET /session/:id returns session", async () => {
|
|
51
51
|
const app = makeApp(makeHandler());
|
|
52
|
-
const res = await app.fetch(req("GET", "/
|
|
52
|
+
const res = await app.fetch(req("GET", "/sessions/s1"));
|
|
53
53
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
54
54
|
(0, vitest_1.expect)(await res.json()).toEqual(session);
|
|
55
55
|
});
|
|
@@ -73,7 +73,7 @@ function req(method, path, body, headers) {
|
|
|
73
73
|
],
|
|
74
74
|
}),
|
|
75
75
|
}));
|
|
76
|
-
const res = await app.fetch(req("GET", "/
|
|
76
|
+
const res = await app.fetch(req("GET", "/sessions/s1"));
|
|
77
77
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
78
78
|
(0, vitest_1.expect)(await res.json()).toEqual({
|
|
79
79
|
...secretSession,
|
|
@@ -119,45 +119,30 @@ function req(method, path, body, headers) {
|
|
|
119
119
|
],
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
|
-
(0, vitest_1.it)("
|
|
122
|
+
(0, vitest_1.it)("POST /sessions returns 201 with sessionId", async () => {
|
|
123
123
|
const app = makeApp(makeHandler());
|
|
124
|
-
const res = await app.fetch(req("
|
|
125
|
-
agent: { name: "a" },
|
|
126
|
-
messages: [{ role: "assistant", content: "hi" }],
|
|
127
|
-
}));
|
|
128
|
-
(0, vitest_1.expect)(res.status).toBe(400);
|
|
129
|
-
});
|
|
130
|
-
(0, vitest_1.it)("PUT /session returns 201 with AgentResponse", async () => {
|
|
131
|
-
const app = makeApp(makeHandler());
|
|
132
|
-
const res = await app.fetch(req("PUT", "/session", { agent: { name: "a" }, messages: [{ role: "user", content: "hi" }] }));
|
|
124
|
+
const res = await app.fetch(req("POST", "/sessions", { agent: { name: "a" } }));
|
|
133
125
|
(0, vitest_1.expect)(res.status).toBe(201);
|
|
134
126
|
(0, vitest_1.expect)(await res.json()).toEqual(createSessionResponse);
|
|
135
127
|
});
|
|
136
|
-
(0, vitest_1.it)("
|
|
137
|
-
const app = makeApp(makeHandler({ createSession: vitest_1.vi.fn().mockResolvedValue(sseEvents()) }));
|
|
138
|
-
const res = await app.fetch(req("PUT", "/session", {
|
|
139
|
-
agent: { name: "a" },
|
|
140
|
-
messages: [{ role: "user", content: "hi" }],
|
|
141
|
-
stream: "message",
|
|
142
|
-
}));
|
|
143
|
-
(0, vitest_1.expect)(res.status).toBe(200);
|
|
144
|
-
(0, vitest_1.expect)(res.headers.get("content-type")).toContain("text/event-stream");
|
|
145
|
-
});
|
|
146
|
-
(0, vitest_1.it)("POST /session/:id returns AgentResponse", async () => {
|
|
128
|
+
(0, vitest_1.it)("POST /sessions/:id/turns returns AgentResponse", async () => {
|
|
147
129
|
const app = makeApp(makeHandler());
|
|
148
|
-
const res = await app.fetch(req("POST", "/
|
|
130
|
+
const res = await app.fetch(req("POST", "/sessions/s1/turns", { messages: [{ role: "user", content: "hi" }] }));
|
|
149
131
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
150
132
|
(0, vitest_1.expect)(await res.json()).toEqual(agentResponse);
|
|
151
133
|
});
|
|
152
|
-
(0, vitest_1.it)("POST /
|
|
134
|
+
(0, vitest_1.it)("POST /sessions/:id/turns with stream returns SSE", async () => {
|
|
153
135
|
const app = makeApp(makeHandler({ sendTurn: vitest_1.vi.fn().mockResolvedValue(sseEvents()) }));
|
|
154
|
-
const res = await app.fetch(req("POST", "/
|
|
136
|
+
const res = await app.fetch(req("POST", "/sessions/s1/turns", {
|
|
137
|
+
messages: [{ role: "user", content: "hi" }],
|
|
138
|
+
stream: "delta",
|
|
139
|
+
}));
|
|
155
140
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
156
141
|
(0, vitest_1.expect)(res.headers.get("content-type")).toContain("text/event-stream");
|
|
157
142
|
});
|
|
158
143
|
(0, vitest_1.it)("DELETE /session/:id returns 204", async () => {
|
|
159
144
|
const app = makeApp(makeHandler());
|
|
160
|
-
const res = await app.fetch(req("DELETE", "/
|
|
145
|
+
const res = await app.fetch(req("DELETE", "/sessions/s1"));
|
|
161
146
|
(0, vitest_1.expect)(res.status).toBe(204);
|
|
162
147
|
});
|
|
163
148
|
(0, vitest_1.it)("auth middleware: returns 401 when rejected", async () => {
|
|
@@ -190,7 +175,7 @@ function req(method, path, body, headers) {
|
|
|
190
175
|
getSession: vitest_1.vi.fn().mockResolvedValue(sessionWithOptions),
|
|
191
176
|
getMeta: vitest_1.vi.fn().mockReturnValue({ agents: [] }),
|
|
192
177
|
}));
|
|
193
|
-
const res = await app.fetch(req("GET", "/
|
|
178
|
+
const res = await app.fetch(req("GET", "/sessions/s1"));
|
|
194
179
|
(0, vitest_1.expect)(await res.json()).toEqual(sessionWithOptions);
|
|
195
180
|
});
|
|
196
181
|
(0, vitest_1.it)("GET /session/:id does not redact when agent has no secret options", async () => {
|
|
@@ -210,14 +195,14 @@ function req(method, path, body, headers) {
|
|
|
210
195
|
],
|
|
211
196
|
}),
|
|
212
197
|
}));
|
|
213
|
-
const res = await app.fetch(req("GET", "/
|
|
198
|
+
const res = await app.fetch(req("GET", "/sessions/s1"));
|
|
214
199
|
(0, vitest_1.expect)(await res.json()).toEqual(sessionWithOptions);
|
|
215
200
|
});
|
|
216
201
|
(0, vitest_1.it)("GET /session/:id/history?type=compacted calls getSessionHistory", async () => {
|
|
217
202
|
const messages = [{ role: "user", content: "hi" }];
|
|
218
203
|
const handler = makeHandler({ getSessionHistory: vitest_1.vi.fn().mockResolvedValue(messages) });
|
|
219
204
|
const app = makeApp(handler);
|
|
220
|
-
const res = await app.fetch(req("GET", "/
|
|
205
|
+
const res = await app.fetch(req("GET", "/sessions/s1/history?type=compacted"));
|
|
221
206
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
222
207
|
(0, vitest_1.expect)(handler.getSessionHistory).toHaveBeenCalledWith("s1", "compacted");
|
|
223
208
|
(0, vitest_1.expect)(await res.json()).toEqual({ history: { compacted: messages } });
|
|
@@ -226,14 +211,14 @@ function req(method, path, body, headers) {
|
|
|
226
211
|
const messages = [{ role: "user", content: "hi" }];
|
|
227
212
|
const handler = makeHandler({ getSessionHistory: vitest_1.vi.fn().mockResolvedValue(messages) });
|
|
228
213
|
const app = makeApp(handler);
|
|
229
|
-
const res = await app.fetch(req("GET", "/
|
|
214
|
+
const res = await app.fetch(req("GET", "/sessions/s1/history?type=full"));
|
|
230
215
|
(0, vitest_1.expect)(res.status).toBe(200);
|
|
231
216
|
(0, vitest_1.expect)(handler.getSessionHistory).toHaveBeenCalledWith("s1", "full");
|
|
232
217
|
(0, vitest_1.expect)(await res.json()).toEqual({ history: { full: messages } });
|
|
233
218
|
});
|
|
234
219
|
(0, vitest_1.it)("GET /session/:id/history without valid ?type returns 400", async () => {
|
|
235
220
|
const app = makeApp(makeHandler());
|
|
236
|
-
const res = await app.fetch(req("GET", "/
|
|
221
|
+
const res = await app.fetch(req("GET", "/sessions/s1/history"));
|
|
237
222
|
(0, vitest_1.expect)(res.status).toBe(400);
|
|
238
223
|
});
|
|
239
224
|
});
|
package/dist/src/session.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HistoryMessage, ToolPermissionMessage, AgentConfig, ToolSpec, SSEEvent, AgentResponse,
|
|
1
|
+
import { HistoryMessage, ToolPermissionMessage, AgentConfig, ToolSpec, SSEEvent, AgentResponse, SessionTurnRequest, SessionResponse, DeltaSSEEvent } from "@agentapplicationprotocol/core";
|
|
2
2
|
import { ModelProvider } from "./model";
|
|
3
3
|
import { Agent } from "./agent";
|
|
4
4
|
/** Messages accepted as input to a turn: regular history messages or client-side tool permission responses. */
|
|
@@ -8,12 +8,12 @@ export declare class Session {
|
|
|
8
8
|
sessionId: string;
|
|
9
9
|
agent: Agent;
|
|
10
10
|
agentConfig: AgentConfig;
|
|
11
|
-
/**
|
|
11
|
+
/** Client-side tools declared for this session. */
|
|
12
12
|
clientTools: ToolSpec[];
|
|
13
13
|
/** Accumulated conversation history across all turns. */
|
|
14
14
|
history: HistoryMessage[];
|
|
15
15
|
model: ModelProvider;
|
|
16
|
-
constructor(sessionId: string, agent: Agent, model: ModelProvider, agentConfig: AgentConfig, clientTools
|
|
16
|
+
constructor(sessionId: string, agent: Agent, model: ModelProvider, agentConfig: AgentConfig, clientTools: ToolSpec[], history: HistoryMessage[]);
|
|
17
17
|
/** Resolves tool_permission messages into tool result messages by executing granted tools. */
|
|
18
18
|
private resolvePermissions;
|
|
19
19
|
/** Returns the set of trusted server tool names from agentConfig. */
|
|
@@ -54,8 +54,6 @@ export declare class Session {
|
|
|
54
54
|
* Loops the LLM call as long as all tool calls are trusted and executed inline.
|
|
55
55
|
*/
|
|
56
56
|
private runTurnNone;
|
|
57
|
-
/** Runs the first turn and wraps the result with `sessionId` for a `createSession` response. */
|
|
58
|
-
runNewSession(req: CreateSessionRequest): Promise<CreateSessionResponse> | AsyncIterable<SSEEvent>;
|
|
59
57
|
/** Applies config overrides from the request that persist for the session lifetime: client tools, enabled/trusted agent tools, and agent options. */
|
|
60
58
|
private applySessionOverrides;
|
|
61
59
|
/** Routes to the appropriate turn runner based on the requested stream mode. */
|
package/dist/src/session.js
CHANGED
|
@@ -4,13 +4,13 @@ exports.Session = void 0;
|
|
|
4
4
|
const core_1 = require("@agentapplicationprotocol/core");
|
|
5
5
|
/** Manages a stateful conversation session, accumulating history across turns. */
|
|
6
6
|
class Session {
|
|
7
|
-
constructor(sessionId, agent, model, agentConfig, clientTools
|
|
7
|
+
constructor(sessionId, agent, model, agentConfig, clientTools, history) {
|
|
8
8
|
this.sessionId = sessionId;
|
|
9
9
|
this.agent = agent;
|
|
10
10
|
this.model = model;
|
|
11
11
|
this.agentConfig = agentConfig;
|
|
12
12
|
this.clientTools = clientTools;
|
|
13
|
-
this.history =
|
|
13
|
+
this.history = history;
|
|
14
14
|
}
|
|
15
15
|
/** Resolves tool_permission messages into tool result messages by executing granted tools. */
|
|
16
16
|
async resolvePermissions(messages) {
|
|
@@ -210,18 +210,6 @@ class Session {
|
|
|
210
210
|
newMessages.push(...next);
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
-
/** Runs the first turn and wraps the result with `sessionId` for a `createSession` response. */
|
|
214
|
-
runNewSession(req) {
|
|
215
|
-
const sessionId = this.sessionId;
|
|
216
|
-
const result = this.dispatchTurn(req.stream, req.messages);
|
|
217
|
-
if (result instanceof Promise) {
|
|
218
|
-
return result.then((res) => ({ ...res, sessionId }));
|
|
219
|
-
}
|
|
220
|
-
return (async function* () {
|
|
221
|
-
yield { event: "session_start", sessionId };
|
|
222
|
-
yield* result;
|
|
223
|
-
})();
|
|
224
|
-
}
|
|
225
213
|
/** Applies config overrides from the request that persist for the session lifetime: client tools, enabled/trusted agent tools, and agent options. */
|
|
226
214
|
applySessionOverrides(req) {
|
|
227
215
|
// Override client-provided tools
|
package/dist/src/session.test.js
CHANGED
|
@@ -26,7 +26,7 @@ function makeAgent() {
|
|
|
26
26
|
return agent;
|
|
27
27
|
}
|
|
28
28
|
function makeSession(agentConfig = { name: "test-agent" }, model = makeModel(), agent = makeAgent()) {
|
|
29
|
-
return new session_1.Session("sess-1", agent, model, agentConfig);
|
|
29
|
+
return new session_1.Session("sess-1", agent, model, agentConfig, [], []);
|
|
30
30
|
}
|
|
31
31
|
const userMsg = { role: "user", content: "hello" };
|
|
32
32
|
(0, vitest_1.describe)("Session", () => {
|
|
@@ -45,7 +45,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
45
45
|
});
|
|
46
46
|
(0, vitest_1.it)("toSessionResponse includes tools when clientTools is set", () => {
|
|
47
47
|
const s = makeSession();
|
|
48
|
-
s.clientTools = [{ name: "t", description: "",
|
|
48
|
+
s.clientTools = [{ name: "t", description: "", parameters: {} }];
|
|
49
49
|
(0, vitest_1.expect)(s.toSessionResponse().tools).toHaveLength(1);
|
|
50
50
|
});
|
|
51
51
|
(0, vitest_1.describe)("runTurn (none mode)", () => {
|
|
@@ -84,7 +84,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
84
84
|
messages: [{ role: "assistant", content: "done" }],
|
|
85
85
|
}),
|
|
86
86
|
});
|
|
87
|
-
const s = new session_1.Session("s", agent, model, agentConfig);
|
|
87
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
88
88
|
const res = await s.runTurn({ messages: [userMsg] });
|
|
89
89
|
(0, vitest_1.expect)(res.stopReason).toBe("end_turn");
|
|
90
90
|
(0, vitest_1.expect)(model.call).toHaveBeenCalledTimes(2);
|
|
@@ -106,7 +106,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
106
106
|
],
|
|
107
107
|
}),
|
|
108
108
|
});
|
|
109
|
-
const s = new session_1.Session("s", agent, model, agentConfig);
|
|
109
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
110
110
|
const res = (await s.runTurn({ messages: [userMsg] }));
|
|
111
111
|
(0, vitest_1.expect)(res.stopReason).toBe("tool_use");
|
|
112
112
|
(0, vitest_1.expect)(model.call).toHaveBeenCalledTimes(1);
|
|
@@ -145,7 +145,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
145
145
|
yield { event: "turn_stop", stopReason: "end_turn" };
|
|
146
146
|
}),
|
|
147
147
|
});
|
|
148
|
-
const s = new session_1.Session("s", agent, model, agentConfig);
|
|
148
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
149
149
|
const events = [];
|
|
150
150
|
for await (const e of s.runTurn({
|
|
151
151
|
messages: [userMsg],
|
|
@@ -210,7 +210,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
210
210
|
messages: [{ role: "assistant", content: "done" }],
|
|
211
211
|
}),
|
|
212
212
|
});
|
|
213
|
-
const s = new session_1.Session("s", agent, model, agentConfig);
|
|
213
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
214
214
|
const events = [];
|
|
215
215
|
for await (const e of s.runTurn({
|
|
216
216
|
messages: [userMsg],
|
|
@@ -228,7 +228,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
228
228
|
const agentConfig = { name: "test-agent" };
|
|
229
229
|
// Seed history with an assistant message containing a tool_use
|
|
230
230
|
const model = makeModel();
|
|
231
|
-
const s = new session_1.Session("s", agent, model, agentConfig);
|
|
231
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
232
232
|
s.history = [
|
|
233
233
|
{ role: "user", content: "hi" },
|
|
234
234
|
{
|
|
@@ -248,7 +248,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
248
248
|
(0, vitest_1.it)("resolves denied tool_permission with denial message", async () => {
|
|
249
249
|
const agent = makeAgent();
|
|
250
250
|
const model = makeModel();
|
|
251
|
-
const s = new session_1.Session("s", agent, model, { name: "test-agent" });
|
|
251
|
+
const s = new session_1.Session("s", agent, model, { name: "test-agent" }, [], []);
|
|
252
252
|
s.history = [
|
|
253
253
|
{
|
|
254
254
|
role: "assistant",
|
|
@@ -266,7 +266,7 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
266
266
|
(0, vitest_1.describe)("applySessionOverrides via runTurn", () => {
|
|
267
267
|
(0, vitest_1.it)("overrides clientTools when req.tools is provided", async () => {
|
|
268
268
|
const s = makeSession();
|
|
269
|
-
const newTool = { name: "x", description: "",
|
|
269
|
+
const newTool = { name: "x", description: "", parameters: {} };
|
|
270
270
|
await s.runTurn({ messages: [userMsg], tools: [newTool] });
|
|
271
271
|
(0, vitest_1.expect)(s.clientTools).toEqual([newTool]);
|
|
272
272
|
});
|
|
@@ -281,23 +281,90 @@ const userMsg = { role: "user", content: "hello" };
|
|
|
281
281
|
(0, vitest_1.expect)(s.agentConfig.options).toEqual({ model: "gpt-5" });
|
|
282
282
|
});
|
|
283
283
|
});
|
|
284
|
-
(0, vitest_1.describe)("
|
|
285
|
-
(0, vitest_1.it)("
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
284
|
+
(0, vitest_1.describe)("runTurn (delta mode) — untrusted tool stops loop", () => {
|
|
285
|
+
(0, vitest_1.it)("stops at untrusted tool in delta mode", async () => {
|
|
286
|
+
const agent = makeAgent();
|
|
287
|
+
const agentConfig = { name: "test-agent", tools: [] }; // echo not trusted
|
|
288
|
+
const model = makeModel({
|
|
289
|
+
stream: vitest_1.vi.fn().mockImplementationOnce(async function* () {
|
|
290
|
+
yield {
|
|
291
|
+
event: "tool_call",
|
|
292
|
+
toolCallId: "c1",
|
|
293
|
+
name: "echo",
|
|
294
|
+
input: { msg: "hi" },
|
|
295
|
+
};
|
|
296
|
+
yield { event: "turn_stop", stopReason: "tool_use" };
|
|
297
|
+
}),
|
|
298
|
+
});
|
|
299
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
300
|
+
const events = [];
|
|
301
|
+
for await (const e of s.runTurn({
|
|
294
302
|
messages: [userMsg],
|
|
295
303
|
stream: "delta",
|
|
304
|
+
}))
|
|
305
|
+
events.push(e);
|
|
306
|
+
(0, vitest_1.expect)(events.at(-1).event).toBe("turn_stop");
|
|
307
|
+
(0, vitest_1.expect)(model.stream).toHaveBeenCalledTimes(1);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
(0, vitest_1.describe)("runTurn (message mode) — tool_use block and untrusted stop", () => {
|
|
311
|
+
(0, vitest_1.it)("yields tool_call event for tool_use blocks in message mode", async () => {
|
|
312
|
+
const model = makeModel({
|
|
313
|
+
call: vitest_1.vi.fn().mockResolvedValue({
|
|
314
|
+
stopReason: "tool_use",
|
|
315
|
+
messages: [
|
|
316
|
+
{
|
|
317
|
+
role: "assistant",
|
|
318
|
+
content: [{ type: "tool_use", toolCallId: "c1", name: "echo", input: { msg: "hi" } }],
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
}),
|
|
296
322
|
});
|
|
323
|
+
const s = makeSession({ name: "test-agent" }, model);
|
|
297
324
|
const events = [];
|
|
298
|
-
for await (const e of
|
|
325
|
+
for await (const e of s.runTurn({
|
|
326
|
+
messages: [userMsg],
|
|
327
|
+
stream: "message",
|
|
328
|
+
}))
|
|
329
|
+
events.push(e);
|
|
330
|
+
(0, vitest_1.expect)(events.some((e) => e.event === "tool_call")).toBe(true);
|
|
331
|
+
});
|
|
332
|
+
(0, vitest_1.it)("stops at untrusted tool in message mode", async () => {
|
|
333
|
+
const agent = makeAgent();
|
|
334
|
+
const agentConfig = { name: "test-agent", tools: [] };
|
|
335
|
+
const model = makeModel({
|
|
336
|
+
call: vitest_1.vi.fn().mockResolvedValue({
|
|
337
|
+
stopReason: "tool_use",
|
|
338
|
+
messages: [
|
|
339
|
+
{
|
|
340
|
+
role: "assistant",
|
|
341
|
+
content: [{ type: "tool_use", toolCallId: "c1", name: "echo", input: { msg: "hi" } }],
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
}),
|
|
345
|
+
});
|
|
346
|
+
const s = new session_1.Session("s", agent, model, agentConfig, [], []);
|
|
347
|
+
const events = [];
|
|
348
|
+
for await (const e of s.runTurn({
|
|
349
|
+
messages: [userMsg],
|
|
350
|
+
stream: "message",
|
|
351
|
+
}))
|
|
299
352
|
events.push(e);
|
|
300
|
-
(0, vitest_1.expect)(events
|
|
353
|
+
(0, vitest_1.expect)(events.at(-1).event).toBe("turn_stop");
|
|
354
|
+
(0, vitest_1.expect)(model.call).toHaveBeenCalledTimes(1);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
(0, vitest_1.describe)("lastToolUses", () => {
|
|
358
|
+
(0, vitest_1.it)("returns empty array when last assistant message has string content", async () => {
|
|
359
|
+
const s = makeSession();
|
|
360
|
+
s.history = [{ role: "assistant", content: "hello" }];
|
|
361
|
+
// runTurnNone will call lastToolUses; with string content it should return []
|
|
362
|
+
const model = makeModel({
|
|
363
|
+
call: vitest_1.vi.fn().mockResolvedValue({ stopReason: "end_turn", messages: [] }),
|
|
364
|
+
});
|
|
365
|
+
const s2 = new session_1.Session("s", makeAgent(), model, { name: "test-agent" }, [], [{ role: "assistant", content: "hello" }]);
|
|
366
|
+
const res = (await s2.runTurn({ messages: [userMsg] }));
|
|
367
|
+
(0, vitest_1.expect)(res.stopReason).toBe("end_turn");
|
|
301
368
|
});
|
|
302
369
|
});
|
|
303
370
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentapplicationprotocol/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
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.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@ai-sdk/openai": "^3.0.48",
|