experimental-a2 0.0.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/CHANGELOG.md +128 -0
- package/dist/ai-server.browser.d.ts +1 -0
- package/dist/ai-server.browser.js +4 -0
- package/dist/ai-server.d.ts +65 -0
- package/dist/ai-server.js +494 -0
- package/dist/ai.d.ts +282 -0
- package/dist/ai.js +922 -0
- package/dist/cache-indexeddb.d.ts +1 -0
- package/dist/cache-indexeddb.js +0 -0
- package/dist/client.d.ts +90 -0
- package/dist/client.js +410 -0
- package/dist/contract-B0kAXoaL.js +60 -0
- package/dist/contract-DL8btVd9.d.ts +161 -0
- package/dist/devtools-server.browser.d.ts +1 -0
- package/dist/devtools-server.browser.js +4 -0
- package/dist/devtools-server.d.ts +22 -0
- package/dist/devtools-server.js +1087 -0
- package/dist/errors-BJRMd-h6.js +23 -0
- package/dist/errors-xL_JTXsY.d.ts +20 -0
- package/dist/http.d.ts +44 -0
- package/dist/http.js +119 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/inspection-E7qbD0Xj.js +10 -0
- package/dist/internal-Dm8Ejnud.js +36 -0
- package/dist/log-Dg1I8NRr.d.ts +245 -0
- package/dist/log-memory.d.ts +11 -0
- package/dist/log-memory.js +345 -0
- package/dist/log-polling-RO7kclzR.js +83 -0
- package/dist/log-postgres.d.ts +40 -0
- package/dist/log-postgres.js +628 -0
- package/dist/log-redis.d.ts +31 -0
- package/dist/log-redis.js +711 -0
- package/dist/log-sqlite.d.ts +17 -0
- package/dist/log-sqlite.js +450 -0
- package/dist/log-yJbXUf72.js +5 -0
- package/dist/otel.d.ts +12 -0
- package/dist/otel.js +41 -0
- package/dist/react.d.ts +54 -0
- package/dist/react.js +85 -0
- package/dist/recovery-vercel.d.ts +60 -0
- package/dist/recovery-vercel.js +120 -0
- package/dist/retryable-lazy-DZWmHpii.js +19 -0
- package/dist/server-DYsnKTTy.js +780 -0
- package/dist/server.browser.d.ts +1 -0
- package/dist/server.browser.js +11 -0
- package/dist/server.d.ts +136 -0
- package/dist/server.js +2 -0
- package/dist/telemetry-C78al20p.d.ts +32 -0
- package/dist/validate-XKT4FSNn.js +28 -0
- package/dist/wire-2QpU1EtJ.js +62 -0
- package/docs/01-quickstart.mdx +214 -0
- package/docs/concepts/01-contracts.mdx +138 -0
- package/docs/concepts/02-handlers.mdx +146 -0
- package/docs/concepts/03-durability.mdx +230 -0
- package/docs/concepts/04-state.mdx +133 -0
- package/docs/guides/01-timers.mdx +85 -0
- package/docs/guides/02-cancellation.mdx +107 -0
- package/docs/guides/03-react.mdx +234 -0
- package/docs/guides/04-local-first.mdx +88 -0
- package/docs/guides/05-production.mdx +179 -0
- package/docs/guides/06-ai-agents.mdx +659 -0
- package/docs/guides/07-devtools.mdx +101 -0
- package/docs/guides/08-application-data.mdx +114 -0
- package/docs/index.mdx +282 -0
- package/docs/reference/01-api.mdx +637 -0
- package/docs/reference/02-errors.mdx +77 -0
- package/package.json +111 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { t as createServer } from "./server-DYsnKTTy.js";
|
|
2
|
+
import { ToolLoopAgent, createAgentUIStream } from "ai";
|
|
3
|
+
//#region src/ai-server.ts
|
|
4
|
+
/**
|
|
5
|
+
* a2/ai/server — the server-only implementation of an a2/ai definition.
|
|
6
|
+
*
|
|
7
|
+
* `createHandlers()` exposes the ordinary A2 handler table;
|
|
8
|
+
* `createAgentServer()` is its batteries-included assembly with createServer.
|
|
9
|
+
*/
|
|
10
|
+
const resolve = async (value, context) => typeof value === "function" ? await value(context) : value;
|
|
11
|
+
const modelName = (model) => {
|
|
12
|
+
if (typeof model === "string") return model;
|
|
13
|
+
if ("modelId" in model && typeof model.modelId === "string") return model.modelId;
|
|
14
|
+
return "custom";
|
|
15
|
+
};
|
|
16
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
17
|
+
const addTokenCounts = (left, right) => left === void 0 && right === void 0 ? void 0 : (left ?? 0) + (right ?? 0);
|
|
18
|
+
const addUsage = (left, right) => {
|
|
19
|
+
return {
|
|
20
|
+
inputTokens: addTokenCounts(left?.inputTokens, right.inputTokens),
|
|
21
|
+
inputTokenDetails: {
|
|
22
|
+
noCacheTokens: addTokenCounts(left?.inputTokenDetails.noCacheTokens, right.inputTokenDetails.noCacheTokens),
|
|
23
|
+
cacheReadTokens: addTokenCounts(left?.inputTokenDetails.cacheReadTokens, right.inputTokenDetails.cacheReadTokens),
|
|
24
|
+
cacheWriteTokens: addTokenCounts(left?.inputTokenDetails.cacheWriteTokens, right.inputTokenDetails.cacheWriteTokens)
|
|
25
|
+
},
|
|
26
|
+
outputTokens: addTokenCounts(left?.outputTokens, right.outputTokens),
|
|
27
|
+
outputTokenDetails: {
|
|
28
|
+
textTokens: addTokenCounts(left?.outputTokenDetails.textTokens, right.outputTokenDetails.textTokens),
|
|
29
|
+
reasoningTokens: addTokenCounts(left?.outputTokenDetails.reasoningTokens, right.outputTokenDetails.reasoningTokens)
|
|
30
|
+
},
|
|
31
|
+
totalTokens: addTokenCounts(left?.totalTokens, right.totalTokens)
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const isBoundaryChunk = (chunk) => chunk !== void 0 && (chunk.type === "text-end" || chunk.type === "reasoning-end" || chunk.type === "tool-input-available" || chunk.type === "tool-input-error" || chunk.type === "tool-output-available" || chunk.type === "tool-output-error" || chunk.type === "tool-output-denied" || chunk.type === "tool-approval-request" || chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error");
|
|
35
|
+
const nextOrTimer = async (next, delayMs) => {
|
|
36
|
+
let timer;
|
|
37
|
+
try {
|
|
38
|
+
return await Promise.race([next.then((result) => ({
|
|
39
|
+
type: "next",
|
|
40
|
+
result
|
|
41
|
+
})), new Promise((finishTimer) => {
|
|
42
|
+
timer = setTimeout(() => finishTimer({ type: "timer" }), delayMs);
|
|
43
|
+
timer.unref?.();
|
|
44
|
+
})]);
|
|
45
|
+
} finally {
|
|
46
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
async function generateWithAISDK(context) {
|
|
50
|
+
const { onStepEnd, onStepFinish, ...settings } = context.generation;
|
|
51
|
+
const userOnStepEnd = onStepEnd ?? onStepFinish;
|
|
52
|
+
const agentSettings = {
|
|
53
|
+
...settings,
|
|
54
|
+
id: context.generationId,
|
|
55
|
+
model: context.model,
|
|
56
|
+
tools: context.tools,
|
|
57
|
+
...context.instructions === void 0 ? {} : { instructions: context.instructions }
|
|
58
|
+
};
|
|
59
|
+
const sdkAgent = new ToolLoopAgent(agentSettings);
|
|
60
|
+
let usage;
|
|
61
|
+
let finishReason;
|
|
62
|
+
return {
|
|
63
|
+
stream: await createAgentUIStream({
|
|
64
|
+
agent: sdkAgent,
|
|
65
|
+
uiMessages: context.messages,
|
|
66
|
+
generateMessageId: () => context.responseMessageId,
|
|
67
|
+
abortSignal: context.signal,
|
|
68
|
+
async onStepEnd(step) {
|
|
69
|
+
usage = addUsage(usage, step.usage);
|
|
70
|
+
await userOnStepEnd?.(step);
|
|
71
|
+
},
|
|
72
|
+
onEnd(event) {
|
|
73
|
+
finishReason = event.finishReason;
|
|
74
|
+
}
|
|
75
|
+
}),
|
|
76
|
+
completion: () => ({
|
|
77
|
+
...finishReason === void 0 ? {} : { finishReason },
|
|
78
|
+
...usage === void 0 ? {} : { usage }
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function* consumeGeneration(options) {
|
|
83
|
+
const pending = [];
|
|
84
|
+
let streamedFinishReason;
|
|
85
|
+
const maxChunks = options.progress?.maxChunks ?? 16;
|
|
86
|
+
const maxDelayMs = options.progress?.maxDelayMs ?? 30;
|
|
87
|
+
let lastFlush = Date.now();
|
|
88
|
+
const chunks = options.source.stream[Symbol.asyncIterator]();
|
|
89
|
+
let pendingChunk = chunks.next();
|
|
90
|
+
try {
|
|
91
|
+
for (;;) {
|
|
92
|
+
let result;
|
|
93
|
+
if (pending.length > 0) {
|
|
94
|
+
const remaining = Math.max(0, maxDelayMs - (Date.now() - lastFlush));
|
|
95
|
+
const outcome = await nextOrTimer(pendingChunk, remaining);
|
|
96
|
+
if (outcome.type === "timer") {
|
|
97
|
+
yield {
|
|
98
|
+
type: "progress",
|
|
99
|
+
chunks: pending.splice(0)
|
|
100
|
+
};
|
|
101
|
+
lastFlush = Date.now();
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
result = outcome.result;
|
|
105
|
+
} else result = await pendingChunk;
|
|
106
|
+
if (result.done) break;
|
|
107
|
+
const chunk = result.value;
|
|
108
|
+
pending.push(chunk);
|
|
109
|
+
if (chunk.type === "finish") streamedFinishReason = chunk.finishReason;
|
|
110
|
+
pendingChunk = chunks.next();
|
|
111
|
+
if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
|
|
112
|
+
yield {
|
|
113
|
+
type: "progress",
|
|
114
|
+
chunks: pending.splice(0)
|
|
115
|
+
};
|
|
116
|
+
lastFlush = Date.now();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (pending.length > 0) yield {
|
|
121
|
+
type: "progress",
|
|
122
|
+
chunks: pending.splice(0)
|
|
123
|
+
};
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
const completion = options.source.completion?.();
|
|
127
|
+
if (pending.length > 0) yield {
|
|
128
|
+
type: "progress",
|
|
129
|
+
chunks: pending.splice(0)
|
|
130
|
+
};
|
|
131
|
+
const finishReason = completion?.finishReason ?? streamedFinishReason;
|
|
132
|
+
yield {
|
|
133
|
+
type: "finish",
|
|
134
|
+
...finishReason === void 0 ? {} : { finishReason },
|
|
135
|
+
...completion?.usage === void 0 ? {} : { usage: completion.usage }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const replay = (definition, history) => {
|
|
139
|
+
let state = definition.reducer.initialState;
|
|
140
|
+
for (const event of history) state = definition.reducer.fold(state, event);
|
|
141
|
+
return state;
|
|
142
|
+
};
|
|
143
|
+
const contextMessages = (state) => {
|
|
144
|
+
const compaction = state.compaction;
|
|
145
|
+
if (compaction?.status !== "completed" || !compaction.messages) return state.messages;
|
|
146
|
+
const boundary = state.messages.findIndex((message) => message.id === compaction.throughMessageId);
|
|
147
|
+
return boundary === -1 ? state.messages : [...compaction.messages, ...state.messages.slice(boundary + 1)];
|
|
148
|
+
};
|
|
149
|
+
const lifecycleEvents = (options) => {
|
|
150
|
+
const result = [];
|
|
151
|
+
for (const [chunkIndex, chunk] of options.chunks.entries()) {
|
|
152
|
+
const resultId = `${options.generationId}:tool-result:${options.sequence}:${chunkIndex}`;
|
|
153
|
+
if (chunk.type === "tool-input-available") {
|
|
154
|
+
const payload = {
|
|
155
|
+
requestId: options.requestId,
|
|
156
|
+
messageId: options.messageId,
|
|
157
|
+
generationId: options.generationId,
|
|
158
|
+
toolCallId: chunk.toolCallId,
|
|
159
|
+
toolName: chunk.toolName,
|
|
160
|
+
input: chunk.input,
|
|
161
|
+
...chunk.dynamic === void 0 ? {} : { dynamic: chunk.dynamic },
|
|
162
|
+
...chunk.providerExecuted === void 0 ? {} : { providerExecuted: chunk.providerExecuted },
|
|
163
|
+
...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata },
|
|
164
|
+
...chunk.toolMetadata === void 0 ? {} : { toolMetadata: chunk.toolMetadata },
|
|
165
|
+
...chunk.title === void 0 ? {} : { title: chunk.title }
|
|
166
|
+
};
|
|
167
|
+
result.push({
|
|
168
|
+
type: "ai.tool.called",
|
|
169
|
+
id: `${options.generationId}:tool:${chunk.toolCallId}:called`,
|
|
170
|
+
payload
|
|
171
|
+
});
|
|
172
|
+
} else if (chunk.type === "tool-input-error") {
|
|
173
|
+
const payload = {
|
|
174
|
+
requestId: options.requestId,
|
|
175
|
+
messageId: options.messageId,
|
|
176
|
+
generationId: options.generationId,
|
|
177
|
+
toolCallId: chunk.toolCallId,
|
|
178
|
+
toolName: chunk.toolName,
|
|
179
|
+
...chunk.dynamic ? { input: chunk.input } : { rawInput: chunk.input },
|
|
180
|
+
error: chunk.errorText,
|
|
181
|
+
phase: "input",
|
|
182
|
+
...chunk.dynamic === void 0 ? {} : { dynamic: chunk.dynamic },
|
|
183
|
+
...chunk.providerExecuted === void 0 ? {} : { providerExecuted: chunk.providerExecuted },
|
|
184
|
+
...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata },
|
|
185
|
+
...chunk.toolMetadata === void 0 ? {} : { toolMetadata: chunk.toolMetadata }
|
|
186
|
+
};
|
|
187
|
+
result.push({
|
|
188
|
+
type: "ai.tool.result",
|
|
189
|
+
id: resultId,
|
|
190
|
+
payload
|
|
191
|
+
});
|
|
192
|
+
} else if (chunk.type === "tool-output-available") {
|
|
193
|
+
const payload = {
|
|
194
|
+
requestId: options.requestId,
|
|
195
|
+
messageId: options.messageId,
|
|
196
|
+
generationId: options.generationId,
|
|
197
|
+
toolCallId: chunk.toolCallId,
|
|
198
|
+
output: chunk.output,
|
|
199
|
+
phase: "execution",
|
|
200
|
+
...chunk.preliminary === void 0 ? {} : { preliminary: chunk.preliminary },
|
|
201
|
+
...chunk.dynamic === void 0 ? {} : { dynamic: chunk.dynamic },
|
|
202
|
+
...chunk.providerExecuted === void 0 ? {} : { providerExecuted: chunk.providerExecuted },
|
|
203
|
+
...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata },
|
|
204
|
+
...chunk.toolMetadata === void 0 ? {} : { toolMetadata: chunk.toolMetadata }
|
|
205
|
+
};
|
|
206
|
+
result.push({
|
|
207
|
+
type: "ai.tool.result",
|
|
208
|
+
id: resultId,
|
|
209
|
+
payload
|
|
210
|
+
});
|
|
211
|
+
} else if (chunk.type === "tool-output-error") {
|
|
212
|
+
const payload = {
|
|
213
|
+
requestId: options.requestId,
|
|
214
|
+
messageId: options.messageId,
|
|
215
|
+
generationId: options.generationId,
|
|
216
|
+
toolCallId: chunk.toolCallId,
|
|
217
|
+
error: chunk.errorText,
|
|
218
|
+
phase: "execution",
|
|
219
|
+
...chunk.dynamic === void 0 ? {} : { dynamic: chunk.dynamic },
|
|
220
|
+
...chunk.providerExecuted === void 0 ? {} : { providerExecuted: chunk.providerExecuted },
|
|
221
|
+
...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata },
|
|
222
|
+
...chunk.toolMetadata === void 0 ? {} : { toolMetadata: chunk.toolMetadata }
|
|
223
|
+
};
|
|
224
|
+
result.push({
|
|
225
|
+
type: "ai.tool.result",
|
|
226
|
+
id: resultId,
|
|
227
|
+
payload
|
|
228
|
+
});
|
|
229
|
+
} else if (chunk.type === "tool-output-denied") {
|
|
230
|
+
const payload = {
|
|
231
|
+
requestId: options.requestId,
|
|
232
|
+
messageId: options.messageId,
|
|
233
|
+
generationId: options.generationId,
|
|
234
|
+
toolCallId: chunk.toolCallId,
|
|
235
|
+
denied: true,
|
|
236
|
+
phase: "execution"
|
|
237
|
+
};
|
|
238
|
+
result.push({
|
|
239
|
+
type: "ai.tool.result",
|
|
240
|
+
id: resultId,
|
|
241
|
+
payload
|
|
242
|
+
});
|
|
243
|
+
} else if (chunk.type === "tool-approval-request") {
|
|
244
|
+
const payload = {
|
|
245
|
+
messageId: options.messageId,
|
|
246
|
+
generationId: options.generationId,
|
|
247
|
+
approvalId: chunk.approvalId,
|
|
248
|
+
toolCallId: chunk.toolCallId,
|
|
249
|
+
...chunk.isAutomatic === void 0 ? {} : { isAutomatic: chunk.isAutomatic },
|
|
250
|
+
...chunk.signature === void 0 ? {} : { signature: chunk.signature }
|
|
251
|
+
};
|
|
252
|
+
result.push({
|
|
253
|
+
type: "ai.approval.requested",
|
|
254
|
+
id: `${options.generationId}:approval:${chunk.approvalId}`,
|
|
255
|
+
payload
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return result;
|
|
260
|
+
};
|
|
261
|
+
/**
|
|
262
|
+
* Build the ordinary A2 handler table for the built-in agent protocol.
|
|
263
|
+
* Application handlers can be spread beside this table.
|
|
264
|
+
*/
|
|
265
|
+
function createHandlers(options) {
|
|
266
|
+
if (options.model === void 0) throw new TypeError("createHandlers requires model");
|
|
267
|
+
if (options.progress?.maxChunks !== void 0 && (!Number.isInteger(options.progress.maxChunks) || options.progress.maxChunks < 1)) throw new TypeError("progress.maxChunks must be a positive integer");
|
|
268
|
+
if (options.progress?.maxDelayMs !== void 0 && (!Number.isFinite(options.progress.maxDelayMs) || options.progress.maxDelayMs < 0)) throw new TypeError("progress.maxDelayMs must be a non-negative number");
|
|
269
|
+
const generationHandler = async (ctx) => {
|
|
270
|
+
const history = await ctx.history();
|
|
271
|
+
const requestId = ctx.event.id;
|
|
272
|
+
const request = ctx.event.payload;
|
|
273
|
+
if (history.some((event) => event.type === "ai.session.closed")) return;
|
|
274
|
+
if (history.some((event) => {
|
|
275
|
+
if (event.type === "ai.generation.completed") return event.payload.requestId === requestId;
|
|
276
|
+
if (event.type !== "ai.generation.failed") return false;
|
|
277
|
+
const payload = event.payload;
|
|
278
|
+
return payload.requestId === requestId && payload.superseded !== true;
|
|
279
|
+
})) return;
|
|
280
|
+
const previousStarts = history.filter((event) => event.type === "ai.generation.started" && event.payload.requestId === requestId);
|
|
281
|
+
const attempt = previousStarts.length + 1;
|
|
282
|
+
const generationId = `${requestId}:generation:${attempt}`;
|
|
283
|
+
const responseMessageId = request.responseMessageId ?? (request.reason === "message" ? `${request.messageId}:assistant` : request.messageId);
|
|
284
|
+
const previous = previousStarts.at(-1);
|
|
285
|
+
const incompleteId = previous ? previous.payload.generationId : void 0;
|
|
286
|
+
const promptHistory = incompleteId === void 0 && request.reason !== "retry" ? history : history.filter((event) => !(event.type === "ai.generation.progress" && (incompleteId !== void 0 && event.payload.generationId === incompleteId || request.reason === "retry" && event.payload.responseMessageId === responseMessageId)));
|
|
287
|
+
let state = replay(options.agent, promptHistory);
|
|
288
|
+
const resolverContext = {
|
|
289
|
+
event: ctx.event,
|
|
290
|
+
state,
|
|
291
|
+
history,
|
|
292
|
+
signal: ctx.signal
|
|
293
|
+
};
|
|
294
|
+
const resolvedModel = await resolve(options.model, resolverContext);
|
|
295
|
+
if (resolvedModel === void 0) throw new TypeError("the model resolver returned undefined");
|
|
296
|
+
const started = {
|
|
297
|
+
requestId,
|
|
298
|
+
messageId: request.messageId,
|
|
299
|
+
generationId,
|
|
300
|
+
responseMessageId,
|
|
301
|
+
attempt,
|
|
302
|
+
model: modelName(resolvedModel)
|
|
303
|
+
};
|
|
304
|
+
const startEvents = [];
|
|
305
|
+
if (previous) {
|
|
306
|
+
const payload = previous.payload;
|
|
307
|
+
const superseded = {
|
|
308
|
+
requestId,
|
|
309
|
+
messageId: payload.messageId,
|
|
310
|
+
generationId: payload.generationId,
|
|
311
|
+
responseMessageId: payload.responseMessageId,
|
|
312
|
+
error: "generation attempt was superseded after an incomplete run",
|
|
313
|
+
superseded: true
|
|
314
|
+
};
|
|
315
|
+
startEvents.push({
|
|
316
|
+
type: "ai.generation.failed",
|
|
317
|
+
id: `${payload.generationId}:superseded`,
|
|
318
|
+
payload: superseded
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
startEvents.push({
|
|
322
|
+
type: "ai.generation.started",
|
|
323
|
+
id: generationId,
|
|
324
|
+
payload: started
|
|
325
|
+
});
|
|
326
|
+
await ctx.append(...startEvents);
|
|
327
|
+
let messages = contextMessages(state);
|
|
328
|
+
if (options.compaction) {
|
|
329
|
+
const compactionContext = {
|
|
330
|
+
...resolverContext,
|
|
331
|
+
messages
|
|
332
|
+
};
|
|
333
|
+
if (await options.compaction.shouldCompact(compactionContext)) {
|
|
334
|
+
const throughMessageId = messages.at(-1)?.id ?? request.messageId;
|
|
335
|
+
await ctx.append({
|
|
336
|
+
type: "ai.compaction.requested",
|
|
337
|
+
id: `${generationId}:compaction:requested`,
|
|
338
|
+
payload: {
|
|
339
|
+
generationId,
|
|
340
|
+
throughMessageId
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
messages = await options.compaction.compact(compactionContext);
|
|
344
|
+
const completed = {
|
|
345
|
+
generationId,
|
|
346
|
+
throughMessageId,
|
|
347
|
+
messages
|
|
348
|
+
};
|
|
349
|
+
await ctx.append({
|
|
350
|
+
type: "ai.compaction.completed",
|
|
351
|
+
id: `${generationId}:compaction:completed`,
|
|
352
|
+
payload: completed
|
|
353
|
+
});
|
|
354
|
+
state = {
|
|
355
|
+
...state,
|
|
356
|
+
compaction: {
|
|
357
|
+
status: "completed",
|
|
358
|
+
...completed
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const resolvedInstructions = options.instructions === void 0 ? void 0 : await resolve(options.instructions, resolverContext);
|
|
365
|
+
const generateContext = {
|
|
366
|
+
request: ctx.event,
|
|
367
|
+
requestId,
|
|
368
|
+
generationId,
|
|
369
|
+
responseMessageId,
|
|
370
|
+
messages,
|
|
371
|
+
state,
|
|
372
|
+
history,
|
|
373
|
+
signal: ctx.signal,
|
|
374
|
+
model: resolvedModel,
|
|
375
|
+
tools: options.tools ?? {},
|
|
376
|
+
...resolvedInstructions === void 0 ? {} : { instructions: resolvedInstructions },
|
|
377
|
+
generation: options.generation ?? {}
|
|
378
|
+
};
|
|
379
|
+
const updates = consumeGeneration({
|
|
380
|
+
source: options.generate === void 0 ? await generateWithAISDK(generateContext) : { stream: await options.generate(generateContext) },
|
|
381
|
+
...options.progress === void 0 ? {} : { progress: options.progress }
|
|
382
|
+
});
|
|
383
|
+
let sequence = 0;
|
|
384
|
+
let finish;
|
|
385
|
+
for await (const update of updates) {
|
|
386
|
+
ctx.signal.throwIfAborted();
|
|
387
|
+
if (update.type === "finish") {
|
|
388
|
+
finish = update;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
const progress = {
|
|
392
|
+
requestId,
|
|
393
|
+
messageId: request.messageId,
|
|
394
|
+
generationId,
|
|
395
|
+
responseMessageId,
|
|
396
|
+
sequence,
|
|
397
|
+
chunks: update.chunks
|
|
398
|
+
};
|
|
399
|
+
const extras = lifecycleEvents({
|
|
400
|
+
requestId,
|
|
401
|
+
messageId: responseMessageId,
|
|
402
|
+
generationId,
|
|
403
|
+
sequence,
|
|
404
|
+
chunks: update.chunks
|
|
405
|
+
});
|
|
406
|
+
await ctx.append({
|
|
407
|
+
type: "ai.generation.progress",
|
|
408
|
+
id: `${generationId}:progress:${sequence}`,
|
|
409
|
+
payload: progress
|
|
410
|
+
}, ...extras);
|
|
411
|
+
sequence += 1;
|
|
412
|
+
}
|
|
413
|
+
if (!finish) throw new Error("agent generation finished without output");
|
|
414
|
+
const completed = {
|
|
415
|
+
requestId,
|
|
416
|
+
messageId: request.messageId,
|
|
417
|
+
generationId,
|
|
418
|
+
responseMessageId,
|
|
419
|
+
...finish.finishReason === void 0 ? {} : { finishReason: finish.finishReason },
|
|
420
|
+
...finish.usage === void 0 ? {} : { usage: finish.usage }
|
|
421
|
+
};
|
|
422
|
+
const messageCompleted = { messageId: responseMessageId };
|
|
423
|
+
await ctx.append({
|
|
424
|
+
type: "ai.generation.completed",
|
|
425
|
+
id: `${generationId}:completed`,
|
|
426
|
+
payload: completed
|
|
427
|
+
}, {
|
|
428
|
+
type: "ai.message.completed",
|
|
429
|
+
id: `${generationId}:message:completed`,
|
|
430
|
+
payload: messageCompleted
|
|
431
|
+
});
|
|
432
|
+
} catch (error) {
|
|
433
|
+
if (ctx.signal.aborted) {
|
|
434
|
+
const interrupted = {
|
|
435
|
+
messageId: responseMessageId,
|
|
436
|
+
generationId,
|
|
437
|
+
reason: "aborted"
|
|
438
|
+
};
|
|
439
|
+
await ctx.append({
|
|
440
|
+
type: "ai.message.interrupted",
|
|
441
|
+
id: `${generationId}:interrupted`,
|
|
442
|
+
payload: interrupted
|
|
443
|
+
});
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
const failed = {
|
|
447
|
+
requestId,
|
|
448
|
+
messageId: request.messageId,
|
|
449
|
+
generationId,
|
|
450
|
+
responseMessageId,
|
|
451
|
+
error: errorMessage(error)
|
|
452
|
+
};
|
|
453
|
+
await ctx.append({
|
|
454
|
+
type: "ai.generation.failed",
|
|
455
|
+
id: `${generationId}:failed`,
|
|
456
|
+
payload: failed
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
return { "ai.generation.requested": {
|
|
461
|
+
abortOn: {
|
|
462
|
+
"ai.message.interrupted": (event, trigger) => {
|
|
463
|
+
const responseMessageId = trigger.payload.responseMessageId ?? (trigger.payload.reason === "message" ? `${trigger.payload.messageId}:assistant` : trigger.payload.messageId);
|
|
464
|
+
return event.payload.messageId === responseMessageId;
|
|
465
|
+
},
|
|
466
|
+
"ai.session.closed": true
|
|
467
|
+
},
|
|
468
|
+
handler: generationHandler
|
|
469
|
+
} };
|
|
470
|
+
}
|
|
471
|
+
/** Assemble an A2 server with the built-in agent handlers and app extensions. */
|
|
472
|
+
function createAgentServer(options) {
|
|
473
|
+
const { agent: definition, model, tools, instructions, generation, generate, compaction, progress, handlers, ...serverOptions } = options;
|
|
474
|
+
const builtIns = createHandlers({
|
|
475
|
+
agent: definition,
|
|
476
|
+
model,
|
|
477
|
+
...tools === void 0 ? {} : { tools },
|
|
478
|
+
...instructions === void 0 ? {} : { instructions },
|
|
479
|
+
...generation === void 0 ? {} : { generation },
|
|
480
|
+
...generate === void 0 ? {} : { generate },
|
|
481
|
+
...compaction === void 0 ? {} : { compaction },
|
|
482
|
+
...progress === void 0 ? {} : { progress }
|
|
483
|
+
});
|
|
484
|
+
return createServer({
|
|
485
|
+
...serverOptions,
|
|
486
|
+
contract: definition.contract,
|
|
487
|
+
handlers: {
|
|
488
|
+
...builtIns,
|
|
489
|
+
...handlers
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
//#endregion
|
|
494
|
+
export { createAgentServer, createHandlers };
|