@byok-sdk/cloud-do 0.0.0-stage → 0.24.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/index.js ADDED
@@ -0,0 +1,3915 @@
1
+ import { DurableObject } from 'cloudflare:workers';
2
+ import { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';
3
+ import { watchEvents, createRegistry, defineExtension, hook, ToolTask, Harness } from '@earendil-works/pi-durable';
4
+ import { validateToolArguments } from '@earendil-works/pi-ai/utils/validation';
5
+ import { createModels, createProvider } from '@earendil-works/pi-ai/models';
6
+ import { AssistantMessageEventStream } from '@earendil-works/pi-ai/utils/event-stream';
7
+ import { getCurrentTools } from '@earendil-works/pi-ai/utils/transcript';
8
+ import { getSystemMessageText } from '@earendil-works/pi-ai/utils/text';
9
+ import { SQLITE_MIGRATIONS, SqliteStorage } from '@earendil-works/pi-durable/storage/sqlite';
10
+
11
+ // src/agent-do.ts
12
+
13
+ // src/errors.ts
14
+ var status = {
15
+ CLOUD_REQUEST_INVALID: 400,
16
+ CLOUD_INBOX_FULL: 429,
17
+ CLOUD_INBOX_CONFLICT: 409,
18
+ CLOUD_INBOX_EXPIRED: 409,
19
+ CLOUD_INBOX_TOO_LARGE: 400,
20
+ CLOUD_WAKE_EXHAUSTED: 409,
21
+ CLOUD_WAKE_EMPTY: 409,
22
+ CLOUD_EVENT_CURSOR_EXPIRED: 410,
23
+ CLOUD_EVENTS_BUSY: 429,
24
+ CLOUD_USER_CREDENTIAL_REJECTED: 400,
25
+ CLOUD_MODEL_CREDENTIAL_UNAVAILABLE: 503,
26
+ CLOUD_MODEL_RESPONSE_REJECTED: 502,
27
+ CLOUD_MODEL_REQUEST_FAILED: 502,
28
+ CLOUD_SESSION_CONFLICT: 409,
29
+ CLOUD_TOOL_NOT_AVAILABLE: 400,
30
+ CLOUD_TOOL_INVOCATION_CONFLICT: 409,
31
+ CLOUD_TOOL_ARGUMENT_INVALID: 400,
32
+ CLOUD_TOOL_LIMIT: 400,
33
+ CLOUD_STEP_LIMIT: 400,
34
+ CLOUD_BUDGET_EXCEEDED: 400,
35
+ CLOUD_TOOL_RESULT_LIMIT: 502,
36
+ CLOUD_TOOL_USAGE_INVALID: 502,
37
+ CLOUD_TOOL_BUSY: 409,
38
+ CLOUD_TOOL_TIMEOUT: 504,
39
+ CLOUD_EXECUTION_TIMEOUT: 504,
40
+ CLOUD_EXECUTION_INTERRUPTED: 409,
41
+ CLOUD_EXECUTION_ABORTED: 409,
42
+ CLOUD_TOOL_FAILED: 502
43
+ };
44
+ var CloudDoError = class extends Error {
45
+ constructor(code) {
46
+ super(code);
47
+ this.code = code;
48
+ this.name = "CloudDoError";
49
+ this.status = status[code];
50
+ }
51
+ code;
52
+ status;
53
+ retryable = false;
54
+ };
55
+ function safeCloudError(error) {
56
+ try {
57
+ if (error instanceof CloudDoError) {
58
+ const code = Object.getOwnPropertyDescriptor(error, "code")?.value;
59
+ if (typeof code === "string" && Object.hasOwn(status, code)) return new CloudDoError(code);
60
+ }
61
+ if (error instanceof Error) {
62
+ const message = Object.getOwnPropertyDescriptor(error, "message")?.value;
63
+ if (typeof message === "string" && Object.hasOwn(status, message)) return new CloudDoError(message);
64
+ }
65
+ } catch {
66
+ }
67
+ return new CloudDoError("CLOUD_MODEL_REQUEST_FAILED");
68
+ }
69
+ function cloudErrorResponse(error) {
70
+ const safe = safeCloudError(error);
71
+ return Response.json({ error: { code: safe.code, retryable: false } }, { status: safe.status });
72
+ }
73
+
74
+ // src/platform-credentials.ts
75
+ var PLATFORM_PROFILES = Object.freeze({
76
+ zai_openai: Object.freeze({ vendor: "zai", baseUrl: "https://api.z.ai/api/coding/paas/v4", model: "glm-5.3-flash", binding: "AIPHABEE_ZAI_API_KEY", secretName: "model-zai_openai-api-key" }),
77
+ deepseek_direct: Object.freeze({ vendor: "deepseek", baseUrl: "https://api.deepseek.com", model: "deepseek-v4-flash", binding: "AIPHABEE_DEEPSEEK_API_KEY", secretName: "model-deepseek_direct-api-key" })
78
+ });
79
+ function platformProfile(id) {
80
+ if (typeof id !== "string" || !Object.hasOwn(PLATFORM_PROFILES, id)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
81
+ return id;
82
+ }
83
+ function requirePlatformKey(value) {
84
+ if (typeof value !== "string" || !/^[A-Za-z0-9._~+/-]{16,512}$/u.test(value)) throw new CloudDoError("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE");
85
+ return value;
86
+ }
87
+ function platformCredentialReader(env) {
88
+ return {
89
+ async get(name) {
90
+ const profile = Object.values(PLATFORM_PROFILES).find((profile2) => profile2.secretName === name);
91
+ if (!profile) throw new CloudDoError("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE");
92
+ try {
93
+ return requirePlatformKey(env[profile.binding]);
94
+ } catch {
95
+ throw new CloudDoError("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE");
96
+ }
97
+ }
98
+ };
99
+ }
100
+
101
+ // src/admission.ts
102
+ var credentialFields = /* @__PURE__ */ new Set(["credential", "credentials", "apikey", "api_key", "secret", "authorization", "x-api-key", "api-key", "x-goog-api-key", "proxy-authorization", "cf-aig-authorization", "headers"]);
103
+ function rejectCredentialFields(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
104
+ if (value === null || typeof value !== "object") return;
105
+ if (depth > 8 || seen.has(value)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
106
+ seen.add(value);
107
+ for (const [name, child] of Object.entries(value)) {
108
+ if (credentialFields.has(name.toLowerCase())) throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
109
+ rejectCredentialFields(child, depth + 1, seen);
110
+ }
111
+ }
112
+ function hasUserKeyShape(text2) {
113
+ return /\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}\b|\b[a-f\d]{32}\.[A-Za-z0-9_-]{16,}\b/u.test(text2);
114
+ }
115
+ function admitCloudSubmission(input) {
116
+ rejectCredentialFields(input);
117
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
118
+ const body = input;
119
+ if (Object.keys(body).some((name) => name !== "instruction" && name !== "profile") || typeof body.instruction !== "string" || !body.instruction.trim() || body.instruction.length > 16e3) throw new CloudDoError("CLOUD_REQUEST_INVALID");
120
+ if (hasUserKeyShape(body.instruction)) throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
121
+ return { instruction: body.instruction, profile: platformProfile(body.profile === void 0 ? "zai_openai" : body.profile) };
122
+ }
123
+
124
+ // src/leak-guard.ts
125
+ var FRAGMENT_LENGTH = 16;
126
+ function percentPattern(secret) {
127
+ return new RegExp(Array.from(secret, (character) => {
128
+ const literal = character.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
129
+ const hex = character.charCodeAt(0).toString(16).padStart(2, "0").replace(/[a-f]/g, (digit) => `[${digit}${digit.toUpperCase()}]`);
130
+ return `(?:${literal}|%${hex})`;
131
+ }).join(""));
132
+ }
133
+ function addEncodedForms(forms, secret) {
134
+ forms.add(secret);
135
+ const encoded = btoa(secret);
136
+ forms.add(encoded);
137
+ forms.add(encoded.replace(/=+$/, ""));
138
+ forms.add(encoded.replace(/\+/g, "-").replace(/\//g, "_"));
139
+ forms.add(encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""));
140
+ for (let offset = 0; offset < 3; offset++) {
141
+ const interior = btoa("\0".repeat(offset) + secret).slice(
142
+ Math.ceil(8 * offset / 6),
143
+ Math.floor(8 * (offset + secret.length) / 6)
144
+ );
145
+ forms.add(interior);
146
+ forms.add(interior.replace(/\+/g, "-").replace(/\//g, "_"));
147
+ }
148
+ }
149
+ var RollingLeakGuard = class {
150
+ tailLength;
151
+ forms;
152
+ percentForms;
153
+ pending = "";
154
+ closed = false;
155
+ constructor(key) {
156
+ this.tailLength = 3 * key.length - 1;
157
+ const secrets = /* @__PURE__ */ new Set([key]);
158
+ const sensitive = key.replace(/^(?:sk-(?:ant-|proj-)?|zai[-_])/, "");
159
+ for (let start = 0; start <= sensitive.length - FRAGMENT_LENGTH; start++) {
160
+ secrets.add(sensitive.slice(start, start + FRAGMENT_LENGTH));
161
+ }
162
+ const forms = /* @__PURE__ */ new Set();
163
+ const percentForms = [];
164
+ for (const secret of secrets) {
165
+ addEncodedForms(forms, secret);
166
+ percentForms.push(percentPattern(secret));
167
+ }
168
+ this.forms = [...forms];
169
+ this.percentForms = percentForms;
170
+ }
171
+ push(text2) {
172
+ if (this.closed) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
173
+ const combined = this.pending + text2;
174
+ this.scan(combined);
175
+ const releaseLength = Math.max(0, combined.length - this.tailLength);
176
+ this.pending = combined.slice(releaseLength);
177
+ return combined.slice(0, releaseLength);
178
+ }
179
+ finish() {
180
+ if (this.closed) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
181
+ this.scan(this.pending);
182
+ const safe = this.pending;
183
+ this.discard();
184
+ return safe;
185
+ }
186
+ discard() {
187
+ this.pending = "";
188
+ this.closed = true;
189
+ }
190
+ scan(text2) {
191
+ if (this.forms.some((form) => text2.includes(form)) || this.percentForms.some((pattern) => pattern.test(text2))) {
192
+ this.discard();
193
+ throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
194
+ }
195
+ }
196
+ };
197
+
198
+ // src/input-guard.ts
199
+ async function admitCloudText(env, text2, selected) {
200
+ if (typeof text2 !== "string") throw new CloudDoError("CLOUD_REQUEST_INVALID");
201
+ if (hasUserKeyShape(text2)) throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
202
+ const credentials2 = platformCredentialReader(env);
203
+ for (const [id, profile] of Object.entries(PLATFORM_PROFILES)) {
204
+ let key;
205
+ try {
206
+ if (env[profile.binding] === void 0) continue;
207
+ key = await credentials2.get(profile.secretName);
208
+ } catch {
209
+ if (selected && id !== selected) continue;
210
+ throw new CloudDoError("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE");
211
+ }
212
+ const guard = new RollingLeakGuard(key);
213
+ try {
214
+ guard.push(text2);
215
+ guard.finish();
216
+ } catch {
217
+ throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
218
+ }
219
+ }
220
+ }
221
+ async function admitCloudPayload(env, value, selected) {
222
+ const ancestors = /* @__PURE__ */ new Set();
223
+ let nodes = 0;
224
+ const visit = async (item, depth) => {
225
+ if (++nodes > 1e4 || depth > 32) throw new CloudDoError("CLOUD_REQUEST_INVALID");
226
+ if (typeof item === "string") {
227
+ await admitCloudText(env, item, selected);
228
+ return;
229
+ }
230
+ if (item === null || typeof item === "boolean" || typeof item === "number" && Number.isFinite(item)) return;
231
+ if (!item || typeof item !== "object" || ancestors.has(item)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
232
+ if (!Array.isArray(item) && Object.getPrototypeOf(item) !== Object.prototype && Object.getPrototypeOf(item) !== null) {
233
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
234
+ }
235
+ ancestors.add(item);
236
+ try {
237
+ if (Array.isArray(item)) {
238
+ if (Reflect.ownKeys(item).length !== item.length + 1) throw new CloudDoError("CLOUD_REQUEST_INVALID");
239
+ for (let i = 0; i < item.length; i++) {
240
+ const field = Object.getOwnPropertyDescriptor(item, String(i));
241
+ if (!field || !("value" in field) || !field.enumerable) throw new CloudDoError("CLOUD_REQUEST_INVALID");
242
+ await visit(field.value, depth + 1);
243
+ }
244
+ } else {
245
+ for (const key of Reflect.ownKeys(item)) {
246
+ const field = Object.getOwnPropertyDescriptor(item, key);
247
+ if (typeof key !== "string" || !field || !("value" in field) || !field.enumerable) {
248
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
249
+ }
250
+ await visit(key, depth + 1);
251
+ await visit(field.value, depth + 1);
252
+ }
253
+ }
254
+ } finally {
255
+ ancestors.delete(item);
256
+ }
257
+ };
258
+ await visit(value, 0);
259
+ }
260
+ async function prepareCloudGuard(env, selected) {
261
+ if (selected !== void 0 && (typeof selected !== "string" || !Object.hasOwn(PLATFORM_PROFILES, selected))) throw new CloudDoError("CLOUD_REQUEST_INVALID");
262
+ const credentials2 = platformCredentialReader(env);
263
+ const keys = [];
264
+ for (const [id, profile] of Object.entries(PLATFORM_PROFILES)) {
265
+ try {
266
+ if (env[profile.binding] === void 0 && id !== selected) continue;
267
+ keys.push(await credentials2.get(profile.secretName));
268
+ } catch {
269
+ if (selected && id !== selected) continue;
270
+ keys.length = 0;
271
+ throw new CloudDoError("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE");
272
+ }
273
+ }
274
+ let disposed = false;
275
+ const guardText = (text2) => {
276
+ if (disposed || typeof text2 !== "string") throw new CloudDoError("CLOUD_REQUEST_INVALID");
277
+ if (hasUserKeyShape(text2)) throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
278
+ for (const key of keys) {
279
+ const guard = new RollingLeakGuard(key);
280
+ try {
281
+ guard.push(text2);
282
+ guard.finish();
283
+ } catch {
284
+ throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
285
+ }
286
+ }
287
+ };
288
+ return {
289
+ guardText,
290
+ guardPayload(dataJson) {
291
+ if (disposed || typeof dataJson !== "string") throw new CloudDoError("CLOUD_REQUEST_INVALID");
292
+ let value;
293
+ try {
294
+ value = JSON.parse(dataJson);
295
+ } catch {
296
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
297
+ }
298
+ let nodes = 0;
299
+ const visit = (item, depth) => {
300
+ if (++nodes > 1e4 || depth > 32) throw new CloudDoError("CLOUD_REQUEST_INVALID");
301
+ if (typeof item === "string") {
302
+ guardText(item);
303
+ return;
304
+ }
305
+ if (item === null || typeof item === "boolean" || typeof item === "number" && Number.isFinite(item)) return;
306
+ if (!item || typeof item !== "object") throw new CloudDoError("CLOUD_REQUEST_INVALID");
307
+ if (Array.isArray(item)) {
308
+ for (const field of item) visit(field, depth + 1);
309
+ } else {
310
+ if (Object.getPrototypeOf(item) !== Object.prototype && Object.getPrototypeOf(item) !== null) throw new CloudDoError("CLOUD_REQUEST_INVALID");
311
+ for (const [key, field] of Object.entries(item)) {
312
+ visit(key, depth + 1);
313
+ visit(field, depth + 1);
314
+ }
315
+ }
316
+ };
317
+ visit(value, 0);
318
+ return JSON.stringify(value);
319
+ },
320
+ dispose() {
321
+ keys.length = 0;
322
+ disposed = true;
323
+ }
324
+ };
325
+ }
326
+
327
+ // src/inbox-admission.ts
328
+ var fields = /* @__PURE__ */ new Set(["dedupKey", "source", "text", "profile", "availableAt", "expiresAt"]);
329
+ var credentials = /* @__PURE__ */ new Set(["credential", "credentials", "apikey", "api_key", "secret", "authorization", "x-api-key", "api-key", "x-goog-api-key", "proxy-authorization", "cf-aig-authorization", "headers"]);
330
+ var INBOX_DAY = 864e5;
331
+ function admitCloudInbox(input, now = Date.now()) {
332
+ if (!input || typeof input !== "object" || Array.isArray(input) || Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null) {
333
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
334
+ }
335
+ for (const key of Reflect.ownKeys(input)) {
336
+ if (typeof key === "string" && credentials.has(key.toLowerCase())) throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
337
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
338
+ if (typeof key !== "string" || !fields.has(key) || !descriptor?.enumerable || !("value" in descriptor)) {
339
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
340
+ }
341
+ }
342
+ const body = input;
343
+ if (typeof body.dedupKey !== "string" || !body.dedupKey.length || body.dedupKey.length > 128 || /[\u0000-\u001f\u007f-\u009f]/u.test(body.dedupKey) || typeof body.text !== "string" || !body.text.trim() || body.text.length > 16e3 || !["message", "schedule", "invocation"].includes(body.source)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
344
+ if (hasUserKeyShape(body.text) || hasUserKeyShape(body.dedupKey)) throw new CloudDoError("CLOUD_USER_CREDENTIAL_REJECTED");
345
+ for (const key of ["availableAt", "expiresAt"]) {
346
+ if (body[key] !== void 0 && !Number.isSafeInteger(body[key])) throw new CloudDoError("CLOUD_REQUEST_INVALID");
347
+ }
348
+ const availableAt = body.availableAt;
349
+ const expiresAt = body.expiresAt;
350
+ if (availableAt !== void 0 && availableAt > now + 30 * INBOX_DAY || expiresAt !== void 0 && availableAt !== void 0 && expiresAt <= availableAt) throw new CloudDoError("CLOUD_REQUEST_INVALID");
351
+ return Object.freeze({
352
+ dedupKey: body.dedupKey,
353
+ source: body.source,
354
+ text: body.text,
355
+ profile: platformProfile(body.profile === void 0 ? "zai_openai" : body.profile),
356
+ ...availableAt === void 0 ? {} : { availableAt },
357
+ ...expiresAt === void 0 ? {} : { expiresAt }
358
+ });
359
+ }
360
+
361
+ // src/tools.ts
362
+ var CLOUD_SAFE_REPLAY_TOOLS = Object.freeze([
363
+ "load_financial_analysis_skill",
364
+ "resolve_security",
365
+ "guarded_screen",
366
+ "search_f10_datasets",
367
+ "query_f10_dataset",
368
+ "get_security_profile",
369
+ "get_quote_snapshot",
370
+ "get_corporate_actions",
371
+ "get_financial_statements",
372
+ "get_financial_facts",
373
+ "get_financial_ratios",
374
+ "get_sdi_disclosures",
375
+ "get_directorate",
376
+ "get_ownership",
377
+ "get_related_warrants"
378
+ ]);
379
+ var CLOUD_LIVE_IPO_TOOLS = Object.freeze([
380
+ "get_ipo_profile",
381
+ "search_ipo_calendar",
382
+ "get_ipo_timetable",
383
+ "get_ipo_offering",
384
+ "get_ipo_allotment",
385
+ "screen_ipos",
386
+ "compare_ipos"
387
+ ]);
388
+ var safeTools = new Set(CLOUD_SAFE_REPLAY_TOOLS);
389
+ var admittedNames = /* @__PURE__ */ new Set([...CLOUD_SAFE_REPLAY_TOOLS, ...CLOUD_LIVE_IPO_TOOLS]);
390
+ var CLOUD_DOMAIN_ERROR_CODES = Object.freeze({
391
+ NOT_FOUND: "CLOUD_TOOL_NOT_AVAILABLE",
392
+ DATA_NOT_LICENSED: "CLOUD_TOOL_NOT_AVAILABLE",
393
+ DATA_QUALITY_HOLD: "CLOUD_TOOL_NOT_AVAILABLE",
394
+ SCOPE_DENIED: "CLOUD_TOOL_NOT_AVAILABLE",
395
+ TOOL_UNAVAILABLE: "CLOUD_TOOL_NOT_AVAILABLE",
396
+ TOOL_ARGUMENT_INVALID: "CLOUD_TOOL_ARGUMENT_INVALID",
397
+ OUT_OF_RANGE: "CLOUD_TOOL_ARGUMENT_INVALID",
398
+ TOO_MANY_ROWS: "CLOUD_TOOL_ARGUMENT_INVALID",
399
+ AMBIGUOUS_SECURITY: "CLOUD_TOOL_ARGUMENT_INVALID",
400
+ SYMBOL_AMBIGUOUS: "CLOUD_TOOL_ARGUMENT_INVALID"
401
+ });
402
+ function policyNames(names2, max, pattern, forbidden) {
403
+ if (names2 === void 0) return Object.freeze([]);
404
+ if (!Array.isArray(names2) || names2.length > max || new Set(names2).size !== names2.length || Array.from(names2).some((name) => typeof name !== "string" || !pattern.test(name) || forbidden(name))) {
405
+ throw new CloudDoError("CLOUD_TOOL_NOT_AVAILABLE");
406
+ }
407
+ return Object.freeze([...names2].sort());
408
+ }
409
+ function admitCloudTools(tools, pureTools = []) {
410
+ const pure = new Set(policyNames(pureTools, 8, /^[a-z][a-z0-9_]{2,63}$/, (name) => admittedNames.has(name)));
411
+ const seen = /* @__PURE__ */ new Set();
412
+ for (const tool of tools) {
413
+ const schema = tool.parameters;
414
+ if (!(tool.execution === "pure" ? pure.has(tool.name) : admittedNames.has(tool.name)) || seen.has(tool.name) || typeof tool.description !== "string" || tool.mode !== void 0 && tool.mode !== "inline" || (tool.requiredCapabilities?.length ?? 0) > 0 || !schema || schema.type !== "object" || schema.additionalProperties !== false || !schema.properties || typeof schema.properties !== "object" || Array.isArray(schema.properties) || (tool.execution === "pure" ? tool.resolverRpc !== void 0 : tool.name === "load_financial_analysis_skill" ? tool.execution !== "skill" || Object.keys(schema.properties).length !== 0 : tool.execution !== "read_only_live" || typeof tool.resolverRpc !== "string" || !tool.resolverRpc.trim())) {
415
+ throw new CloudDoError("CLOUD_TOOL_NOT_AVAILABLE");
416
+ }
417
+ seen.add(tool.name);
418
+ }
419
+ return Object.freeze([...tools]);
420
+ }
421
+ function admitCloudDispatcher(dispatcher) {
422
+ const pureTools = policyNames(dispatcher.pureTools, 8, /^[a-z][a-z0-9_]{2,63}$/, (name) => admittedNames.has(name));
423
+ const domainErrors = policyNames(dispatcher.domainErrors, 64, /^[A-Z][A-Z0-9_]{2,63}$/, (name) => name.startsWith("CLOUD_") || Object.hasOwn(CLOUD_DOMAIN_ERROR_CODES, name));
424
+ if (dispatcher.modelViews !== void 0 && typeof dispatcher.modelViews !== "boolean") throw new CloudDoError("CLOUD_TOOL_NOT_AVAILABLE");
425
+ const tools = admitCloudTools(dispatcher.tools, pureTools);
426
+ const snapshot = JSON.parse(JSON.stringify({ tools }));
427
+ const freeze = (value) => {
428
+ if (value && typeof value === "object") {
429
+ Object.values(value).forEach(freeze);
430
+ Object.freeze(value);
431
+ }
432
+ };
433
+ freeze(snapshot);
434
+ return Object.freeze({
435
+ tools: snapshot.tools,
436
+ pureTools,
437
+ domainErrors,
438
+ modelViews: dispatcher.modelViews ?? false,
439
+ execute: dispatcher.execute.bind(dispatcher)
440
+ });
441
+ }
442
+ function dispatcherDigest(dispatcher) {
443
+ return digest(canonicalArgs({
444
+ tools: dispatcher.tools.map(({ name, execution, parameters }) => ({ name, execution, parameters })).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0),
445
+ pureTools: [...dispatcher.pureTools ?? []].sort(),
446
+ domainErrors: [...dispatcher.domainErrors ?? []].sort(),
447
+ modelViews: dispatcher.modelViews ?? false
448
+ }));
449
+ }
450
+ function replayForTool(name) {
451
+ return safeTools.has(name) ? "safe" : "unsafe";
452
+ }
453
+ function canonical(value, ancestors) {
454
+ if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
455
+ if (typeof value === "number" && Number.isFinite(value)) return JSON.stringify(value);
456
+ if (typeof value !== "object" || ancestors.has(value)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
457
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
458
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
459
+ }
460
+ ancestors.add(value);
461
+ try {
462
+ if (Array.isArray(value)) {
463
+ if (Object.keys(value).length !== value.length) throw new CloudDoError("CLOUD_REQUEST_INVALID");
464
+ return `[${value.map((item) => canonical(item, ancestors)).join(",")}]`;
465
+ }
466
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key], ancestors)}`).join(",")}}`;
467
+ } finally {
468
+ ancestors.delete(value);
469
+ }
470
+ }
471
+ function canonicalArgs(args) {
472
+ if (!args || typeof args !== "object" || Array.isArray(args)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
473
+ return canonical(args, /* @__PURE__ */ new Set());
474
+ }
475
+ async function digest(value) {
476
+ const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
477
+ return Array.from(new Uint8Array(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
478
+ }
479
+ function invocationId(conversationId, assistantEntryId, toolCallId) {
480
+ return digest(JSON.stringify([conversationId, assistantEntryId, toolCallId]));
481
+ }
482
+ function argsDigest(toolName, args) {
483
+ return digest(`[${JSON.stringify(toolName)},${canonicalArgs(args)}]`);
484
+ }
485
+
486
+ // src/cloud-state.ts
487
+ var encoder = new TextEncoder();
488
+ var CLOUD_CONTEXT_BYTES = 48e3;
489
+ var RETENTION = 7 * INBOX_DAY;
490
+ var terminalInbox = "state NOT IN ('queued','running')";
491
+ var terminalRun = "state NOT IN ('starting','running')";
492
+ var terminalInvocation = "state NOT IN ('accepted','running')";
493
+ function inboxInput(rows) {
494
+ return rows.map((row2) => ({ seq: row2.seq, source: row2.source, text: JSON.parse(row2.payloadJson).text }));
495
+ }
496
+ function admissionIdentity(rows) {
497
+ return { digest: sha256(JSON.stringify(rows.map((row2) => [
498
+ row2.seq,
499
+ row2.dedupKey,
500
+ sha256(JSON.parse(row2.payloadJson).text),
501
+ row2.profile
502
+ ]))), seqs: rows.map((row2) => row2.seq) };
503
+ }
504
+ function runInputSeqs(entries) {
505
+ if (!Array.isArray(entries)) return [];
506
+ const entry = entries.find((value) => value !== null && typeof value === "object" && value.kind === "byok.run-input");
507
+ if (!entry || typeof entry !== "object") return [];
508
+ const data = entry.data;
509
+ if (!data || typeof data !== "object" || Array.isArray(data)) return [];
510
+ const items = data.items;
511
+ if (!Array.isArray(items) || items.length > 16) return [];
512
+ const seqs = [];
513
+ for (const item of items) {
514
+ if (!item || typeof item !== "object" || Array.isArray(item)) return [];
515
+ const { seq, source, text: text2 } = item;
516
+ if (typeof seq !== "number" || !Number.isSafeInteger(seq) || seq <= 0 || seqs.includes(seq) || (typeof source !== "string" || !["message", "schedule", "invocation"].includes(source)) || typeof text2 !== "string") return [];
517
+ seqs.push(seq);
518
+ }
519
+ return seqs;
520
+ }
521
+ function payloadText(row2) {
522
+ if (row2?.payloadJson === null || row2?.payloadJson === void 0) return null;
523
+ const value = JSON.parse(row2.payloadJson);
524
+ return typeof value.text === "string" ? value.text : null;
525
+ }
526
+ function composeCloudInput(rows, historyNewestFirst = []) {
527
+ const inbox = inboxInput(rows);
528
+ const history = [];
529
+ for (const item of historyNewestFirst.slice(0, 20)) {
530
+ const candidate = [item, ...history];
531
+ if (encoder.encode(canonicalArgs({ history: candidate, inbox })).byteLength > CLOUD_CONTEXT_BYTES) break;
532
+ history.unshift(item);
533
+ }
534
+ return canonicalArgs({ history, inbox });
535
+ }
536
+ function utf8Prefix(text2, maxBytes) {
537
+ let bytes = 0;
538
+ let end = 0;
539
+ for (const point of text2) {
540
+ const size = encoder.encode(point).length;
541
+ if (bytes + size > maxBytes) break;
542
+ bytes += size;
543
+ end += point.length;
544
+ }
545
+ return text2.slice(0, end);
546
+ }
547
+ function sha256(text2) {
548
+ const constants = [
549
+ 1116352408,
550
+ 1899447441,
551
+ 3049323471,
552
+ 3921009573,
553
+ 961987163,
554
+ 1508970993,
555
+ 2453635748,
556
+ 2870763221,
557
+ 3624381080,
558
+ 310598401,
559
+ 607225278,
560
+ 1426881987,
561
+ 1925078388,
562
+ 2162078206,
563
+ 2614888103,
564
+ 3248222580,
565
+ 3835390401,
566
+ 4022224774,
567
+ 264347078,
568
+ 604807628,
569
+ 770255983,
570
+ 1249150122,
571
+ 1555081692,
572
+ 1996064986,
573
+ 2554220882,
574
+ 2821834349,
575
+ 2952996808,
576
+ 3210313671,
577
+ 3336571891,
578
+ 3584528711,
579
+ 113926993,
580
+ 338241895,
581
+ 666307205,
582
+ 773529912,
583
+ 1294757372,
584
+ 1396182291,
585
+ 1695183700,
586
+ 1986661051,
587
+ 2177026350,
588
+ 2456956037,
589
+ 2730485921,
590
+ 2820302411,
591
+ 3259730800,
592
+ 3345764771,
593
+ 3516065817,
594
+ 3600352804,
595
+ 4094571909,
596
+ 275423344,
597
+ 430227734,
598
+ 506948616,
599
+ 659060556,
600
+ 883997877,
601
+ 958139571,
602
+ 1322822218,
603
+ 1537002063,
604
+ 1747873779,
605
+ 1955562222,
606
+ 2024104815,
607
+ 2227730452,
608
+ 2361852424,
609
+ 2428436474,
610
+ 2756734187,
611
+ 3204031479,
612
+ 3329325298
613
+ ];
614
+ const source = encoder.encode(text2);
615
+ const data = new Uint8Array(Math.ceil((source.length + 9) / 64) * 64);
616
+ data.set(source);
617
+ data[source.length] = 128;
618
+ const view = new DataView(data.buffer);
619
+ view.setUint32(data.length - 8, Math.floor(source.length / 536870912));
620
+ view.setUint32(data.length - 4, source.length * 8);
621
+ const hash = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225];
622
+ const rotate = (value, count) => value >>> count | value << 32 - count;
623
+ const words = new Uint32Array(64);
624
+ for (let offset = 0; offset < data.length; offset += 64) {
625
+ for (let i = 0; i < 16; i++) words[i] = view.getUint32(offset + i * 4);
626
+ for (let i = 16; i < 64; i++) {
627
+ const a2 = words[i - 15];
628
+ const b2 = words[i - 2];
629
+ words[i] = words[i - 16] + (rotate(a2, 7) ^ rotate(a2, 18) ^ a2 >>> 3) + words[i - 7] + (rotate(b2, 17) ^ rotate(b2, 19) ^ b2 >>> 10);
630
+ }
631
+ let [a, b, c, d, e, f, g, h] = hash;
632
+ for (let i = 0; i < 64; i++) {
633
+ const first = h + (rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25)) + (e & f ^ ~e & g) + constants[i] + words[i] | 0;
634
+ const second = (rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22)) + (a & b ^ a & c ^ b & c) | 0;
635
+ h = g;
636
+ g = f;
637
+ f = e;
638
+ e = d + first | 0;
639
+ d = c;
640
+ c = b;
641
+ b = a;
642
+ a = first + second | 0;
643
+ }
644
+ for (const [index, value] of [a, b, c, d, e, f, g, h].entries()) hash[index] = hash[index] + value >>> 0;
645
+ }
646
+ return hash.map((value) => value.toString(16).padStart(8, "0")).join("");
647
+ }
648
+ var CloudState = class {
649
+ constructor(storage) {
650
+ this.storage = storage;
651
+ }
652
+ storage;
653
+ scheduling = {};
654
+ rows(query, ...values) {
655
+ return this.storage.sql.exec(query, ...values).toArray();
656
+ }
657
+ ensureSchema() {
658
+ this.storage.transactionSync(() => {
659
+ this.storage.sql.exec(`CREATE TABLE IF NOT EXISTS cloud_inbox (
660
+ seq INTEGER PRIMARY KEY AUTOINCREMENT, dedupKey TEXT NOT NULL UNIQUE, payloadDigest TEXT NOT NULL,
661
+ source TEXT NOT NULL CHECK(source IN ('message','schedule','invocation')), profile TEXT NOT NULL, payloadJson TEXT,
662
+ availableAt INTEGER NOT NULL, expiresAt INTEGER NOT NULL,
663
+ state TEXT NOT NULL CHECK(state IN ('queued','running','done','failed','interrupted','cancelled','expired')),
664
+ runId INTEGER, attempts INTEGER NOT NULL DEFAULT 0, errorCode TEXT, createdAt INTEGER NOT NULL, settledAt INTEGER);
665
+ CREATE INDEX IF NOT EXISTS cloud_inbox_runnable ON cloud_inbox(state,availableAt,seq);
666
+ CREATE TABLE IF NOT EXISTS cloud_events (
667
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,eventKey TEXT NOT NULL UNIQUE,type TEXT NOT NULL,
668
+ conversationId INTEGER,ref TEXT,dataJson TEXT NOT NULL,createdAt INTEGER NOT NULL);
669
+ CREATE TABLE IF NOT EXISTS cloud_event_meta (
670
+ singleton INTEGER PRIMARY KEY CHECK(singleton=1),trimmedThrough INTEGER NOT NULL DEFAULT 0,
671
+ highWater INTEGER NOT NULL DEFAULT 0,pendingMaintenanceAt INTEGER);
672
+ INSERT INTO cloud_event_meta(singleton) VALUES(1) ON CONFLICT DO NOTHING;
673
+ CREATE TABLE IF NOT EXISTS cloud_projections (
674
+ key TEXT PRIMARY KEY,invocationId TEXT NOT NULL,state TEXT NOT NULL,payloadDigest TEXT NOT NULL,
675
+ dataJson TEXT NOT NULL,errorCode TEXT,createdAt INTEGER NOT NULL)`);
676
+ const legacyMembership = !this.rows("PRAGMA table_info(cloud_executions)").some((row2) => row2.name === "membershipPending");
677
+ this.migrate("cloud_inbox", { inputDurable: "INTEGER NOT NULL DEFAULT 0", revision: "INTEGER" });
678
+ this.storage.sql.exec(`CREATE TABLE IF NOT EXISTS cloud_run_turns (
679
+ runId INTEGER NOT NULL, seq INTEGER NOT NULL, claimEvent INTEGER, releaseEvent INTEGER,
680
+ PRIMARY KEY (runId,seq));
681
+ CREATE INDEX IF NOT EXISTS cloud_run_turns_by_seq ON cloud_run_turns(seq,runId)`);
682
+ this.migrate("cloud_executions", {
683
+ trigger: "TEXT NOT NULL DEFAULT 'submit'",
684
+ requestId: "TEXT",
685
+ submissionId: "INTEGER",
686
+ state: "TEXT NOT NULL DEFAULT 'interrupted'",
687
+ errorCode: "TEXT",
688
+ startedAt: "INTEGER",
689
+ settledAt: "INTEGER",
690
+ reservation: "TEXT NOT NULL DEFAULT 'none'",
691
+ eligibilityJson: "TEXT",
692
+ admissionDigest: "TEXT",
693
+ admittedSeqs: "TEXT",
694
+ settlementAck: "INTEGER",
695
+ revision: "INTEGER",
696
+ membershipPending: "INTEGER"
697
+ });
698
+ if (legacyMembership) {
699
+ this.storage.sql.exec("INSERT OR IGNORE INTO cloud_run_turns(runId,seq) SELECT runId,seq FROM cloud_inbox WHERE runId IS NOT NULL");
700
+ this.storage.sql.exec("UPDATE cloud_executions SET membershipPending=1 WHERE trigger='wake'");
701
+ }
702
+ this.migrate("cloud_invocations", { deliveredState: "TEXT NOT NULL DEFAULT 'undelivered'", taskId: "INTEGER", resultEntryId: "INTEGER" });
703
+ });
704
+ }
705
+ migrate(table, columns) {
706
+ const existing = new Set(this.rows(`PRAGMA table_info(${table})`).map((row2) => row2.name));
707
+ for (const [name, type] of Object.entries(columns)) if (!existing.has(name)) this.storage.sql.exec(`ALTER TABLE ${table} ADD COLUMN ${name} ${type}`);
708
+ }
709
+ readInboxItem(seq) {
710
+ return this.rows("SELECT * FROM cloud_inbox WHERE seq=?", seq)[0];
711
+ }
712
+ run(conversationId) {
713
+ return this.rows("SELECT * FROM cloud_executions WHERE conversationId=?", conversationId)[0];
714
+ }
715
+ unsettledRuns() {
716
+ return this.rows(`SELECT * FROM cloud_executions WHERE ${terminalRun.replace("NOT IN", "IN")} ORDER BY conversationId`);
717
+ }
718
+ completedRuns() {
719
+ return this.rows("SELECT * FROM cloud_executions WHERE state='completed' ORDER BY conversationId DESC LIMIT 20");
720
+ }
721
+ invocationRowsForRun(id) {
722
+ return this.rows("SELECT * FROM cloud_invocations WHERE conversationId=? ORDER BY seq", id);
723
+ }
724
+ stamp(table, key, revision) {
725
+ this.storage.sql.exec(`UPDATE ${table} SET revision=? WHERE ${table === "cloud_inbox" ? "seq" : "conversationId"}=? AND (revision IS NULL OR revision<?)`, revision, key, revision);
726
+ }
727
+ claimedSeqs(id) {
728
+ return this.rows("SELECT seq FROM cloud_run_turns WHERE runId=? ORDER BY seq", id).map((row2) => row2.seq);
729
+ }
730
+ markInputDurable(id, seqs) {
731
+ this.storage.transactionSync(() => {
732
+ for (const seq of seqs) this.storage.sql.exec("UPDATE cloud_inbox SET inputDurable=1 WHERE seq=? AND runId=? AND state='running'", seq, id);
733
+ });
734
+ }
735
+ pendingBackfills(before = Number.MAX_SAFE_INTEGER) {
736
+ return this.rows("SELECT * FROM cloud_executions WHERE membershipPending=1 AND conversationId<? ORDER BY conversationId DESC LIMIT 25", before);
737
+ }
738
+ applyBackfill(id, seqs) {
739
+ this.storage.transactionSync(() => {
740
+ if (this.run(id)?.membershipPending !== 1) return;
741
+ for (const seq of seqs) this.storage.sql.exec(`INSERT INTO cloud_run_turns(runId,seq)
742
+ SELECT ?,? WHERE NOT EXISTS(SELECT 1 FROM cloud_run_turns WHERE seq=?)
743
+ AND NOT EXISTS(SELECT 1 FROM cloud_inbox WHERE seq=?)`, id, seq, seq, seq);
744
+ this.storage.sql.exec("UPDATE cloud_executions SET membershipPending=0 WHERE conversationId=?", id);
745
+ });
746
+ }
747
+ unackedRuns() {
748
+ return this.rows(`SELECT * FROM cloud_executions WHERE ${terminalRun} AND settlementAck=0 ORDER BY conversationId`);
749
+ }
750
+ ackSettlement(id, guard, now = Date.now()) {
751
+ return this.storage.transactionSync(() => {
752
+ if (this.run(id)?.settlementAck !== 0) return false;
753
+ this.storage.sql.exec("UPDATE cloud_executions SET settlementAck=1 WHERE conversationId=?", id);
754
+ const event = this.appendEvent({
755
+ eventKey: `run:${id}:settlement`,
756
+ type: "run.settlement",
757
+ conversationId: id,
758
+ data: { nativeRunId: id, ack: true },
759
+ createdAt: now
760
+ }, guard);
761
+ this.stamp("cloud_executions", id, event.seq);
762
+ return true;
763
+ });
764
+ }
765
+ /** Read-only preflight also works before this DO has initialized its schema. */
766
+ validateEnqueue(input, guard, now = Date.now()) {
767
+ guard.guardText(input.text);
768
+ guard.guardText(input.dedupKey);
769
+ const exists = this.rows("SELECT name FROM sqlite_master WHERE type='table' AND name='cloud_inbox'").length > 0;
770
+ const previous = exists ? this.rows("SELECT * FROM cloud_inbox WHERE dedupKey=?", input.dedupKey)[0] : void 0;
771
+ this.enqueueIdentity(input, previous, now);
772
+ }
773
+ enqueueIdentity(input, previous, now) {
774
+ const retained = previous && (previous.settledAt === null || previous.settledAt + RETENTION > now) ? previous : void 0;
775
+ const availableAt = input.availableAt ?? retained?.availableAt ?? now;
776
+ const expiresAt = input.expiresAt ?? retained?.expiresAt ?? availableAt + INBOX_DAY;
777
+ if (!Number.isSafeInteger(availableAt) || !Number.isSafeInteger(expiresAt)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
778
+ const payloadDigest = sha256(canonicalArgs({ source: input.source, text: input.text, profile: input.profile, availableAt, expiresAt }));
779
+ if (retained && retained.payloadDigest !== payloadDigest) throw new CloudDoError("CLOUD_INBOX_CONFLICT");
780
+ if (expiresAt <= availableAt || !retained && availableAt > now + 30 * INBOX_DAY) throw new CloudDoError("CLOUD_REQUEST_INVALID");
781
+ return { retained, availableAt, expiresAt, payloadDigest };
782
+ }
783
+ async enqueue(input, guard, now = Date.now(), options) {
784
+ guard.guardText(input.text);
785
+ guard.guardText(input.dedupKey);
786
+ if (options) this.setSchedulingState(options);
787
+ return this.storage.transaction(async () => {
788
+ const previous = this.rows("SELECT * FROM cloud_inbox WHERE dedupKey=?", input.dedupKey)[0];
789
+ const { retained, availableAt, expiresAt, payloadDigest } = this.enqueueIdentity(input, previous, now);
790
+ if (retained) return { accepted: false, row: retained };
791
+ if (this.rows("SELECT COUNT(*) AS count FROM cloud_inbox WHERE state='queued'")[0].count >= 100) throw new CloudDoError("CLOUD_INBOX_FULL");
792
+ if (previous) this.storage.sql.exec("DELETE FROM cloud_inbox WHERE seq=?", previous.seq);
793
+ const row2 = this.rows(
794
+ `INSERT INTO cloud_inbox(dedupKey,payloadDigest,source,profile,payloadJson,availableAt,expiresAt,state,createdAt)
795
+ VALUES(?,?,?,?,?,?,?,'queued',?) RETURNING *`,
796
+ input.dedupKey,
797
+ payloadDigest,
798
+ input.source,
799
+ input.profile,
800
+ guard.guardPayload(JSON.stringify({ text: input.text })),
801
+ availableAt,
802
+ expiresAt,
803
+ now
804
+ )[0];
805
+ const event = this.appendEvent({ eventKey: `inbox:${row2.seq}:accepted`, type: "inbox.accepted", ref: String(row2.seq), data: { seq: row2.seq, source: row2.source, profile: row2.profile, availableAt, expiresAt }, createdAt: now }, guard);
806
+ this.stamp("cloud_inbox", row2.seq, event.seq);
807
+ await this.rearmAlarm(void 0, now);
808
+ return { accepted: true, row: this.readInboxItem(row2.seq) };
809
+ });
810
+ }
811
+ /** Selection never skips another profile or a prefix item that exceeds the budget. */
812
+ selectBatch(now = Date.now(), guard) {
813
+ return this.storage.transactionSync(() => {
814
+ const candidates = this.rows("SELECT * FROM cloud_inbox WHERE state='queued' AND availableAt<=? AND expiresAt>? ORDER BY availableAt,seq LIMIT 17", now, now);
815
+ const selected = [];
816
+ for (const row2 of candidates) {
817
+ if (selected.length >= 16 || selected.length && row2.profile !== selected[0].profile) break;
818
+ if (encoder.encode(composeCloudInput([...selected, row2])).length > CLOUD_CONTEXT_BYTES) {
819
+ if (!selected.length && guard) this.settleItem(row2, "failed", "CLOUD_INBOX_TOO_LARGE", guard, now);
820
+ break;
821
+ }
822
+ selected.push(row2);
823
+ }
824
+ return selected;
825
+ });
826
+ }
827
+ startRun(id, trigger, deadlineAt, guard, now = Date.now()) {
828
+ return this.storage.transactionSync(() => {
829
+ this.storage.sql.exec(`INSERT INTO cloud_executions(conversationId,deadlineAt,trigger,requestId,state,startedAt,settlementAck)
830
+ VALUES(?,?,?,?,?,?,0) ON CONFLICT(conversationId) DO UPDATE SET trigger=excluded.trigger,
831
+ requestId=excluded.requestId,state=excluded.state,startedAt=excluded.startedAt,settlementAck=0 WHERE cloud_executions.startedAt IS NULL`, id, deadlineAt, trigger, `${trigger}:${id}`, trigger === "wake" ? "starting" : "running", now);
832
+ if (trigger === "submit") {
833
+ const event = this.appendEvent({ eventKey: `run:${id}:started`, type: "run.started", conversationId: id, data: { trigger }, createdAt: now }, guard);
834
+ this.stamp("cloud_executions", id, event.seq);
835
+ }
836
+ return this.run(id);
837
+ });
838
+ }
839
+ markRunning(id, guard, now = Date.now()) {
840
+ this.storage.transactionSync(() => {
841
+ const row2 = this.run(id);
842
+ if (!row2 || row2.state !== "starting") return;
843
+ this.storage.sql.exec("UPDATE cloud_executions SET state='running' WHERE conversationId=?", id);
844
+ const event = this.appendEvent({ eventKey: `run:${id}:started`, type: "run.started", conversationId: id, data: { trigger: row2.trigger }, createdAt: now }, guard);
845
+ this.stamp("cloud_executions", id, event.seq);
846
+ });
847
+ }
848
+ recordSubmission(id, submissionId) {
849
+ this.storage.sql.exec("UPDATE cloud_executions SET submissionId=? WHERE conversationId=?", submissionId, id);
850
+ }
851
+ markReservation(id, reservation, guard, now = Date.now(), admission) {
852
+ this.storage.transactionSync(() => {
853
+ const row2 = this.run(id);
854
+ if (!row2 || row2.state !== "starting" && row2.state !== "running") return;
855
+ if (reservation === "pending" && admission && row2.admissionDigest === null) this.storage.sql.exec(
856
+ "UPDATE cloud_executions SET admissionDigest=?,admittedSeqs=? WHERE conversationId=? AND admissionDigest IS NULL",
857
+ admission.digest,
858
+ JSON.stringify(admission.seqs),
859
+ id
860
+ );
861
+ if (row2.reservation === reservation) return;
862
+ this.storage.sql.exec("UPDATE cloud_executions SET reservation=? WHERE conversationId=?", reservation, id);
863
+ if (reservation !== "pending") this.appendEvent({
864
+ eventKey: `run:${id}:reservation:${reservation}`,
865
+ type: "run.reservation",
866
+ conversationId: id,
867
+ data: { key: row2.requestId, reservation, action: reservation === "released" ? "release" : "reserve" },
868
+ createdAt: now
869
+ }, guard);
870
+ });
871
+ }
872
+ captureEligibility(originalStale) {
873
+ return this.storage.transactionSync(() => {
874
+ for (const row2 of this.unsettledRuns()) if (row2.eligibilityJson === null) this.storage.sql.exec(
875
+ "UPDATE cloud_executions SET eligibilityJson=? WHERE conversationId=? AND eligibilityJson IS NULL",
876
+ JSON.stringify({ steps: row2.steps, aborted: row2.aborted, fatalCode: row2.fatalCode, wasStale: originalStale?.has(row2.conversationId) ?? false }),
877
+ row2.conversationId
878
+ );
879
+ return this.unsettledRuns();
880
+ });
881
+ }
882
+ claim(id, seqs, profile, guard, now = Date.now()) {
883
+ return this.storage.transactionSync(() => {
884
+ const run = this.run(id);
885
+ if (!run || run.state !== "starting") return [];
886
+ const stopped = run.fatalCode ?? (run.aborted ? "CLOUD_EXECUTION_ABORTED" : now >= run.deadlineAt ? "CLOUD_EXECUTION_TIMEOUT" : void 0);
887
+ if (stopped) {
888
+ this.settleRun(id, { state: "interrupted", errorCode: stopped }, guard, now);
889
+ return [];
890
+ }
891
+ const allowed = new Set(seqs);
892
+ const selected = [];
893
+ for (const row2 of this.selectBatch(now, guard)) {
894
+ if (!allowed.has(row2.seq) || row2.profile !== profile) break;
895
+ selected.push(row2);
896
+ }
897
+ const claimed = [];
898
+ for (const row2 of selected) {
899
+ if (row2.attempts >= 3) {
900
+ this.storage.sql.exec("UPDATE cloud_inbox SET attempts=attempts+1 WHERE seq=?", row2.seq);
901
+ this.settleItem(row2, "failed", "CLOUD_WAKE_EXHAUSTED", guard, now);
902
+ continue;
903
+ }
904
+ this.storage.sql.exec("UPDATE cloud_inbox SET state='running',runId=?,attempts=attempts+1 WHERE seq=? AND state='queued'", id, row2.seq);
905
+ claimed.push(this.readInboxItem(row2.seq));
906
+ }
907
+ if (!claimed.length) {
908
+ this.settleRun(id, { state: "interrupted", errorCode: "CLOUD_WAKE_EMPTY" }, guard, now);
909
+ return [];
910
+ }
911
+ this.storage.sql.exec("UPDATE cloud_executions SET state='running' WHERE conversationId=?", id);
912
+ const event = this.appendEvent({ eventKey: `run:${id}:started`, type: "run.started", conversationId: id, data: { trigger: "wake", seqs: claimed.map((row2) => row2.seq) }, createdAt: now }, guard);
913
+ for (const item of claimed) {
914
+ this.storage.sql.exec("INSERT INTO cloud_run_turns(runId,seq,claimEvent) VALUES(?,?,?)", id, item.seq, event.seq);
915
+ this.stamp("cloud_inbox", item.seq, event.seq);
916
+ }
917
+ this.stamp("cloud_executions", id, event.seq);
918
+ return claimed.map((item) => this.readInboxItem(item.seq));
919
+ });
920
+ }
921
+ settleItem(row2, state, code, guard, now) {
922
+ this.storage.sql.exec("UPDATE cloud_inbox SET state=?,errorCode=?,payloadJson=CASE WHEN inputDurable=1 THEN NULL ELSE payloadJson END,settledAt=? WHERE seq=? AND state IN ('queued','running')", state, code ?? null, now, row2.seq);
923
+ const event = this.appendEvent({ eventKey: `inbox:${row2.seq}:settled`, type: "inbox.settled", conversationId: row2.runId ?? void 0, ref: String(row2.seq), data: { seq: row2.seq, state, errorCode: code ?? null }, createdAt: now }, guard);
924
+ this.stamp("cloud_inbox", row2.seq, event.seq);
925
+ }
926
+ failQueued(seqs, code, guard, now = Date.now()) {
927
+ this.storage.transactionSync(() => {
928
+ for (const seq of seqs) {
929
+ const row2 = this.readInboxItem(seq);
930
+ if (row2?.state === "queued") this.settleItem(row2, "failed", code, guard, now);
931
+ }
932
+ });
933
+ }
934
+ cancelQueued(seq, guard, now = Date.now()) {
935
+ return this.storage.transactionSync(() => {
936
+ const row2 = this.readInboxItem(seq);
937
+ if (row2?.state === "queued") this.settleItem(row2, "cancelled", "CLOUD_EXECUTION_ABORTED", guard, now);
938
+ return this.readInboxItem(seq);
939
+ });
940
+ }
941
+ expireQueued(guard, now = Date.now()) {
942
+ return this.storage.transactionSync(() => {
943
+ const rows = this.rows("SELECT * FROM cloud_inbox WHERE state='queued' AND expiresAt<=? ORDER BY expiresAt,seq LIMIT 100", now);
944
+ for (const row2 of rows) this.settleItem(row2, "expired", "CLOUD_INBOX_EXPIRED", guard, now);
945
+ return rows.length;
946
+ });
947
+ }
948
+ settleRun(id, outcome, guard, now = Date.now()) {
949
+ return this.storage.transactionSync(() => {
950
+ const row2 = this.run(id);
951
+ if (!row2 || row2.state !== "starting" && row2.state !== "running") return row2;
952
+ const items = this.rows("SELECT * FROM cloud_inbox WHERE runId=? AND state='running' ORDER BY seq", id);
953
+ for (const item of items) {
954
+ if (outcome.requeue && item.expiresAt > now) this.storage.sql.exec("UPDATE cloud_inbox SET state='queued',runId=NULL,inputDurable=0 WHERE seq=? AND state='running'", item.seq);
955
+ else {
956
+ const expiredRequeue = outcome.requeue && item.expiresAt <= now;
957
+ this.settleItem(
958
+ item,
959
+ expiredRequeue ? "expired" : outcome.state === "completed" ? "done" : outcome.state === "failed" ? "failed" : "interrupted",
960
+ expiredRequeue ? "CLOUD_INBOX_EXPIRED" : outcome.errorCode,
961
+ guard,
962
+ now
963
+ );
964
+ }
965
+ }
966
+ if (row2.reservation === "pending" || row2.reservation === "held") {
967
+ this.storage.sql.exec("UPDATE cloud_executions SET reservation='released' WHERE conversationId=?", id);
968
+ this.appendEvent({ eventKey: `run:${id}:reservation:released`, type: "run.reservation", conversationId: id, data: { key: row2.requestId, reservation: "released", action: "release" }, createdAt: now }, guard);
969
+ }
970
+ this.storage.sql.exec("UPDATE cloud_executions SET state=?,errorCode=?,settledAt=?,settlementAck=0 WHERE conversationId=?", outcome.state, outcome.errorCode ?? null, now, id);
971
+ const data = { state: outcome.state, errorCode: outcome.errorCode ?? null, seqs: items.map((item) => item.seq) };
972
+ if (outcome.requeue) data.requeued = items.filter((item) => item.expiresAt > now).map((item) => item.seq);
973
+ if (outcome.entryId !== void 0) data.entryId = outcome.entryId;
974
+ if (outcome.state === "completed" && outcome.text !== void 0) {
975
+ try {
976
+ guard.guardText(outcome.text);
977
+ data.text = outcome.text;
978
+ } catch {
979
+ data.errorCode = "CLOUD_MODEL_RESPONSE_REJECTED";
980
+ }
981
+ if (encoder.encode(JSON.stringify(data)).length > 65536) {
982
+ data.text = utf8Prefix(outcome.text, 1024);
983
+ data.truncated = true;
984
+ }
985
+ }
986
+ const event = this.appendEvent({ eventKey: `run:${id}:settled`, type: `run.${outcome.state}`, conversationId: id, data, createdAt: now }, guard);
987
+ for (const item of items) if (outcome.requeue && item.expiresAt > now) {
988
+ this.storage.sql.exec("UPDATE cloud_run_turns SET releaseEvent=? WHERE runId=? AND seq=? AND releaseEvent IS NULL", event.seq, id, item.seq);
989
+ this.stamp("cloud_inbox", item.seq, event.seq);
990
+ }
991
+ this.stamp("cloud_executions", id, event.seq);
992
+ return this.run(id);
993
+ });
994
+ }
995
+ /** The caller must wrap this and its state write in one transaction. */
996
+ appendEvent(event, guard) {
997
+ guard.guardText(event.eventKey);
998
+ guard.guardText(event.type);
999
+ if (event.ref !== void 0) guard.guardText(event.ref);
1000
+ const dataJson = guard.guardPayload(JSON.stringify(event.data));
1001
+ if (encoder.encode(dataJson).length > 65536) throw new CloudDoError("CLOUD_REQUEST_INVALID");
1002
+ const previous = this.rows("SELECT * FROM cloud_events WHERE eventKey=?", event.eventKey)[0];
1003
+ if (previous) {
1004
+ if (previous.type !== event.type || previous.conversationId !== (event.conversationId ?? null) || previous.ref !== (event.ref ?? null) || previous.dataJson !== dataJson) throw new CloudDoError("CLOUD_REQUEST_INVALID");
1005
+ return previous;
1006
+ }
1007
+ const count = this.rows("SELECT COUNT(*) AS count FROM cloud_events")[0].count;
1008
+ if (count >= 1e4) this.trimPrefix(count - 9500);
1009
+ const row2 = this.rows(`INSERT INTO cloud_events(eventKey,type,conversationId,ref,dataJson,createdAt)
1010
+ VALUES(?,?,?,?,?,?) RETURNING *`, event.eventKey, event.type, event.conversationId ?? null, event.ref ?? null, dataJson, event.createdAt ?? Date.now())[0];
1011
+ this.storage.sql.exec("UPDATE cloud_event_meta SET highWater=? WHERE singleton=1", row2.seq);
1012
+ return row2;
1013
+ }
1014
+ eventMeta() {
1015
+ return this.rows("SELECT trimmedThrough,highWater FROM cloud_event_meta WHERE singleton=1")[0];
1016
+ }
1017
+ eventPage(after, limit = 100) {
1018
+ return this.storage.transactionSync(() => {
1019
+ const meta = this.eventMeta();
1020
+ if (!Number.isSafeInteger(after) || after < 0 || after !== 0 && after < meta.trimmedThrough || after > meta.highWater) throw new CloudDoError("CLOUD_EVENT_CURSOR_EXPIRED");
1021
+ return this.rows("SELECT * FROM cloud_events WHERE seq>? ORDER BY seq LIMIT ?", after === 0 ? meta.trimmedThrough : after, this.pageLimit(limit));
1022
+ });
1023
+ }
1024
+ pageLimit(value = 100) {
1025
+ if (!Number.isSafeInteger(value) || value < 1 || value > 100) throw new CloudDoError("CLOUD_REQUEST_INVALID");
1026
+ return value;
1027
+ }
1028
+ /** Capture ownership and payloads before any asynchronous pi context read. */
1029
+ planTranscript(after, limit) {
1030
+ return this.storage.transactionSync(() => {
1031
+ const highWater = this.eventMeta().highWater;
1032
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 50) throw new CloudDoError("CLOUD_REQUEST_INVALID");
1033
+ if (after !== void 0) {
1034
+ if (!after || typeof after !== "object" || Array.isArray(after) || Object.keys(after).length !== 3 || !["horizon", "run", "item"].every((key) => Object.hasOwn(after, key)) || !Number.isSafeInteger(after.horizon) || after.horizon < 0 || after.horizon > highWater || [after.run, after.item].some((value) => value !== null && (!Number.isSafeInteger(value) || value <= 0))) {
1035
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
1036
+ }
1037
+ }
1038
+ const horizon = after?.horizon ?? highWater;
1039
+ const runRows = after?.run === null ? [] : this.rows(
1040
+ "SELECT * FROM cloud_executions WHERE conversationId<? ORDER BY conversationId DESC LIMIT ?",
1041
+ after?.run ?? Number.MAX_SAFE_INTEGER,
1042
+ limit
1043
+ );
1044
+ const runs = runRows.map((run) => {
1045
+ const memberships = this.rows(`SELECT seq FROM cloud_run_turns WHERE runId=?
1046
+ AND (claimEvent IS NULL OR claimEvent<=?) AND (releaseEvent IS NULL OR releaseEvent>?) ORDER BY seq`, run.conversationId, horizon, horizon);
1047
+ const turns = memberships.map(({ seq }) => {
1048
+ const inbox = this.readInboxItem(seq);
1049
+ const current = inbox ? inbox.runId : this.rows(`SELECT runId FROM cloud_run_turns
1050
+ WHERE seq=? AND claimEvent IS NOT NULL AND releaseEvent IS NULL ORDER BY runId DESC LIMIT 1`, seq)[0]?.runId ?? null;
1051
+ return {
1052
+ seq,
1053
+ runId: current,
1054
+ state: inbox?.state ?? null,
1055
+ errorCode: inbox?.errorCode ?? null,
1056
+ revision: inbox?.revision ?? null,
1057
+ text: payloadText(inbox)
1058
+ };
1059
+ });
1060
+ const invocations = this.invocationRowsForRun(run.conversationId).map((row2) => ({
1061
+ invocationId: row2.invocationId,
1062
+ toolName: row2.toolName,
1063
+ state: row2.state,
1064
+ errorCode: row2.errorCode,
1065
+ revision: row2.state === "accepted" || row2.state === "running" ? null : row2.settledEventSeq
1066
+ }));
1067
+ return { run, turns, invocations };
1068
+ });
1069
+ const itemRows = after?.item === null ? [] : this.rows(`SELECT i.* FROM cloud_inbox i WHERE i.seq<?
1070
+ AND NOT EXISTS(SELECT 1 FROM cloud_run_turns t WHERE t.seq=i.seq
1071
+ AND (t.claimEvent IS NULL OR t.claimEvent<=?) AND (t.releaseEvent IS NULL OR t.releaseEvent>?))
1072
+ ORDER BY i.seq DESC LIMIT ?`, after?.item ?? Number.MAX_SAFE_INTEGER, horizon, horizon, limit);
1073
+ const items = itemRows.map((row2) => ({
1074
+ seq: row2.seq,
1075
+ dedupKey: row2.dedupKey,
1076
+ state: row2.state,
1077
+ errorCode: row2.errorCode,
1078
+ runId: row2.runId,
1079
+ attempts: row2.attempts,
1080
+ revision: row2.revision,
1081
+ text: payloadText(row2)
1082
+ }));
1083
+ return { runs, items, next: {
1084
+ horizon,
1085
+ run: runRows.length < limit ? null : runRows.at(-1).conversationId,
1086
+ item: itemRows.length < limit ? null : itemRows.at(-1).seq
1087
+ } };
1088
+ });
1089
+ }
1090
+ readRun(id) {
1091
+ return this.run(id);
1092
+ }
1093
+ readRuns(options = {}) {
1094
+ return this.rows(`SELECT * FROM cloud_executions WHERE ${terminalRun} AND conversationId<? ORDER BY conversationId DESC LIMIT ?`, this.pageAfter(options.after), this.pageLimit(options.limit));
1095
+ }
1096
+ readInbox(options = {}) {
1097
+ return this.rows(`SELECT * FROM cloud_inbox WHERE ${terminalInbox} AND seq<? ORDER BY seq DESC LIMIT ?`, this.pageAfter(options.after), this.pageLimit(options.limit)).map((row2) => ({ ...row2, payloadJson: null }));
1098
+ }
1099
+ readInvocations(options = {}) {
1100
+ return this.rows(`SELECT seq,invocationId,toolName,state,errorCode FROM cloud_invocations WHERE ${terminalInvocation} AND seq<? ORDER BY seq DESC LIMIT ?`, this.pageAfter(options.after), this.pageLimit(options.limit));
1101
+ }
1102
+ pageAfter(after) {
1103
+ if (after !== void 0 && (!Number.isSafeInteger(after) || after < 0)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
1104
+ return after ?? Number.MAX_SAFE_INTEGER;
1105
+ }
1106
+ snapshot() {
1107
+ return this.storage.transactionSync(() => {
1108
+ const inbox = [...this.rows("SELECT * FROM cloud_inbox WHERE state IN ('queued','running') ORDER BY seq"), ...this.readInbox()].map((row2) => ({ ...row2, payloadJson: null }));
1109
+ const runs = [...this.unsettledRuns(), ...this.readRuns()];
1110
+ const invocations = [...this.rows("SELECT seq,invocationId,toolName,state,errorCode FROM cloud_invocations WHERE state IN ('accepted','running') ORDER BY seq"), ...this.readInvocations()];
1111
+ return { ...this.eventMeta(), inbox, runs, invocations };
1112
+ });
1113
+ }
1114
+ setDelivery(id, state, taskId, entryId, guard, now = Date.now()) {
1115
+ const row2 = this.rows("SELECT * FROM cloud_invocations WHERE invocationId=?", id)[0];
1116
+ if (!row2 || row2.deliveredState === state && row2.taskId === taskId && row2.resultEntryId === entryId) return;
1117
+ this.storage.sql.exec("UPDATE cloud_invocations SET deliveredState=?,taskId=?,resultEntryId=? WHERE invocationId=?", state, taskId, entryId, id);
1118
+ this.appendEvent({
1119
+ eventKey: `tool:${id}:delivered:${state}:${taskId ?? ""}:${entryId ?? ""}`,
1120
+ type: "tool.delivered",
1121
+ conversationId: row2.conversationId,
1122
+ ref: id,
1123
+ data: { invocationId: id, deliveredState: state, taskId, resultEntryId: entryId },
1124
+ createdAt: now
1125
+ }, guard);
1126
+ }
1127
+ projectInvocation(row2, project, guard, now = Date.now()) {
1128
+ if (!project) return;
1129
+ let admitted;
1130
+ try {
1131
+ const value = project(Object.freeze({ ...row2 }));
1132
+ if (value === void 0) return;
1133
+ const key = value.key;
1134
+ const rawDataJson = value.dataJson;
1135
+ if (typeof key !== "string" || !key.length || key.length > 128 || /[\u0000-\u001f\u007f-\u009f]/u.test(key) || typeof rawDataJson !== "string") throw new Error();
1136
+ if (rawDataJson.length > 16384 || encoder.encode(rawDataJson).byteLength > 16384) throw new Error();
1137
+ guard.guardText(key);
1138
+ const dataJson = guard.guardPayload(rawDataJson);
1139
+ if (encoder.encode(dataJson).length > 16384) throw new Error();
1140
+ admitted = { key: `projection:${row2.invocationId}:${key}`, dataJson, digest: sha256(dataJson) };
1141
+ } catch {
1142
+ this.projectionFailed(row2, guard, now);
1143
+ return;
1144
+ }
1145
+ const previous = this.rows("SELECT invocationId,state,payloadDigest FROM cloud_projections WHERE key=?", admitted.key)[0];
1146
+ if (previous) {
1147
+ if (previous.invocationId !== row2.invocationId || previous.state !== row2.state || previous.payloadDigest !== admitted.digest) this.projectionFailed(row2, guard, now);
1148
+ return;
1149
+ }
1150
+ this.storage.sql.exec("INSERT INTO cloud_projections(key,invocationId,state,payloadDigest,dataJson,createdAt) VALUES(?,?,?,?,?,?)", admitted.key, row2.invocationId, row2.state, admitted.digest, admitted.dataJson, now);
1151
+ this.appendEvent({
1152
+ eventKey: admitted.key,
1153
+ type: "projection",
1154
+ conversationId: row2.conversationId,
1155
+ ref: row2.invocationId,
1156
+ data: { key: admitted.key, invocationId: row2.invocationId, data: JSON.parse(admitted.dataJson) },
1157
+ createdAt: now
1158
+ }, guard);
1159
+ }
1160
+ projectionFailed(row2, guard, now) {
1161
+ const key = `sdk:${row2.invocationId}:projection-failed`;
1162
+ const existing = this.rows("SELECT key FROM cloud_projections WHERE key=?", key)[0];
1163
+ if (existing) return;
1164
+ const dataJson = '{"code":"CLOUD_PROJECTION_FAILED"}';
1165
+ this.storage.sql.exec("INSERT INTO cloud_projections(key,invocationId,state,payloadDigest,dataJson,errorCode,createdAt) VALUES(?,?,?,?,?,?,?)", key, row2.invocationId, row2.state, sha256(dataJson), dataJson, "CLOUD_PROJECTION_FAILED", now);
1166
+ this.appendEvent({ eventKey: key, type: "projection.failed", conversationId: row2.conversationId, ref: row2.invocationId, data: { invocationId: row2.invocationId, code: "CLOUD_PROJECTION_FAILED" }, createdAt: now }, guard);
1167
+ }
1168
+ trimPrefix(count) {
1169
+ const rows = this.rows("SELECT seq FROM cloud_events ORDER BY seq LIMIT ?", count);
1170
+ if (!rows.length) return 0;
1171
+ const through = rows.at(-1).seq;
1172
+ this.storage.sql.exec("DELETE FROM cloud_events WHERE seq<=?", through);
1173
+ this.storage.sql.exec("UPDATE cloud_event_meta SET trimmedThrough=MAX(trimmedThrough,?) WHERE singleton=1", through);
1174
+ return rows.length;
1175
+ }
1176
+ retention(now = Date.now()) {
1177
+ return this.storage.transactionSync(() => {
1178
+ const head = this.rows("SELECT seq,createdAt FROM cloud_events ORDER BY seq LIMIT 500");
1179
+ let count = 0;
1180
+ for (const row2 of head) {
1181
+ if (row2.createdAt + RETENTION > now) break;
1182
+ count++;
1183
+ }
1184
+ const events = this.trimPrefix(count);
1185
+ const expired = this.rows(`SELECT seq FROM cloud_inbox WHERE ${terminalInbox} AND settledAt<=? ORDER BY seq LIMIT 500`, now - RETENTION);
1186
+ for (const row2 of expired) this.storage.sql.exec("DELETE FROM cloud_inbox WHERE seq=?", row2.seq);
1187
+ return { events, inbox: expired.length };
1188
+ });
1189
+ }
1190
+ setSchedulingState(options) {
1191
+ if (options.busy !== void 0) this.scheduling.busy = options.busy;
1192
+ if (options.repairRetrying !== void 0) this.scheduling.repairRetrying = options.repairRetrying;
1193
+ }
1194
+ nextAlarm(now = Date.now(), busy = this.scheduling.busy ?? false) {
1195
+ const targets = [];
1196
+ const queued = this.rows("SELECT availableAt,expiresAt FROM cloud_inbox WHERE state='queued'");
1197
+ for (const row2 of queued) {
1198
+ if (!busy || row2.availableAt > now) targets.push(Math.max(now, row2.availableAt));
1199
+ targets.push(Math.max(now, row2.expiresAt));
1200
+ }
1201
+ if (!busy && (this.unsettledRuns().length || this.unackedRuns().length)) targets.push(now);
1202
+ const head = this.rows("SELECT createdAt FROM cloud_events ORDER BY seq LIMIT 1")[0];
1203
+ if (head) targets.push(Math.max(now, head.createdAt + RETENTION));
1204
+ const settled = this.rows(`SELECT settledAt FROM cloud_inbox WHERE ${terminalInbox} AND settledAt IS NOT NULL ORDER BY settledAt LIMIT 1`)[0];
1205
+ if (settled) targets.push(Math.max(now, settled.settledAt + RETENTION));
1206
+ return targets.length ? Math.min(...targets) : null;
1207
+ }
1208
+ /** This is the only alarm mutation path. Async enqueue calls it inside its storage transaction. */
1209
+ async rearmAlarm(options, now = Date.now()) {
1210
+ if (options) this.setSchedulingState(options);
1211
+ const target = this.nextAlarm(now);
1212
+ if (this.scheduling.repairRetrying) {
1213
+ this.storage.sql.exec("UPDATE cloud_event_meta SET pendingMaintenanceAt=? WHERE singleton=1", target);
1214
+ return;
1215
+ }
1216
+ this.storage.sql.exec("UPDATE cloud_event_meta SET pendingMaintenanceAt=NULL WHERE singleton=1");
1217
+ if (target === null) await this.storage.deleteAlarm();
1218
+ else await this.storage.setAlarm(target);
1219
+ }
1220
+ };
1221
+
1222
+ // src/provider-fetch.ts
1223
+ var FRAME_LIMIT = 65536;
1224
+ var TOOL_ARGUMENT_LIMIT = 65536;
1225
+ var TOOL_CALL_LIMIT = 12;
1226
+ var ToolCallAssembly = class {
1227
+ constructor(key, config) {
1228
+ this.key = key;
1229
+ this.config = config;
1230
+ }
1231
+ key;
1232
+ config;
1233
+ calls = /* @__PURE__ */ new Map();
1234
+ argumentBytes = 0;
1235
+ encoder = new TextEncoder();
1236
+ reject() {
1237
+ throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1238
+ }
1239
+ checkString(value) {
1240
+ if (hasUserKeyShape(value)) this.reject();
1241
+ const guard = new RollingLeakGuard(this.key);
1242
+ guard.push(value);
1243
+ guard.finish();
1244
+ }
1245
+ checkValues(value) {
1246
+ const pending = [value];
1247
+ while (pending.length) {
1248
+ const next = pending.pop();
1249
+ if (typeof next === "string") this.checkString(next);
1250
+ else if (Array.isArray(next)) pending.push(...next);
1251
+ else if (object(next)) {
1252
+ for (const [name, child] of Object.entries(next)) {
1253
+ this.checkString(name);
1254
+ pending.push(child);
1255
+ }
1256
+ }
1257
+ }
1258
+ }
1259
+ add(value) {
1260
+ if (!this.config || !Array.isArray(value) || value.length > TOOL_CALL_LIMIT) this.reject();
1261
+ const indices = /* @__PURE__ */ new Set();
1262
+ for (const item of value) {
1263
+ const row2 = object(item);
1264
+ if (!row2 || !Number.isSafeInteger(row2.index) || row2.index < 0 || row2.index >= TOOL_CALL_LIMIT) this.reject();
1265
+ const index = row2.index;
1266
+ if (indices.has(index)) this.reject();
1267
+ indices.add(index);
1268
+ const call = this.calls.get(index) ?? { arguments: "" };
1269
+ if (!this.calls.has(index)) this.calls.set(index, call);
1270
+ if (row2.id != null) {
1271
+ if (call.id !== void 0 || typeof row2.id !== "string" || !row2.id || row2.id.length > 512) this.reject();
1272
+ this.checkString(row2.id);
1273
+ call.id = row2.id;
1274
+ }
1275
+ if (row2.type != null) {
1276
+ if (call.type !== void 0 || row2.type !== "function") this.reject();
1277
+ call.type = "function";
1278
+ }
1279
+ if (row2.function != null) {
1280
+ const fn = object(row2.function);
1281
+ if (!fn) this.reject();
1282
+ if (fn.name != null) {
1283
+ if (call.name !== void 0 || typeof fn.name !== "string" || !this.config.offeredToolNames.includes(fn.name)) this.reject();
1284
+ this.checkString(fn.name);
1285
+ call.name = fn.name;
1286
+ }
1287
+ if (fn.arguments != null) {
1288
+ if (typeof fn.arguments !== "string") this.reject();
1289
+ this.argumentBytes += this.encoder.encode(fn.arguments).byteLength;
1290
+ if (this.argumentBytes > TOOL_ARGUMENT_LIMIT) this.reject();
1291
+ call.arguments += fn.arguments;
1292
+ }
1293
+ }
1294
+ }
1295
+ }
1296
+ get size() {
1297
+ return this.calls.size;
1298
+ }
1299
+ async finish() {
1300
+ const checked = [];
1301
+ const ids = /* @__PURE__ */ new Set();
1302
+ const ordered = [...this.calls].sort(([left], [right]) => left - right);
1303
+ for (const [index, call] of ordered) {
1304
+ if (index !== checked.length || !call.id || !call.name || call.type !== "function" || ids.has(call.id)) this.reject();
1305
+ ids.add(call.id);
1306
+ let parsed;
1307
+ try {
1308
+ parsed = JSON.parse(call.arguments);
1309
+ } catch {
1310
+ this.reject();
1311
+ }
1312
+ const args = object(parsed);
1313
+ if (!args) this.reject();
1314
+ this.checkValues(args);
1315
+ checked.push({ index, call, args });
1316
+ }
1317
+ for (const { call, args } of checked) await this.config.admitToolCall(call.name, call.id, args);
1318
+ return checked.map(({ index, call, args }) => ({
1319
+ index,
1320
+ id: `call_${index + 1}`,
1321
+ type: "function",
1322
+ function: { name: call.name, arguments: JSON.stringify(args) }
1323
+ }));
1324
+ }
1325
+ };
1326
+ var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1327
+ async function* frames(reader) {
1328
+ const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false });
1329
+ let frame = "";
1330
+ let line = "";
1331
+ let lastWasCR = false;
1332
+ while (true) {
1333
+ const next = await reader.read();
1334
+ const text2 = next.done ? decoder.decode() : decoder.decode(next.value, { stream: true });
1335
+ for (const character of text2) {
1336
+ if (character === "\n" && lastWasCR) {
1337
+ lastWasCR = false;
1338
+ continue;
1339
+ }
1340
+ lastWasCR = character === "\r";
1341
+ if (character === "\n" || character === "\r") {
1342
+ if (!line) {
1343
+ if (frame) yield frame;
1344
+ frame = "";
1345
+ } else {
1346
+ frame += `${line}
1347
+ `;
1348
+ line = "";
1349
+ }
1350
+ } else line += character;
1351
+ if (frame.length + line.length > FRAME_LIMIT) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1352
+ }
1353
+ if (next.done) {
1354
+ if (line || frame) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1355
+ return;
1356
+ }
1357
+ }
1358
+ }
1359
+ function eventData(frame) {
1360
+ return frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
1361
+ }
1362
+ async function* readSseData(body) {
1363
+ const reader = body.getReader();
1364
+ try {
1365
+ for await (const frame of frames(reader)) {
1366
+ const data = eventData(frame);
1367
+ if (data) yield data;
1368
+ }
1369
+ } finally {
1370
+ try {
1371
+ await reader.cancel();
1372
+ } catch {
1373
+ }
1374
+ }
1375
+ }
1376
+ function numericUsage(value) {
1377
+ const usage = object(value);
1378
+ if (!usage) return void 0;
1379
+ const result = {};
1380
+ for (const field of ["prompt_tokens", "completion_tokens", "total_tokens"]) {
1381
+ const n = usage[field];
1382
+ if (typeof n === "number" && Number.isSafeInteger(n) && n >= 0) result[field] = n;
1383
+ }
1384
+ return Object.keys(result).length ? result : void 0;
1385
+ }
1386
+ function guardedBody(body, key, profile, abort, cleanup, transport) {
1387
+ const reader = body.getReader();
1388
+ const guard = new RollingLeakGuard(key);
1389
+ const laneGuards = { content: new RollingLeakGuard(key), reasoning_content: new RollingLeakGuard(key) };
1390
+ const segments = [];
1391
+ const encoder2 = new TextEncoder();
1392
+ let finishReason;
1393
+ const tools = new ToolCallAssembly(key, transport);
1394
+ let usage;
1395
+ const encode = (delta, finish = null) => `data: ${JSON.stringify({
1396
+ id: "cloud",
1397
+ object: "chat.completion.chunk",
1398
+ created: 0,
1399
+ model: profile.model,
1400
+ choices: [{ index: 0, delta, finish_reason: finish }]
1401
+ })}
1402
+
1403
+ `;
1404
+ const release = (text2) => {
1405
+ let remaining = text2.length;
1406
+ let result = "";
1407
+ while (remaining > 0) {
1408
+ const first = segments[0];
1409
+ const size = Math.min(first.text.length, remaining);
1410
+ result += encode({ [first.lane]: first.text.slice(0, size) });
1411
+ first.text = first.text.slice(size);
1412
+ remaining -= size;
1413
+ if (!first.text) segments.shift();
1414
+ }
1415
+ return result;
1416
+ };
1417
+ const stop = async () => {
1418
+ guard.discard();
1419
+ laneGuards.content.discard();
1420
+ laneGuards.reasoning_content.discard();
1421
+ segments.length = 0;
1422
+ try {
1423
+ await reader.cancel();
1424
+ } catch {
1425
+ } finally {
1426
+ abort.abort();
1427
+ cleanup();
1428
+ }
1429
+ };
1430
+ const checkedLane = (lane, text2) => {
1431
+ if (!text2) return "";
1432
+ const previous = segments.at(-1);
1433
+ if (previous?.lane === lane) previous.text += text2;
1434
+ else segments.push({ lane, text: text2 });
1435
+ return release(guard.push(text2));
1436
+ };
1437
+ async function* output() {
1438
+ let done = false;
1439
+ try {
1440
+ for await (const frame of frames(reader)) {
1441
+ const data = eventData(frame);
1442
+ if (!data) continue;
1443
+ if (data === "[DONE]") {
1444
+ done = true;
1445
+ break;
1446
+ }
1447
+ const payload = object(JSON.parse(data));
1448
+ if (!payload || payload.error) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1449
+ const currentUsage = numericUsage(payload.usage);
1450
+ if (currentUsage) {
1451
+ for (const [field, value] of Object.entries(currentUsage)) {
1452
+ if (usage?.[field] !== void 0 && value < usage[field]) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1453
+ }
1454
+ usage = { ...usage, ...currentUsage };
1455
+ transport?.onUsage?.(usage);
1456
+ }
1457
+ if (!Array.isArray(payload.choices)) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1458
+ const choice = payload.choices.find((item) => object(item)?.index === 0);
1459
+ if (!choice) continue;
1460
+ const row2 = object(choice);
1461
+ const delta = object(row2.delta);
1462
+ if (!delta || delta.function_call || delta.refusal) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1463
+ if (finishReason && (delta.tool_calls != null || delta.content || delta.reasoning_content)) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1464
+ if (delta.tool_calls != null) tools.add(delta.tool_calls);
1465
+ for (const lane of ["content", "reasoning_content"]) {
1466
+ const text2 = delta[lane];
1467
+ if (text2 === void 0 || text2 === null) continue;
1468
+ if (typeof text2 !== "string") throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1469
+ if (!text2) continue;
1470
+ const safe = checkedLane(lane, laneGuards[lane].push(text2));
1471
+ if (safe) yield safe;
1472
+ }
1473
+ if (row2.finish_reason != null) {
1474
+ if (finishReason || !["stop", "length", "content_filter", "tool_calls"].includes(String(row2.finish_reason))) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1475
+ finishReason = row2.finish_reason;
1476
+ }
1477
+ }
1478
+ if (!done && !finishReason) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1479
+ if (tools.size > 0 !== (finishReason === "tool_calls")) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1480
+ const checkedTools = tools.size ? await tools.finish() : [];
1481
+ const terminal2 = encode(checkedTools.length ? { tool_calls: checkedTools } : {}, finishReason ?? "stop");
1482
+ if (terminal2.length > FRAME_LIMIT) throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
1483
+ for (const lane of ["content", "reasoning_content"]) {
1484
+ const safe = checkedLane(lane, laneGuards[lane].finish());
1485
+ if (safe) yield safe;
1486
+ }
1487
+ const final = release(guard.finish());
1488
+ if (final) yield final;
1489
+ yield terminal2;
1490
+ if (usage) yield `data: ${JSON.stringify({ choices: [], usage })}
1491
+
1492
+ `;
1493
+ yield "data: [DONE]\n\n";
1494
+ } catch (error) {
1495
+ throw safeCloudError(error);
1496
+ } finally {
1497
+ await stop();
1498
+ }
1499
+ }
1500
+ const iterator = output();
1501
+ return new ReadableStream({
1502
+ async pull(controller) {
1503
+ try {
1504
+ const next = await iterator.next();
1505
+ if (next.done) controller.close();
1506
+ else controller.enqueue(encoder2.encode(next.value));
1507
+ } catch (error) {
1508
+ controller.error(safeCloudError(error));
1509
+ }
1510
+ },
1511
+ async cancel() {
1512
+ await stop();
1513
+ await iterator.return(void 0);
1514
+ }
1515
+ });
1516
+ }
1517
+ function createProviderFetch(profile, secret, fetchImpl = globalThis.fetch, transport) {
1518
+ const key = requirePlatformKey(secret);
1519
+ const endpoint = `${profile.baseUrl.replace(/\/$/, "")}/chat/completions`;
1520
+ return async (input, init) => {
1521
+ let request;
1522
+ try {
1523
+ request = new Request(input, init);
1524
+ } catch {
1525
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
1526
+ }
1527
+ if (request.url !== endpoint || request.method !== "POST") throw new CloudDoError("CLOUD_REQUEST_INVALID");
1528
+ const abort = new AbortController();
1529
+ const onAbort = () => abort.abort();
1530
+ request.signal.addEventListener("abort", onAbort, { once: true });
1531
+ if (request.signal.aborted) abort.abort();
1532
+ const cleanup = () => request.signal.removeEventListener("abort", onAbort);
1533
+ try {
1534
+ const dispatch = new Request(request, {
1535
+ signal: abort.signal,
1536
+ redirect: "manual",
1537
+ headers: { authorization: `Bearer ${key}`, "content-type": "application/json", accept: "text/event-stream" }
1538
+ });
1539
+ if (abort.signal.aborted) throw new CloudDoError("CLOUD_MODEL_REQUEST_FAILED");
1540
+ transport?.onSend?.();
1541
+ const response = await fetchImpl(dispatch);
1542
+ if (!response.ok || response.status >= 300 && response.status < 400 || !response.body || !response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream")) {
1543
+ abort.abort();
1544
+ cleanup();
1545
+ try {
1546
+ await response.body?.cancel();
1547
+ } catch {
1548
+ }
1549
+ throw new CloudDoError("CLOUD_MODEL_REQUEST_FAILED");
1550
+ }
1551
+ return new Response(guardedBody(response.body, key, profile, abort, cleanup, transport), { headers: { "content-type": "text/event-stream" } });
1552
+ } catch (error) {
1553
+ abort.abort();
1554
+ cleanup();
1555
+ throw safeCloudError(error);
1556
+ }
1557
+ };
1558
+ }
1559
+
1560
+ // src/platform-provider.ts
1561
+ var PLATFORM_MAX_OUTPUT_TOKENS = 4096;
1562
+ var REQUEST_FRAMING_BYTES = 4096;
1563
+ function emptyAssistant(model) {
1564
+ return {
1565
+ role: "assistant",
1566
+ content: [],
1567
+ api: model.api,
1568
+ provider: model.provider,
1569
+ model: model.id,
1570
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
1571
+ stopReason: "stop",
1572
+ timestamp: Date.now()
1573
+ };
1574
+ }
1575
+ function fixedModelErrors(source, model) {
1576
+ const events = new AssistantMessageEventStream();
1577
+ const run = async () => {
1578
+ let terminal2;
1579
+ try {
1580
+ for await (const event of source) {
1581
+ if (event.type === "error") {
1582
+ const message = event.error.errorMessage;
1583
+ const code = message?.includes("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE") ? "CLOUD_MODEL_CREDENTIAL_UNAVAILABLE" : safeCloudError(new Error(message)).code;
1584
+ terminal2 = {
1585
+ ...emptyAssistant(model),
1586
+ content: event.error.content,
1587
+ usage: event.error.usage,
1588
+ stopReason: event.reason,
1589
+ errorMessage: code
1590
+ };
1591
+ events.push({ type: "error", reason: event.reason, error: terminal2 });
1592
+ } else {
1593
+ if (event.type === "done") terminal2 = event.message;
1594
+ events.push(event);
1595
+ }
1596
+ }
1597
+ if (!terminal2) throw new CloudDoError("CLOUD_MODEL_REQUEST_FAILED");
1598
+ } catch {
1599
+ terminal2 = { ...emptyAssistant(model), stopReason: "error", errorMessage: "CLOUD_MODEL_REQUEST_FAILED" };
1600
+ events.push({ type: "error", reason: "error", error: terminal2 });
1601
+ } finally {
1602
+ events.end(terminal2);
1603
+ }
1604
+ };
1605
+ void run();
1606
+ return events;
1607
+ }
1608
+ function messages(context) {
1609
+ return context.messages.map((message) => {
1610
+ if (message.role === "system") return { role: "system", content: getSystemMessageText(message) };
1611
+ if (message.role === "toolResult") return {
1612
+ role: "tool",
1613
+ tool_call_id: message.toolCallId,
1614
+ content: message.content.map((block) => {
1615
+ if (block.type !== "text") throw new CloudDoError("CLOUD_REQUEST_INVALID");
1616
+ return block.text;
1617
+ }).join("")
1618
+ };
1619
+ if (message.role !== "user" && message.role !== "assistant") throw new CloudDoError("CLOUD_REQUEST_INVALID");
1620
+ const calls = [];
1621
+ const content = typeof message.content === "string" ? message.content : message.content.map((block) => {
1622
+ if (block.type === "toolCall" && message.role === "assistant") {
1623
+ calls.push({ id: block.id, type: "function", function: { name: block.name, arguments: JSON.stringify(block.arguments) } });
1624
+ return "";
1625
+ }
1626
+ if (block.type !== "text" && block.type !== "thinking") throw new CloudDoError("CLOUD_REQUEST_INVALID");
1627
+ return block.type === "text" ? block.text : "";
1628
+ }).join("");
1629
+ return { role: message.role, content, ...calls.length ? { tool_calls: calls } : {} };
1630
+ });
1631
+ }
1632
+ function stream(profile, model, context, options, runtime) {
1633
+ const events = new AssistantMessageEventStream();
1634
+ const output = emptyAssistant(model);
1635
+ const blocks = /* @__PURE__ */ new Map();
1636
+ const run = async () => {
1637
+ try {
1638
+ const currentTools = getCurrentTools(context.messages);
1639
+ const body = JSON.stringify({
1640
+ model: profile.model,
1641
+ messages: messages(context),
1642
+ stream: true,
1643
+ stream_options: { include_usage: true },
1644
+ max_tokens: PLATFORM_MAX_OUTPUT_TOKENS,
1645
+ ...currentTools.length ? { tools: currentTools.map((tool) => ({
1646
+ type: "function",
1647
+ function: { name: tool.name, description: tool.description, parameters: tool.parameters }
1648
+ })) } : {}
1649
+ });
1650
+ const account = await runtime?.beforeRequest({ inputBytes: new TextEncoder().encode(body).byteLength });
1651
+ const key = requirePlatformKey(options?.apiKey);
1652
+ const request = createProviderFetch(profile, key, globalThis.fetch, {
1653
+ offeredToolNames: currentTools.map((tool) => tool.name),
1654
+ admitToolCall: (name, id, args) => runtime?.admitToolCall(name, id, args),
1655
+ onSend: () => account?.sent(),
1656
+ onUsage: (usage) => account?.usage({ input: usage.prompt_tokens, output: usage.completion_tokens })
1657
+ });
1658
+ const response = await request(`${profile.baseUrl}/chat/completions`, {
1659
+ method: "POST",
1660
+ signal: runtime?.requestSignal?.(options?.signal) ?? options?.signal,
1661
+ body
1662
+ });
1663
+ events.push({ type: "start", partial: output });
1664
+ for await (const data of readSseData(response.body)) {
1665
+ if (data === "[DONE]") break;
1666
+ const frame = JSON.parse(data);
1667
+ if (frame.usage) {
1668
+ output.usage.input = frame.usage.prompt_tokens ?? 0;
1669
+ output.usage.output = frame.usage.completion_tokens ?? 0;
1670
+ output.usage.totalTokens = frame.usage.total_tokens ?? output.usage.input + output.usage.output;
1671
+ }
1672
+ for (const choice of frame.choices) {
1673
+ if (choice.finish_reason === "length") output.stopReason = "length";
1674
+ if (choice.finish_reason === "tool_calls") output.stopReason = "toolUse";
1675
+ for (const call of choice.delta.tool_calls ?? []) {
1676
+ const index = output.content.length;
1677
+ const toolCall = {
1678
+ type: "toolCall",
1679
+ id: call.id,
1680
+ name: call.function.name,
1681
+ arguments: JSON.parse(call.function.arguments)
1682
+ };
1683
+ output.content.push(toolCall);
1684
+ events.push({ type: "toolcall_start", contentIndex: index, partial: output });
1685
+ events.push({ type: "toolcall_delta", contentIndex: index, delta: call.function.arguments, partial: output });
1686
+ events.push({ type: "toolcall_end", contentIndex: index, toolCall, partial: output });
1687
+ }
1688
+ for (const lane of ["content", "reasoning_content"]) {
1689
+ const delta = choice.delta[lane];
1690
+ if (!delta) continue;
1691
+ let index = blocks.get(lane);
1692
+ if (index === void 0) {
1693
+ index = output.content.length;
1694
+ blocks.set(lane, index);
1695
+ output.content.push(lane === "content" ? { type: "text", text: "" } : { type: "thinking", thinking: "" });
1696
+ events.push({ type: lane === "content" ? "text_start" : "thinking_start", contentIndex: index, partial: output });
1697
+ }
1698
+ const block = output.content[index];
1699
+ if (block.type === "text") block.text += delta;
1700
+ else if (block.type === "thinking") block.thinking += delta;
1701
+ events.push({ type: lane === "content" ? "text_delta" : "thinking_delta", contentIndex: index, delta, partial: output });
1702
+ }
1703
+ }
1704
+ }
1705
+ for (const [lane, index] of blocks) {
1706
+ const block = output.content[index];
1707
+ events.push({
1708
+ type: lane === "content" ? "text_end" : "thinking_end",
1709
+ contentIndex: index,
1710
+ content: block.type === "text" ? block.text : block.type === "thinking" ? block.thinking : "",
1711
+ partial: output
1712
+ });
1713
+ }
1714
+ events.push({ type: "done", reason: output.stopReason, message: output });
1715
+ } catch (error) {
1716
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
1717
+ output.errorMessage = safeCloudError(error).code;
1718
+ events.push({ type: "error", reason: output.stopReason, error: output });
1719
+ } finally {
1720
+ events.end(output);
1721
+ }
1722
+ };
1723
+ void run();
1724
+ return events;
1725
+ }
1726
+ function createPlatformModels(env, credentials2 = platformCredentialReader(env), runtime) {
1727
+ const models = createModels({ authContext: { env: async () => void 0, fileExists: async () => false } });
1728
+ for (const [id, profile] of Object.entries(PLATFORM_PROFILES)) {
1729
+ const implementation = {
1730
+ stream: (model2, context, options) => stream(profile, model2, context, options, runtime),
1731
+ streamSimple: (model2, context, options) => stream(profile, model2, context, options, runtime)
1732
+ };
1733
+ const model = {
1734
+ id: profile.model,
1735
+ name: profile.model,
1736
+ provider: id,
1737
+ api: "openai-completions",
1738
+ baseUrl: profile.baseUrl,
1739
+ reasoning: false,
1740
+ input: ["text"],
1741
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1742
+ contextWindow: 65536,
1743
+ maxTokens: PLATFORM_MAX_OUTPUT_TOKENS
1744
+ };
1745
+ models.setProvider(createProvider({
1746
+ id,
1747
+ models: [model],
1748
+ api: implementation,
1749
+ auth: { apiKey: { name: "Platform model key", resolve: async () => {
1750
+ try {
1751
+ const key = requirePlatformKey(await credentials2.get(profile.secretName));
1752
+ return { auth: { apiKey: key }, source: "platform" };
1753
+ } catch {
1754
+ throw new CloudDoError("CLOUD_MODEL_CREDENTIAL_UNAVAILABLE");
1755
+ }
1756
+ } } }
1757
+ }));
1758
+ }
1759
+ const rawStream = models.stream.bind(models);
1760
+ const rawSimple = models.streamSimple.bind(models);
1761
+ models.stream = (model, context, options) => fixedModelErrors(rawStream(model, context, options), model);
1762
+ models.streamSimple = (model, context, options) => fixedModelErrors(rawSimple(model, context, options), model);
1763
+ return models;
1764
+ }
1765
+
1766
+ // src/invocation-ledger.ts
1767
+ var terminal = (state) => state !== "accepted" && state !== "running";
1768
+ var fatalCodes = /* @__PURE__ */ new Set([
1769
+ "CLOUD_TOOL_RESULT_LIMIT",
1770
+ "CLOUD_TOOL_LIMIT",
1771
+ "CLOUD_STEP_LIMIT",
1772
+ "CLOUD_TOOL_TIMEOUT",
1773
+ "CLOUD_EXECUTION_TIMEOUT"
1774
+ ]);
1775
+ var InvocationLedger = class {
1776
+ constructor(storage, options = {}) {
1777
+ this.storage = storage;
1778
+ this.options = options;
1779
+ }
1780
+ storage;
1781
+ options;
1782
+ /** The host calls this only after credential and identity preflight. */
1783
+ ensureSchema() {
1784
+ this.storage.transactionSync(() => {
1785
+ this.storage.sql.exec(`CREATE TABLE IF NOT EXISTS cloud_invocations (
1786
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
1787
+ invocationId TEXT NOT NULL UNIQUE, sessionId TEXT NOT NULL,
1788
+ conversationId INTEGER NOT NULL, assistantEntryId INTEGER NOT NULL,
1789
+ toolCallId TEXT NOT NULL, toolName TEXT NOT NULL,
1790
+ argsDigest TEXT NOT NULL, argsJson TEXT NOT NULL,
1791
+ replay TEXT NOT NULL CHECK (replay IN ('safe','unsafe')),
1792
+ state TEXT NOT NULL CHECK (state IN ('accepted','running','succeeded','failed','aborted','interrupted','timed_out')),
1793
+ attempt INTEGER NOT NULL, replayCount INTEGER NOT NULL DEFAULT 0,
1794
+ deadlineAt INTEGER NOT NULL, abortRequested INTEGER NOT NULL DEFAULT 0,
1795
+ resultJson TEXT, errorCode TEXT,
1796
+ mode TEXT NOT NULL DEFAULT 'inline' CHECK (mode IN ('inline','job')),
1797
+ segmentStartedAt INTEGER, nextSegmentAt INTEGER, jobStateJson TEXT, progressJson TEXT
1798
+ );
1799
+ CREATE INDEX IF NOT EXISTS cloud_invocations_pending ON cloud_invocations(state,seq);
1800
+ CREATE TABLE IF NOT EXISTS cloud_executions (
1801
+ conversationId INTEGER PRIMARY KEY, deadlineAt INTEGER NOT NULL,
1802
+ steps INTEGER NOT NULL DEFAULT 0, tools INTEGER NOT NULL DEFAULT 0,
1803
+ fatalCode TEXT, aborted INTEGER NOT NULL DEFAULT 0
1804
+ );
1805
+ CREATE TABLE IF NOT EXISTS cloud_counted_tools (
1806
+ conversationId INTEGER NOT NULL, taskId TEXT NOT NULL,
1807
+ PRIMARY KEY(conversationId,taskId)
1808
+ )`);
1809
+ const columns = new Set(this.storage.sql.exec("PRAGMA table_info(cloud_invocations)").toArray().map((row2) => row2.name));
1810
+ for (const name of ["settledAt", "settledEventSeq"]) {
1811
+ if (!columns.has(name)) this.storage.sql.exec(`ALTER TABLE cloud_invocations ADD COLUMN ${name} INTEGER`);
1812
+ }
1813
+ const executionColumns = new Set(this.storage.sql.exec("PRAGMA table_info(cloud_executions)").toArray().map((row2) => row2.name));
1814
+ for (const name of ["inputTokens", "outputTokens", "credits", "sentRequests"]) {
1815
+ if (!executionColumns.has(name)) this.storage.sql.exec(`ALTER TABLE cloud_executions ADD COLUMN ${name} INTEGER NOT NULL DEFAULT 0`);
1816
+ }
1817
+ });
1818
+ }
1819
+ read(id) {
1820
+ return this.storage.sql.exec("SELECT * FROM cloud_invocations WHERE invocationId = ?", id).toArray()[0];
1821
+ }
1822
+ pending() {
1823
+ return this.storage.sql.exec("SELECT * FROM cloud_invocations WHERE state IN ('accepted','running') ORDER BY seq").toArray();
1824
+ }
1825
+ begin(input, guard) {
1826
+ const begun = this.storage.transactionSync(() => {
1827
+ const previous = this.read(input.invocationId);
1828
+ if (previous) {
1829
+ if (previous.argsDigest !== input.argsDigest || previous.toolName !== input.toolName) {
1830
+ throw new CloudDoError("CLOUD_TOOL_INVOCATION_CONFLICT");
1831
+ }
1832
+ return { kind: terminal(previous.state) ? "settled" : "pending", row: previous };
1833
+ }
1834
+ this.storage.sql.exec(
1835
+ `INSERT INTO cloud_invocations
1836
+ (invocationId,sessionId,conversationId,assistantEntryId,toolCallId,toolName,argsDigest,argsJson,replay,state,attempt,deadlineAt)
1837
+ VALUES (?,?,?,?,?,?,?,?,?,'running',1,?)`,
1838
+ input.invocationId,
1839
+ input.sessionId,
1840
+ input.conversationId,
1841
+ input.assistantEntryId,
1842
+ input.toolCallId,
1843
+ input.toolName,
1844
+ input.argsDigest,
1845
+ input.argsJson,
1846
+ input.replay,
1847
+ input.deadlineAt
1848
+ );
1849
+ const row2 = this.read(input.invocationId);
1850
+ this.options.started?.(row2, guard);
1851
+ return { kind: "started", row: row2 };
1852
+ });
1853
+ if (begun.kind === "started") {
1854
+ try {
1855
+ this.options.startedCommitted?.(begun.row);
1856
+ } catch {
1857
+ }
1858
+ }
1859
+ return begun;
1860
+ }
1861
+ finish(id, state, result, errorCode, now = Date.now(), options = {}) {
1862
+ let changed;
1863
+ const resultRow = this.storage.transactionSync(() => {
1864
+ const row2 = this.read(id);
1865
+ if (!row2 || terminal(row2.state) || options.attempt !== void 0 && options.attempt !== row2.attempt) return row2;
1866
+ const execution = this.execution(row2.conversationId);
1867
+ let settledState = state;
1868
+ let settledError = errorCode ?? null;
1869
+ if (state === "succeeded") {
1870
+ if (row2.abortRequested || options.clientConnected === false || !options.recovery && execution?.aborted) {
1871
+ settledState = "aborted";
1872
+ settledError = "CLOUD_EXECUTION_ABORTED";
1873
+ } else if (now >= row2.deadlineAt || execution && now >= execution.deadlineAt) {
1874
+ settledState = "timed_out";
1875
+ settledError = execution && now >= execution.deadlineAt ? "CLOUD_EXECUTION_TIMEOUT" : "CLOUD_TOOL_TIMEOUT";
1876
+ } else if (!options.recovery && execution?.fatalCode) {
1877
+ settledState = "failed";
1878
+ settledError = execution.fatalCode;
1879
+ }
1880
+ }
1881
+ this.storage.sql.exec(
1882
+ `UPDATE cloud_invocations SET state=?,resultJson=?,errorCode=?
1883
+ WHERE invocationId=? AND attempt=? AND state IN ('accepted','running')`,
1884
+ settledState,
1885
+ settledState === "succeeded" && result !== void 0 ? JSON.stringify(result) : null,
1886
+ settledError,
1887
+ id,
1888
+ row2.attempt
1889
+ );
1890
+ const credits = result?.usage?.credits;
1891
+ if (typeof credits === "number" && Number.isSafeInteger(credits) && credits >= 0) {
1892
+ this.storage.sql.exec("UPDATE cloud_executions SET credits=MIN(credits+?,9007199254740991) WHERE conversationId=?", credits, row2.conversationId);
1893
+ if (options.creditCap !== void 0 && (this.execution(row2.conversationId)?.credits ?? 0) > options.creditCap) {
1894
+ this.failExecution(row2.conversationId, "CLOUD_BUDGET_EXCEEDED");
1895
+ }
1896
+ }
1897
+ if (settledError && fatalCodes.has(settledError)) this.failExecution(row2.conversationId, settledError);
1898
+ changed = this.read(id);
1899
+ changed = this.#terminal(changed, options.recovery === true);
1900
+ return changed;
1901
+ });
1902
+ if (changed) this.#notify(changed);
1903
+ return resultRow;
1904
+ }
1905
+ #terminal(row2, recovery) {
1906
+ const event = this.options.terminal?.(row2, recovery);
1907
+ if (event) {
1908
+ this.storage.sql.exec("UPDATE cloud_invocations SET settledAt=?,settledEventSeq=? WHERE invocationId=?", event.createdAt, event.seq, row2.invocationId);
1909
+ }
1910
+ return this.read(row2.invocationId);
1911
+ }
1912
+ #notify(row2) {
1913
+ try {
1914
+ this.options.committed?.(row2);
1915
+ } catch {
1916
+ }
1917
+ }
1918
+ /** Claim before network replay. A second restart never dispatches a claimed row again. */
1919
+ claimRecovery(now = Date.now()) {
1920
+ const settled = [];
1921
+ const claimed = this.storage.transactionSync(() => {
1922
+ const claimed2 = [];
1923
+ for (const row2 of this.pending()) {
1924
+ const execution = this.execution(row2.conversationId);
1925
+ if (row2.abortRequested || execution?.aborted) {
1926
+ this.storage.sql.exec(`UPDATE cloud_invocations SET state='aborted',resultJson=NULL,errorCode='CLOUD_EXECUTION_ABORTED'
1927
+ WHERE invocationId=? AND state IN ('accepted','running')`, row2.invocationId);
1928
+ } else if (now >= row2.deadlineAt || execution && now >= execution.deadlineAt) {
1929
+ const code = execution && now >= execution.deadlineAt ? "CLOUD_EXECUTION_TIMEOUT" : "CLOUD_TOOL_TIMEOUT";
1930
+ this.storage.sql.exec(`UPDATE cloud_invocations SET state='timed_out',resultJson=NULL,errorCode=?
1931
+ WHERE invocationId=? AND state IN ('accepted','running')`, code, row2.invocationId);
1932
+ this.failExecution(row2.conversationId, code);
1933
+ } else if (row2.replay === "safe" && row2.mode === "inline" && row2.replayCount === 0) {
1934
+ this.storage.sql.exec(`UPDATE cloud_invocations SET replayCount=1,attempt=attempt+1,state='running'
1935
+ WHERE invocationId=? AND replayCount=0 AND state IN ('accepted','running')`, row2.invocationId);
1936
+ claimed2.push(this.read(row2.invocationId));
1937
+ } else {
1938
+ this.storage.sql.exec(
1939
+ `UPDATE cloud_invocations SET state=?,resultJson=NULL,errorCode='CLOUD_EXECUTION_INTERRUPTED'
1940
+ WHERE invocationId=? AND state IN ('accepted','running')`,
1941
+ row2.replayCount >= 1 ? "failed" : "interrupted",
1942
+ row2.invocationId
1943
+ );
1944
+ }
1945
+ const updated = this.read(row2.invocationId);
1946
+ if (terminal(updated.state)) {
1947
+ settled.push(this.#terminal(updated, true));
1948
+ }
1949
+ }
1950
+ return claimed2;
1951
+ });
1952
+ for (const row2 of settled) this.#notify(row2);
1953
+ return claimed;
1954
+ }
1955
+ forConversation(conversationId) {
1956
+ return this.storage.sql.exec("SELECT * FROM cloud_invocations WHERE conversationId=? ORDER BY seq", conversationId).toArray();
1957
+ }
1958
+ startExecution(conversationId, deadlineAt) {
1959
+ this.storage.sql.exec("INSERT INTO cloud_executions(conversationId,deadlineAt) VALUES (?,?) ON CONFLICT(conversationId) DO NOTHING", conversationId, deadlineAt);
1960
+ return this.execution(conversationId);
1961
+ }
1962
+ execution(conversationId) {
1963
+ return this.storage.sql.exec("SELECT * FROM cloud_executions WHERE conversationId=?", conversationId).toArray()[0];
1964
+ }
1965
+ failExecution(conversationId, code) {
1966
+ this.storage.sql.exec("UPDATE cloud_executions SET fatalCode=COALESCE(fatalCode,?) WHERE conversationId=?", code, conversationId);
1967
+ return this.execution(conversationId);
1968
+ }
1969
+ abortExecution(conversationId, code) {
1970
+ return this.storage.transactionSync(() => {
1971
+ this.storage.sql.exec("UPDATE cloud_executions SET aborted=1,fatalCode=COALESCE(fatalCode,?) WHERE conversationId=?", code, conversationId);
1972
+ this.storage.sql.exec(`UPDATE cloud_invocations SET abortRequested=1
1973
+ WHERE conversationId=? AND state IN ('accepted','running')`, conversationId);
1974
+ return this.execution(conversationId);
1975
+ });
1976
+ }
1977
+ executionRejection(row2, now) {
1978
+ if (row2.fatalCode) return row2.fatalCode;
1979
+ if (row2.aborted) return "CLOUD_EXECUTION_ABORTED";
1980
+ if (now >= row2.deadlineAt) return "CLOUD_EXECUTION_TIMEOUT";
1981
+ return void 0;
1982
+ }
1983
+ countModel(conversationId, maxSteps = 8, now = Date.now(), budget) {
1984
+ const outcome = this.storage.transactionSync(() => {
1985
+ const row2 = this.execution(conversationId);
1986
+ if (!row2) return { code: "CLOUD_EXECUTION_INTERRUPTED" };
1987
+ const code = this.executionRejection(row2, now) ?? (row2.steps >= maxSteps ? "CLOUD_STEP_LIMIT" : void 0);
1988
+ if (code) {
1989
+ this.failExecution(conversationId, code);
1990
+ return { code };
1991
+ }
1992
+ if (budget && (row2.inputTokens + budget.inputBytes + REQUEST_FRAMING_BYTES > budget.inputTokens || row2.outputTokens + PLATFORM_MAX_OUTPUT_TOKENS > budget.outputTokens)) {
1993
+ this.failExecution(conversationId, "CLOUD_BUDGET_EXCEEDED");
1994
+ return { code: "CLOUD_BUDGET_EXCEEDED" };
1995
+ }
1996
+ this.storage.sql.exec("UPDATE cloud_executions SET steps=steps+1 WHERE conversationId=?", conversationId);
1997
+ return { row: this.execution(conversationId) };
1998
+ });
1999
+ if (outcome.code) throw new CloudDoError(outcome.code);
2000
+ return outcome.row;
2001
+ }
2002
+ addModelUsage(conversationId, input, output) {
2003
+ this.storage.sql.exec(`UPDATE cloud_executions SET inputTokens=MIN(inputTokens+?,9007199254740991),
2004
+ outputTokens=MIN(outputTokens+?,9007199254740991) WHERE conversationId=?`, input, output, conversationId);
2005
+ }
2006
+ /** This mark records durable dispatch intent. It does not prove network receipt. */
2007
+ markModelSent(conversationId) {
2008
+ const update = this.storage.sql.exec(`UPDATE cloud_executions SET sentRequests=sentRequests+1
2009
+ WHERE conversationId=? AND sentRequests < steps`, conversationId);
2010
+ if (update.rowsWritten === 0) throw new CloudDoError("CLOUD_MODEL_REQUEST_FAILED");
2011
+ }
2012
+ countTool(conversationId, taskId, maxTools = 12, now = Date.now()) {
2013
+ const outcome = this.storage.transactionSync(() => {
2014
+ const row2 = this.execution(conversationId);
2015
+ if (!row2) return { code: "CLOUD_EXECUTION_INTERRUPTED" };
2016
+ const stopped = this.executionRejection(row2, now);
2017
+ if (stopped) {
2018
+ this.failExecution(conversationId, stopped);
2019
+ return { code: stopped };
2020
+ }
2021
+ const counted = this.storage.sql.exec("SELECT taskId FROM cloud_counted_tools WHERE conversationId=? AND taskId=?", conversationId, taskId).toArray()[0];
2022
+ if (counted) return { row: row2 };
2023
+ if (row2.tools >= maxTools) {
2024
+ this.failExecution(conversationId, "CLOUD_TOOL_LIMIT");
2025
+ return { code: "CLOUD_TOOL_LIMIT" };
2026
+ }
2027
+ this.storage.sql.exec("INSERT INTO cloud_counted_tools(conversationId,taskId) VALUES (?,?)", conversationId, taskId);
2028
+ this.storage.sql.exec("UPDATE cloud_executions SET tools=tools+1 WHERE conversationId=?", conversationId);
2029
+ return { row: this.execution(conversationId) };
2030
+ });
2031
+ if (outcome.code) throw new CloudDoError(outcome.code);
2032
+ return outcome.row;
2033
+ }
2034
+ };
2035
+
2036
+ // src/session-config.ts
2037
+ var CLOUD_LIMITS = Object.freeze({
2038
+ modelSteps: 8,
2039
+ toolCalls: 12,
2040
+ inlineFetches: 4,
2041
+ callTimeoutMs: 6e4,
2042
+ turnTimeoutMs: 24e4,
2043
+ resultBytes: 48e3
2044
+ });
2045
+ var CLOUD_BUDGET = Object.freeze({ credits: 100, inputTokens: 128e3, outputTokens: 32768 });
2046
+ function record(value, keys) {
2047
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
2048
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2049
+ }
2050
+ const result = {};
2051
+ for (const key of Reflect.ownKeys(value)) {
2052
+ const field = Object.getOwnPropertyDescriptor(value, key);
2053
+ if (typeof key !== "string" || !keys.includes(key) || !field || !("value" in field) || !field.enumerable) {
2054
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2055
+ }
2056
+ result[key] = field.value;
2057
+ }
2058
+ return result;
2059
+ }
2060
+ function text(value, max = 256) {
2061
+ if (typeof value !== "string" || !value.trim() || value.length > max || /\p{Cc}/u.test(value)) {
2062
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2063
+ }
2064
+ return value;
2065
+ }
2066
+ function admitSessionConfig(input) {
2067
+ const body = record(input, ["identity", "principal", "scopes", "dispatcherId", "limits"]);
2068
+ const ids = record(body.identity, ["tenantId", "workspaceId", "agentId", "sessionId"]);
2069
+ const identity = {
2070
+ tenantId: text(ids.tenantId),
2071
+ workspaceId: text(ids.workspaceId),
2072
+ agentId: text(ids.agentId),
2073
+ sessionId: text(ids.sessionId)
2074
+ };
2075
+ const rawPrincipal = record(body.principal, ["accountId", "workspaceId", "channel"]);
2076
+ const principal = { accountId: text(rawPrincipal.accountId), workspaceId: text(rawPrincipal.workspaceId), channel: text(rawPrincipal.channel) };
2077
+ if (principal.workspaceId !== identity.workspaceId || !["web", "api", "mcp"].includes(principal.channel)) {
2078
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2079
+ }
2080
+ if (!Array.isArray(body.scopes) || body.scopes.length > 64 || Reflect.ownKeys(body.scopes).length !== body.scopes.length + 1) {
2081
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2082
+ }
2083
+ const scopes = [];
2084
+ for (let i = 0; i < body.scopes.length; i++) {
2085
+ const field = Object.getOwnPropertyDescriptor(body.scopes, String(i));
2086
+ if (!field || !("value" in field) || !field.enumerable) throw new CloudDoError("CLOUD_REQUEST_INVALID");
2087
+ scopes.push(text(field.value, 128));
2088
+ }
2089
+ if (new Set(scopes).size !== scopes.length) throw new CloudDoError("CLOUD_REQUEST_INVALID");
2090
+ const limits = { ...CLOUD_LIMITS };
2091
+ if (Object.hasOwn(body, "limits")) {
2092
+ const overrides = record(body.limits, Object.keys(CLOUD_LIMITS));
2093
+ for (const key of Object.keys(overrides)) {
2094
+ const value = overrides[key];
2095
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0 || value > CLOUD_LIMITS[key]) {
2096
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2097
+ }
2098
+ limits[key] = value;
2099
+ }
2100
+ }
2101
+ return { identity, principal, scopes, dispatcherId: text(body.dispatcherId), limits };
2102
+ }
2103
+ var names = /* @__PURE__ */ new Set(["durable_schema"]);
2104
+ for (const migration of SQLITE_MIGRATIONS) for (const sql of migration.statements) {
2105
+ for (const match of sql.matchAll(/\bCREATE\s+(?:UNIQUE\s+)?(?:TABLE|INDEX)\s+(?:IF\s+NOT\s+EXISTS\s+)?([A-Za-z_][A-Za-z0-9_]*)/gi)) names.add(match[1]);
2106
+ }
2107
+ var identifiers = new RegExp(`\\b(${[...names].join("|")})\\b`, "g");
2108
+ function prefixed(sql) {
2109
+ return sql.split(/('(?:[^']|'')*')/).map((part, i) => i % 2 ? part : part.replace(identifiers, (name) => `pi_${name}`)).join("");
2110
+ }
2111
+ function binding(value) {
2112
+ if (typeof value === "bigint") {
2113
+ if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) throw new RangeError("SQLite integer outside safe range");
2114
+ return Number(value);
2115
+ }
2116
+ if (value instanceof Uint8Array) return new Uint8Array(value).buffer;
2117
+ return value;
2118
+ }
2119
+ function row(raw) {
2120
+ const result = { ...raw };
2121
+ for (const [key, value] of Object.entries(result)) if (value instanceof ArrayBuffer) result[key] = new Uint8Array(value);
2122
+ return result;
2123
+ }
2124
+ var DurableObjectSqliteDatabase = class {
2125
+ constructor(storage) {
2126
+ this.storage = storage;
2127
+ }
2128
+ storage;
2129
+ tail = Promise.resolve();
2130
+ closed = false;
2131
+ queued(operation, allowClosed = false) {
2132
+ const result = this.tail.then(() => {
2133
+ if (this.closed && !allowClosed) throw new Error("SQLite database is closed");
2134
+ return operation();
2135
+ });
2136
+ this.tail = result.then(() => {
2137
+ }, () => {
2138
+ });
2139
+ return result;
2140
+ }
2141
+ executor(active) {
2142
+ const query = (sql, params) => {
2143
+ if (!active()) throw new Error("SQLite transaction handle is no longer active");
2144
+ return this.storage.sql.exec(prefixed(sql), ...params.map(binding));
2145
+ };
2146
+ return {
2147
+ exec: async (sql) => {
2148
+ query(sql, []).toArray();
2149
+ },
2150
+ run: async (sql, ...params) => {
2151
+ query(sql, params).toArray();
2152
+ },
2153
+ get: async (sql, ...params) => {
2154
+ const rows = query(sql, params).toArray();
2155
+ return rows[0] === void 0 ? void 0 : row(rows[0]);
2156
+ },
2157
+ all: async (sql, ...params) => query(sql, params).toArray().map((raw) => row(raw))
2158
+ };
2159
+ }
2160
+ exec(sql) {
2161
+ return this.queued(() => this.executor(() => true).exec(sql));
2162
+ }
2163
+ run(sql, ...params) {
2164
+ return this.queued(() => this.executor(() => true).run(sql, ...params));
2165
+ }
2166
+ get(sql, ...params) {
2167
+ return this.queued(() => this.executor(() => true).get(sql, ...params));
2168
+ }
2169
+ all(sql, ...params) {
2170
+ return this.queued(() => this.executor(() => true).all(sql, ...params));
2171
+ }
2172
+ transaction(callback) {
2173
+ return this.queued(() => this.storage.transaction(async () => {
2174
+ let active = true;
2175
+ try {
2176
+ return await callback(this.executor(() => active));
2177
+ } finally {
2178
+ active = false;
2179
+ }
2180
+ }));
2181
+ }
2182
+ close() {
2183
+ return this.queued(() => {
2184
+ if (this.closed) return;
2185
+ this.closed = true;
2186
+ }, true);
2187
+ }
2188
+ };
2189
+ var openDurableObjectStorage = (storage) => SqliteStorage.open(new DurableObjectSqliteDatabase(storage));
2190
+
2191
+ // src/session-runtime.ts
2192
+ var CLOUD_HARNESS_SETTINGS = {
2193
+ compaction: { enabled: false },
2194
+ retry: { enabled: false, maxRetries: 0 },
2195
+ stream: { maxRetries: 0 }
2196
+ };
2197
+ var StaleInvocationAttempt = class extends CloudDoError {
2198
+ constructor() {
2199
+ super("CLOUD_EXECUTION_INTERRUPTED");
2200
+ }
2201
+ };
2202
+ async function raceSignal(work, signal, code) {
2203
+ let remove = () => {
2204
+ };
2205
+ const cancelled = new Promise((_resolve, reject) => {
2206
+ const abort = () => reject(new CloudDoError(code()));
2207
+ signal.addEventListener("abort", abort, { once: true });
2208
+ remove = () => signal.removeEventListener("abort", abort);
2209
+ if (signal.aborted) abort();
2210
+ });
2211
+ try {
2212
+ return await Promise.race([work, cancelled]);
2213
+ } finally {
2214
+ remove();
2215
+ }
2216
+ }
2217
+ function raceLease(work, lease) {
2218
+ return raceSignal(
2219
+ work,
2220
+ lease.controller.signal,
2221
+ () => Date.now() >= lease.deadlineAt ? "CLOUD_EXECUTION_TIMEOUT" : "CLOUD_EXECUTION_ABORTED"
2222
+ );
2223
+ }
2224
+ var SessionRuntime = class {
2225
+ constructor(state, env, options) {
2226
+ this.state = state;
2227
+ this.env = env;
2228
+ this.options = options;
2229
+ this.cloud = new CloudState(state.storage);
2230
+ this.ledger = new InvocationLedger(state.storage, {
2231
+ started: (row2, guard) => {
2232
+ this.cloud.appendEvent({
2233
+ eventKey: `tool:${row2.invocationId}:started`,
2234
+ type: "tool.started",
2235
+ conversationId: row2.conversationId,
2236
+ ref: row2.invocationId,
2237
+ data: { invocationId: row2.invocationId, toolName: row2.toolName, state: row2.state }
2238
+ }, guard ?? this.#guard());
2239
+ },
2240
+ startedCommitted: () => this.#doorbell(),
2241
+ terminal: (row2, recovery) => {
2242
+ const guard = this.#guard();
2243
+ const event = this.cloud.appendEvent({
2244
+ eventKey: `tool:${row2.invocationId}:settled`,
2245
+ type: "tool.settled",
2246
+ conversationId: row2.conversationId,
2247
+ ref: row2.invocationId,
2248
+ data: { invocationId: row2.invocationId, state: row2.state, errorCode: row2.errorCode, late: recovery }
2249
+ }, guard);
2250
+ row2.settledAt = event.createdAt;
2251
+ row2.settledEventSeq = event.seq;
2252
+ this.cloud.projectInvocation(row2, this.options.projectInvocation, guard);
2253
+ return event;
2254
+ },
2255
+ committed: (row2) => {
2256
+ if (this.#initializing) this.#deferredSettlements.push(row2);
2257
+ else this.#notifyCommitted(row2);
2258
+ }
2259
+ });
2260
+ }
2261
+ state;
2262
+ env;
2263
+ options;
2264
+ ledger;
2265
+ cloud;
2266
+ #piStorage;
2267
+ #recoveryGuard;
2268
+ #repairRetrying = false;
2269
+ #repairing = false;
2270
+ #settlementFlights = /* @__PURE__ */ new Map();
2271
+ #initializing = false;
2272
+ #deferredSettlements = [];
2273
+ #opened;
2274
+ #recovery;
2275
+ #recovered = false;
2276
+ #config;
2277
+ #dispatcher;
2278
+ #bootstrapFailure;
2279
+ #stale = /* @__PURE__ */ new Set();
2280
+ #active;
2281
+ #inline = 0;
2282
+ #invocations = /* @__PURE__ */ new Map();
2283
+ #fatalDispositions = /* @__PURE__ */ new Map();
2284
+ get recovering() {
2285
+ return !this.#recovered;
2286
+ }
2287
+ get activeLease() {
2288
+ return this.#active;
2289
+ }
2290
+ get hasLiveOwner() {
2291
+ return this.#active?.liveOwner === true;
2292
+ }
2293
+ get busy() {
2294
+ return this.#active !== void 0 || this.#repairing;
2295
+ }
2296
+ get repairRetrying() {
2297
+ return this.#repairRetrying;
2298
+ }
2299
+ #schedulingBusy() {
2300
+ return this.hasLiveOwner || this.#repairing;
2301
+ }
2302
+ #clearSettlementRetry() {
2303
+ if (!this.#repairing && (!this.#active || this.hasLiveOwner)) this.#repairRetrying = false;
2304
+ }
2305
+ prepareGuard(profile) {
2306
+ return prepareCloudGuard(this.env, profile);
2307
+ }
2308
+ #guard() {
2309
+ const guard = this.#active?.guard ?? this.#recoveryGuard;
2310
+ if (!guard) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2311
+ return guard;
2312
+ }
2313
+ #doorbell() {
2314
+ try {
2315
+ this.options.onCommit?.();
2316
+ } catch {
2317
+ }
2318
+ }
2319
+ #notifyCommitted(row2) {
2320
+ this.#doorbell();
2321
+ void Promise.resolve().then(() => this.options.onInvocationSettled?.(row2.invocationId, row2.state)).catch(() => void 0);
2322
+ }
2323
+ #flushSettlements() {
2324
+ this.#initializing = false;
2325
+ for (const row2 of this.#deferredSettlements.splice(0)) this.#notifyCommitted(row2);
2326
+ }
2327
+ /** Binding/RPC callers authorize the session before calling this immutable configuration operation. */
2328
+ async configure(input) {
2329
+ const config = admitSessionConfig(input);
2330
+ await admitCloudPayload(this.env, config);
2331
+ const candidate = this.options.createDispatcher(config.dispatcherId);
2332
+ if (!candidate) throw new CloudDoError("CLOUD_TOOL_NOT_AVAILABLE");
2333
+ const dispatcher = admitCloudDispatcher(candidate);
2334
+ await this.#guardToolMetadata(dispatcher);
2335
+ const policyDigest = await dispatcherDigest(dispatcher);
2336
+ this.#sessionSchema();
2337
+ this.state.storage.transactionSync(() => {
2338
+ const existing = this.#storedConfig();
2339
+ if (existing) {
2340
+ if (JSON.stringify(existing) !== JSON.stringify(config) || this.#storedDispatcherDigest() !== policyDigest) throw new CloudDoError("CLOUD_SESSION_CONFLICT");
2341
+ return;
2342
+ }
2343
+ if (this.#opened) throw new CloudDoError("CLOUD_SESSION_CONFLICT");
2344
+ this.state.storage.sql.exec("UPDATE cloud_session SET configJson=?,dispatcherDigest=? WHERE id=1", JSON.stringify(config), policyDigest);
2345
+ });
2346
+ }
2347
+ open(selected) {
2348
+ if (!this.#opened) {
2349
+ const initialized = prepareCloudGuard(this.env, selected).then((guard) => {
2350
+ this.#recoveryGuard = guard;
2351
+ this.#initializing = true;
2352
+ return this.state.blockConcurrencyWhile(async () => {
2353
+ this.ledger.ensureSchema();
2354
+ this.cloud.ensureSchema();
2355
+ this.#sessionSchema();
2356
+ this.#config = this.#storedConfig();
2357
+ if (!this.#config && this.ledger.pending().length) this.#bootstrapFailure = "CLOUD_TOOL_NOT_AVAILABLE";
2358
+ if (this.#config) {
2359
+ this.#config = admitSessionConfig(this.#config);
2360
+ const candidate = this.options.createDispatcher(this.#config.dispatcherId);
2361
+ if (!candidate) this.#bootstrapFailure = "CLOUD_TOOL_NOT_AVAILABLE";
2362
+ else {
2363
+ const dispatcher = admitCloudDispatcher(candidate);
2364
+ const metadata = dispatcher.tools.map(({ name, description, parameters }) => ({ name, description, parameters }));
2365
+ guard.guardPayload(JSON.stringify(metadata));
2366
+ if (await dispatcherDigest(dispatcher) !== this.#storedDispatcherDigest()) this.#bootstrapFailure = "CLOUD_SESSION_CONFLICT";
2367
+ else this.#dispatcher = dispatcher;
2368
+ }
2369
+ }
2370
+ const registry = createRegistry();
2371
+ const tools = this.#dispatcher?.tools.map((tool) => ({
2372
+ name: tool.name,
2373
+ description: tool.description,
2374
+ parameters: tool.parameters,
2375
+ replay: "unsafe",
2376
+ outputLimits: { maxBytes: CLOUD_LIMITS.resultBytes, maxLines: CLOUD_LIMITS.resultBytes },
2377
+ execute: (args, api, context) => this.#execute(tool.name, args, api, context)
2378
+ })) ?? [];
2379
+ registry.install(defineExtension({
2380
+ name: "cloud-session-tools",
2381
+ tools,
2382
+ hooks: [hook(ToolTask, { beforeTool: async (_call, api) => {
2383
+ if (this.#stale.has(api.conversationId)) return { block: "CLOUD_EXECUTION_INTERRUPTED" };
2384
+ try {
2385
+ this.ledger.countTool(api.conversationId, String(api.taskId), this.#limits().toolCalls);
2386
+ } catch (error) {
2387
+ const code = safeCloudError(error).code;
2388
+ this.#recordFatal(api.conversationId, code);
2389
+ return { block: code };
2390
+ }
2391
+ } })]
2392
+ }));
2393
+ this.#piStorage = await openDurableObjectStorage(this.state.storage);
2394
+ const harness = await Harness.open(this.#piStorage, {
2395
+ models: createPlatformModels(this.env, platformCredentialReader(this.env), {
2396
+ beforeRequest: (info) => this.#beforeRequest(info),
2397
+ admitToolCall: async (name, id, args) => {
2398
+ try {
2399
+ await admitCloudPayload(this.env, { name, id, args }, this.#active?.profile);
2400
+ } catch (error) {
2401
+ if (error instanceof CloudDoError && error.code === "CLOUD_USER_CREDENTIAL_REJECTED") {
2402
+ throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
2403
+ }
2404
+ throw error;
2405
+ }
2406
+ const tool = this.#dispatcher?.tools.find((tool2) => tool2.name === name);
2407
+ if (!tool) throw new CloudDoError("CLOUD_TOOL_NOT_AVAILABLE");
2408
+ try {
2409
+ validateToolArguments(tool, { type: "toolCall", id, name, arguments: args });
2410
+ } catch {
2411
+ throw new CloudDoError("CLOUD_TOOL_ARGUMENT_INVALID");
2412
+ }
2413
+ },
2414
+ requestSignal: (signal) => this.#requestSignal(signal)
2415
+ }),
2416
+ registry,
2417
+ settings: CLOUD_HARNESS_SETTINGS
2418
+ }, BACKGROUND_CONTEXT);
2419
+ const inspection = await harness.inspect(BACKGROUND_CONTEXT);
2420
+ this.#stale = /* @__PURE__ */ new Set([
2421
+ ...inspection.tasks.map((task) => task.record.conversationId),
2422
+ ...inspection.submissions.map((submission) => submission.conversationId)
2423
+ ]);
2424
+ this.state.storage.sql.exec("UPDATE cloud_session SET staleJson=? WHERE id=1", JSON.stringify([...this.#stale]));
2425
+ this.cloud.captureEligibility(this.#stale);
2426
+ const replay = this.ledger.claimRecovery();
2427
+ await this.cloud.rearmAlarm({ busy: false, repairRetrying: false });
2428
+ return { harness, replay };
2429
+ });
2430
+ });
2431
+ this.#opened = initialized.then(({ harness, replay }) => {
2432
+ this.#flushSettlements();
2433
+ this.#recovery = this.#recover(harness, replay).finally(() => {
2434
+ this.#recoveryGuard?.dispose();
2435
+ this.#recoveryGuard = void 0;
2436
+ });
2437
+ void this.#recovery.catch(() => void 0);
2438
+ return harness;
2439
+ }, (error) => {
2440
+ this.#flushSettlements();
2441
+ this.#recoveryGuard?.dispose();
2442
+ this.#recoveryGuard = void 0;
2443
+ throw error;
2444
+ });
2445
+ }
2446
+ return this.#opened;
2447
+ }
2448
+ async ready(selected) {
2449
+ const harness = await this.open(selected);
2450
+ await this.#recovery;
2451
+ return harness;
2452
+ }
2453
+ agentChange(profile, guard) {
2454
+ const model = { provider: profile, modelId: PLATFORM_PROFILES[profile].model };
2455
+ try {
2456
+ const text2 = this.options.instructions?.(profile);
2457
+ if (text2 === void 0) return { model };
2458
+ if (typeof text2 !== "string" || !text2.trim() || new TextEncoder().encode(text2).length > CLOUD_CONTEXT_BYTES) {
2459
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2460
+ }
2461
+ guard.guardText(text2);
2462
+ return { model, instructions: text2 };
2463
+ } catch {
2464
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
2465
+ }
2466
+ }
2467
+ reserve(profile, guard) {
2468
+ if (!this.#recovered) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2469
+ if (this.#bootstrapFailure) throw new CloudDoError(this.#bootstrapFailure);
2470
+ if (this.#active) throw new CloudDoError("CLOUD_TOOL_BUSY");
2471
+ if (this.#repairing) throw new CloudDoError("CLOUD_TOOL_BUSY");
2472
+ const lease = {
2473
+ profile,
2474
+ deadlineAt: Date.now() + this.#limits().turnTimeoutMs,
2475
+ controller: new AbortController(),
2476
+ connected: true,
2477
+ liveOwner: true,
2478
+ settled: false,
2479
+ guard
2480
+ };
2481
+ this.#active = lease;
2482
+ this.cloud.setSchedulingState({ busy: true, repairRetrying: this.#repairRetrying });
2483
+ return lease;
2484
+ }
2485
+ attach(lease, conversationId, trigger = "submit", guard = lease.guard) {
2486
+ if (this.#active !== lease || lease.conversationId !== void 0) throw new CloudDoError("CLOUD_TOOL_BUSY");
2487
+ lease.conversationId = conversationId;
2488
+ lease.trigger = trigger;
2489
+ lease.guard = guard;
2490
+ if (!lease.guard) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2491
+ this.cloud.startRun(conversationId, trigger, lease.deadlineAt, lease.guard);
2492
+ if (trigger === "submit") this.cloud.markRunning(conversationId, lease.guard);
2493
+ lease.timer = setTimeout(() => {
2494
+ if (this.#active !== lease || lease.settled) return;
2495
+ this.#recordFatal(conversationId, "CLOUD_EXECUTION_TIMEOUT");
2496
+ lease.controller.abort();
2497
+ }, Math.max(0, lease.deadlineAt - Date.now()));
2498
+ this.#doorbell();
2499
+ }
2500
+ cancel(lease, code = "CLOUD_EXECUTION_ABORTED") {
2501
+ if (this.#active !== lease || lease.settled) return;
2502
+ if (lease.conversationId !== void 0) {
2503
+ const row2 = this.cloud.run(lease.conversationId);
2504
+ if (row2 && row2.state !== "starting" && row2.state !== "running") return;
2505
+ }
2506
+ lease.connected = false;
2507
+ if (lease.conversationId !== void 0) {
2508
+ this.#recordFatal(lease.conversationId, code);
2509
+ try {
2510
+ this.ledger.abortExecution(lease.conversationId, code);
2511
+ } catch {
2512
+ }
2513
+ }
2514
+ lease.controller.abort();
2515
+ }
2516
+ async release(lease, retryCount = 0) {
2517
+ clearTimeout(lease.timer);
2518
+ lease.liveOwner = false;
2519
+ if (this.#active !== lease) return;
2520
+ try {
2521
+ const run = lease.conversationId === void 0 ? void 0 : this.cloud.run(lease.conversationId);
2522
+ if (run?.state === "running") {
2523
+ this.#repairRetrying = lease.trigger === "wake";
2524
+ await this.cloud.rearmAlarm({ busy: false, repairRetrying: this.#repairRetrying });
2525
+ return;
2526
+ }
2527
+ if (run?.state === "starting") {
2528
+ this.cloud.settleRun(run.conversationId, { state: "interrupted", errorCode: this.fatal(run.conversationId) ?? "CLOUD_WAKE_EMPTY" }, this.#guard());
2529
+ this.#doorbell();
2530
+ }
2531
+ this.#active = void 0;
2532
+ try {
2533
+ await this.#deliverSettlements(lease.guard);
2534
+ this.#clearSettlementRetry();
2535
+ } catch (error) {
2536
+ if (lease.trigger === "wake") {
2537
+ this.#repairRetrying = retryCount < 6;
2538
+ this.cloud.setSchedulingState({ busy: this.#schedulingBusy(), repairRetrying: this.#repairRetrying });
2539
+ throw error;
2540
+ }
2541
+ }
2542
+ await this.cloud.rearmAlarm({ busy: this.#schedulingBusy(), repairRetrying: this.#repairRetrying });
2543
+ } catch (error) {
2544
+ if (this.#active === lease) {
2545
+ this.#repairRetrying = lease.trigger === "wake";
2546
+ this.cloud.setSchedulingState({ busy: false, repairRetrying: this.#repairRetrying });
2547
+ if (!this.#repairRetrying) await this.cloud.rearmAlarm({ busy: false, repairRetrying: false });
2548
+ }
2549
+ throw error;
2550
+ } finally {
2551
+ lease.guard?.dispose();
2552
+ lease.guard = void 0;
2553
+ }
2554
+ }
2555
+ recordSubmission(conversationId, submissionId) {
2556
+ this.cloud.recordSubmission(conversationId, submissionId);
2557
+ }
2558
+ markReservation(conversationId, reservation, admission) {
2559
+ this.cloud.markReservation(conversationId, reservation, this.#guard(), Date.now(), admission);
2560
+ this.#doorbell();
2561
+ }
2562
+ claimWake(lease, seqs, profile = lease.profile) {
2563
+ if (this.#active !== lease || lease.conversationId === void 0 || !lease.liveOwner) throw new CloudDoError("CLOUD_TOOL_BUSY");
2564
+ const claimed = this.cloud.claim(lease.conversationId, [...seqs], profile, this.#guard());
2565
+ this.#doorbell();
2566
+ return claimed;
2567
+ }
2568
+ async settle(lease, outcome) {
2569
+ if (this.#active !== lease || lease.conversationId === void 0) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2570
+ const delivery = await this.#deliveryEvidence(await this.#opened, lease.conversationId, outcome.state === "completed");
2571
+ this.state.storage.transactionSync(() => {
2572
+ const fatal = this.fatal(lease.conversationId) ?? (lease.controller.signal.aborted ? "CLOUD_EXECUTION_ABORTED" : Date.now() >= lease.deadlineAt ? "CLOUD_EXECUTION_TIMEOUT" : void 0);
2573
+ const finalOutcome = outcome.state === "completed" && fatal ? { state: "failed", errorCode: fatal } : outcome;
2574
+ const stored = this.cloud.settleRun(lease.conversationId, finalOutcome, this.#guard());
2575
+ for (const link of delivery) this.cloud.setDelivery(
2576
+ link.invocationId,
2577
+ stored?.state === "completed" ? link.state : "undelivered",
2578
+ stored?.state === "completed" ? link.taskId : null,
2579
+ stored?.state === "completed" ? link.entryId : null,
2580
+ this.#guard()
2581
+ );
2582
+ });
2583
+ lease.settled = true;
2584
+ clearTimeout(lease.timer);
2585
+ this.#doorbell();
2586
+ }
2587
+ cancelActive(code = "CLOUD_EXECUTION_ABORTED") {
2588
+ if (!this.#active || this.#active.settled) return false;
2589
+ this.cancel(this.#active, code);
2590
+ return true;
2591
+ }
2592
+ /** Only an owner that exited may be repaired. A live provider run is never adjudicated here. */
2593
+ async repairPendingRuns(retryCount = 0) {
2594
+ if (this.hasLiveOwner || this.#repairing) return false;
2595
+ const runs = this.cloud.unsettledRuns();
2596
+ if (!runs.length) {
2597
+ if (this.#repairRetrying && !this.cloud.unackedRuns().length) {
2598
+ this.#repairRetrying = false;
2599
+ await this.cloud.rearmAlarm({ busy: this.busy, repairRetrying: false });
2600
+ }
2601
+ return false;
2602
+ }
2603
+ this.#repairing = true;
2604
+ this.#repairRetrying = true;
2605
+ this.cloud.setSchedulingState({ busy: true, repairRetrying: true });
2606
+ let guard;
2607
+ const previousGuard = this.#active?.guard;
2608
+ try {
2609
+ guard = await this.prepareGuard();
2610
+ this.#recoveryGuard = guard;
2611
+ if (this.#active) this.#active.guard = guard;
2612
+ const harness = await this.#opened;
2613
+ const inspection = await harness.inspect(BACKGROUND_CONTEXT);
2614
+ const live = /* @__PURE__ */ new Set([...inspection.tasks.map((task) => task.record.conversationId), ...inspection.submissions.map((submission) => submission.conversationId)]);
2615
+ this.cloud.captureEligibility(live);
2616
+ for (const run of runs) {
2617
+ const id = run.conversationId;
2618
+ if (!live.has(id)) continue;
2619
+ this.#stale.add(id);
2620
+ this.#recordFatal(id, "CLOUD_EXECUTION_INTERRUPTED");
2621
+ const conversation = await harness.conversation(id, BACKGROUND_CONTEXT);
2622
+ if (conversation) {
2623
+ await conversation.abort(BACKGROUND_CONTEXT, { background: true });
2624
+ await conversation.waitForIdle(BACKGROUND_CONTEXT);
2625
+ }
2626
+ }
2627
+ await this.#adjudicateRuns(harness);
2628
+ clearTimeout(this.#active?.timer);
2629
+ this.#active = void 0;
2630
+ this.#repairRetrying = this.cloud.unackedRuns().length > 0;
2631
+ await this.cloud.rearmAlarm({ busy: false, repairRetrying: this.#repairRetrying });
2632
+ return true;
2633
+ } catch (error) {
2634
+ this.#repairRetrying = retryCount < 6;
2635
+ this.cloud.setSchedulingState({ busy: false, repairRetrying: this.#repairRetrying });
2636
+ throw error;
2637
+ } finally {
2638
+ this.#repairing = false;
2639
+ guard?.dispose();
2640
+ previousGuard?.dispose();
2641
+ this.#recoveryGuard = void 0;
2642
+ if (this.#active) this.#active.guard = void 0;
2643
+ }
2644
+ }
2645
+ async deliverSettlementsForAlarm(retryCount = 0, providedGuard) {
2646
+ let ownGuard;
2647
+ try {
2648
+ if (this.cloud.unackedRuns().length) {
2649
+ const guard = providedGuard ?? (ownGuard = await this.prepareGuard());
2650
+ await this.#deliverSettlements(guard);
2651
+ }
2652
+ this.#clearSettlementRetry();
2653
+ await this.cloud.rearmAlarm({ busy: this.#schedulingBusy(), repairRetrying: this.#repairRetrying });
2654
+ } catch (error) {
2655
+ this.#repairRetrying = retryCount < 6;
2656
+ this.cloud.setSchedulingState({ busy: this.#schedulingBusy(), repairRetrying: this.#repairRetrying });
2657
+ throw safeCloudError(error);
2658
+ } finally {
2659
+ ownGuard?.dispose();
2660
+ }
2661
+ }
2662
+ async #deliverSettlements(guard) {
2663
+ const rows = this.cloud.unackedRuns();
2664
+ if (!rows.length) return;
2665
+ if (!guard) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2666
+ const jobs = rows.map((row2) => {
2667
+ const previous = this.#settlementFlights.get(row2.conversationId);
2668
+ if (previous) return previous;
2669
+ const job = this.#deliverSettlement(row2, guard).finally(() => this.#settlementFlights.delete(row2.conversationId));
2670
+ this.#settlementFlights.set(row2.conversationId, job);
2671
+ return job;
2672
+ });
2673
+ const results = await Promise.allSettled(jobs);
2674
+ const failures = results.filter((result) => result.status === "rejected");
2675
+ if (failures.length) throw safeCloudError(failures[0].reason);
2676
+ }
2677
+ async #deliverSettlement(row2, guard) {
2678
+ if (this.cloud.readRun(row2.conversationId)?.settlementAck !== 0) return;
2679
+ const input = Object.freeze({
2680
+ nativeRunId: row2.conversationId,
2681
+ requestId: row2.requestId,
2682
+ trigger: row2.trigger,
2683
+ state: row2.state,
2684
+ errorCode: row2.errorCode,
2685
+ reservation: row2.reservation,
2686
+ admissionDigest: row2.admissionDigest,
2687
+ admittedSeqs: Object.freeze(JSON.parse(row2.admittedSeqs ?? "[]")),
2688
+ claimedSeqs: Object.freeze(this.cloud.claimedSeqs(row2.conversationId)),
2689
+ usage: Object.freeze({
2690
+ steps: row2.steps,
2691
+ sentRequests: row2.sentRequests,
2692
+ inputTokens: row2.inputTokens,
2693
+ outputTokens: row2.outputTokens,
2694
+ credits: row2.credits
2695
+ })
2696
+ });
2697
+ const controller = new AbortController();
2698
+ const timer = setTimeout(() => controller.abort(), CLOUD_LIMITS.callTimeoutMs);
2699
+ try {
2700
+ await raceSignal(
2701
+ Promise.resolve().then(() => this.options.settleRun?.(input, controller.signal)),
2702
+ controller.signal,
2703
+ () => "CLOUD_EXECUTION_TIMEOUT"
2704
+ );
2705
+ if (this.cloud.ackSettlement(row2.conversationId, guard)) this.#doorbell();
2706
+ } catch (error) {
2707
+ throw safeCloudError(error);
2708
+ } finally {
2709
+ clearTimeout(timer);
2710
+ controller.abort();
2711
+ }
2712
+ }
2713
+ async #adjudicateRuns(harness) {
2714
+ for (const run of this.cloud.unsettledRuns()) {
2715
+ const eligibility = JSON.parse(run.eligibilityJson ?? JSON.stringify({ steps: run.steps, aborted: run.aborted, fatalCode: run.fatalCode }));
2716
+ const aborted = eligibility.aborted || run.aborted;
2717
+ let outcome;
2718
+ const submission = run.requestId ? await this.#piStorage.submissionByRequest(run.conversationId, run.requestId, BACKGROUND_CONTEXT) : void 0;
2719
+ if (run.state === "starting") outcome = { state: "interrupted", errorCode: "CLOUD_WAKE_EMPTY" };
2720
+ else if (!aborted && !eligibility.fatalCode && submission?.status === "done") {
2721
+ const conversation = await harness.conversation(run.conversationId, BACKGROUND_CONTEXT);
2722
+ const context = conversation ? await conversation.context(BACKGROUND_CONTEXT) : void 0;
2723
+ const final = context ? [...context.entries].reverse().find((entry) => entry.kind === "pi.assistant" && entry.model?.some((message2) => message2.role === "assistant" && message2.stopReason !== "toolUse")) : void 0;
2724
+ const message = final?.model?.find((message2) => message2.role === "assistant" && message2.stopReason !== "toolUse");
2725
+ const text2 = message?.role === "assistant" ? message.content.filter((part) => part.type === "text").map((part) => part.text).join("") : "";
2726
+ outcome = { state: "completed", text: text2, entryId: final?.id };
2727
+ } else if (!aborted && !eligibility.fatalCode && submission?.status === "unanswered" && submission.reason !== "aborted") {
2728
+ outcome = { state: "failed", errorCode: safeCloudError(new Error(typeof submission.detail === "string" ? submission.detail : "")).code };
2729
+ } else {
2730
+ outcome = {
2731
+ state: "interrupted",
2732
+ errorCode: eligibility.fatalCode ?? (aborted ? "CLOUD_EXECUTION_ABORTED" : "CLOUD_EXECUTION_INTERRUPTED"),
2733
+ requeue: run.trigger === "wake" && eligibility.steps === 0 && !aborted && !eligibility.fatalCode
2734
+ };
2735
+ }
2736
+ const delivery = await this.#deliveryEvidence(harness, run.conversationId, outcome.state === "completed");
2737
+ this.state.storage.transactionSync(() => {
2738
+ const current = this.cloud.run(run.conversationId);
2739
+ const finalOutcome = current?.aborted && !eligibility.aborted ? { state: "interrupted", errorCode: "CLOUD_EXECUTION_ABORTED" } : outcome;
2740
+ const stored = this.cloud.settleRun(run.conversationId, finalOutcome, this.#guard());
2741
+ for (const link of delivery) this.cloud.setDelivery(
2742
+ link.invocationId,
2743
+ stored?.state === "completed" ? link.state : "undelivered",
2744
+ stored?.state === "completed" ? link.taskId : null,
2745
+ stored?.state === "completed" ? link.entryId : null,
2746
+ this.#guard()
2747
+ );
2748
+ });
2749
+ this.#doorbell();
2750
+ }
2751
+ }
2752
+ async #deliveryEvidence(harness, conversationId, completed) {
2753
+ const rows = this.ledger.forConversation(conversationId);
2754
+ const links = rows.map((row2) => ({ invocationId: row2.invocationId, state: "undelivered", taskId: null, entryId: null }));
2755
+ if (!completed || !rows.length) return links;
2756
+ const conversation = await harness.conversation(conversationId, BACKGROUND_CONTEXT);
2757
+ if (!conversation) return links;
2758
+ const context = await conversation.context(BACKGROUND_CONTEXT);
2759
+ let cursor;
2760
+ do {
2761
+ const page = await this.#piStorage.scanTasks({ conversationId, kind: ToolTask.definition.name }, 100, cursor, BACKGROUND_CONTEXT);
2762
+ for (const task of page.items) {
2763
+ if (task.state.status !== "terminal" || task.state.outcome.status !== "completed") continue;
2764
+ const input = task.input;
2765
+ const rowIndex = rows.findIndex((row2) => row2.assistantEntryId === input.assistant && row2.toolCallId === input.callId);
2766
+ if (rowIndex < 0) continue;
2767
+ const result = task.state.outcome.result;
2768
+ const entryIndex = context.entries.findIndex((entry) => entry.id === result.entryId && entry.kind === "pi.tool-result" && entry.byTaskId === task.id);
2769
+ if (entryIndex < 0 || !context.contributions[entryIndex]?.some((message) => message.role === "toolResult")) continue;
2770
+ links[rowIndex] = { invocationId: rows[rowIndex].invocationId, state: "delivered", taskId: task.id, entryId: result.entryId };
2771
+ }
2772
+ cursor = page.next;
2773
+ } while (cursor !== void 0);
2774
+ return links;
2775
+ }
2776
+ fatal(conversationId) {
2777
+ const remembered = this.#fatalDispositions.get(conversationId);
2778
+ if (remembered) return remembered;
2779
+ try {
2780
+ const code = this.ledger.execution(conversationId)?.fatalCode;
2781
+ return code ? this.#toolErrorCode(new Error(code)) : void 0;
2782
+ } catch {
2783
+ return this.#recordFatal(conversationId, "CLOUD_TOOL_FAILED");
2784
+ }
2785
+ }
2786
+ readInvocation(id) {
2787
+ return this.ledger.read(id);
2788
+ }
2789
+ #limits() {
2790
+ return this.#config?.limits ?? CLOUD_LIMITS;
2791
+ }
2792
+ async #guardToolMetadata(dispatcher) {
2793
+ const metadata = dispatcher.tools.map(({ name, description, parameters }) => ({ name, description, parameters }));
2794
+ await admitCloudPayload(this.env, JSON.parse(JSON.stringify(metadata)));
2795
+ }
2796
+ #sessionSchema() {
2797
+ this.state.storage.sql.exec(`CREATE TABLE IF NOT EXISTS cloud_session (
2798
+ id INTEGER PRIMARY KEY CHECK(id=1), configJson TEXT, staleJson TEXT NOT NULL DEFAULT '[]'
2799
+ ); INSERT OR IGNORE INTO cloud_session(id) VALUES(1)`);
2800
+ const columns = this.state.storage.sql.exec("PRAGMA table_info(cloud_session)").toArray();
2801
+ if (!columns.some((row2) => row2.name === "dispatcherDigest")) this.state.storage.sql.exec("ALTER TABLE cloud_session ADD COLUMN dispatcherDigest TEXT");
2802
+ }
2803
+ #storedDispatcherDigest() {
2804
+ return this.state.storage.sql.exec("SELECT dispatcherDigest FROM cloud_session WHERE id=1").one().dispatcherDigest;
2805
+ }
2806
+ #storedConfig() {
2807
+ const row2 = this.state.storage.sql.exec("SELECT configJson FROM cloud_session WHERE id=1").toArray()[0];
2808
+ return row2?.configJson ? JSON.parse(row2.configJson) : void 0;
2809
+ }
2810
+ async #renew(request, signal) {
2811
+ const result = this.options.renew ? await this.options.renew(Object.freeze(request), signal) : { ok: true };
2812
+ if (!result || typeof result !== "object" || typeof result.ok !== "boolean") throw new CloudDoError("CLOUD_MODEL_REQUEST_FAILED");
2813
+ if (!result.ok) throw safeCloudError(new Error(result.code));
2814
+ }
2815
+ async #beforeRequest(info) {
2816
+ if (!this.#recovered || !this.#active?.liveOwner || this.#active.conversationId === void 0) {
2817
+ throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2818
+ }
2819
+ const lease = this.#active;
2820
+ const id = lease.conversationId;
2821
+ const fatal = this.fatal(id);
2822
+ if (fatal) throw new CloudDoError(fatal);
2823
+ try {
2824
+ await raceLease(Promise.resolve().then(() => this.#renew({
2825
+ nativeRunId: id,
2826
+ requestId: this.cloud.readRun(id)?.requestId ?? null,
2827
+ kind: "model",
2828
+ recovery: false
2829
+ }, lease.controller.signal)), lease);
2830
+ if (this.#active !== lease || !lease.liveOwner) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2831
+ const stopped = this.fatal(id);
2832
+ if (stopped) throw new CloudDoError(stopped);
2833
+ this.ledger.countModel(id, this.#limits().modelSteps, Date.now(), {
2834
+ inputBytes: info.inputBytes,
2835
+ inputTokens: CLOUD_BUDGET.inputTokens,
2836
+ outputTokens: CLOUD_BUDGET.outputTokens
2837
+ });
2838
+ } catch (error) {
2839
+ throw new CloudDoError(this.#recordFatal(id, safeCloudError(error).code));
2840
+ }
2841
+ const seen = { input: 0, output: 0 };
2842
+ const record2 = (work) => {
2843
+ try {
2844
+ work();
2845
+ } catch {
2846
+ throw new CloudDoError(this.#recordFatal(id, "CLOUD_MODEL_REQUEST_FAILED"));
2847
+ }
2848
+ };
2849
+ return {
2850
+ sent: () => record2(() => this.ledger.markModelSent(id)),
2851
+ usage: (usage) => record2(() => {
2852
+ const input = usage.input ?? seen.input;
2853
+ const output = usage.output ?? seen.output;
2854
+ if (!Number.isSafeInteger(input) || !Number.isSafeInteger(output) || input < seen.input || output < seen.output) {
2855
+ throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
2856
+ }
2857
+ if (input !== seen.input || output !== seen.output) this.ledger.addModelUsage(id, input - seen.input, output - seen.output);
2858
+ seen.input = input;
2859
+ seen.output = output;
2860
+ })
2861
+ };
2862
+ }
2863
+ #requestSignal(native) {
2864
+ const signals = [...native ? [native] : [], ...this.#active ? [this.#active.controller.signal] : []];
2865
+ return AbortSignal.any(signals);
2866
+ }
2867
+ async #recover(harness, replay) {
2868
+ for (const id of this.#stale) {
2869
+ this.#recordFatal(id, "CLOUD_EXECUTION_INTERRUPTED");
2870
+ const conversation = await harness.conversation(id, BACKGROUND_CONTEXT);
2871
+ if (conversation) {
2872
+ await conversation.abort(BACKGROUND_CONTEXT, { background: true });
2873
+ await conversation.waitForIdle(BACKGROUND_CONTEXT);
2874
+ }
2875
+ }
2876
+ for (const row2 of replay) {
2877
+ if (!this.#config || !this.#dispatcher) {
2878
+ this.ledger.finish(row2.invocationId, "failed", void 0, "CLOUD_EXECUTION_INTERRUPTED");
2879
+ continue;
2880
+ }
2881
+ await this.#runInvocation(row2, void 0, true).catch(() => void 0);
2882
+ }
2883
+ await this.#adjudicateRuns(harness);
2884
+ await this.#backfillTurns(harness);
2885
+ await this.cloud.rearmAlarm({ busy: false, repairRetrying: false });
2886
+ this.#recovered = true;
2887
+ this.#recoveryGuard?.dispose();
2888
+ this.#recoveryGuard = void 0;
2889
+ }
2890
+ async #backfillTurns(harness) {
2891
+ let before = Number.MAX_SAFE_INTEGER;
2892
+ for (; ; ) {
2893
+ const runs = this.cloud.pendingBackfills(before);
2894
+ if (!runs.length) return;
2895
+ for (const run of runs) {
2896
+ let seqs;
2897
+ try {
2898
+ const conversation = await harness.conversation(run.conversationId, BACKGROUND_CONTEXT);
2899
+ const view = conversation ? await conversation.context(BACKGROUND_CONTEXT) : void 0;
2900
+ seqs = view ? runInputSeqs(view.entries) : [];
2901
+ } catch {
2902
+ continue;
2903
+ }
2904
+ this.cloud.applyBackfill(run.conversationId, seqs);
2905
+ }
2906
+ before = runs[runs.length - 1].conversationId;
2907
+ }
2908
+ }
2909
+ async #execute(name, args, api, context) {
2910
+ try {
2911
+ return await this.#executeChecked(name, args, api, context);
2912
+ } catch (error) {
2913
+ const code = this.#toolErrorCode(error);
2914
+ this.#recordFatal(api.conversationId, code);
2915
+ try {
2916
+ if (error instanceof StaleInvocationAttempt) {
2917
+ const harness = await this.#opened;
2918
+ void harness.abortTask(api.taskId, BACKGROUND_CONTEXT).catch(() => void 0);
2919
+ await harness.getTask(api.taskId, BACKGROUND_CONTEXT);
2920
+ }
2921
+ } catch {
2922
+ }
2923
+ return this.#errorResult(code);
2924
+ }
2925
+ }
2926
+ async #executeChecked(name, args, api, context) {
2927
+ if (this.#stale.has(api.conversationId) || !this.#config || !this.#dispatcher) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2928
+ const task = await api.getTask(api.taskId, context);
2929
+ const input = task?.input;
2930
+ if (!input || typeof input !== "object" || Array.isArray(input) || typeof input.assistant !== "number") {
2931
+ throw new CloudDoError("CLOUD_TOOL_FAILED");
2932
+ }
2933
+ this.#guard().guardPayload(canonicalArgs({ name, id: api.callId, args }));
2934
+ const id = await invocationId(api.conversationId, input.assistant, api.callId);
2935
+ const execution = this.ledger.execution(api.conversationId);
2936
+ if (!execution) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2937
+ const begun = this.ledger.begin({
2938
+ invocationId: id,
2939
+ sessionId: this.#config.identity.sessionId,
2940
+ conversationId: api.conversationId,
2941
+ assistantEntryId: input.assistant,
2942
+ toolCallId: api.callId,
2943
+ toolName: name,
2944
+ argsDigest: await argsDigest(name, args),
2945
+ argsJson: canonicalArgs(args),
2946
+ replay: replayForTool(name),
2947
+ deadlineAt: Math.min(Date.now() + this.#limits().callTimeoutMs, execution.deadlineAt)
2948
+ });
2949
+ if (begun.kind === "pending") {
2950
+ const pending = this.#invocations.get(id);
2951
+ if (!pending) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
2952
+ await pending;
2953
+ } else if (begun.kind === "started") {
2954
+ const running = this.#runInvocation(begun.row, context.abortSignal, false);
2955
+ this.#invocations.set(id, running);
2956
+ try {
2957
+ await running;
2958
+ } finally {
2959
+ this.#invocations.delete(id);
2960
+ }
2961
+ }
2962
+ return this.#modelResult(this.ledger.read(id));
2963
+ }
2964
+ #modelResult(row2) {
2965
+ const result = this.#result(row2);
2966
+ const error = result.error;
2967
+ if (Object.hasOwn(result, "modelView")) return {
2968
+ isError: result.ok === false,
2969
+ content: [{ type: "text", text: JSON.stringify(result.modelView) }]
2970
+ };
2971
+ if (result.ok === false) {
2972
+ if (this.#dispatcher?.domainErrors?.includes(error.code)) return {
2973
+ isError: true,
2974
+ content: [{ type: "text", text: JSON.stringify({ ok: false, error }) }]
2975
+ };
2976
+ return this.#errorResult(error.code);
2977
+ }
2978
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
2979
+ }
2980
+ #errorResult(code) {
2981
+ const fixed = safeCloudError(new Error(typeof code === "string" ? code : "CLOUD_TOOL_FAILED")).code;
2982
+ return { isError: true, content: [{ type: "text", text: JSON.stringify({ ok: false, error: { code: fixed } }) }] };
2983
+ }
2984
+ #toolErrorCode(error) {
2985
+ const code = safeCloudError(error).code;
2986
+ return code === "CLOUD_MODEL_REQUEST_FAILED" ? "CLOUD_TOOL_FAILED" : code;
2987
+ }
2988
+ #recordFatal(conversationId, code) {
2989
+ let first = this.#fatalDispositions.get(conversationId);
2990
+ if (!first) {
2991
+ try {
2992
+ const stored = this.ledger.execution(conversationId)?.fatalCode;
2993
+ first = stored ? this.#toolErrorCode(new Error(stored)) : code;
2994
+ } catch {
2995
+ first = code;
2996
+ }
2997
+ this.#fatalDispositions.set(conversationId, first);
2998
+ }
2999
+ try {
3000
+ this.ledger.failExecution(conversationId, first);
3001
+ } catch {
3002
+ }
3003
+ return first;
3004
+ }
3005
+ #result(row2) {
3006
+ if (row2.state !== "succeeded" || row2.resultJson === null) throw new CloudDoError(row2.errorCode ?? "CLOUD_TOOL_FAILED");
3007
+ return JSON.parse(row2.resultJson);
3008
+ }
3009
+ async #runInvocation(row2, native, recovery) {
3010
+ const lease = recovery ? void 0 : this.#active;
3011
+ const controller = new AbortController();
3012
+ let deadline = row2.deadlineAt;
3013
+ const signals = [controller.signal, ...native ? [native] : [], ...lease ? [lease.controller.signal] : []];
3014
+ const signal = AbortSignal.any(signals);
3015
+ let timer;
3016
+ let removeAbort;
3017
+ try {
3018
+ deadline = Math.min(row2.deadlineAt, this.ledger.execution(row2.conversationId)?.deadlineAt ?? row2.deadlineAt);
3019
+ if (Date.now() >= deadline) throw new CloudDoError("CLOUD_TOOL_TIMEOUT");
3020
+ if (!this.#config || !this.#dispatcher) throw new CloudDoError("CLOUD_EXECUTION_INTERRUPTED");
3021
+ if (!recovery && this.fatal(row2.conversationId)) throw new CloudDoError(this.fatal(row2.conversationId));
3022
+ const args = JSON.parse(row2.argsJson);
3023
+ await admitCloudPayload(this.env, args, lease?.profile);
3024
+ if (Date.now() >= deadline) throw new CloudDoError(this.#timeoutCode(row2.conversationId));
3025
+ signal.throwIfAborted();
3026
+ const cancelled = new Promise((_resolve, reject) => {
3027
+ const abort = () => reject(new CloudDoError(Date.now() >= deadline ? Date.now() >= (this.ledger.execution(row2.conversationId)?.deadlineAt ?? Infinity) ? "CLOUD_EXECUTION_TIMEOUT" : "CLOUD_TOOL_TIMEOUT" : "CLOUD_EXECUTION_ABORTED"));
3028
+ signal.addEventListener("abort", abort, { once: true });
3029
+ removeAbort = () => signal.removeEventListener("abort", abort);
3030
+ if (signal.aborted) abort();
3031
+ });
3032
+ timer = setTimeout(() => controller.abort(), Math.max(0, deadline - Date.now()));
3033
+ await Promise.race([Promise.resolve().then(() => this.#renew({
3034
+ nativeRunId: row2.conversationId,
3035
+ requestId: this.cloud.readRun(row2.conversationId)?.requestId ?? null,
3036
+ kind: "tool",
3037
+ toolName: row2.toolName,
3038
+ recovery
3039
+ }, signal)), cancelled]);
3040
+ if (Date.now() >= deadline) throw new CloudDoError(this.#timeoutCode(row2.conversationId));
3041
+ signal.throwIfAborted();
3042
+ if (!recovery && this.fatal(row2.conversationId)) throw new CloudDoError(this.fatal(row2.conversationId));
3043
+ if ((this.ledger.execution(row2.conversationId)?.credits ?? 0) > CLOUD_BUDGET.credits) throw new CloudDoError("CLOUD_BUDGET_EXCEEDED");
3044
+ const usesFetchSlot = this.#dispatcher.tools.find((tool) => tool.name === row2.toolName)?.execution !== "pure";
3045
+ if (usesFetchSlot && this.#inline >= this.#limits().inlineFetches) throw new CloudDoError("CLOUD_TOOL_BUSY");
3046
+ if (usesFetchSlot) this.#inline++;
3047
+ const dispatchContext = Object.freeze({
3048
+ identity: Object.freeze({ ...this.#config.identity }),
3049
+ principal: Object.freeze({ ...this.#config.principal }),
3050
+ scopes: Object.freeze([...this.#config.scopes]),
3051
+ dispatcherId: this.#config.dispatcherId,
3052
+ call: Object.freeze({ invocationId: row2.invocationId, conversationId: row2.conversationId, toolCallId: row2.toolCallId, attempt: row2.attempt }),
3053
+ lookup: (id) => {
3054
+ const found = this.ledger.read(id);
3055
+ if (!found || found.sessionId !== this.#config?.identity.sessionId) return void 0;
3056
+ return Object.freeze({
3057
+ toolName: found.toolName,
3058
+ state: found.state,
3059
+ errorCode: found.errorCode,
3060
+ resultJson: found.resultJson,
3061
+ conversationId: found.conversationId,
3062
+ toolCallId: found.toolCallId,
3063
+ settledAt: found.settledAt,
3064
+ settledEventSeq: found.settledEventSeq
3065
+ });
3066
+ }
3067
+ });
3068
+ const dispatcher = this.#dispatcher;
3069
+ const work = Promise.resolve().then(() => {
3070
+ if (Date.now() >= deadline) throw new CloudDoError(this.#timeoutCode(row2.conversationId));
3071
+ signal.throwIfAborted();
3072
+ return dispatcher.execute(dispatchContext, row2.toolName, args, signal);
3073
+ });
3074
+ void work.finally(() => {
3075
+ if (usesFetchSlot) this.#inline--;
3076
+ }).catch(() => void 0);
3077
+ let result = await Promise.race([work, cancelled]);
3078
+ try {
3079
+ await admitCloudPayload(this.env, result, lease?.profile);
3080
+ result = JSON.parse(this.#guard().guardPayload(JSON.stringify(result)));
3081
+ } catch (error) {
3082
+ if (error instanceof CloudDoError && error.code === "CLOUD_USER_CREDENTIAL_REJECTED") {
3083
+ throw new CloudDoError("CLOUD_MODEL_RESPONSE_REJECTED");
3084
+ }
3085
+ throw error;
3086
+ }
3087
+ if (Object.hasOwn(result, "modelView") && !this.#dispatcher.modelViews) throw new CloudDoError("CLOUD_TOOL_FAILED");
3088
+ const usage = result.usage;
3089
+ if (!usage || typeof usage !== "object" || Array.isArray(usage) || !Number.isSafeInteger(usage.credits) || Number(usage.credits) < 0) {
3090
+ throw new CloudDoError("CLOUD_TOOL_USAGE_INVALID");
3091
+ }
3092
+ if (typeof result.ok !== "boolean" || result.ok && result.error != null) throw new CloudDoError("CLOUD_TOOL_FAILED");
3093
+ let responseFailure;
3094
+ if (result.ok === false) {
3095
+ const rawCode = result.error && typeof result.error === "object" && !Array.isArray(result.error) ? result.error.code : void 0;
3096
+ const domainCode = typeof rawCode === "string" && Object.hasOwn(CLOUD_DOMAIN_ERROR_CODES, rawCode) ? CLOUD_DOMAIN_ERROR_CODES[rawCode] : void 0;
3097
+ if (typeof rawCode === "string" && this.#dispatcher.domainErrors?.includes(rawCode)) {
3098
+ const rawError = result.error;
3099
+ const hasData = Object.hasOwn(rawError, "data");
3100
+ if (hasData && new TextEncoder().encode(JSON.stringify(rawError.data)).length > 2048) throw new CloudDoError("CLOUD_TOOL_RESULT_LIMIT");
3101
+ result = { ...result, error: { code: rawCode, ...hasData ? { data: rawError.data } : {} } };
3102
+ } else {
3103
+ const code = domainCode ?? "CLOUD_TOOL_FAILED";
3104
+ const bill = usage;
3105
+ result = { ok: false, error: { code }, usage: {
3106
+ credits: bill.credits,
3107
+ ...Number.isSafeInteger(bill.rows) && Number(bill.rows) >= 0 ? { rows: bill.rows } : {},
3108
+ ...typeof bill.cached === "boolean" ? { cached: bill.cached } : {}
3109
+ } };
3110
+ if (!domainCode) responseFailure = code;
3111
+ }
3112
+ }
3113
+ if (new TextEncoder().encode(JSON.stringify(result)).length > this.#limits().resultBytes) throw new CloudDoError("CLOUD_TOOL_RESULT_LIMIT");
3114
+ const settled = this.ledger.finish(row2.invocationId, "succeeded", result, void 0, Date.now(), {
3115
+ attempt: row2.attempt,
3116
+ clientConnected: recovery || lease?.connected === true,
3117
+ recovery,
3118
+ creditCap: CLOUD_BUDGET.credits
3119
+ });
3120
+ if (!settled) throw new CloudDoError("CLOUD_TOOL_FAILED");
3121
+ if (settled.attempt !== row2.attempt) throw new StaleInvocationAttempt();
3122
+ if (responseFailure && !recovery) this.#recordFatal(row2.conversationId, responseFailure);
3123
+ return this.#result(settled);
3124
+ } catch (error) {
3125
+ if (error instanceof StaleInvocationAttempt) throw error;
3126
+ const code = signal.aborted ? Date.now() >= deadline ? this.#timeoutCode(row2.conversationId) : "CLOUD_EXECUTION_ABORTED" : this.#toolErrorCode(error);
3127
+ const state = code === "CLOUD_TOOL_TIMEOUT" || code === "CLOUD_EXECUTION_TIMEOUT" ? "timed_out" : code === "CLOUD_EXECUTION_ABORTED" ? "aborted" : "failed";
3128
+ let settled;
3129
+ try {
3130
+ settled = this.ledger.finish(row2.invocationId, state, void 0, code, Date.now(), { attempt: row2.attempt, recovery });
3131
+ } catch {
3132
+ }
3133
+ if (settled && settled.attempt !== row2.attempt) throw new StaleInvocationAttempt();
3134
+ if (!recovery) this.#recordFatal(row2.conversationId, code);
3135
+ throw new CloudDoError(code);
3136
+ } finally {
3137
+ clearTimeout(timer);
3138
+ removeAbort?.();
3139
+ controller.abort();
3140
+ }
3141
+ }
3142
+ #timeoutCode(conversationId) {
3143
+ return Date.now() >= (this.ledger.execution(conversationId)?.deadlineAt ?? Infinity) ? "CLOUD_EXECUTION_TIMEOUT" : "CLOUD_TOOL_TIMEOUT";
3144
+ }
3145
+ };
3146
+
3147
+ // src/event-stream.ts
3148
+ var CloudEventDoorbell = class {
3149
+ generation = 0;
3150
+ listeners = /* @__PURE__ */ new Set();
3151
+ ring() {
3152
+ this.generation++;
3153
+ for (const listener of [...this.listeners]) listener();
3154
+ }
3155
+ get version() {
3156
+ return this.generation;
3157
+ }
3158
+ wait(version, signal, duration = 15e3) {
3159
+ return new Promise((resolve) => {
3160
+ let timer;
3161
+ const finish = () => {
3162
+ clearTimeout(timer);
3163
+ this.listeners.delete(finish);
3164
+ signal.removeEventListener("abort", finish);
3165
+ resolve();
3166
+ };
3167
+ timer = setTimeout(finish, duration);
3168
+ this.listeners.add(finish);
3169
+ signal.addEventListener("abort", finish, { once: true });
3170
+ if (signal.aborted || version !== this.generation) finish();
3171
+ });
3172
+ }
3173
+ };
3174
+ var CloudEventStreams = class {
3175
+ constructor(bell) {
3176
+ this.bell = bell;
3177
+ }
3178
+ bell;
3179
+ readers = 0;
3180
+ open(state, after, waitUntil) {
3181
+ if (this.readers >= 8) throw new CloudDoError("CLOUD_EVENTS_BUSY");
3182
+ const meta = state.eventMeta();
3183
+ const cursor = after === void 0 ? meta.highWater : after === 0 ? meta.trimmedThrough : after;
3184
+ try {
3185
+ state.eventPage(cursor, 1);
3186
+ } catch (error) {
3187
+ if (safeCloudError(error).code === "CLOUD_EVENT_CURSOR_EXPIRED") return Response.json({ error: { code: "CLOUD_EVENT_CURSOR_EXPIRED", retryable: false }, ...meta }, { status: 410 });
3188
+ throw error;
3189
+ }
3190
+ this.readers++;
3191
+ const body = new IdentityTransformStream();
3192
+ const writer = body.writable.getWriter();
3193
+ const controller = new AbortController();
3194
+ const encoder2 = new TextEncoder();
3195
+ let cleaned = false;
3196
+ let last = cursor;
3197
+ const close = () => {
3198
+ if (!cleaned) {
3199
+ cleaned = true;
3200
+ this.readers--;
3201
+ controller.abort();
3202
+ }
3203
+ };
3204
+ const limit = setTimeout(() => {
3205
+ close();
3206
+ void writer.abort().catch(() => void 0);
3207
+ }, 11e4);
3208
+ void writer.closed.catch(close);
3209
+ let probing = false;
3210
+ const probe = setInterval(() => {
3211
+ if (controller.signal.aborted || probing) return;
3212
+ probing = true;
3213
+ void writer.write(encoder2.encode(": keepalive\n\n")).catch(close).finally(() => {
3214
+ probing = false;
3215
+ });
3216
+ }, 250);
3217
+ const run = async () => {
3218
+ try {
3219
+ while (!controller.signal.aborted) {
3220
+ const version = this.bell.version;
3221
+ let rows;
3222
+ try {
3223
+ rows = state.eventPage(last);
3224
+ } catch (error) {
3225
+ if (safeCloudError(error).code !== "CLOUD_EVENT_CURSOR_EXPIRED") throw error;
3226
+ await writer.write(encoder2.encode("event: reset\ndata: " + JSON.stringify(state.eventMeta()) + "\n\n"));
3227
+ break;
3228
+ }
3229
+ for (const row2 of rows) {
3230
+ if (controller.signal.aborted) break;
3231
+ await writer.write(encoder2.encode("id: " + row2.seq + "\nevent: " + row2.type + "\ndata: " + row2.dataJson + "\n\n"));
3232
+ last = row2.seq;
3233
+ }
3234
+ if (!rows.length && !controller.signal.aborted) {
3235
+ await this.bell.wait(version, controller.signal);
3236
+ if (!controller.signal.aborted && version === this.bell.version) await writer.write(encoder2.encode(": keepalive\n\n"));
3237
+ }
3238
+ }
3239
+ try {
3240
+ await writer.close();
3241
+ } catch {
3242
+ }
3243
+ } catch {
3244
+ try {
3245
+ await writer.abort();
3246
+ } catch {
3247
+ }
3248
+ } finally {
3249
+ clearTimeout(limit);
3250
+ clearInterval(probe);
3251
+ close();
3252
+ }
3253
+ };
3254
+ waitUntil(run());
3255
+ return new Response(body.readable, { headers: { "content-type": "text/event-stream", "cache-control": "no-store" } });
3256
+ }
3257
+ };
3258
+ async function cloudRunHistory(runtime, harness) {
3259
+ const history = [];
3260
+ for (const run of runtime.cloud.completedRuns()) {
3261
+ const conversation = await harness.conversation(run.conversationId, BACKGROUND_CONTEXT);
3262
+ if (!conversation) continue;
3263
+ let view;
3264
+ try {
3265
+ view = await conversation.context(BACKGROUND_CONTEXT);
3266
+ } catch (error) {
3267
+ if (run.membershipPending === 1) continue;
3268
+ throw error;
3269
+ }
3270
+ const input = run.trigger === "wake" ? view.entries.find((entry2) => entry2.kind === "byok.run-input")?.data : view.entries.find((entry2) => entry2.kind === "pi.user")?.model?.find((message) => message.role === "user")?.content;
3271
+ const entry = [...view.entries].reverse().find((entry2) => entry2.kind === "pi.assistant");
3272
+ const reply = entry?.model?.find((message) => message.role === "assistant");
3273
+ if (input === void 0 || reply?.role !== "assistant") continue;
3274
+ history.push({ input, reply: reply.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("") });
3275
+ }
3276
+ return history;
3277
+ }
3278
+ async function committedRunOutcome(conversation, runtime, status2, detail) {
3279
+ const view = await conversation.context(BACKGROUND_CONTEXT);
3280
+ const entry = [...view.entries].reverse().find((entry2) => entry2.kind === "pi.assistant");
3281
+ const last = entry?.model?.find((message) => message.role === "assistant");
3282
+ const failure = runtime.fatal(conversation.id) ?? (last?.role === "assistant" && (last.stopReason === "error" || last.stopReason === "aborted") ? safeCloudError(new Error(last.errorMessage)).code : void 0) ?? (status2 !== "done" ? safeCloudError(new Error(typeof detail === "string" ? detail : "")).code : void 0);
3283
+ if (failure) return { state: "failed", errorCode: failure };
3284
+ return {
3285
+ state: "completed",
3286
+ entryId: entry?.id,
3287
+ text: last?.role === "assistant" ? last.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("") : ""
3288
+ };
3289
+ }
3290
+ async function runCloudWake(runtime, harness, env, admit, notify, retryCount = 0) {
3291
+ const guard = await runtime.prepareGuard();
3292
+ let lease;
3293
+ let conversation;
3294
+ let selected = [];
3295
+ let settling = false;
3296
+ try {
3297
+ runtime.cloud.expireQueued(guard);
3298
+ runtime.cloud.retention();
3299
+ selected = runtime.cloud.selectBatch(Date.now(), guard);
3300
+ notify();
3301
+ if (!selected.length) {
3302
+ await runtime.cloud.rearmAlarm({ busy: runtime.hasLiveOwner, repairRetrying: runtime.repairRetrying });
3303
+ return false;
3304
+ }
3305
+ lease = runtime.reserve(selected[0].profile, guard);
3306
+ const profile = PLATFORM_PROFILES[lease.profile];
3307
+ conversation = await harness.createConversation({
3308
+ ownership: { kind: "ownerless" },
3309
+ agent: runtime.agentChange(lease.profile, guard)
3310
+ }, BACKGROUND_CONTEXT);
3311
+ runtime.attach(lease, conversation.id, "wake", guard);
3312
+ const identity = admissionIdentity(selected);
3313
+ runtime.markReservation(conversation.id, "pending", identity);
3314
+ const key = runtime.cloud.readRun(conversation.id).requestId;
3315
+ const admission = await raceLease(Promise.resolve().then(() => admit(
3316
+ Object.freeze(selected.map((row2) => Object.freeze({ ...row2 }))),
3317
+ lease.controller.signal,
3318
+ key,
3319
+ identity
3320
+ )), lease);
3321
+ if (!admission || typeof admission !== "object" || typeof admission.accepted !== "boolean") throw new CloudDoError("CLOUD_REQUEST_INVALID");
3322
+ if (!admission.accepted) {
3323
+ runtime.markReservation(conversation.id, "none");
3324
+ throw safeCloudError(new Error(admission.code));
3325
+ }
3326
+ if (admission.reservation !== "held" && admission.reservation !== "none") throw new CloudDoError("CLOUD_REQUEST_INVALID");
3327
+ runtime.markReservation(conversation.id, admission.reservation);
3328
+ await platformCredentialReader(env).get(profile.secretName);
3329
+ const claimed = runtime.claimWake(lease, selected.map((row2) => row2.seq));
3330
+ notify();
3331
+ if (!claimed.length) {
3332
+ const closed = runtime.cloud.readRun(conversation.id);
3333
+ if (closed?.errorCode && closed.errorCode !== "CLOUD_WAKE_EMPTY") throw new CloudDoError(closed.errorCode);
3334
+ return true;
3335
+ }
3336
+ const inputs = { items: inboxInput(claimed) };
3337
+ const data = JSON.parse(guard.guardPayload(JSON.stringify(inputs)));
3338
+ await conversation.commit((tx) => {
3339
+ if (lease.controller.signal.aborted) throw new CloudDoError(runtime.fatal(conversation.id) ?? "CLOUD_EXECUTION_ABORTED");
3340
+ return tx.appendEntry(conversation.id, { kind: "byok.run-input", data });
3341
+ }, BACKGROUND_CONTEXT);
3342
+ const committed = (await conversation.context(BACKGROUND_CONTEXT)).entries.find((entry) => entry.kind === "byok.run-input")?.data;
3343
+ const durable = claimed.filter((row2) => committed?.items.some((item) => item.seq === row2.seq && item.text === JSON.parse(row2.payloadJson).text)).map((row2) => row2.seq);
3344
+ runtime.cloud.markInputDurable(conversation.id, durable);
3345
+ const content = composeCloudInput(claimed, await cloudRunHistory(runtime, harness));
3346
+ guard.guardText(content);
3347
+ const submission = await conversation.submit({ type: "input", content, whenBusy: "reject", requestId: key }, BACKGROUND_CONTEXT);
3348
+ runtime.recordSubmission(conversation.id, submission.id);
3349
+ const settled = await submission.wait(BACKGROUND_CONTEXT);
3350
+ await conversation.waitForIdle(BACKGROUND_CONTEXT);
3351
+ const outcome = await committedRunOutcome(conversation, runtime, settled.status, settled.status === "unanswered" ? settled.detail : void 0);
3352
+ settling = true;
3353
+ await runtime.settle(lease, outcome);
3354
+ } catch (error) {
3355
+ if (!lease || error instanceof CloudDoError && error.code === "CLOUD_TOOL_BUSY") {
3356
+ if (error instanceof CloudDoError && error.code === "CLOUD_TOOL_BUSY") return false;
3357
+ throw safeCloudError(error);
3358
+ }
3359
+ if (settling || !(error instanceof CloudDoError)) throw safeCloudError(error);
3360
+ const code = (lease.conversationId === void 0 ? void 0 : runtime.fatal(lease.conversationId)) ?? safeCloudError(error).code;
3361
+ runtime.cloud.failQueued(selected.map((row2) => row2.seq), code, guard);
3362
+ if (conversation && runtime.cloud.readRun(conversation.id)?.state === "running") {
3363
+ runtime.cancel(lease, code);
3364
+ await conversation.abort(BACKGROUND_CONTEXT, { background: true });
3365
+ await conversation.waitForIdle(BACKGROUND_CONTEXT);
3366
+ }
3367
+ if (conversation) {
3368
+ settling = true;
3369
+ await runtime.settle(lease, { state: "interrupted", errorCode: code });
3370
+ }
3371
+ notify();
3372
+ } finally {
3373
+ if (lease) await runtime.release(lease, retryCount);
3374
+ else guard.dispose();
3375
+ }
3376
+ return lease !== void 0;
3377
+ }
3378
+
3379
+ // src/agent-do.ts
3380
+ function modelFailureCode(message) {
3381
+ return safeCloudError(new Error(message)).code;
3382
+ }
3383
+ function assistantText(message) {
3384
+ return message.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("");
3385
+ }
3386
+ function finalAssistant(entries) {
3387
+ const entry = [...entries].reverse().find((entry2) => entry2.kind === "pi.assistant" && entry2.model?.some((message) => message.role === "assistant" && message.stopReason !== "toolUse"));
3388
+ const assistant = entry?.model?.find((message) => message.role === "assistant" && message.stopReason !== "toolUse");
3389
+ return assistant?.role === "assistant" && entry ? { entry, assistant } : void 0;
3390
+ }
3391
+ function inputTexts(entries) {
3392
+ const seqs = new Set(runInputSeqs(entries));
3393
+ if (!seqs.size) return /* @__PURE__ */ new Map();
3394
+ const data = entries.find((entry) => entry.kind === "byok.run-input")?.data;
3395
+ return new Map((data?.items ?? []).filter((item) => seqs.has(item.seq)).map((item) => [item.seq, item.text]));
3396
+ }
3397
+ function transcriptRecord(value, keys) {
3398
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3399
+ const result = {};
3400
+ for (const key of Reflect.ownKeys(value)) {
3401
+ const field = Object.getOwnPropertyDescriptor(value, key);
3402
+ if (typeof key !== "string" || !keys.includes(key) || !field?.enumerable || !("value" in field)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3403
+ result[key] = field.value;
3404
+ }
3405
+ return result;
3406
+ }
3407
+ function projectText(blocks, event) {
3408
+ const replace = (message) => {
3409
+ blocks.clear();
3410
+ message.content.forEach((block, index) => {
3411
+ if (block.type === "text") blocks.set(index, block.text);
3412
+ });
3413
+ };
3414
+ if (event.type === "message_start" && event.message.role === "assistant") replace(event.message);
3415
+ else if (event.type === "snapshot" && event.generation?.message) replace(event.generation.message);
3416
+ else if (event.type === "message_update") {
3417
+ for (const change of event.changes) {
3418
+ if (change.type === "text_delta") blocks.set(change.contentIndex, (blocks.get(change.contentIndex) ?? "") + change.delta);
3419
+ if (change.type === "text_start" || change.type === "block") {
3420
+ if (change.block.type === "text") blocks.set(change.contentIndex, change.block.text);
3421
+ else blocks.delete(change.contentIndex);
3422
+ }
3423
+ if (change.type === "message") replace(change.message);
3424
+ }
3425
+ } else if (event.type === "message_end" && event.entry.model?.[0]?.role === "assistant") return assistantText(event.entry.model[0]);
3426
+ else return void 0;
3427
+ return [...blocks.entries()].sort(([a], [b]) => a - b).map(([, text2]) => text2).join("");
3428
+ }
3429
+ var AgentDO = class extends DurableObject {
3430
+ #runtime;
3431
+ #doorbell = new CloudEventDoorbell();
3432
+ #eventStreams = new CloudEventStreams(this.#doorbell);
3433
+ /** The consuming Worker supplies trusted code. No executable function is persisted. */
3434
+ createDispatcher(_id) {
3435
+ return void 0;
3436
+ }
3437
+ /** Post-commit notification. Consumer failures never change the invocation outcome. */
3438
+ onInvocationSettled(_id, _state) {
3439
+ }
3440
+ projectInvocation(_row) {
3441
+ return void 0;
3442
+ }
3443
+ /** The consumer owns billing truth and fences every pending admission key on release. */
3444
+ admitWake(_items, _signal, _key, _admission) {
3445
+ return { accepted: true, reservation: "none" };
3446
+ }
3447
+ instructions(_profile) {
3448
+ return void 0;
3449
+ }
3450
+ renew(_request, _signal) {
3451
+ return { ok: true };
3452
+ }
3453
+ settleRun(_run, _signal) {
3454
+ }
3455
+ sessionRuntime() {
3456
+ return this.#runtime ??= new SessionRuntime(this.ctx, this.env, {
3457
+ createDispatcher: (id) => this.createDispatcher(id),
3458
+ projectInvocation: (row2) => this.projectInvocation(row2),
3459
+ onCommit: () => this.#doorbell.ring(),
3460
+ onInvocationSettled: (id, state) => this.onInvocationSettled(id, state),
3461
+ instructions: (profile) => this.instructions(profile),
3462
+ renew: (request, signal) => this.renew(request, signal),
3463
+ settleRun: (run, signal) => this.settleRun(run, signal)
3464
+ });
3465
+ }
3466
+ async configureSession(input) {
3467
+ try {
3468
+ await this.sessionRuntime().configure(input);
3469
+ return Response.json({ configured: true });
3470
+ } catch (error) {
3471
+ return cloudErrorResponse(error);
3472
+ }
3473
+ }
3474
+ async readInvocation(id) {
3475
+ await this.sessionRuntime().ready();
3476
+ if (typeof id !== "string" || !/^[a-f0-9]{64}$/.test(id)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3477
+ return this.sessionRuntime().readInvocation(id);
3478
+ }
3479
+ async enqueue(input) {
3480
+ let guard;
3481
+ try {
3482
+ const admitted = admitCloudInbox(input);
3483
+ const runtime = this.sessionRuntime();
3484
+ guard = await runtime.prepareGuard();
3485
+ runtime.cloud.validateEnqueue(admitted, guard);
3486
+ await runtime.ready();
3487
+ const result = await runtime.cloud.enqueue(admitted, guard, Date.now(), {
3488
+ busy: runtime.hasLiveOwner,
3489
+ repairRetrying: runtime.repairRetrying
3490
+ });
3491
+ this.#doorbell.ring();
3492
+ return Response.json({ accepted: result.accepted, ...result.row });
3493
+ } catch (error) {
3494
+ return cloudErrorResponse(error);
3495
+ } finally {
3496
+ guard?.dispose();
3497
+ }
3498
+ }
3499
+ /** The platform supplies retryCount. This handler never replaces a live owner. */
3500
+ async alarm(info) {
3501
+ const runtime = this.sessionRuntime();
3502
+ let harness;
3503
+ try {
3504
+ harness = await runtime.ready();
3505
+ } catch (error) {
3506
+ if (runtime.recovering) return;
3507
+ throw safeCloudError(error);
3508
+ }
3509
+ if (runtime.hasLiveOwner) {
3510
+ const guard = runtime.activeLease?.guard;
3511
+ if (guard) runtime.cloud.expireQueued(guard);
3512
+ runtime.cloud.retention();
3513
+ this.#doorbell.ring();
3514
+ if (runtime.cloud.unackedRuns().length) await runtime.deliverSettlementsForAlarm(info?.retryCount ?? 0, guard);
3515
+ else await runtime.cloud.rearmAlarm({ busy: true, repairRetrying: runtime.repairRetrying });
3516
+ return;
3517
+ }
3518
+ try {
3519
+ await runtime.repairPendingRuns(info?.retryCount ?? 0);
3520
+ if (runtime.busy) return;
3521
+ const woke = await runCloudWake(
3522
+ runtime,
3523
+ harness,
3524
+ this.env,
3525
+ (items, signal, key, admission) => this.admitWake(items, signal, key, admission),
3526
+ () => this.#doorbell.ring(),
3527
+ info?.retryCount ?? 0
3528
+ );
3529
+ if (!woke) await runtime.deliverSettlementsForAlarm(info?.retryCount ?? 0);
3530
+ } catch (error) {
3531
+ throw safeCloudError(error);
3532
+ }
3533
+ }
3534
+ async events(input = {}) {
3535
+ try {
3536
+ const fields2 = this.#readOptions(input, ["after"]);
3537
+ const runtime = this.sessionRuntime();
3538
+ await runtime.ready();
3539
+ return this.#eventStreams.open(runtime.cloud, fields2.after, (work) => this.ctx.waitUntil(work));
3540
+ } catch (error) {
3541
+ return cloudErrorResponse(error);
3542
+ }
3543
+ }
3544
+ async readSnapshot() {
3545
+ await this.sessionRuntime().ready();
3546
+ return this.sessionRuntime().cloud.snapshot();
3547
+ }
3548
+ async readRuns(input = {}) {
3549
+ await this.sessionRuntime().ready();
3550
+ return this.sessionRuntime().cloud.readRuns(this.#readOptions(input, ["after", "limit"]));
3551
+ }
3552
+ async readInbox(input = {}) {
3553
+ await this.sessionRuntime().ready();
3554
+ return this.sessionRuntime().cloud.readInbox(this.#readOptions(input, ["after", "limit"]));
3555
+ }
3556
+ async readInvocations(input = {}) {
3557
+ await this.sessionRuntime().ready();
3558
+ return this.sessionRuntime().cloud.readInvocations(this.#readOptions(input, ["after", "limit"]));
3559
+ }
3560
+ async readTranscript(input = {}) {
3561
+ const options = transcriptRecord(input, ["after", "limit"]);
3562
+ const limit = options.limit === void 0 ? 20 : options.limit;
3563
+ if (typeof limit !== "number" || !Number.isSafeInteger(limit) || limit < 1 || limit > 50) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3564
+ let after;
3565
+ if (options.after !== void 0) {
3566
+ const cursor = transcriptRecord(options.after, ["horizon", "run", "item"]);
3567
+ if (Object.keys(cursor).length !== 3 || typeof cursor.horizon !== "number" || !Number.isSafeInteger(cursor.horizon) || cursor.horizon < 0 || [cursor.run, cursor.item].some((value) => value !== null && (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0))) {
3568
+ throw new CloudDoError("CLOUD_REQUEST_INVALID");
3569
+ }
3570
+ after = cursor;
3571
+ }
3572
+ const runtime = this.sessionRuntime();
3573
+ const harness = await runtime.ready();
3574
+ const plan = runtime.cloud.planTranscript(after, limit);
3575
+ const contexts = /* @__PURE__ */ new Map();
3576
+ const entries = (id) => {
3577
+ const cached = contexts.get(id);
3578
+ if (cached) return cached;
3579
+ const read = harness.conversation(id, BACKGROUND_CONTEXT).then(async (conversation) => conversation ? (await conversation.context(BACKGROUND_CONTEXT)).entries : []).catch((error) => {
3580
+ if (runtime.cloud.readRun(id)?.membershipPending === 1) return [];
3581
+ throw error;
3582
+ });
3583
+ contexts.set(id, read);
3584
+ return read;
3585
+ };
3586
+ const runs = [];
3587
+ for (const { run, turns, invocations } of plan.runs) {
3588
+ const claimedSeqs = runtime.cloud.claimedSeqs(run.conversationId);
3589
+ const view = await entries(run.conversationId);
3590
+ const texts = inputTexts(view);
3591
+ const final = finalAssistant(view);
3592
+ const result = {
3593
+ nativeRunId: run.conversationId,
3594
+ revision: run.revision,
3595
+ state: run.state,
3596
+ errorCode: run.errorCode,
3597
+ trigger: run.trigger,
3598
+ settlementAck: run.settlementAck === null || run.settlementAck === 1,
3599
+ claimedSeqs,
3600
+ turns: turns.map((turn) => ({ ...turn, text: texts.get(turn.seq) ?? turn.text })),
3601
+ invocations
3602
+ };
3603
+ if (final) {
3604
+ const text2 = assistantText(final.assistant);
3605
+ const truncated = new TextEncoder().encode(text2).length > 16384;
3606
+ result.text = truncated ? utf8Prefix(text2, 1024) : text2;
3607
+ if (truncated) result.truncated = true;
3608
+ }
3609
+ runs.push(result);
3610
+ }
3611
+ for (const item of plan.items) if (item.text === null && item.runId !== null) {
3612
+ item.text = inputTexts(await entries(item.runId)).get(item.seq) ?? null;
3613
+ }
3614
+ return { runs, items: plan.items, next: plan.next };
3615
+ }
3616
+ #readOptions(input, allowed) {
3617
+ if (!input || typeof input !== "object" || Array.isArray(input) || Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3618
+ const result = {};
3619
+ for (const key of Reflect.ownKeys(input)) {
3620
+ const field = Object.getOwnPropertyDescriptor(input, key);
3621
+ if (typeof key !== "string" || !allowed.includes(key) || !field?.enumerable || !("value" in field) || field.value !== void 0 && typeof field.value !== "number") throw new CloudDoError("CLOUD_REQUEST_INVALID");
3622
+ result[key] = field.value;
3623
+ }
3624
+ return result;
3625
+ }
3626
+ async readRunOutput(conversationId, input = {}) {
3627
+ if (!Number.isSafeInteger(conversationId) || conversationId < 2) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3628
+ const options = this.#readOptions(input, ["entryId", "offset"]);
3629
+ const runtime = this.sessionRuntime();
3630
+ const harness = await runtime.ready();
3631
+ if (!runtime.cloud.readRun(conversationId)) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3632
+ const conversation = await harness.conversation(conversationId, BACKGROUND_CONTEXT);
3633
+ if (!conversation) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3634
+ const context = await conversation.context(BACKGROUND_CONTEXT);
3635
+ const final = finalAssistant(context.entries);
3636
+ if (!final || options.entryId !== void 0 && options.entryId !== final.entry.id) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3637
+ const { entry, assistant } = final;
3638
+ const bytes = new TextEncoder().encode(assistantText(assistant));
3639
+ const offset = options.offset ?? 0;
3640
+ if (!Number.isSafeInteger(offset) || offset < 0 || offset > bytes.length || offset < bytes.length && (bytes[offset] & 192) === 128) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3641
+ let end = Math.min(bytes.length, offset + 65536);
3642
+ while (end < bytes.length && (bytes[end] & 192) === 128) end--;
3643
+ return {
3644
+ entryId: entry.id,
3645
+ offset,
3646
+ nextOffset: end,
3647
+ done: end === bytes.length,
3648
+ text: new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(offset, end))
3649
+ };
3650
+ }
3651
+ async cancelActiveRun() {
3652
+ try {
3653
+ const runtime = this.sessionRuntime();
3654
+ await runtime.ready();
3655
+ return Response.json({ cancelled: runtime.cancelActive() });
3656
+ } catch (error) {
3657
+ return cloudErrorResponse(error);
3658
+ }
3659
+ }
3660
+ async cancelInboxItem(seq) {
3661
+ let guard;
3662
+ try {
3663
+ if (!Number.isSafeInteger(seq) || seq < 1) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3664
+ const runtime = this.sessionRuntime();
3665
+ await runtime.ready();
3666
+ const row2 = runtime.cloud.readInboxItem(seq);
3667
+ if (!row2) throw new CloudDoError("CLOUD_REQUEST_INVALID");
3668
+ if (row2.state === "running") {
3669
+ if (runtime.activeLease?.conversationId === row2.runId) runtime.cancelActive();
3670
+ } else if (row2.state === "queued") {
3671
+ guard = await runtime.prepareGuard();
3672
+ runtime.cloud.cancelQueued(seq, guard);
3673
+ }
3674
+ await runtime.cloud.rearmAlarm({ busy: runtime.hasLiveOwner, repairRetrying: runtime.repairRetrying });
3675
+ this.#doorbell.ring();
3676
+ return Response.json({ item: runtime.cloud.readInboxItem(seq) });
3677
+ } catch (error) {
3678
+ return cloudErrorResponse(error);
3679
+ } finally {
3680
+ guard?.dispose();
3681
+ }
3682
+ }
3683
+ // Admission and credential preflight happen before even schema initialization.
3684
+ #harness() {
3685
+ return this.sessionRuntime().open();
3686
+ }
3687
+ async open() {
3688
+ const harness = await this.#harness();
3689
+ return { scheduling: (await harness.inspect(BACKGROUND_CONTEXT)).scheduling };
3690
+ }
3691
+ /** D1: every call allocates a new ownerless conversation, including after a restart. */
3692
+ async openExecution() {
3693
+ const harness = await this.#harness();
3694
+ const conversation = await harness.createConversation({ ownership: { kind: "ownerless" } }, BACKGROUND_CONTEXT);
3695
+ return { conversationId: conversation.id };
3696
+ }
3697
+ async #execution(id) {
3698
+ if (!Number.isSafeInteger(id) || id < 2) throw new Error("Invalid execution conversation");
3699
+ const conversation = await (await this.#harness()).conversation(id, BACKGROUND_CONTEXT);
3700
+ if (!conversation) throw new Error("Unknown execution conversation");
3701
+ return conversation;
3702
+ }
3703
+ async #admitText(text2, selected) {
3704
+ await admitCloudText(this.env, text2, selected);
3705
+ }
3706
+ /** Passive native pi entries prove storage without starting a model or tool task. */
3707
+ async appendExecution(conversationId, text2) {
3708
+ if (typeof text2 !== "string") throw new Error("Execution text must be a string");
3709
+ await this.#admitText(text2);
3710
+ const conversation = await this.#execution(conversationId);
3711
+ await conversation.commit((tx) => tx.appendEntry(conversation.id, { kind: "byok.execution", data: { text: text2 } }), BACKGROUND_CONTEXT);
3712
+ }
3713
+ async readExecution(conversationId) {
3714
+ const conversation = await this.#execution(conversationId);
3715
+ const context = await conversation.context(BACKGROUND_CONTEXT);
3716
+ return context.entries.filter((entry) => entry.kind === "byok.execution").map((entry) => {
3717
+ const data = entry.data;
3718
+ return data.text;
3719
+ });
3720
+ }
3721
+ /** Binding/RPC-only. The consumer authorizes identity before obtaining this stub.
3722
+ * Errors are structured Responses so the same code/status survive DO RPC. */
3723
+ async submit(input) {
3724
+ let lease;
3725
+ let guard;
3726
+ try {
3727
+ const admitted = admitCloudSubmission(input);
3728
+ const profile = PLATFORM_PROFILES[admitted.profile];
3729
+ await platformCredentialReader(this.env).get(profile.secretName);
3730
+ await this.#admitText(admitted.instruction, admitted.profile);
3731
+ const runtime = this.sessionRuntime();
3732
+ const harness = await runtime.ready(admitted.profile);
3733
+ guard = await runtime.prepareGuard(admitted.profile);
3734
+ lease = runtime.reserve(admitted.profile, guard);
3735
+ const conversation = await harness.createConversation({
3736
+ ownership: { kind: "ownerless" },
3737
+ agent: runtime.agentChange(admitted.profile, guard)
3738
+ }, BACKGROUND_CONTEXT);
3739
+ const execution = lease;
3740
+ runtime.attach(execution, conversation.id);
3741
+ const events = await watchEvents(harness, conversation.id, BACKGROUND_CONTEXT);
3742
+ const encoder2 = new TextEncoder();
3743
+ let bodyController;
3744
+ const body = new TransformStream({ start(controller) {
3745
+ bodyController = controller;
3746
+ } });
3747
+ const writer = body.writable.getWriter();
3748
+ let cancelled = false;
3749
+ let aborting;
3750
+ let failure;
3751
+ let released = "";
3752
+ const textBlocks = /* @__PURE__ */ new Map();
3753
+ const deliveryGraceMs = 250;
3754
+ let deliveryTimer;
3755
+ const stopDelivery = () => {
3756
+ cancelled = true;
3757
+ clearTimeout(deliveryTimer);
3758
+ clearInterval(probe);
3759
+ bodyController.error(new CloudDoError("CLOUD_EXECUTION_ABORTED"));
3760
+ void writer.abort().catch(() => void 0);
3761
+ };
3762
+ const boundAbortedDelivery = () => {
3763
+ if (cancelled) return;
3764
+ clearTimeout(deliveryTimer);
3765
+ deliveryTimer = setTimeout(stopDelivery, deliveryGraceMs);
3766
+ };
3767
+ deliveryTimer = setTimeout(stopDelivery, Math.max(0, execution.deadlineAt - Date.now()) + deliveryGraceMs);
3768
+ execution.controller.signal.addEventListener("abort", boundAbortedDelivery, { once: true });
3769
+ if (execution.controller.signal.aborted) boundAbortedDelivery();
3770
+ const cancel = () => {
3771
+ stopDelivery();
3772
+ if (!aborting && !execution.settled && execution.liveOwner) {
3773
+ runtime.cancel(execution);
3774
+ aborting = conversation.abort(BACKGROUND_CONTEXT).finally(() => events.stop()).catch(() => void 0);
3775
+ }
3776
+ return aborting;
3777
+ };
3778
+ void writer.closed.catch(cancel);
3779
+ const write = async (value) => {
3780
+ if (cancelled) return;
3781
+ try {
3782
+ await writer.write(encoder2.encode(`data: ${JSON.stringify(value)}
3783
+
3784
+ `));
3785
+ } catch {
3786
+ void cancel();
3787
+ }
3788
+ };
3789
+ let probing = false;
3790
+ const probe = setInterval(() => {
3791
+ if (cancelled || probing) return;
3792
+ probing = true;
3793
+ void writer.write(encoder2.encode(": keepalive\n\n")).catch(() => cancel()).finally(() => {
3794
+ probing = false;
3795
+ });
3796
+ }, 250);
3797
+ const publish = async (text2) => {
3798
+ if (text2.startsWith(released) && text2.length > released.length) {
3799
+ const delta = text2.slice(released.length);
3800
+ released = text2;
3801
+ await write({ type: "text_delta", delta });
3802
+ }
3803
+ };
3804
+ events.start(async (batch) => {
3805
+ for (const event of batch) {
3806
+ if (event.type === "message_start" && event.message.role === "assistant") released = "";
3807
+ const text2 = projectText(textBlocks, event);
3808
+ if (text2 !== void 0) await publish(text2);
3809
+ if (event.type === "message_end") {
3810
+ const message = event.entry.model?.[0];
3811
+ if (message?.role === "assistant" && message.stopReason === "error") {
3812
+ failure = modelFailureCode(message.errorMessage);
3813
+ }
3814
+ }
3815
+ if (event.type === "task_failed") failure ??= runtime.fatal(conversation.id) ?? "CLOUD_MODEL_REQUEST_FAILED";
3816
+ }
3817
+ });
3818
+ const run = async () => {
3819
+ let outcomeWriting = false;
3820
+ let ownerReleased = false;
3821
+ const release = async () => {
3822
+ if (ownerReleased) return;
3823
+ ownerReleased = true;
3824
+ await runtime.release(execution);
3825
+ };
3826
+ try {
3827
+ const submission = await conversation.submit({ type: "input", content: admitted.instruction, whenBusy: "reject", requestId: runtime.cloud.readRun(conversation.id).requestId }, BACKGROUND_CONTEXT);
3828
+ runtime.recordSubmission(conversation.id, submission.id);
3829
+ const settled = await submission.wait(BACKGROUND_CONTEXT);
3830
+ await conversation.waitForIdle(BACKGROUND_CONTEXT);
3831
+ const stopped = await events.stop();
3832
+ const context = await conversation.context(BACKGROUND_CONTEXT);
3833
+ const last = [...context.entries].reverse().find((entry) => entry.kind === "pi.assistant")?.model?.[0];
3834
+ if (last?.role === "assistant" && last.stopReason === "error") failure = modelFailureCode(last.errorMessage);
3835
+ failure = runtime.fatal(conversation.id) ?? failure;
3836
+ if (settled.status !== "done" || stopped.reason === "listener_error") failure ??= "CLOUD_MODEL_REQUEST_FAILED";
3837
+ const outcome = await committedRunOutcome(conversation, runtime, settled.status, settled.status === "unanswered" ? settled.detail : void 0);
3838
+ if (failure) {
3839
+ outcome.state = "failed";
3840
+ outcome.errorCode = modelFailureCode(failure);
3841
+ delete outcome.text;
3842
+ }
3843
+ outcomeWriting = true;
3844
+ await runtime.settle(execution, outcome);
3845
+ const committed = runtime.cloud.readRun(conversation.id);
3846
+ if (committed?.state !== "completed") failure = committed?.errorCode ?? "CLOUD_MODEL_REQUEST_FAILED";
3847
+ await release();
3848
+ if (last?.role === "assistant") await publish(assistantText(last));
3849
+ if (failure) await write({ type: "error", code: failure, retryable: false });
3850
+ else await write({ type: "done", conversationId: conversation.id });
3851
+ } catch (error) {
3852
+ const code = runtime.fatal(conversation.id) ?? safeCloudError(error).code;
3853
+ await events.stop();
3854
+ if (!outcomeWriting && error instanceof CloudDoError && runtime.cloud.readRun(conversation.id)?.state === "running") {
3855
+ runtime.cancel(execution, code);
3856
+ await conversation.abort(BACKGROUND_CONTEXT, { background: true });
3857
+ await conversation.waitForIdle(BACKGROUND_CONTEXT);
3858
+ await runtime.settle(execution, { state: "failed", errorCode: code });
3859
+ }
3860
+ await release();
3861
+ await write({ type: "error", code, retryable: false });
3862
+ } finally {
3863
+ try {
3864
+ await release();
3865
+ if (!cancelled) {
3866
+ try {
3867
+ await writer.close();
3868
+ } catch {
3869
+ void cancel();
3870
+ }
3871
+ }
3872
+ } finally {
3873
+ clearInterval(probe);
3874
+ clearTimeout(deliveryTimer);
3875
+ execution.controller.signal.removeEventListener("abort", boundAbortedDelivery);
3876
+ if (!cancelled) stopDelivery();
3877
+ }
3878
+ }
3879
+ };
3880
+ this.ctx.waitUntil(run());
3881
+ return new Response(body.readable, { headers: { "content-type": "text/event-stream", "cache-control": "no-store" } });
3882
+ } catch (error) {
3883
+ if (lease) await this.sessionRuntime().release(lease);
3884
+ else guard?.dispose();
3885
+ return cloudErrorResponse(error);
3886
+ }
3887
+ }
3888
+ };
3889
+
3890
+ // src/identity.ts
3891
+ async function agentObjectName(identity) {
3892
+ const ids = [identity.tenantId, identity.workspaceId, identity.agentId];
3893
+ if (ids.some((id) => typeof id !== "string" || !id)) throw new Error("Agent identity requires three nonempty ids");
3894
+ const digest2 = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify(ids)));
3895
+ return `agent:${Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
3896
+ }
3897
+ async function getAgentObject(namespace, identity) {
3898
+ return namespace.getByName(await agentObjectName(identity));
3899
+ }
3900
+ async function sessionObjectName(identity) {
3901
+ const ids = [identity.tenantId, identity.workspaceId, identity.agentId, identity.sessionId];
3902
+ if (ids.some((id) => typeof id !== "string" || !id)) throw new Error("Session identity requires four nonempty ids");
3903
+ const digest2 = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify(ids)));
3904
+ return `session:${Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
3905
+ }
3906
+ async function getSessionObject(namespace, identity) {
3907
+ return namespace.getByName(await sessionObjectName(identity));
3908
+ }
3909
+
3910
+ // src/index.ts
3911
+ var index_default = { fetch: () => new Response("Not found", { status: 404 }) };
3912
+
3913
+ export { AgentDO, CLOUD_LIVE_IPO_TOOLS, CLOUD_SAFE_REPLAY_TOOLS, DurableObjectSqliteDatabase, agentObjectName, index_default as default, getAgentObject, getSessionObject, openDurableObjectStorage, sessionObjectName };
3914
+ //# sourceMappingURL=index.js.map
3915
+ //# sourceMappingURL=index.js.map