experimental-a2 0.18.1 → 0.19.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 +28 -0
- package/dist/{ai-BMLlI2Ff.d.ts → ai-Cz3hqVhk.d.ts} +33 -16
- package/dist/ai-Cz3hqVhk.d.ts.map +1 -0
- package/dist/ai-client.d.ts +1 -1
- package/dist/ai-client.js +1 -1
- package/dist/ai-control-CvLbW10B.js +46 -0
- package/dist/ai-control-CvLbW10B.js.map +1 -0
- package/dist/ai-fx.d.ts +1 -1
- package/dist/ai-fx.d.ts.map +1 -1
- package/dist/ai-fx.js +30 -10
- package/dist/ai-fx.js.map +1 -1
- package/dist/{ai-harness-BuLh_EYi.js → ai-harness-BuuC-gJ3.js} +79 -15
- package/dist/ai-harness-BuuC-gJ3.js.map +1 -0
- package/dist/{ai-harness-B2suP2Qh.d.ts → ai-harness-CV6rXbB3.d.ts} +2 -2
- package/dist/ai-harness-CV6rXbB3.d.ts.map +1 -0
- package/dist/{ai-D6mGlO8j.js → ai-mMiWul1T.js} +116 -77
- package/dist/ai-mMiWul1T.js.map +1 -0
- package/dist/ai-pi.d.ts +1 -1
- package/dist/ai-pi.d.ts.map +1 -1
- package/dist/ai-pi.js +55 -10
- package/dist/ai-pi.js.map +1 -1
- package/dist/ai-react.d.ts +1 -1
- package/dist/ai-react.js +1 -1
- package/dist/ai-server.d.ts +2 -2
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +118 -50
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +1 -1
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +1 -4
- package/dist/scheduler-vercel.js.map +1 -1
- package/docs/agents/03-conversations.mdx +25 -13
- package/docs/agents/04-harnesses.mdx +51 -5
- package/docs/contract/03-sessions.mdx +1 -1
- package/docs/reference/04-ai.mdx +27 -18
- package/docs/reference/05-adapters.mdx +2 -2
- package/docs/server/02-timers.mdx +1 -1
- package/docs/server/05-production.mdx +2 -2
- package/examples/playground/DEPLOY.md +9 -0
- package/examples/playground/app/a0/a0.css +244 -5
- package/examples/playground/app/a0/app-view.tsx +2 -1
- package/examples/playground/app/a0/attachments.ts +133 -0
- package/examples/playground/app/a0/chat.test.tsx +504 -0
- package/examples/playground/app/a0/chat.tsx +623 -63
- package/examples/playground/app/a0/context-menu.tsx +38 -11
- package/examples/playground/app/a0/model.test.ts +28 -0
- package/examples/playground/app/a0/model.ts +30 -0
- package/examples/playground/app/a0/server.ts +5 -0
- package/examples/playground/app/a0/uploads/route.ts +29 -0
- package/examples/playground/app/agent/[agentId]/agent-client.tsx +2 -1
- package/examples/playground/app/agent/[agentId]/agent-queue.test.tsx +1 -0
- package/examples/playground/app/agent/model.test.ts +12 -3
- package/examples/playground/app/chat/[chatId]/agent-state.test.ts +1 -5
- package/examples/playground/next.config.ts +7 -4
- package/examples/playground/package.json +3 -1
- package/package.json +1 -1
- package/src/ai-agent.ts +4 -0
- package/src/ai-client-state.ts +21 -9
- package/src/ai-context-schema.ts +28 -4
- package/src/ai-context.ts +83 -3
- package/src/ai-control-server.ts +70 -43
- package/src/ai-control-state.ts +3 -4
- package/src/ai-control.ts +59 -10
- package/src/ai-coordinator.ts +7 -6
- package/src/ai-fx.ts +58 -20
- package/src/ai-harness.ts +153 -29
- package/src/ai-message-shape.ts +41 -0
- package/src/ai-pi.ts +88 -32
- package/src/ai-stored-state.ts +1 -3
- package/src/ai.ts +116 -77
- package/src/libfx.d.ts +8 -1
- package/src/scheduler-vercel.ts +1 -12
- package/dist/ai-BMLlI2Ff.d.ts.map +0 -1
- package/dist/ai-D6mGlO8j.js.map +0 -1
- package/dist/ai-harness-B2suP2Qh.d.ts.map +0 -1
- package/dist/ai-harness-BuLh_EYi.js.map +0 -1
- package/examples/playground/app/a0/no-photon.cjs +0 -4
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
|
|
2
|
+
import "./ai-control-CvLbW10B.js";
|
|
3
|
+
import { createDownload } from "ai";
|
|
2
4
|
//#region src/ai-harness.ts
|
|
3
5
|
const DRIVER = Symbol.for("experimental-a2.ai.harness");
|
|
4
6
|
function defineHarness(type, driver) {
|
|
@@ -124,14 +126,13 @@ function savedEnvelope(value) {
|
|
|
124
126
|
state
|
|
125
127
|
} : void 0;
|
|
126
128
|
}
|
|
127
|
-
const STEERED = "steered after step";
|
|
128
129
|
/**
|
|
129
130
|
* Groups the log since a harness snapshot into harness turns. A response
|
|
130
131
|
* steered after a step continues its turn, with the next response's prompt as
|
|
131
132
|
* steering. `covered` is the response the snapshot already holds.
|
|
132
133
|
*/
|
|
133
134
|
function harnessTurns(step, events, covered) {
|
|
134
|
-
const
|
|
135
|
+
const userInput = new Map(step.messages.filter((message) => message.role === "user").map((message) => [message.id, inputOf(message)]));
|
|
135
136
|
let passive = [];
|
|
136
137
|
const responses = /* @__PURE__ */ new Map();
|
|
137
138
|
const byStart = /* @__PURE__ */ new Map();
|
|
@@ -141,10 +142,8 @@ function harnessTurns(step, events, covered) {
|
|
|
141
142
|
const payload = event.payload;
|
|
142
143
|
switch (event.type) {
|
|
143
144
|
case "ai.message.created": {
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
-
userText.set(message.id, textOf(message));
|
|
147
|
-
if (payload["generate"] === false) passive.push(message.id);
|
|
145
|
+
const admitted = event.payload;
|
|
146
|
+
if (admitted.role === "user" && admitted.generate === false) passive.push(admitted.messageId);
|
|
148
147
|
break;
|
|
149
148
|
}
|
|
150
149
|
case "ai.generation.requested": {
|
|
@@ -155,7 +154,7 @@ function harnessTurns(step, events, covered) {
|
|
|
155
154
|
passive = [];
|
|
156
155
|
responses.set(id, {
|
|
157
156
|
id,
|
|
158
|
-
prompt: ids.flatMap((p) =>
|
|
157
|
+
prompt: ids.flatMap((p) => userInput.get(p) ?? []),
|
|
159
158
|
generations: []
|
|
160
159
|
});
|
|
161
160
|
break;
|
|
@@ -190,7 +189,7 @@ function harnessTurns(step, events, covered) {
|
|
|
190
189
|
}
|
|
191
190
|
case "ai.message.interrupted": {
|
|
192
191
|
const response = responses.get(payload["messageId"]);
|
|
193
|
-
if (response) response.end = payload["reason"] ===
|
|
192
|
+
if (response) response.end = payload["reason"] === "steered after step" ? "steered" : "interrupted";
|
|
194
193
|
break;
|
|
195
194
|
}
|
|
196
195
|
}
|
|
@@ -198,14 +197,17 @@ function harnessTurns(step, events, covered) {
|
|
|
198
197
|
const turns = [];
|
|
199
198
|
let steered = false;
|
|
200
199
|
for (const response of responses.values()) {
|
|
201
|
-
const
|
|
200
|
+
const input = {
|
|
201
|
+
text: response.prompt.map((prompt) => prompt.text).join("\n\n"),
|
|
202
|
+
files: response.prompt.flatMap((prompt) => prompt.files)
|
|
203
|
+
};
|
|
202
204
|
let turn = turns.at(-1);
|
|
203
205
|
if (steered && turn !== void 0) {
|
|
204
206
|
const at = Math.max(0, turn.generations.length - 1);
|
|
205
|
-
turn.steers.set(at, [...turn.steers.get(at) ?? [],
|
|
207
|
+
turn.steers.set(at, [...turn.steers.get(at) ?? [], input]);
|
|
206
208
|
} else {
|
|
207
209
|
turn = {
|
|
208
|
-
prompt:
|
|
210
|
+
prompt: input,
|
|
209
211
|
generations: [],
|
|
210
212
|
steers: /* @__PURE__ */ new Map(),
|
|
211
213
|
end: "live"
|
|
@@ -224,8 +226,70 @@ function harnessTurns(step, events, covered) {
|
|
|
224
226
|
results
|
|
225
227
|
};
|
|
226
228
|
}
|
|
227
|
-
function
|
|
228
|
-
return
|
|
229
|
+
function inputOf(message) {
|
|
230
|
+
return {
|
|
231
|
+
text: message.parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n"),
|
|
232
|
+
files: message.parts.filter((part) => part.type === "file")
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const MAX_ATTACHMENT_BYTES = 33554432;
|
|
236
|
+
const attachments = boundedCache({
|
|
237
|
+
maxEntries: 256,
|
|
238
|
+
maxBytes: 67108864
|
|
239
|
+
});
|
|
240
|
+
/**
|
|
241
|
+
* The images an input attaches, as its engine takes them: engines take
|
|
242
|
+
* bytes, not URLs. A file it can't attach fails the step, naming the file,
|
|
243
|
+
* and is never left out: the failure may pass, and the step is retried like
|
|
244
|
+
* any other.
|
|
245
|
+
*/
|
|
246
|
+
async function harnessImages({ harness, input, signal }) {
|
|
247
|
+
const images = [];
|
|
248
|
+
let budget = MAX_ATTACHMENT_BYTES;
|
|
249
|
+
for (const file of input.files) try {
|
|
250
|
+
if (!file.mediaType.startsWith("image/")) throw new Error(`it takes images only, not ${file.mediaType}`);
|
|
251
|
+
const attached = await attachment({
|
|
252
|
+
url: file.url,
|
|
253
|
+
budget,
|
|
254
|
+
signal
|
|
255
|
+
});
|
|
256
|
+
budget -= attached.bytes;
|
|
257
|
+
images.push({
|
|
258
|
+
mediaType: file.mediaType,
|
|
259
|
+
data: attached.data
|
|
260
|
+
});
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (signal.aborted) throw error;
|
|
263
|
+
throw new Error(`${harness} couldn't attach ${file.filename ?? "a file"}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
264
|
+
}
|
|
265
|
+
return images;
|
|
266
|
+
}
|
|
267
|
+
async function attachment({ url, budget, signal }) {
|
|
268
|
+
const tooLarge = () => /* @__PURE__ */ new Error(`a message's files may hold ${MAX_ATTACHMENT_BYTES / 1024 / 1024} MiB in a step`);
|
|
269
|
+
const cached = attachments.get(url);
|
|
270
|
+
if (cached !== void 0) {
|
|
271
|
+
if (cached.bytes > budget) throw tooLarge();
|
|
272
|
+
return cached;
|
|
273
|
+
}
|
|
274
|
+
const { protocol } = new URL(url);
|
|
275
|
+
if (protocol !== "https:" && protocol !== "data:") throw new Error(`attachments must be https: or data: URLs, not ${protocol}`);
|
|
276
|
+
const bytes = protocol === "data:" ? dataBytes(url) : (await createDownload({ maxBytes: budget })({
|
|
277
|
+
url: new URL(url),
|
|
278
|
+
abortSignal: signal
|
|
279
|
+
})).data;
|
|
280
|
+
if (bytes.byteLength > budget) throw tooLarge();
|
|
281
|
+
const attached = {
|
|
282
|
+
data: Buffer.from(bytes).toString("base64"),
|
|
283
|
+
bytes: bytes.byteLength
|
|
284
|
+
};
|
|
285
|
+
if (protocol === "https:") attachments.set(url, attached, attached.data.length);
|
|
286
|
+
return attached;
|
|
287
|
+
}
|
|
288
|
+
function dataBytes(url) {
|
|
289
|
+
const comma = url.indexOf(",");
|
|
290
|
+
if (comma === -1) throw new Error("its data: URL has no data");
|
|
291
|
+
const body = url.slice(comma + 1);
|
|
292
|
+
return url.slice(0, comma).endsWith(";base64") ? Buffer.from(body, "base64") : Buffer.from(decodeURIComponent(body));
|
|
229
293
|
}
|
|
230
294
|
/** Read per step: on Vercel the OIDC token rides on each function request. */
|
|
231
295
|
function gatewayCredential(harness) {
|
|
@@ -268,6 +332,6 @@ function pending(signal) {
|
|
|
268
332
|
});
|
|
269
333
|
}
|
|
270
334
|
//#endregion
|
|
271
|
-
export { harnessDriver as a,
|
|
335
|
+
export { harnessDriver as a, harnessStates as c, registerHarnessStates as d, saveHarness as f, gatewayCredential as i, pending as l, deferred as n, harnessImages as o, defineHarness as r, harnessLog as s, Divergence as t, readHarness as u };
|
|
272
336
|
|
|
273
|
-
//# sourceMappingURL=ai-harness-
|
|
337
|
+
//# sourceMappingURL=ai-harness-BuuC-gJ3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-harness-BuuC-gJ3.js","names":[],"sources":["../src/ai-harness.ts"],"sourcesContent":["import {\n createDownload,\n type Experimental_SandboxSession,\n type FileUIPart,\n type FinishReason,\n type LanguageModelUsage,\n type ToolSet,\n type UIMessage,\n type UIMessageChunk,\n} from 'ai'\nimport type {\n GenerationCompletedPayload,\n MessageCreatedPayload,\n ReasoningLevel,\n ToolResultPayload,\n} from './ai.ts'\nimport { STEERED_REASON } from './ai-control.ts'\nimport { boundedCache, type BoundedCache } from './bounded-cache.ts'\nimport type { ContractEvent, EventDefs } from './contract.ts'\n\ndeclare const harnessBrand: unique symbol\n\n/**\n * A coding agent's own loop for `agent({ harness })`, from `fx()` or `pi()`.\n * `Tools` names the tools the harness brings, which `toolRecovery` may name.\n */\nexport type Harness<\n Type extends 'fx' | 'pi' = 'fx' | 'pi',\n Tools extends string = string,\n> = {\n readonly type: Type\n readonly [harnessBrand]: { readonly tools: Tools }\n}\n\n/** What a harness's sandbox resolver receives for one step or tool execution. */\nexport type HarnessSandboxContext = {\n session: { readonly id: string }\n signal: AbortSignal\n}\n\n/** Resolves the AI SDK sandbox session for an agent session, the same one every time. */\nexport type HarnessSandbox = (\n context: HarnessSandboxContext,\n) => Experimental_SandboxSession | Promise<Experimental_SandboxSession>\n\n/** What a harness step streams, as the default generator does. */\nexport type HarnessGeneration = {\n stream: ReadableStream<UIMessageChunk>\n completion: () => { finishReason?: FinishReason; usage?: LanguageModelUsage }\n}\n\n/** One stored snapshot and the log after it, read in one store operation. */\nexport type HarnessLogRead = {\n snapshot: { index: number; state: unknown } | null\n events: ContractEvent<EventDefs>[]\n}\n\n/** The session log as a harness step reads it, plus the state saved in it. */\nexport type HarnessLog = {\n /** The latest saved state under `name` and the log after it; `fresh` reads it all. */\n read(options: {\n name: string\n throughIndex: number\n fresh?: boolean\n }): Promise<HarnessLogRead>\n write(options: { name: string; index: number; state: unknown }): Promise<void>\n}\n\n/** Everything one durable generation hands its harness. */\nexport type HarnessStep = {\n agentName: string\n sessionId: string\n requestIndex: number\n /** This attempt at the generation. */\n generationId: string\n responseMessageId: string\n /** The log index this step's context was read through. */\n throughIndex: number\n /** The transcript through that index. */\n messages: readonly UIMessage[]\n model: string\n reasoning?: ReasoningLevel\n speed?: 'fast' | 'standard'\n instructions: string[]\n tools: ToolSet\n log: HarnessLog\n signal: AbortSignal\n}\n\n/** The internal side of a harness value. */\nexport type HarnessDriver = {\n /** The session's sandbox; every local tool execution receives it. */\n readonly sandbox?: HarnessSandbox\n /** Tools the harness brings; A2 executes them like the agent's own. */\n readonly tools: ToolSet\n step(step: HarnessStep): Promise<HarnessGeneration>\n}\n\n// A global symbol, so harness values work across separately bundled copies.\nconst DRIVER = Symbol.for('experimental-a2.ai.harness')\n\nexport function defineHarness<\n Type extends 'fx' | 'pi',\n Tools extends string = never,\n>(type: Type, driver: HarnessDriver): Harness<Type, Tools> {\n const harness = { type }\n Object.defineProperty(harness, DRIVER, { value: driver })\n return Object.freeze(harness) as unknown as Harness<Type, Tools>\n}\n\nexport function harnessDriver(harness: unknown): HarnessDriver {\n const driver =\n typeof harness === 'object' && harness !== null\n ? (harness as { [DRIVER]?: HarnessDriver })[DRIVER]\n : undefined\n if (driver === undefined)\n throw new TypeError(\n \"harness must be { type: 'ai-sdk' }, or come from fx() or pi()\",\n )\n return driver\n}\n\n// ------------------------------------------------------- saved state\n\n/**\n * What an agent's steps saved in this process at the end of a response, per\n * session and harness. A cache: a cold process rebuilds from the whole log.\n */\nexport type HarnessStates = BoundedCache<\n string,\n { index: number; state: unknown }\n>\n\nexport const harnessStates = (): HarnessStates =>\n boundedCache({ maxEntries: 1_000, maxBytes: 64 * 1024 * 1024 })\n\nconst savedKey = (sessionId: string, name: string): string =>\n `${sessionId}\\u0000${name}`\n\n// Binary state counts its bytes; everything else its JSON text.\nconst sizeOf = (value: unknown): number => {\n let binary = 0\n const text = JSON.stringify(value, (_key, item: unknown) => {\n if (!(item instanceof Uint8Array)) return item\n binary += item.byteLength\n return null\n })\n return binary + (text?.length ?? 0)\n}\n\n/**\n * The session log as a harness step reads it: the state this process saved\n * at the end of the last response, when it has one, and the log after it.\n * Saved states are copied in and out, so a step cannot change one in place.\n */\nexport function harnessLog(options: {\n states: HarnessStates\n session: {\n readonly id: string\n history(bounds: {\n gte?: number\n lte?: number\n }): Promise<ContractEvent<EventDefs>[]>\n }\n}): HarnessLog {\n const { states, session } = options\n return {\n read: async ({ name, throughIndex, fresh }) => {\n const entry = fresh ? undefined : states.get(savedKey(session.id, name))\n const snapshot =\n entry === undefined || entry.index > throughIndex\n ? null\n : { index: entry.index, state: structuredClone(entry.state) }\n const events = await session.history(\n snapshot === null\n ? { lte: throughIndex }\n : { gte: snapshot.index + 1, lte: throughIndex },\n )\n return { snapshot, events }\n },\n write: async ({ name, index, state }) => {\n const copy = structuredClone(state)\n states.set(\n savedKey(session.id, name),\n { index, state: copy },\n sizeOf(copy),\n )\n },\n }\n}\n\nconst agentStates = new WeakMap<object, HarnessStates>()\n\n/** Registers an agent server's saved harness states, for `savedHarnessState`. */\nexport function registerHarnessStates(\n server: object,\n states: HarnessStates,\n): void {\n agentStates.set(server, states)\n}\n\n/** What an agent's process saved for one session's harness; tests read it. */\nexport function savedHarnessState(\n server: object,\n options: { sessionId: string; name: string },\n): { index: number; state: unknown } | undefined {\n return agentStates.get(server)?.get(savedKey(options.sessionId, options.name))\n}\n\n/** A harness's state at the end of a response, from the attempt that ran it. */\ntype SavedEnvelope = {\n generationId: string\n responseMessageId: string\n state: unknown\n}\n\nexport type HarnessRead<S> = {\n /** The state saved at the end of the last response, when it is usable. */\n saved: S | undefined\n turns: HarnessTurn[]\n results: Map<string, ToolResultPayload>\n}\n\n/**\n * Reads a harness's saved state and the log since, as turns to replay. A\n * snapshot counts only when the attempt that wrote it committed: a stopped,\n * superseded, or still-running attempt can write one the log never kept.\n * `replayAll` reads the whole log instead, for a state that fails to restore.\n */\nexport async function readHarness<S>({\n step,\n name,\n parse,\n}: {\n step: HarnessStep\n name: string\n parse: (state: unknown) => S | undefined\n}): Promise<HarnessRead<S> & { replayAll: () => Promise<HarnessRead<S>> }> {\n const replayAll = async (): Promise<HarnessRead<S>> => {\n const read = await step.log.read({\n name,\n throughIndex: step.throughIndex,\n fresh: true,\n })\n return { saved: undefined, ...harnessTurns(step, read.events, undefined) }\n }\n const read = await step.log.read({ name, throughIndex: step.throughIndex })\n if (read.snapshot === null)\n return {\n saved: undefined,\n ...harnessTurns(step, read.events, undefined),\n replayAll,\n }\n const envelope = savedEnvelope(read.snapshot.state)\n const saved = envelope === undefined ? undefined : parse(envelope.state)\n const committed =\n envelope !== undefined &&\n read.events.some(\n (event) =>\n event.type === 'ai.generation.completed' &&\n (event.payload as { generationId?: unknown }).generationId ===\n envelope.generationId,\n )\n // A snapshot of this very response belongs to an earlier attempt at it.\n if (\n saved === undefined ||\n !committed ||\n envelope.responseMessageId === step.responseMessageId\n )\n return { ...(await replayAll()), replayAll }\n return {\n saved,\n ...harnessTurns(step, read.events, envelope.responseMessageId),\n replayAll,\n }\n}\n\n/** Saves a harness's state at the end of a response; losing it costs a longer replay. */\nexport async function saveHarness({\n step,\n name,\n state,\n}: {\n step: HarnessStep\n name: string\n state: unknown\n}): Promise<void> {\n const envelope: SavedEnvelope = {\n generationId: step.generationId,\n responseMessageId: step.responseMessageId,\n state,\n }\n try {\n await step.log.write({ name, index: step.requestIndex, state: envelope })\n } catch {\n // The snapshot is a cache.\n }\n}\n\nfunction savedEnvelope(value: unknown): SavedEnvelope | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const { generationId, responseMessageId, state } = value as Record<\n string,\n unknown\n >\n return typeof generationId === 'string' &&\n typeof responseMessageId === 'string'\n ? { generationId, responseMessageId, state }\n : undefined\n}\n\n// ------------------------------------------------- the log as harness turns\n\n/** A completed generation as the log recorded it. */\nexport type RecordedGeneration = {\n chunks: UIMessageChunk[]\n completed: GenerationCompletedPayload\n}\n\n/** What user messages hand a harness: their text, and the files they attach. */\nexport type HarnessInput = { text: string; files: FileUIPart[] }\n\n/** One harness turn to rebuild: its prompt, completed generations, and end. */\nexport type HarnessTurn = {\n prompt: HarnessInput\n generations: RecordedGeneration[]\n /** Steering that entered after the generation at that index. */\n steers: Map<number, HarnessInput[]>\n end: 'stop' | 'interrupted' | 'live'\n}\n\n/**\n * Groups the log since a harness snapshot into harness turns. A response\n * steered after a step continues its turn, with the next response's prompt as\n * steering. `covered` is the response the snapshot already holds.\n */\nexport function harnessTurns(\n step: HarnessStep,\n events: readonly ContractEvent<EventDefs>[],\n covered: string | undefined,\n): { turns: HarnessTurn[]; results: Map<string, ToolResultPayload> } {\n type Generation = {\n id: string\n chunks: UIMessageChunk[]\n completed?: GenerationCompletedPayload\n }\n type Response = {\n id: string\n prompt: HarnessInput[]\n generations: Generation[]\n end?: 'stop' | 'steered' | 'interrupted'\n }\n // Prompts take their content from the transcript: a harness agent never\n // runs A2's compaction, so the step's messages hold every input admitted by\n // its read, before the snapshot or after it. A session another loop\n // compacted can't move to a harness.\n const userInput = new Map<string, HarnessInput>(\n step.messages\n .filter((message) => message.role === 'user')\n .map((message) => [message.id, inputOf(message)]),\n )\n let passive: string[] = []\n const responses = new Map<string, Response>()\n const byStart = new Map<number, Generation>()\n const byId = new Map<string, Generation>()\n const results = new Map<string, ToolResultPayload>()\n\n for (const event of events) {\n const payload = event.payload as Record<string, unknown>\n switch (event.type) {\n case 'ai.message.created': {\n const admitted = event.payload as MessageCreatedPayload\n if (admitted.role === 'user' && admitted.generate === false)\n passive.push(admitted.messageId)\n break\n }\n case 'ai.generation.requested': {\n const id = payload['responseMessageId'] as string\n if (id === covered || responses.has(id)) break\n const messageId = payload['messageId'] as string\n const ids = [...passive.filter((p) => p !== messageId), messageId]\n passive = []\n responses.set(id, {\n id,\n prompt: ids.flatMap((p) => userInput.get(p) ?? []),\n generations: [],\n })\n break\n }\n case 'ai.generation.started': {\n const response = responses.get(payload['responseMessageId'] as string)\n if (response === undefined) break\n const generation: Generation = {\n id: payload['generationId'] as string,\n chunks: [],\n }\n response.generations.push(generation)\n byStart.set(event.index, generation)\n byId.set(generation.id, generation)\n break\n }\n case 'ai.generation.progress':\n byStart\n .get(payload['startIndex'] as number)\n ?.chunks.push(...(payload['chunks'] as UIMessageChunk[]))\n break\n case 'ai.generation.completed': {\n const generation = byId.get(payload['generationId'] as string)\n if (generation)\n generation.completed = event.payload as GenerationCompletedPayload\n break\n }\n case 'ai.tool.result':\n if (payload['preliminary'] !== true)\n results.set(\n payload['toolCallId'] as string,\n event.payload as ToolResultPayload,\n )\n break\n case 'ai.message.completed': {\n const response = responses.get(payload['messageId'] as string)\n if (response) response.end = 'stop'\n break\n }\n case 'ai.message.interrupted': {\n const response = responses.get(payload['messageId'] as string)\n if (response)\n response.end =\n payload['reason'] === STEERED_REASON ? 'steered' : 'interrupted'\n break\n }\n }\n }\n\n const turns: HarnessTurn[] = []\n let steered = false\n for (const response of responses.values()) {\n const input: HarnessInput = {\n text: response.prompt.map((prompt) => prompt.text).join('\\n\\n'),\n files: response.prompt.flatMap((prompt) => prompt.files),\n }\n let turn = turns.at(-1)\n if (steered && turn !== undefined) {\n const at = Math.max(0, turn.generations.length - 1)\n turn.steers.set(at, [...(turn.steers.get(at) ?? []), input])\n } else {\n turn = { prompt: input, generations: [], steers: new Map(), end: 'live' }\n turns.push(turn)\n }\n for (const generation of response.generations)\n if (generation.completed !== undefined)\n turn.generations.push({\n chunks: generation.chunks,\n completed: generation.completed,\n })\n turn.end =\n response.id === step.responseMessageId\n ? 'live'\n : response.end === 'stop'\n ? 'stop'\n : 'interrupted'\n steered = response.end === 'steered'\n }\n return { turns, results }\n}\n\nfunction inputOf(message: UIMessage): HarnessInput {\n return {\n text: message.parts\n .flatMap((part) => (part.type === 'text' ? [part.text] : []))\n .join('\\n'),\n files: message.parts.filter(\n (part): part is FileUIPart => part.type === 'file',\n ),\n }\n}\n\n// ------------------------------------------------------------- attachments\n\n/** An attached image as an engine takes it: its bytes in base64. */\nexport type HarnessImage = { mediaType: string; data: string }\n\n// What one message's files hold in a step's memory, at most.\nconst MAX_ATTACHMENT_BYTES = 32 * 1024 * 1024\n\ntype Attachment = { data: string; bytes: number }\n\n// Every step of a response replays its turn, and a URL's file doesn't change,\n// so the process keeps what it fetched.\nconst attachments = boundedCache<string, Attachment>({\n maxEntries: 256,\n maxBytes: 64 * 1024 * 1024,\n})\n\n/**\n * The images an input attaches, as its engine takes them: engines take\n * bytes, not URLs. A file it can't attach fails the step, naming the file,\n * and is never left out: the failure may pass, and the step is retried like\n * any other.\n */\nexport async function harnessImages({\n harness,\n input,\n signal,\n}: {\n /** As the error names it: `fx()` or `pi()`. */\n harness: string\n input: HarnessInput\n signal: AbortSignal\n}): Promise<HarnessImage[]> {\n const images: HarnessImage[] = []\n let budget = MAX_ATTACHMENT_BYTES\n // One at a time, so the budget bounds what the step holds.\n for (const file of input.files) {\n try {\n if (!file.mediaType.startsWith('image/'))\n throw new Error(`it takes images only, not ${file.mediaType}`)\n const attached = await attachment({ url: file.url, budget, signal })\n budget -= attached.bytes\n images.push({\n mediaType: file.mediaType,\n data: attached.data,\n })\n } catch (error) {\n if (signal.aborted) throw error\n throw new Error(\n `${harness} couldn't attach ${file.filename ?? 'a file'}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n )\n }\n }\n return images\n}\n\nasync function attachment({\n url,\n budget,\n signal,\n}: {\n url: string\n budget: number\n signal: AbortSignal\n}): Promise<Attachment> {\n const tooLarge = () =>\n new Error(\n `a message's files may hold ${MAX_ATTACHMENT_BYTES / 1024 / 1024} MiB in a step`,\n )\n const cached = attachments.get(url)\n if (cached !== undefined) {\n if (cached.bytes > budget) throw tooLarge()\n return cached\n }\n const { protocol } = new URL(url)\n if (protocol !== 'https:' && protocol !== 'data:')\n throw new Error(`attachments must be https: or data: URLs, not ${protocol}`)\n // AI SDK's download checks an https: URL's address and its redirects,\n // which a message's sender chooses; a data: URL holds its bytes.\n const bytes =\n protocol === 'data:'\n ? dataBytes(url)\n : (\n await createDownload({ maxBytes: budget })({\n url: new URL(url),\n abortSignal: signal,\n })\n ).data\n if (bytes.byteLength > budget) throw tooLarge()\n const attached: Attachment = {\n data: Buffer.from(bytes).toString('base64'),\n bytes: bytes.byteLength,\n }\n if (protocol === 'https:')\n attachments.set(url, attached, attached.data.length)\n return attached\n}\n\nfunction dataBytes(url: string): Uint8Array {\n const comma = url.indexOf(',')\n if (comma === -1) throw new Error('its data: URL has no data')\n const body = url.slice(comma + 1)\n return url.slice(0, comma).endsWith(';base64')\n ? Buffer.from(body, 'base64')\n : Buffer.from(decodeURIComponent(body))\n}\n\n// ------------------------------------------------------------- Gateway\n\nexport type GatewayCredential = { token: string; method: 'api-key' | 'oidc' }\n\n/** Read per step: on Vercel the OIDC token rides on each function request. */\nexport function gatewayCredential(harness: string): GatewayCredential {\n const key = process.env['AI_GATEWAY_API_KEY']\n if (key) return { token: key, method: 'api-key' }\n const oidc = requestOidcToken() ?? process.env['VERCEL_OIDC_TOKEN']\n if (oidc) return { token: oidc, method: 'oidc' }\n throw new Error(`${harness}() needs AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN`)\n}\n\n// Where Vercel Functions keep the current request, as @vercel/oidc reads it.\nconst REQUEST_CONTEXT = Symbol.for('@vercel/request-context')\n\nfunction requestOidcToken(): string | undefined {\n const context = (\n globalThis as {\n [REQUEST_CONTEXT]?: { get?: () => { headers?: Record<string, unknown> } }\n }\n )[REQUEST_CONTEXT]\n const token = context?.get?.()?.headers?.['x-vercel-oidc-token']\n return typeof token === 'string' && token !== '' ? token : undefined\n}\n\n// ------------------------------------------------------------- helpers\n\nexport class Divergence extends Error {\n constructor(harness: string, message: string) {\n super(`${harness} replay diverged from the log: ${message}`)\n }\n}\n\nexport type Deferred = { promise: Promise<void>; resolve: () => void }\n\nexport function deferred(): Deferred {\n let resolve!: () => void\n const promise = new Promise<void>((done) => {\n resolve = done\n })\n return { promise, resolve }\n}\n\n/** A result that never settles; the harness is stopped instead. */\nexport function pending(\n signal: AbortSignal | null | undefined,\n): Promise<never> {\n return new Promise((_, reject) => {\n if (signal?.aborted) reject(signal.reason)\n signal?.addEventListener('abort', () => reject(signal.reason), {\n once: true,\n })\n })\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./ai-
|
|
1
|
+
import "./ai-Cz3hqVhk.js";
|
|
2
2
|
import { Experimental_SandboxSession, ToolSet, UIMessage, UIMessageChunk } from "ai";
|
|
3
3
|
//#region src/ai-harness.d.ts
|
|
4
4
|
declare const harnessBrand: unique symbol;
|
|
@@ -23,4 +23,4 @@ type HarnessSandboxContext = {
|
|
|
23
23
|
type HarnessSandbox = (context: HarnessSandboxContext) => Experimental_SandboxSession | Promise<Experimental_SandboxSession>;
|
|
24
24
|
//#endregion
|
|
25
25
|
export { HarnessSandbox as n, HarnessSandboxContext as r, Harness as t };
|
|
26
|
-
//# sourceMappingURL=ai-harness-
|
|
26
|
+
//# sourceMappingURL=ai-harness-CV6rXbB3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-harness-CV6rXbB3.d.ts","names":[],"sources":["../src/ai-harness.ts"],"mappings":";;;cAoBc;;;;;KAMF,QACV,wCACA;WAES,MAAM;YACL;aAA0B,OAAO;;;;KAIjC;EACV;aAAoB;;EACpB,QAAQ;;;KAIE,kBACV,SAAS,0BACN,8BAA8B,QAAQ"}
|