stitchkit 0.56.4 → 0.57.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.
@@ -2,6 +2,34 @@ import {
2
2
  ToolExecutionControlError,
3
3
  isToolExecutionControlError
4
4
  } from "./index-sa2mbwa7.js";
5
+ import {
6
+ AgentAssistantPlaceholderSchema,
7
+ AgentControlPartSchema,
8
+ AgentCostValueSchema,
9
+ AgentFilePartSchema,
10
+ AgentJsonObjectSchema,
11
+ AgentMessagePartSchema,
12
+ AgentMessageRoleSchema,
13
+ AgentMessageSchema,
14
+ AgentMessageStatusSchema,
15
+ AgentOpaquePartSchema,
16
+ AgentProviderEnvelopeSchema,
17
+ AgentReasoningPartSchema,
18
+ AgentRecordIdSchema,
19
+ AgentRecordVersionSchema,
20
+ AgentRunMetricsSchema,
21
+ AgentRunSchema,
22
+ AgentRunStateSchema,
23
+ AgentSnapshotSchema,
24
+ AgentSourcePartSchema,
25
+ AgentTerminalReasonSchema,
26
+ AgentTextPartSchema,
27
+ AgentTimestampSchema,
28
+ AgentToolCallPartSchema,
29
+ AgentToolResultPartSchema,
30
+ AgentUsageSchema,
31
+ AgentUsageValueSchema
32
+ } from "./index-1f4fcj0b.js";
5
33
  import"./index-6djpbnda.js";
6
34
  import"./index-cby4ar3v.js";
7
35
  import {
@@ -226,196 +254,82 @@ function createAgentSessionCoordinator() {
226
254
  };
227
255
  }
228
256
  // src/agent-runtime/events.ts
229
- import { z as z2 } from "zod";
230
-
231
- // src/agent-runtime/schemas.ts
232
257
  import { z } from "zod";
233
- var AgentRecordIdSchema = z.string().min(1);
234
- var AgentRecordVersionSchema = z.int().nonnegative();
235
- var AgentTimestampSchema = z.iso.datetime({ offset: true });
236
- var AgentJsonObjectSchema = z.record(z.string(), z.json());
237
- var AgentProviderEnvelopeSchema = z.object({
238
- schemaVersion: z.int().positive(),
239
- provider: z.string().min(1),
240
- data: AgentJsonObjectSchema
241
- });
242
- var AgentTextPartSchema = z.object({
243
- type: z.literal("text"),
244
- text: z.string()
245
- });
246
- var AgentReasoningPartSchema = z.object({
247
- type: z.literal("reasoning"),
248
- text: z.string(),
249
- provider: AgentProviderEnvelopeSchema.optional()
250
- });
251
- var AgentFilePartSchema = z.object({
252
- type: z.literal("file"),
253
- mediaType: z.string().min(1),
254
- reference: z.string().min(1),
255
- filename: z.string().min(1).optional()
256
- });
257
- var AgentSourcePartSchema = z.object({
258
- type: z.literal("source"),
259
- sourceId: z.string().min(1),
260
- url: z.url().optional(),
261
- title: z.string().optional()
262
- });
263
- var AgentToolCallPartSchema = z.object({
264
- type: z.literal("tool-call"),
265
- callId: z.string().min(1),
266
- toolName: z.string().min(1),
267
- input: z.json(),
268
- provider: AgentProviderEnvelopeSchema.optional()
269
- });
270
- var AgentToolResultPartSchema = z.object({
271
- type: z.literal("tool-result"),
272
- callId: z.string().min(1),
273
- toolName: z.string().min(1),
274
- outcome: z.enum(["success", "error", "interrupted"]),
275
- output: z.json().optional()
276
- });
277
- var AgentOpaquePartSchema = z.object({
278
- type: z.literal("provider"),
279
- envelope: AgentProviderEnvelopeSchema
280
- });
281
- var AgentControlPartSchema = z.object({
282
- type: z.literal("control"),
283
- reason: z.enum(["run-interrupted", "stale-run"])
284
- });
285
- var AgentMessagePartSchema = z.discriminatedUnion("type", [
286
- AgentTextPartSchema,
287
- AgentReasoningPartSchema,
288
- AgentFilePartSchema,
289
- AgentSourcePartSchema,
290
- AgentToolCallPartSchema,
291
- AgentToolResultPartSchema,
292
- AgentOpaquePartSchema,
293
- AgentControlPartSchema
294
- ]);
295
- var AgentMessageRoleSchema = z.enum(["user", "assistant", "system", "summary"]);
296
- var AgentMessageStatusSchema = z.enum([
297
- "committed",
298
- "streaming",
299
- "completed",
300
- "interrupted",
301
- "failed"
302
- ]);
303
- var AgentMessageSchema = z.object({
304
- schemaVersion: z.literal(1),
305
- id: AgentRecordIdSchema,
306
- conversationId: AgentRecordIdSchema,
307
- runId: AgentRecordIdSchema.optional(),
308
- role: AgentMessageRoleSchema,
309
- status: AgentMessageStatusSchema,
310
- parts: z.array(AgentMessagePartSchema),
311
- metadata: AgentJsonObjectSchema.optional(),
312
- createdAt: AgentTimestampSchema,
313
- updatedAt: AgentTimestampSchema
314
- });
315
- var AgentRunStateSchema = z.enum([
316
- "queued",
317
- "running",
318
- "interrupt_requested",
319
- "completed",
320
- "interrupted",
321
- "failed",
322
- "cancelled",
323
- "abandoned"
324
- ]);
325
- var AgentTerminalReasonSchema = z.enum([
326
- "success",
327
- "policy_stop",
328
- "interrupted",
329
- "cancelled",
330
- "timeout",
331
- "shutdown",
332
- "provider_failure",
333
- "tool_failure",
334
- "abandoned"
335
- ]);
336
- var AgentRunSchema = z.object({
337
- schemaVersion: z.literal(1),
338
- id: AgentRecordIdSchema,
258
+ var AgentAdmissionEventSchema = z.object({
259
+ type: z.literal("admission"),
260
+ eventId: AgentRecordIdSchema,
339
261
  conversationId: AgentRecordIdSchema,
340
- inputMessageIds: z.array(AgentRecordIdSchema).min(1),
341
- assistantMessageId: AgentRecordIdSchema,
342
- state: AgentRunStateSchema,
343
- revision: AgentRecordVersionSchema,
344
- ownerId: z.string().min(1).optional(),
345
- terminalReason: AgentTerminalReasonSchema.optional(),
346
- terminalPolicyName: z.string().min(1).optional(),
347
- createdAt: AgentTimestampSchema,
348
- updatedAt: AgentTimestampSchema
262
+ runId: AgentRecordIdSchema,
263
+ snapshotVersion: AgentRecordVersionSchema,
264
+ input: AgentMessageSchema,
265
+ run: AgentRunSchema,
266
+ assistant: z.union([AgentAssistantPlaceholderSchema, AgentMessageSchema]),
267
+ emittedAt: AgentTimestampSchema
349
268
  });
350
- var AgentSnapshotSchema = z.object({
351
- schemaVersion: z.literal(1),
269
+ var EventIdentitySchema = z.object({
352
270
  conversationId: AgentRecordIdSchema,
353
- version: AgentRecordVersionSchema,
354
- messages: z.array(AgentMessageSchema),
355
- runs: z.array(AgentRunSchema)
271
+ runId: AgentRecordIdSchema,
272
+ emittedAt: AgentTimestampSchema
356
273
  });
357
- var AgentUsageValueSchema = z.object({
358
- value: z.number().nonnegative().optional(),
359
- provenance: z.enum(["provider-reported", "computed", "estimated", "unavailable"])
274
+ var AgentTransientDeltaEventSchema = EventIdentitySchema.extend({
275
+ type: z.literal("assistant-delta"),
276
+ runtimeEpoch: z.string().min(1),
277
+ sequence: z.int().nonnegative(),
278
+ textDelta: z.string()
360
279
  });
361
- var AgentCostValueSchema = z.object({
362
- value: z.number().nonnegative().optional(),
363
- currency: z.string().length(3).optional(),
364
- provenance: z.enum(["provider-reported", "computed", "estimated", "unavailable"])
280
+ var AgentTransientReasoningIdentitySchema = EventIdentitySchema.extend({
281
+ runtimeEpoch: z.string().min(1),
282
+ sequence: z.int().nonnegative(),
283
+ provider: AgentProviderEnvelopeSchema.optional()
365
284
  });
366
- var AgentUsageSchema = z.object({
367
- inputTokens: AgentUsageValueSchema,
368
- outputTokens: AgentUsageValueSchema,
369
- reasoningTokens: AgentUsageValueSchema.optional(),
370
- cacheReadTokens: AgentUsageValueSchema.optional(),
371
- cacheWriteTokens: AgentUsageValueSchema.optional(),
372
- cost: AgentCostValueSchema.optional()
285
+ var AgentReasoningStartEventSchema = AgentTransientReasoningIdentitySchema.extend({
286
+ type: z.literal("reasoning-start")
373
287
  });
374
-
375
- // src/agent-runtime/events.ts
376
- var EventIdentitySchema = z2.object({
377
- conversationId: AgentRecordIdSchema,
378
- runId: AgentRecordIdSchema,
379
- emittedAt: AgentTimestampSchema
288
+ var AgentReasoningDeltaEventSchema = AgentTransientReasoningIdentitySchema.extend({
289
+ type: z.literal("reasoning-delta"),
290
+ textDelta: z.string()
380
291
  });
381
- var AgentTransientDeltaEventSchema = EventIdentitySchema.extend({
382
- type: z2.literal("assistant-delta"),
383
- runtimeEpoch: z2.string().min(1),
384
- sequence: z2.int().nonnegative(),
385
- textDelta: z2.string()
292
+ var AgentReasoningEndEventSchema = AgentTransientReasoningIdentitySchema.extend({
293
+ type: z.literal("reasoning-end")
386
294
  });
387
295
  var AgentCheckpointEventSchema = EventIdentitySchema.extend({
388
- type: z2.literal("assistant-checkpoint"),
296
+ type: z.literal("assistant-checkpoint"),
389
297
  eventId: AgentRecordIdSchema,
390
298
  snapshotVersion: AgentRecordVersionSchema,
391
- message: AgentMessageSchema
299
+ message: AgentMessageSchema,
300
+ metrics: AgentRunMetricsSchema.optional()
392
301
  });
393
302
  var AgentRunStateEventSchema = EventIdentitySchema.extend({
394
- type: z2.literal("run-state"),
303
+ type: z.literal("run-state"),
395
304
  eventId: AgentRecordIdSchema,
396
305
  snapshotVersion: AgentRecordVersionSchema,
397
306
  state: AgentRunStateSchema
398
307
  });
399
308
  var AgentToolStatusEventSchema = EventIdentitySchema.extend({
400
- type: z2.literal("tool-status"),
401
- runtimeEpoch: z2.string().min(1),
402
- sequence: z2.int().nonnegative(),
309
+ type: z.literal("tool-status"),
310
+ runtimeEpoch: z.string().min(1),
311
+ sequence: z.int().nonnegative(),
403
312
  callId: AgentRecordIdSchema,
404
- toolName: z2.string().min(1),
405
- status: z2.enum(["started", "completed", "failed", "interrupted"]),
406
- input: z2.json().optional(),
407
- output: z2.json().optional()
313
+ toolName: z.string().min(1),
314
+ status: z.enum(["started", "completed", "failed", "interrupted"]),
315
+ input: z.json().optional(),
316
+ output: z.json().optional()
408
317
  });
409
318
  var AgentTerminalEventSchema = EventIdentitySchema.extend({
410
- type: z2.literal("terminal"),
319
+ type: z.literal("terminal"),
411
320
  eventId: AgentRecordIdSchema,
412
321
  snapshotVersion: AgentRecordVersionSchema,
413
322
  reason: AgentTerminalReasonSchema,
414
- policyName: z2.string().min(1).optional(),
415
- message: AgentMessageSchema
323
+ policyName: z.string().min(1).optional(),
324
+ message: AgentMessageSchema,
325
+ metrics: AgentRunMetricsSchema.optional()
416
326
  });
417
- var AgentRuntimeEventSchema = z2.discriminatedUnion("type", [
327
+ var AgentRuntimeEventSchema = z.discriminatedUnion("type", [
328
+ AgentAdmissionEventSchema,
418
329
  AgentTransientDeltaEventSchema,
330
+ AgentReasoningStartEventSchema,
331
+ AgentReasoningDeltaEventSchema,
332
+ AgentReasoningEndEventSchema,
419
333
  AgentCheckpointEventSchema,
420
334
  AgentRunStateEventSchema,
421
335
  AgentToolStatusEventSchema,
@@ -547,15 +461,15 @@ function createAgentToolFenceLifecycle(config) {
547
461
  };
548
462
  }
549
463
  // src/agent-runtime/models.ts
550
- import { z as z3 } from "zod";
551
- var AgentModelCapabilitySchema = z3.enum(["tools", "vision", "reasoning", "files"]);
552
- var AgentModelDescriptorSchema = z3.object({
553
- provider: z3.string().min(1),
554
- modelId: z3.string().min(1),
555
- contextWindow: z3.int().positive(),
556
- capabilities: z3.array(AgentModelCapabilitySchema),
557
- observedAt: z3.iso.datetime({ offset: true }).optional(),
558
- source: z3.string().min(1).optional()
464
+ import { z as z2 } from "zod";
465
+ var AgentModelCapabilitySchema = z2.enum(["tools", "vision", "reasoning", "files"]);
466
+ var AgentModelDescriptorSchema = z2.object({
467
+ provider: z2.string().min(1),
468
+ modelId: z2.string().min(1),
469
+ contextWindow: z2.int().positive(),
470
+ capabilities: z2.array(AgentModelCapabilitySchema),
471
+ observedAt: z2.iso.datetime({ offset: true }).optional(),
472
+ source: z2.string().min(1).optional()
559
473
  });
560
474
  function defineModelRegistry(config) {
561
475
  const descriptors = new Map;
@@ -595,25 +509,25 @@ function defineModelRegistry(config) {
595
509
  };
596
510
  }
597
511
  // src/agent-runtime/observability.ts
598
- import { z as z4 } from "zod";
599
- var AgentRunEventSchema = z4.object({
600
- schemaVersion: z4.literal(1),
512
+ import { z as z3 } from "zod";
513
+ var AgentRunEventSchema = z3.object({
514
+ schemaVersion: z3.literal(1),
601
515
  eventId: AgentRecordIdSchema,
602
- type: z4.enum(["run-started", "step-finished", "run-terminal"]),
516
+ type: z3.enum(["run-started", "step-finished", "run-terminal"]),
603
517
  conversationId: AgentRecordIdSchema,
604
518
  runId: AgentRecordIdSchema,
605
- traceId: z4.string().min(1),
606
- spanId: z4.string().min(1),
607
- parentSpanId: z4.string().min(1).optional(),
519
+ traceId: z3.string().min(1),
520
+ spanId: z3.string().min(1),
521
+ parentSpanId: z3.string().min(1).optional(),
608
522
  state: AgentRunStateSchema,
609
523
  terminalReason: AgentTerminalReasonSchema.optional(),
610
- modelId: z4.string().min(1).optional(),
611
- step: z4.int().nonnegative().optional(),
612
- queueWaitMs: z4.number().nonnegative().optional(),
613
- durationMs: z4.number().nonnegative().optional(),
614
- ttftMs: z4.number().nonnegative().optional(),
524
+ modelId: z3.string().min(1).optional(),
525
+ step: z3.int().nonnegative().optional(),
526
+ queueWaitMs: z3.number().nonnegative().optional(),
527
+ durationMs: z3.number().nonnegative().optional(),
528
+ ttftMs: z3.number().nonnegative().optional(),
615
529
  usage: AgentUsageSchema.optional(),
616
- internalCause: z4.unknown().optional(),
530
+ internalCause: z3.unknown().optional(),
617
531
  emittedAt: AgentTimestampSchema
618
532
  });
619
533
  function createAgentObservability(config) {
@@ -638,10 +552,10 @@ function createAgentObservability(config) {
638
552
  };
639
553
  }
640
554
  // src/agent-runtime/prompt.ts
641
- import { z as z5 } from "zod";
642
- var AgentTokenCountSchema = z5.object({
643
- value: z5.int().nonnegative().optional(),
644
- provenance: z5.enum(["measured", "estimated", "unavailable"])
555
+ import { z as z4 } from "zod";
556
+ var AgentTokenCountSchema = z4.object({
557
+ value: z4.int().nonnegative().optional(),
558
+ provenance: z4.enum(["measured", "estimated", "unavailable"])
645
559
  });
646
560
  function knownValue(value) {
647
561
  return value.provenance === "unavailable" ? undefined : value.value;
@@ -720,7 +634,7 @@ import {
720
634
  stepCountIs,
721
635
  streamText
722
636
  } from "ai";
723
- import { z as z6 } from "zod";
637
+ import { z as z5 } from "zod";
724
638
  class AgentRuntimeConflictError extends Error {
725
639
  constructor(operation) {
726
640
  super(`Agent runtime store conflict during ${operation}`);
@@ -739,7 +653,7 @@ function findRun(runs, runId) {
739
653
  return run;
740
654
  }
741
655
  function jsonValue(value) {
742
- const parsed = z6.json().safeParse(value);
656
+ const parsed = z5.json().safeParse(value);
743
657
  return parsed.success ? parsed.data : { message: "Non-JSON tool output omitted" };
744
658
  }
745
659
  function providerEnvelope(value) {
@@ -984,6 +898,12 @@ function createAgentRuntime(config) {
984
898
  assistant
985
899
  }), "assistant checkpoint");
986
900
  run = findRun(snapshot.runs, run.id);
901
+ const checkpointMetrics = {
902
+ partial: true,
903
+ durationMs: performance.now() - runStartedAt,
904
+ ...usage && { usage },
905
+ ...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt }
906
+ };
987
907
  await publish({
988
908
  type: "assistant-checkpoint",
989
909
  eventId: generateId(),
@@ -991,6 +911,7 @@ function createAgentRuntime(config) {
991
911
  runId: run.id,
992
912
  snapshotVersion: snapshot.version,
993
913
  message: assistant,
914
+ metrics: checkpointMetrics,
994
915
  emittedAt: now().toISOString()
995
916
  });
996
917
  };
@@ -1102,11 +1023,42 @@ function createAgentRuntime(config) {
1102
1023
  } else if (part.type === "reasoning-start") {
1103
1024
  reasoningPartIndex = undefined;
1104
1025
  updateReasoning("", part.providerMetadata);
1026
+ const provider = providerEnvelope(part.providerMetadata);
1027
+ await publish({
1028
+ type: "reasoning-start",
1029
+ conversationId: run.conversationId,
1030
+ runId: run.id,
1031
+ runtimeEpoch,
1032
+ sequence,
1033
+ ...provider && { provider },
1034
+ emittedAt: now().toISOString()
1035
+ });
1105
1036
  } else if (part.type === "reasoning-delta") {
1106
1037
  updateReasoning(part.text, part.providerMetadata);
1038
+ const provider = providerEnvelope(part.providerMetadata);
1039
+ await publish({
1040
+ type: "reasoning-delta",
1041
+ conversationId: run.conversationId,
1042
+ runId: run.id,
1043
+ runtimeEpoch,
1044
+ sequence,
1045
+ textDelta: part.text,
1046
+ ...provider && { provider },
1047
+ emittedAt: now().toISOString()
1048
+ });
1107
1049
  } else if (part.type === "reasoning-end") {
1108
1050
  updateReasoning("", part.providerMetadata);
1109
1051
  reasoningPartIndex = undefined;
1052
+ const provider = providerEnvelope(part.providerMetadata);
1053
+ await publish({
1054
+ type: "reasoning-end",
1055
+ conversationId: run.conversationId,
1056
+ runId: run.id,
1057
+ runtimeEpoch,
1058
+ sequence,
1059
+ ...provider && { provider },
1060
+ emittedAt: now().toISOString()
1061
+ });
1110
1062
  } else if (part.type === "tool-call") {
1111
1063
  const provider = providerEnvelope(part.providerMetadata);
1112
1064
  parts.push(AgentMessagePartSchema.parse({
@@ -1329,6 +1281,12 @@ function createAgentRuntime(config) {
1329
1281
  ...terminalPolicyName && { policyName: terminalPolicyName }
1330
1282
  }), "terminal commit");
1331
1283
  run = findRun(snapshot.runs, run.id);
1284
+ const terminalMetrics = {
1285
+ partial: false,
1286
+ durationMs: performance.now() - runStartedAt,
1287
+ ...usage && { usage },
1288
+ ...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt }
1289
+ };
1332
1290
  config.observe?.emit({
1333
1291
  schemaVersion: 1,
1334
1292
  eventId: generateId(),
@@ -1341,7 +1299,7 @@ function createAgentRuntime(config) {
1341
1299
  state: run.state,
1342
1300
  terminalReason,
1343
1301
  ...selectedModel && { modelId: selectedModel.descriptor.modelId },
1344
- durationMs: performance.now() - runStartedAt,
1302
+ durationMs: terminalMetrics.durationMs,
1345
1303
  ...usage && { usage },
1346
1304
  ...internalCause !== undefined && { internalCause },
1347
1305
  ...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt },
@@ -1356,6 +1314,7 @@ function createAgentRuntime(config) {
1356
1314
  reason: terminalReason,
1357
1315
  ...terminalPolicyName && { policyName: terminalPolicyName },
1358
1316
  message: assistant,
1317
+ metrics: terminalMetrics,
1359
1318
  emittedAt: now().toISOString()
1360
1319
  });
1361
1320
  return {
@@ -1363,9 +1322,38 @@ function createAgentRuntime(config) {
1363
1322
  message: assistant,
1364
1323
  reason: terminalReason,
1365
1324
  snapshotVersion: snapshot.version,
1325
+ metrics: terminalMetrics,
1366
1326
  ...terminalPolicyName && { policyName: terminalPolicyName }
1367
1327
  };
1368
1328
  };
1329
+ const resume = (rawInput) => {
1330
+ const context = config.protocol.parseContext(rawInput.context);
1331
+ const accepted = Promise.withResolvers();
1332
+ const result = Promise.withResolvers();
1333
+ (async () => {
1334
+ try {
1335
+ const snapshot = await config.store.loadSnapshot(rawInput.conversationId);
1336
+ const recoveredRun = findRun(snapshot.runs, rawInput.runId);
1337
+ if (recoveredRun.state !== "queued") {
1338
+ throw new Error("Only a queued recovered agent run can be resumed");
1339
+ }
1340
+ accepted.resolve();
1341
+ const ticket = coordinator.submit({
1342
+ key: rawInput.conversationKey ?? rawInput.conversationId,
1343
+ policy: "queue",
1344
+ create: (signal) => ({
1345
+ runId: recoveredRun.id,
1346
+ execute: () => executeRun({ acceptedRun: recoveredRun, context, signal })
1347
+ })
1348
+ });
1349
+ ticket.result.then(result.resolve, result.reject);
1350
+ } catch (error) {
1351
+ accepted.reject(error);
1352
+ result.reject(error);
1353
+ }
1354
+ })();
1355
+ return { accepted: accepted.promise, result: result.promise };
1356
+ };
1369
1357
  return {
1370
1358
  submit(rawInput) {
1371
1359
  const metadata = rawInput.metadata === undefined ? undefined : config.protocol.parseInputMetadata(rawInput.metadata);
@@ -1456,10 +1444,41 @@ function createAgentRuntime(config) {
1456
1444
  const acceptedSnapshot = appliedSnapshot(acceptance, "input acceptance");
1457
1445
  const assignedRunId = acceptance.outcome === "duplicate" ? acceptance.runId : reservation?.admission.runId ?? runId;
1458
1446
  const acceptedRun = findRun(acceptedSnapshot.runs, assignedRunId);
1459
- outerAdmission.resolve({
1447
+ const actualInputMessageId = acceptance.outcome === "duplicate" ? acceptance.inputMessageId : userMessage2.id;
1448
+ const acceptedInput = acceptance.outcome === "duplicate" ? acceptance.input : acceptedSnapshot.messages.find((candidate) => candidate.id === actualInputMessageId);
1449
+ if (!acceptedInput) {
1450
+ throw new AgentRuntimeConflictError("admission input projection");
1451
+ }
1452
+ const assistantPlaceholder = AgentAssistantPlaceholderSchema.parse({
1453
+ schemaVersion: 1,
1454
+ id: acceptedRun.assistantMessageId,
1455
+ conversationId: acceptedRun.conversationId,
1456
+ runId: acceptedRun.id,
1457
+ status: "pending",
1458
+ createdAt: acceptedRun.createdAt,
1459
+ updatedAt: acceptedRun.updatedAt
1460
+ });
1461
+ const acceptedAssistant = acceptance.outcome === "duplicate" ? acceptedSnapshot.messages.find((candidate) => candidate.id === acceptedRun.assistantMessageId) ?? assistantPlaceholder : assistantPlaceholder;
1462
+ const admission = {
1463
+ inputMessageId: acceptedInput.id,
1460
1464
  runId: acceptedRun.id,
1461
- assistantMessageId: acceptedRun.assistantMessageId,
1465
+ assistantMessageId: assistantPlaceholder.id,
1466
+ input: acceptedInput,
1467
+ run: acceptedRun,
1468
+ assistant: acceptedAssistant,
1462
1469
  snapshotVersion: acceptedSnapshot.version
1470
+ };
1471
+ outerAdmission.resolve(admission);
1472
+ await publish({
1473
+ type: "admission",
1474
+ eventId: generateId(),
1475
+ conversationId: acceptedRun.conversationId,
1476
+ runId: acceptedRun.id,
1477
+ snapshotVersion: acceptedSnapshot.version,
1478
+ input: acceptedInput,
1479
+ run: acceptedRun,
1480
+ assistant: acceptedAssistant,
1481
+ emittedAt: now().toISOString()
1463
1482
  });
1464
1483
  await publish({
1465
1484
  type: "run-state",
@@ -1548,34 +1567,7 @@ function createAgentRuntime(config) {
1548
1567
  })();
1549
1568
  return publicTicket;
1550
1569
  },
1551
- resume(rawInput) {
1552
- const context = config.protocol.parseContext(rawInput.context);
1553
- const accepted = Promise.withResolvers();
1554
- const result = Promise.withResolvers();
1555
- (async () => {
1556
- try {
1557
- const snapshot = await config.store.loadSnapshot(rawInput.conversationId);
1558
- const recoveredRun = findRun(snapshot.runs, rawInput.runId);
1559
- if (recoveredRun.state !== "queued") {
1560
- throw new Error("Only a queued recovered agent run can be resumed");
1561
- }
1562
- accepted.resolve();
1563
- const ticket = coordinator.submit({
1564
- key: rawInput.conversationKey ?? rawInput.conversationId,
1565
- policy: "queue",
1566
- create: (signal) => ({
1567
- runId: recoveredRun.id,
1568
- execute: () => executeRun({ acceptedRun: recoveredRun, context, signal })
1569
- })
1570
- });
1571
- ticket.result.then(result.resolve, result.reject);
1572
- } catch (error) {
1573
- accepted.reject(error);
1574
- result.reject(error);
1575
- }
1576
- })();
1577
- return { accepted: accepted.promise, result: result.promise };
1578
- },
1570
+ resume,
1579
1571
  async interrupt(input) {
1580
1572
  const snapshot = await config.store.loadSnapshot(input.conversationId);
1581
1573
  const run = findRun(snapshot.runs, input.runId);
@@ -1599,101 +1591,298 @@ function createAgentRuntime(config) {
1599
1591
  }
1600
1592
  return requested;
1601
1593
  },
1594
+ async recover(options) {
1595
+ if (!config.store.scanRecoverablePage) {
1596
+ throw new Error("The configured agent store does not support bounded recovery scans");
1597
+ }
1598
+ const pageSize = options.pageSize ?? 100;
1599
+ const maxRuns = options.maxRuns ?? 1000;
1600
+ if (!Number.isSafeInteger(pageSize) || pageSize < 1 || pageSize > 1000) {
1601
+ throw new TypeError("Recovery pageSize must be an integer between 1 and 1000");
1602
+ }
1603
+ if (!Number.isSafeInteger(maxRuns) || maxRuns < 1) {
1604
+ throw new TypeError("Recovery maxRuns must be a positive safe integer");
1605
+ }
1606
+ const outcomes = [];
1607
+ let cursor;
1608
+ while (outcomes.length < maxRuns && !options.signal?.aborted) {
1609
+ const page = await config.store.scanRecoverablePage({
1610
+ ...cursor && { cursor },
1611
+ limit: Math.min(pageSize, maxRuns - outcomes.length)
1612
+ });
1613
+ for (const item of page.items) {
1614
+ if (options.signal?.aborted)
1615
+ break;
1616
+ try {
1617
+ if (item.run.state === "queued") {
1618
+ const snapshot = await config.store.loadSnapshot(item.conversationId);
1619
+ const blockedByAcquiredPredecessor = snapshot.runs.some((run) => run.id !== item.run.id && (run.state === "running" || run.state === "interrupt_requested"));
1620
+ if (blockedByAcquiredPredecessor) {
1621
+ outcomes.push({
1622
+ conversationId: item.conversationId,
1623
+ runId: item.run.id,
1624
+ outcome: "skipped"
1625
+ });
1626
+ continue;
1627
+ }
1628
+ }
1629
+ const decision = await options.decide?.(item) ?? (item.run.state === "queued" ? { action: "resume" } : { action: "skip" });
1630
+ if (decision.action === "skip") {
1631
+ outcomes.push({
1632
+ conversationId: item.conversationId,
1633
+ runId: item.run.id,
1634
+ outcome: "skipped"
1635
+ });
1636
+ continue;
1637
+ }
1638
+ if (decision.action === "abandon") {
1639
+ const abandoned = await config.store.recoverRun({
1640
+ conversationId: item.conversationId,
1641
+ runId: item.run.id,
1642
+ expectedRevision: item.run.revision,
1643
+ action: "abandon"
1644
+ });
1645
+ if (abandoned.outcome !== "applied") {
1646
+ throw new AgentRuntimeConflictError("recovery abandon");
1647
+ }
1648
+ outcomes.push({
1649
+ conversationId: item.conversationId,
1650
+ runId: item.run.id,
1651
+ outcome: "abandoned"
1652
+ });
1653
+ continue;
1654
+ }
1655
+ if (decision.action === "requeue") {
1656
+ const requeued = await config.store.recoverRun({
1657
+ conversationId: item.conversationId,
1658
+ runId: item.run.id,
1659
+ expectedRevision: item.run.revision,
1660
+ action: "requeue",
1661
+ replaySafe: true
1662
+ });
1663
+ if (requeued.outcome !== "applied") {
1664
+ throw new AgentRuntimeConflictError("recovery requeue");
1665
+ }
1666
+ }
1667
+ const context = await options.resolveContext(item);
1668
+ const resumed = resume({
1669
+ conversationId: item.conversationId,
1670
+ runId: item.run.id,
1671
+ context
1672
+ });
1673
+ resumed.result.catch(() => {
1674
+ return;
1675
+ });
1676
+ await resumed.accepted;
1677
+ outcomes.push({
1678
+ conversationId: item.conversationId,
1679
+ runId: item.run.id,
1680
+ outcome: decision.action === "requeue" ? "requeued" : "resumed"
1681
+ });
1682
+ } catch (error) {
1683
+ outcomes.push({
1684
+ conversationId: item.conversationId,
1685
+ runId: item.run.id,
1686
+ outcome: "failed",
1687
+ error
1688
+ });
1689
+ }
1690
+ }
1691
+ cursor = page.nextCursor;
1692
+ if (!cursor || page.items.length === 0)
1693
+ break;
1694
+ }
1695
+ return outcomes;
1696
+ },
1602
1697
  stop: (conversationKey, reason) => coordinator.stop(conversationKey, reason),
1603
1698
  close: (options) => coordinator.close(options)
1604
1699
  };
1605
1700
  }
1606
1701
  // src/agent-runtime/store.ts
1607
- import { z as z7 } from "zod";
1608
- var AgentStoreConflictSchema = z7.object({
1609
- outcome: z7.literal("conflict"),
1702
+ import { z as z6 } from "zod";
1703
+ var AgentStoreConflictSchema = z6.object({
1704
+ outcome: z6.literal("conflict"),
1610
1705
  actualVersion: AgentRecordVersionSchema
1611
1706
  });
1612
- var AgentStoreNotFoundSchema = z7.object({
1613
- outcome: z7.literal("not_found")
1614
- });
1615
- var AgentStoreAppliedSchema = z7.object({
1616
- outcome: z7.literal("applied"),
1707
+ var AgentStoreNotFoundSchema = z6.object({ outcome: z6.literal("not_found") });
1708
+ var AgentStoreAppliedSchema = z6.object({
1709
+ outcome: z6.literal("applied"),
1617
1710
  snapshot: AgentSnapshotSchema
1618
1711
  });
1619
- var AgentStoreDuplicateSchema = z7.object({
1620
- outcome: z7.literal("duplicate"),
1712
+ var AgentStoreDuplicateSchema = z6.object({
1713
+ outcome: z6.literal("duplicate"),
1714
+ input: AgentMessageSchema,
1715
+ inputMessageId: AgentRecordIdSchema,
1621
1716
  runId: AgentRecordIdSchema,
1717
+ assistantMessageId: AgentRecordIdSchema,
1622
1718
  snapshot: AgentSnapshotSchema
1623
1719
  });
1624
- var AgentStoreMutationResultSchema = z7.discriminatedUnion("outcome", [
1720
+ var AgentStoreMutationResultSchema = z6.discriminatedUnion("outcome", [
1625
1721
  AgentStoreAppliedSchema,
1626
1722
  AgentStoreDuplicateSchema,
1627
1723
  AgentStoreConflictSchema,
1628
1724
  AgentStoreNotFoundSchema
1629
1725
  ]);
1630
- var AcceptInputAndAssignRunSchema = z7.object({
1631
- idempotencyKey: z7.string().min(1),
1726
+ var AcceptInputAndAssignRunSchema = z6.object({
1727
+ idempotencyKey: z6.string().min(1),
1632
1728
  expectedVersion: AgentRecordVersionSchema.optional(),
1633
1729
  input: AgentMessageSchema,
1634
1730
  run: AgentRunSchema,
1635
1731
  coalesceIntoRunId: AgentRecordIdSchema.optional()
1636
1732
  });
1637
- var AcquireAgentRunSchema = z7.object({
1733
+ var AcquireAgentRunSchema = z6.object({
1638
1734
  conversationId: AgentRecordIdSchema,
1639
1735
  runId: AgentRecordIdSchema,
1640
1736
  expectedRevision: AgentRecordVersionSchema,
1641
- ownerId: z7.string().min(1)
1737
+ ownerId: z6.string().min(1)
1642
1738
  });
1643
- var CheckpointRunAssistantSchema = z7.object({
1739
+ var CheckpointRunAssistantSchema = z6.object({
1644
1740
  conversationId: AgentRecordIdSchema,
1645
1741
  runId: AgentRecordIdSchema,
1646
1742
  expectedRevision: AgentRecordVersionSchema,
1647
- ownerId: z7.string().min(1),
1743
+ ownerId: z6.string().min(1),
1648
1744
  assistant: AgentMessageSchema
1649
1745
  });
1650
- var CommitRunTerminalSchema = z7.object({
1746
+ var CommitRunTerminalSchema = z6.object({
1651
1747
  conversationId: AgentRecordIdSchema,
1652
1748
  runId: AgentRecordIdSchema,
1653
1749
  expectedRevision: AgentRecordVersionSchema,
1654
- ownerId: z7.string().min(1),
1750
+ ownerId: z6.string().min(1),
1655
1751
  assistant: AgentMessageSchema,
1656
1752
  reason: AgentTerminalReasonSchema,
1657
- policyName: z7.string().min(1).optional()
1753
+ policyName: z6.string().min(1).optional()
1658
1754
  });
1659
- var RequestRunInterruptSchema = z7.object({
1755
+ var RequestRunInterruptSchema = z6.object({
1660
1756
  conversationId: AgentRecordIdSchema,
1661
1757
  runId: AgentRecordIdSchema,
1662
1758
  expectedRevision: AgentRecordVersionSchema
1663
1759
  });
1664
- var RecoverAgentRunSchema = z7.object({
1760
+ var RecoverAgentRunSchema = z6.object({
1665
1761
  conversationId: AgentRecordIdSchema,
1666
1762
  runId: AgentRecordIdSchema,
1667
1763
  expectedRevision: AgentRecordVersionSchema,
1668
- action: z7.enum(["requeue", "abandon"]),
1669
- replaySafe: z7.boolean().optional()
1764
+ action: z6.enum(["requeue", "abandon"]),
1765
+ replaySafe: z6.boolean().optional()
1670
1766
  });
1671
- var ReplaceCompactedRangeSchema = z7.object({
1767
+ var ReplaceCompactedRangeSchema = z6.object({
1672
1768
  conversationId: AgentRecordIdSchema,
1673
1769
  expectedVersion: AgentRecordVersionSchema,
1674
- replacedMessageIds: z7.array(AgentRecordIdSchema).min(1),
1770
+ replacedMessageIds: z6.array(AgentRecordIdSchema).min(1),
1675
1771
  summary: AgentMessageSchema
1676
1772
  });
1677
- function emptySnapshot(conversationId) {
1678
- return AgentSnapshotSchema.parse({
1773
+ // src/agent-runtime/store-driver.ts
1774
+ import { z as z7 } from "zod";
1775
+ var AgentAdmissionIdentitySchema = z7.object({
1776
+ idempotencyKey: z7.string().min(1),
1777
+ inputMessageId: AgentRecordIdSchema,
1778
+ runId: AgentRecordIdSchema,
1779
+ assistantMessageId: AgentRecordIdSchema
1780
+ });
1781
+ var AgentStoredStateSchema = z7.object({
1782
+ schemaVersion: z7.literal(1),
1783
+ conversationId: AgentRecordIdSchema,
1784
+ version: AgentRecordVersionSchema,
1785
+ runs: z7.array(AgentRunSchema),
1786
+ admissions: z7.array(AgentAdmissionIdentitySchema)
1787
+ });
1788
+ var AgentHistoryMutationSchema = z7.discriminatedUnion("type", [
1789
+ z7.object({ type: z7.literal("admit"), input: AgentMessageSchema }),
1790
+ z7.object({
1791
+ type: z7.literal("upsert-assistant"),
1792
+ message: AgentMessageSchema
1793
+ }),
1794
+ z7.object({
1795
+ type: z7.literal("replace-compacted-range"),
1796
+ replacedMessageIds: z7.array(AgentRecordIdSchema).min(1),
1797
+ summary: AgentMessageSchema
1798
+ })
1799
+ ]);
1800
+ var AgentRecoverableDescriptorSchema = z7.object({
1801
+ conversationId: AgentRecordIdSchema,
1802
+ run: AgentRunSchema
1803
+ });
1804
+ var AgentRecoverablePageSchema = z7.object({
1805
+ items: z7.array(AgentRecoverableDescriptorSchema),
1806
+ nextCursor: z7.string().min(1).optional()
1807
+ });
1808
+ var AgentRecoverableScanInputSchema = z7.object({
1809
+ cursor: z7.string().min(1).optional(),
1810
+ limit: z7.number().int().min(1).max(1000)
1811
+ });
1812
+ function emptyState(conversationId) {
1813
+ return AgentStoredStateSchema.parse({
1679
1814
  schemaVersion: 1,
1680
1815
  conversationId,
1681
1816
  version: 0,
1682
- messages: [],
1683
- runs: []
1817
+ runs: [],
1818
+ admissions: []
1684
1819
  });
1685
1820
  }
1686
- function cloneSnapshot(snapshot) {
1687
- return AgentSnapshotSchema.parse(structuredClone(snapshot));
1821
+ function snapshotOf(state, messages) {
1822
+ validateAggregate(state, messages);
1823
+ return AgentSnapshotSchema.parse({
1824
+ schemaVersion: 1,
1825
+ conversationId: state.conversationId,
1826
+ version: state.version,
1827
+ messages,
1828
+ runs: state.runs
1829
+ });
1830
+ }
1831
+ function validateAggregate(state, messages) {
1832
+ const runIds = new Set;
1833
+ const assistantIds = new Set;
1834
+ const messageIds = new Set;
1835
+ const idempotencyKeys = new Set;
1836
+ const admittedInputIds = new Set;
1837
+ for (const run of state.runs) {
1838
+ if (run.conversationId !== state.conversationId || runIds.has(run.id) || assistantIds.has(run.assistantMessageId)) {
1839
+ throw new TypeError("Stored agent state contains inconsistent run identities");
1840
+ }
1841
+ runIds.add(run.id);
1842
+ assistantIds.add(run.assistantMessageId);
1843
+ }
1844
+ for (const message of messages) {
1845
+ if (message.conversationId !== state.conversationId || messageIds.has(message.id)) {
1846
+ throw new TypeError("Stored agent history contains inconsistent message identities");
1847
+ }
1848
+ messageIds.add(message.id);
1849
+ if (assistantIds.has(message.id) && message.runId === undefined) {
1850
+ throw new TypeError("Stored history occupies a reserved assistant identity");
1851
+ }
1852
+ if (message.runId !== undefined) {
1853
+ const run = state.runs.find((candidate) => candidate.id === message.runId);
1854
+ if (!run || message.role !== "assistant" || run.assistantMessageId !== message.id) {
1855
+ throw new TypeError("Stored assistant history does not match its reserved run identity");
1856
+ }
1857
+ }
1858
+ }
1859
+ for (const admission of state.admissions) {
1860
+ const run = state.runs.find((candidate) => candidate.id === admission.runId);
1861
+ if (idempotencyKeys.has(admission.idempotencyKey) || admittedInputIds.has(admission.inputMessageId) || !run || run.assistantMessageId !== admission.assistantMessageId || !run.inputMessageIds.includes(admission.inputMessageId)) {
1862
+ throw new TypeError("Stored admission identity is inconsistent with its assigned run");
1863
+ }
1864
+ idempotencyKeys.add(admission.idempotencyKey);
1865
+ admittedInputIds.add(admission.inputMessageId);
1866
+ }
1867
+ }
1868
+ function recoverableDescriptors(state) {
1869
+ return state.runs.filter((run) => ["queued", "running", "interrupt_requested"].includes(run.state)).map((run) => ({ conversationId: state.conversationId, run }));
1870
+ }
1871
+ var RecoverableCursorSchema = z7.tuple([AgentRecordIdSchema, AgentRecordIdSchema]);
1872
+ function recoverableCursor(input) {
1873
+ return JSON.stringify([input.conversationId, input.run.id]);
1874
+ }
1875
+ function parseRecoverableCursor(cursor) {
1876
+ return RecoverableCursorSchema.parse(JSON.parse(cursor));
1688
1877
  }
1689
1878
  function replaceRun(runs, next) {
1690
1879
  return runs.map((run) => run.id === next.id ? next : run);
1691
1880
  }
1692
1881
  function replaceMessage(messages, next) {
1693
- const exists = messages.some((message) => message.id === next.id);
1694
- if (!exists)
1695
- return [...messages, next];
1696
- return messages.map((message) => message.id === next.id ? next : message);
1882
+ return messages.some((message) => message.id === next.id) ? messages.map((message) => message.id === next.id ? next : message) : [...messages, next];
1883
+ }
1884
+ function conflict(actualVersion) {
1885
+ return { outcome: "conflict", actualVersion };
1697
1886
  }
1698
1887
  function terminalState(reason) {
1699
1888
  if (reason === "success" || reason === "policy_stop")
@@ -1715,217 +1904,426 @@ function terminalMessageStatus(reason) {
1715
1904
  }
1716
1905
  return "failed";
1717
1906
  }
1718
- function createMemoryAgentRuntimeStore() {
1719
- const conversations = new Map;
1720
- const get = (conversationId) => {
1721
- const existing = conversations.get(conversationId);
1722
- if (existing)
1723
- return existing;
1724
- const created = { snapshot: emptySnapshot(conversationId), idempotency: new Map };
1725
- conversations.set(conversationId, created);
1726
- return created;
1727
- };
1728
- const conflict = (actualVersion) => ({
1729
- outcome: "conflict",
1730
- actualVersion
1731
- });
1732
- const apply = (entry, snapshot) => {
1733
- entry.snapshot = AgentSnapshotSchema.parse(snapshot);
1734
- return { outcome: "applied", snapshot: cloneSnapshot(entry.snapshot) };
1735
- };
1907
+ function applied(current, admissions, input, historyMutation) {
1736
1908
  return {
1737
- async loadSnapshot(conversationId) {
1738
- return cloneSnapshot(get(conversationId).snapshot);
1739
- },
1740
- async acceptInputAndAssignRun(rawInput) {
1741
- const input = AcceptInputAndAssignRunSchema.parse(rawInput);
1742
- const entry = get(input.input.conversationId);
1743
- const duplicateRunId = entry.idempotency.get(input.idempotencyKey);
1744
- if (duplicateRunId !== undefined) {
1745
- return {
1746
- outcome: "duplicate",
1747
- runId: duplicateRunId,
1748
- snapshot: cloneSnapshot(entry.snapshot)
1749
- };
1750
- }
1751
- if (input.expectedVersion !== undefined && input.expectedVersion !== entry.snapshot.version) {
1752
- return conflict(entry.snapshot.version);
1753
- }
1754
- const coalescedRun = input.coalesceIntoRunId ? entry.snapshot.runs.find((candidate) => candidate.id === input.coalesceIntoRunId) : undefined;
1755
- if (input.coalesceIntoRunId !== undefined && (!coalescedRun || coalescedRun.conversationId !== input.input.conversationId || coalescedRun.state !== "queued" || coalescedRun.ownerId !== undefined || coalescedRun.terminalReason !== undefined)) {
1756
- return coalescedRun ? conflict(coalescedRun.revision) : { outcome: "not_found" };
1757
- }
1758
- if (input.run.conversationId !== input.input.conversationId || input.run.inputMessageIds.length !== 1 || input.run.inputMessageIds[0] !== input.input.id || input.run.state !== "queued" || input.run.revision !== 0 || input.run.ownerId !== undefined || input.run.terminalReason !== undefined || input.run.terminalPolicyName !== undefined || input.input.role !== "user" || input.input.status !== "committed" || input.input.runId !== undefined || entry.snapshot.messages.some((message) => message.id === input.input.id) || !coalescedRun && (input.run.assistantMessageId === input.input.id || entry.snapshot.runs.some((candidate) => candidate.id === input.run.id) || entry.snapshot.runs.some((candidate) => candidate.assistantMessageId === input.run.assistantMessageId) || entry.snapshot.messages.some((message) => message.id === input.run.assistantMessageId))) {
1759
- throw new TypeError("Input and queued run do not form one valid assignment");
1909
+ outcome: "applied",
1910
+ snapshot: AgentSnapshotSchema.parse({
1911
+ ...current,
1912
+ version: current.version + 1,
1913
+ runs: input.runs ?? current.runs,
1914
+ messages: input.messages ?? current.messages
1915
+ }),
1916
+ admissions,
1917
+ ...historyMutation && { historyMutation }
1918
+ };
1919
+ }
1920
+ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
1921
+ if (operation.type === "accept") {
1922
+ const input = operation.input;
1923
+ const duplicate = currentAdmissions.find((candidate) => candidate.idempotencyKey === input.idempotencyKey);
1924
+ if (duplicate) {
1925
+ if (!duplicateInput) {
1926
+ throw new Error("Duplicate admission input is unavailable from canonical history");
1760
1927
  }
1761
- const assignedRun = coalescedRun ? AgentRunSchema.parse({
1762
- ...coalescedRun,
1763
- inputMessageIds: [...coalescedRun.inputMessageIds, input.input.id],
1764
- revision: coalescedRun.revision + 1,
1928
+ return {
1929
+ outcome: "duplicate",
1930
+ input: duplicateInput,
1931
+ inputMessageId: duplicate.inputMessageId,
1932
+ runId: duplicate.runId,
1933
+ assistantMessageId: duplicate.assistantMessageId,
1934
+ snapshot: current
1935
+ };
1936
+ }
1937
+ if (input.expectedVersion !== undefined && input.expectedVersion !== current.version) {
1938
+ return conflict(current.version);
1939
+ }
1940
+ const coalescedRun = input.coalesceIntoRunId ? current.runs.find((candidate) => candidate.id === input.coalesceIntoRunId) : undefined;
1941
+ if (input.coalesceIntoRunId !== undefined && (!coalescedRun || coalescedRun.conversationId !== input.input.conversationId || coalescedRun.state !== "queued" || coalescedRun.ownerId !== undefined || coalescedRun.terminalReason !== undefined)) {
1942
+ return coalescedRun ? conflict(coalescedRun.revision) : { outcome: "not_found" };
1943
+ }
1944
+ if (input.run.conversationId !== input.input.conversationId || input.run.inputMessageIds.length !== 1 || input.run.inputMessageIds[0] !== input.input.id || input.run.state !== "queued" || input.run.revision !== 0 || input.run.ownerId !== undefined || input.run.terminalReason !== undefined || input.run.terminalPolicyName !== undefined || input.input.role !== "user" || input.input.status !== "committed" || input.input.runId !== undefined || current.messages.some((message) => message.id === input.input.id) || coalescedRun !== undefined && input.input.id === coalescedRun.assistantMessageId || !coalescedRun && (input.run.assistantMessageId === input.input.id || current.runs.some((candidate) => candidate.id === input.run.id) || current.runs.some((candidate) => candidate.assistantMessageId === input.run.assistantMessageId) || current.messages.some((message) => message.id === input.run.assistantMessageId))) {
1945
+ throw new TypeError("Input and queued run do not form one valid assignment");
1946
+ }
1947
+ const assignedRun = coalescedRun ? AgentRunSchema.parse({
1948
+ ...coalescedRun,
1949
+ inputMessageIds: [...coalescedRun.inputMessageIds, input.input.id],
1950
+ revision: coalescedRun.revision + 1,
1951
+ updatedAt: new Date().toISOString()
1952
+ }) : input.run;
1953
+ const admission = AgentAdmissionIdentitySchema.parse({
1954
+ idempotencyKey: input.idempotencyKey,
1955
+ inputMessageId: input.input.id,
1956
+ runId: assignedRun.id,
1957
+ assistantMessageId: assignedRun.assistantMessageId
1958
+ });
1959
+ return applied(current, [...currentAdmissions, admission], {
1960
+ messages: [...current.messages, input.input],
1961
+ runs: coalescedRun ? replaceRun(current.runs, assignedRun) : [...current.runs, assignedRun]
1962
+ }, { type: "admit", input: input.input });
1963
+ }
1964
+ const conversationId = operation.input.conversationId;
1965
+ const run = operation.type === "compact" ? undefined : current.runs.find((candidate) => candidate.id === operation.input.runId);
1966
+ if (operation.type !== "compact" && !run)
1967
+ return { outcome: "not_found" };
1968
+ if (operation.type === "acquire" && run) {
1969
+ const runPosition = current.runs.findIndex((candidate) => candidate.id === run.id);
1970
+ const acquisitionBlocked = current.runs.some((candidate, index) => candidate.id !== run.id && (candidate.state === "running" || candidate.state === "interrupt_requested" || index < runPosition && candidate.state === "queued"));
1971
+ if (run.revision !== operation.input.expectedRevision || run.state !== "queued" || acquisitionBlocked) {
1972
+ return conflict(run.revision);
1973
+ }
1974
+ const next = AgentRunSchema.parse({
1975
+ ...run,
1976
+ state: "running",
1977
+ ownerId: operation.input.ownerId,
1978
+ revision: run.revision + 1,
1979
+ updatedAt: new Date().toISOString()
1980
+ });
1981
+ return applied(current, currentAdmissions, {
1982
+ runs: replaceRun(current.runs, next)
1983
+ });
1984
+ }
1985
+ if (operation.type === "checkpoint" && run) {
1986
+ const input = operation.input;
1987
+ if (run.revision !== input.expectedRevision || run.state !== "running" || run.ownerId !== input.ownerId || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !== "streaming") {
1988
+ return conflict(run.revision);
1989
+ }
1990
+ const next = AgentRunSchema.parse({
1991
+ ...run,
1992
+ revision: run.revision + 1,
1993
+ updatedAt: new Date().toISOString()
1994
+ });
1995
+ return applied(current, currentAdmissions, {
1996
+ runs: replaceRun(current.runs, next),
1997
+ messages: replaceMessage(current.messages, input.assistant)
1998
+ }, { type: "upsert-assistant", message: input.assistant });
1999
+ }
2000
+ if (operation.type === "interrupt" && run) {
2001
+ if (run.revision !== operation.input.expectedRevision || run.state !== "running") {
2002
+ return conflict(run.revision);
2003
+ }
2004
+ const next = AgentRunSchema.parse({
2005
+ ...run,
2006
+ state: "interrupt_requested",
2007
+ revision: run.revision + 1,
2008
+ updatedAt: new Date().toISOString()
2009
+ });
2010
+ return applied(current, currentAdmissions, {
2011
+ runs: replaceRun(current.runs, next)
2012
+ });
2013
+ }
2014
+ if (operation.type === "recover" && run) {
2015
+ const input = operation.input;
2016
+ if (run.revision !== input.expectedRevision || !["queued", "running", "interrupt_requested"].includes(run.state)) {
2017
+ return conflict(run.revision);
2018
+ }
2019
+ if (input.action === "requeue" && run.state !== "queued" && input.replaySafe !== true) {
2020
+ throw new TypeError("Recovering an acquired run requires explicit replaySafe evidence");
2021
+ }
2022
+ const next = AgentRunSchema.parse({
2023
+ schemaVersion: 1,
2024
+ id: run.id,
2025
+ conversationId: run.conversationId,
2026
+ inputMessageIds: run.inputMessageIds,
2027
+ assistantMessageId: run.assistantMessageId,
2028
+ state: input.action === "requeue" ? "queued" : "abandoned",
2029
+ revision: run.revision + 1,
2030
+ ...input.action === "abandon" && { terminalReason: "abandoned" },
2031
+ createdAt: run.createdAt,
2032
+ updatedAt: new Date().toISOString()
2033
+ });
2034
+ if (input.action === "abandon") {
2035
+ const existingAssistant = current.messages.find((message) => message.id === run.assistantMessageId);
2036
+ const assistant = AgentMessageSchema.parse({
2037
+ ...existingAssistant ?? {
2038
+ schemaVersion: 1,
2039
+ id: run.assistantMessageId,
2040
+ conversationId: run.conversationId,
2041
+ runId: run.id,
2042
+ role: "assistant",
2043
+ parts: [],
2044
+ createdAt: run.createdAt
2045
+ },
2046
+ status: "failed",
1765
2047
  updatedAt: new Date().toISOString()
1766
- }) : input.run;
1767
- const next = AgentSnapshotSchema.parse({
1768
- ...entry.snapshot,
1769
- version: entry.snapshot.version + 1,
1770
- messages: [...entry.snapshot.messages, input.input],
1771
- runs: coalescedRun ? replaceRun(entry.snapshot.runs, assignedRun) : [...entry.snapshot.runs, assignedRun]
1772
2048
  });
1773
- entry.idempotency.set(input.idempotencyKey, assignedRun.id);
1774
- return apply(entry, next);
2049
+ return applied(current, currentAdmissions, {
2050
+ runs: replaceRun(current.runs, next),
2051
+ messages: replaceMessage(current.messages, assistant)
2052
+ }, { type: "upsert-assistant", message: assistant });
2053
+ }
2054
+ return applied(current, currentAdmissions, {
2055
+ runs: replaceRun(current.runs, next)
2056
+ });
2057
+ }
2058
+ if (operation.type === "terminal" && run) {
2059
+ const input = operation.input;
2060
+ if (run.revision !== input.expectedRevision || run.state !== "running" && run.state !== "interrupt_requested" || run.ownerId !== input.ownerId || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !== terminalMessageStatus(input.reason)) {
2061
+ return conflict(run.revision);
2062
+ }
2063
+ const next = AgentRunSchema.parse({
2064
+ ...run,
2065
+ state: terminalState(input.reason),
2066
+ terminalReason: input.reason,
2067
+ ...input.policyName && { terminalPolicyName: input.policyName },
2068
+ revision: run.revision + 1,
2069
+ updatedAt: new Date().toISOString()
2070
+ });
2071
+ return applied(current, currentAdmissions, {
2072
+ runs: replaceRun(current.runs, next),
2073
+ messages: replaceMessage(current.messages, input.assistant)
2074
+ }, { type: "upsert-assistant", message: input.assistant });
2075
+ }
2076
+ if (operation.type === "compact") {
2077
+ const input = operation.input;
2078
+ if (current.conversationId !== conversationId)
2079
+ return { outcome: "not_found" };
2080
+ if (current.version !== input.expectedVersion)
2081
+ return conflict(current.version);
2082
+ const replaced = new Set(input.replacedMessageIds);
2083
+ if (!input.replacedMessageIds.every((id) => current.messages.some((m) => m.id === id))) {
2084
+ return { outcome: "not_found" };
2085
+ }
2086
+ const positions = current.messages.map((message, index) => replaced.has(message.id) ? index : undefined).filter((index) => index !== undefined);
2087
+ const first = positions[0];
2088
+ if (first === undefined || positions.some((position, offset) => position !== first + offset) || input.summary.conversationId !== input.conversationId || input.summary.runId !== undefined || input.summary.role !== "summary" || input.summary.status !== "committed" || current.messages.some((message) => message.id === input.summary.id) || current.runs.some((candidate) => candidate.assistantMessageId === input.summary.id)) {
2089
+ throw new TypeError("Compaction replacement must be one valid contiguous history range");
2090
+ }
2091
+ const messages = [
2092
+ ...current.messages.slice(0, first),
2093
+ input.summary,
2094
+ ...current.messages.slice(first + positions.length)
2095
+ ];
2096
+ return applied(current, currentAdmissions, { messages }, {
2097
+ type: "replace-compacted-range",
2098
+ replacedMessageIds: input.replacedMessageIds,
2099
+ summary: input.summary
2100
+ });
2101
+ }
2102
+ return { outcome: "not_found" };
2103
+ }
2104
+ function operationConversationId(operation) {
2105
+ return operation.type === "accept" ? operation.input.input.conversationId : operation.input.conversationId;
2106
+ }
2107
+ function createAgentRuntimeStore(driver) {
2108
+ const loadSnapshot = (conversationId) => driver.transaction(async (transaction) => {
2109
+ const [stored, messages] = await Promise.all([
2110
+ driver.state.load(transaction, conversationId),
2111
+ driver.history.load(transaction, conversationId)
2112
+ ]);
2113
+ return snapshotOf(stored ?? emptyState(conversationId), messages);
2114
+ });
2115
+ const mutate = (operation) => driver.transaction(async (transaction) => {
2116
+ const conversationId = operationConversationId(operation);
2117
+ const [stored, messages] = await Promise.all([
2118
+ driver.state.load(transaction, conversationId),
2119
+ driver.history.load(transaction, conversationId)
2120
+ ]);
2121
+ const state = AgentStoredStateSchema.parse(stored ?? emptyState(conversationId));
2122
+ const current = snapshotOf(state, messages);
2123
+ const duplicateIdentity = operation.type === "accept" ? state.admissions.find((candidate) => candidate.idempotencyKey === operation.input.idempotencyKey) : undefined;
2124
+ const duplicateInput = duplicateIdentity ? await driver.history.loadById(transaction, {
2125
+ conversationId,
2126
+ messageId: duplicateIdentity.inputMessageId
2127
+ }) : undefined;
2128
+ if (duplicateIdentity && duplicateInput && (duplicateInput.id !== duplicateIdentity.inputMessageId || duplicateInput.conversationId !== conversationId || duplicateInput.role !== "user" || duplicateInput.status !== "committed" || duplicateInput.runId !== undefined)) {
2129
+ throw new TypeError("Canonical duplicate input does not match its admission identity");
2130
+ }
2131
+ const reduced = reduceStore(current, state.admissions, operation, duplicateInput);
2132
+ if (reduced.outcome !== "applied")
2133
+ return reduced;
2134
+ const nextState = AgentStoredStateSchema.parse({
2135
+ schemaVersion: 1,
2136
+ conversationId,
2137
+ version: reduced.snapshot.version,
2138
+ runs: reduced.snapshot.runs,
2139
+ admissions: reduced.admissions
2140
+ });
2141
+ const outcome = await driver.state.compareAndSwap(transaction, {
2142
+ conversationId,
2143
+ expectedVersion: current.version,
2144
+ next: nextState,
2145
+ recoverable: recoverableDescriptors(nextState)
2146
+ });
2147
+ if (outcome.outcome === "conflict")
2148
+ return conflict(outcome.actualVersion);
2149
+ if (reduced.historyMutation) {
2150
+ await driver.history.apply(transaction, reduced.historyMutation);
2151
+ }
2152
+ return { outcome: "applied", snapshot: reduced.snapshot };
2153
+ });
2154
+ return {
2155
+ loadSnapshot,
2156
+ acceptInputAndAssignRun: (input) => mutate({
2157
+ type: "accept",
2158
+ input: AcceptInputAndAssignRunSchema.parse(input)
2159
+ }),
2160
+ acquireRun: (input) => mutate({ type: "acquire", input: AcquireAgentRunSchema.parse(input) }),
2161
+ checkpointRunAssistant: (input) => mutate({
2162
+ type: "checkpoint",
2163
+ input: CheckpointRunAssistantSchema.parse(input)
2164
+ }),
2165
+ requestRunInterrupt: (input) => mutate({
2166
+ type: "interrupt",
2167
+ input: RequestRunInterruptSchema.parse(input)
2168
+ }),
2169
+ recoverRun: (input) => mutate({ type: "recover", input: RecoverAgentRunSchema.parse(input) }),
2170
+ commitRunTerminal: (input) => mutate({ type: "terminal", input: CommitRunTerminalSchema.parse(input) }),
2171
+ replaceCompactedRange: (input) => mutate({
2172
+ type: "compact",
2173
+ input: ReplaceCompactedRangeSchema.parse(input)
2174
+ }),
2175
+ async scanRecoverable() {
2176
+ const snapshots = [];
2177
+ const seenConversationIds = new Set;
2178
+ let cursor;
2179
+ do {
2180
+ const page = AgentRecoverablePageSchema.parse(await driver.scanRecoverable({
2181
+ ...cursor && { cursor },
2182
+ limit: 100
2183
+ }));
2184
+ const conversationIds = [
2185
+ ...new Set(page.items.map((item) => item.conversationId))
2186
+ ].filter((conversationId) => !seenConversationIds.has(conversationId));
2187
+ for (const conversationId of conversationIds)
2188
+ seenConversationIds.add(conversationId);
2189
+ snapshots.push(...await Promise.all(conversationIds.map(loadSnapshot)));
2190
+ cursor = page.nextCursor;
2191
+ } while (cursor !== undefined);
2192
+ return snapshots;
1775
2193
  },
1776
- async acquireRun(rawInput) {
1777
- const input = AcquireAgentRunSchema.parse(rawInput);
1778
- const entry = get(input.conversationId);
1779
- const run = entry.snapshot.runs.find((candidate) => candidate.id === input.runId);
1780
- if (!run)
1781
- return { outcome: "not_found" };
1782
- if (run.revision !== input.expectedRevision || run.state !== "queued") {
1783
- return conflict(run.revision);
1784
- }
1785
- const nextRun = AgentRunSchema.parse({
1786
- ...run,
1787
- state: "running",
1788
- ownerId: input.ownerId,
1789
- revision: run.revision + 1,
1790
- updatedAt: new Date().toISOString()
2194
+ async scanRecoverablePage(input) {
2195
+ const parsed = AgentRecoverableScanInputSchema.parse(input);
2196
+ return AgentRecoverablePageSchema.parse(await driver.scanRecoverable(parsed));
2197
+ }
2198
+ };
2199
+ }
2200
+ function cloneStateMap(source) {
2201
+ return new Map([...source].map(([key, value]) => [
2202
+ key,
2203
+ AgentStoredStateSchema.parse(structuredClone(value))
2204
+ ]));
2205
+ }
2206
+ function cloneHistoryMap(source) {
2207
+ return new Map([...source].map(([key, value]) => [
2208
+ key,
2209
+ value.map((message) => AgentMessageSchema.parse(structuredClone(message)))
2210
+ ]));
2211
+ }
2212
+ function createMemoryAgentRuntimeStore() {
2213
+ let states = new Map;
2214
+ let histories = new Map;
2215
+ let archivedMessages = new Map;
2216
+ let transactionTail = Promise.resolve();
2217
+ const driver = {
2218
+ async transaction(work) {
2219
+ const previous = transactionTail;
2220
+ const release = Promise.withResolvers();
2221
+ transactionTail = previous.catch(() => {
2222
+ return;
2223
+ }).then(() => release.promise);
2224
+ await previous.catch(() => {
2225
+ return;
1791
2226
  });
1792
- return apply(entry, AgentSnapshotSchema.parse({
1793
- ...entry.snapshot,
1794
- version: entry.snapshot.version + 1,
1795
- runs: replaceRun(entry.snapshot.runs, nextRun)
1796
- }));
1797
- },
1798
- async checkpointRunAssistant(rawInput) {
1799
- const input = CheckpointRunAssistantSchema.parse(rawInput);
1800
- const entry = get(input.conversationId);
1801
- const run = entry.snapshot.runs.find((candidate) => candidate.id === input.runId);
1802
- if (!run)
1803
- return { outcome: "not_found" };
1804
- if (run.revision !== input.expectedRevision || run.state !== "running" || run.ownerId !== input.ownerId || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !== "streaming") {
1805
- return conflict(run.revision);
2227
+ const transaction = {
2228
+ states: cloneStateMap(states),
2229
+ histories: cloneHistoryMap(histories),
2230
+ archivedMessages: new Map([...archivedMessages].map(([conversationId, messages]) => [
2231
+ conversationId,
2232
+ new Map([...messages].map(([messageId, message]) => [
2233
+ messageId,
2234
+ AgentMessageSchema.parse(structuredClone(message))
2235
+ ]))
2236
+ ]))
2237
+ };
2238
+ try {
2239
+ const result = await work(transaction);
2240
+ states = transaction.states;
2241
+ histories = transaction.histories;
2242
+ archivedMessages = transaction.archivedMessages;
2243
+ return result;
2244
+ } finally {
2245
+ release.resolve();
1806
2246
  }
1807
- const nextRun = AgentRunSchema.parse({
1808
- ...run,
1809
- revision: run.revision + 1,
1810
- updatedAt: new Date().toISOString()
1811
- });
1812
- return apply(entry, AgentSnapshotSchema.parse({
1813
- ...entry.snapshot,
1814
- version: entry.snapshot.version + 1,
1815
- messages: replaceMessage(entry.snapshot.messages, input.assistant),
1816
- runs: replaceRun(entry.snapshot.runs, nextRun)
1817
- }));
1818
2247
  },
1819
- async requestRunInterrupt(rawInput) {
1820
- const input = RequestRunInterruptSchema.parse(rawInput);
1821
- const entry = get(input.conversationId);
1822
- const run = entry.snapshot.runs.find((candidate) => candidate.id === input.runId);
1823
- if (!run)
1824
- return { outcome: "not_found" };
1825
- if (run.revision !== input.expectedRevision || run.state !== "running") {
1826
- return conflict(run.revision);
2248
+ state: {
2249
+ async load(transaction, conversationId) {
2250
+ const state = transaction.states.get(conversationId);
2251
+ return state ? AgentStoredStateSchema.parse(structuredClone(state)) : undefined;
2252
+ },
2253
+ async compareAndSwap(transaction, input) {
2254
+ const current = transaction.states.get(input.conversationId);
2255
+ const actualVersion = current?.version ?? 0;
2256
+ if (actualVersion !== input.expectedVersion) {
2257
+ return { outcome: "conflict", actualVersion };
2258
+ }
2259
+ transaction.states.set(input.conversationId, AgentStoredStateSchema.parse(structuredClone(input.next)));
2260
+ return { outcome: "applied" };
1827
2261
  }
1828
- const nextRun = AgentRunSchema.parse({
1829
- ...run,
1830
- state: "interrupt_requested",
1831
- revision: run.revision + 1,
1832
- updatedAt: new Date().toISOString()
1833
- });
1834
- return apply(entry, AgentSnapshotSchema.parse({
1835
- ...entry.snapshot,
1836
- version: entry.snapshot.version + 1,
1837
- runs: replaceRun(entry.snapshot.runs, nextRun)
1838
- }));
1839
2262
  },
1840
- async recoverRun(rawInput) {
1841
- const input = RecoverAgentRunSchema.parse(rawInput);
1842
- const entry = get(input.conversationId);
1843
- const run = entry.snapshot.runs.find((candidate) => candidate.id === input.runId);
1844
- if (!run)
1845
- return { outcome: "not_found" };
1846
- if (run.revision !== input.expectedRevision || !["queued", "running", "interrupt_requested"].includes(run.state)) {
1847
- return conflict(run.revision);
1848
- }
1849
- if (input.action === "requeue" && run.state !== "queued" && input.replaySafe !== true) {
1850
- throw new TypeError("Recovering an acquired run requires explicit replaySafe evidence");
2263
+ history: {
2264
+ async load(transaction, conversationId) {
2265
+ return (transaction.histories.get(conversationId) ?? []).map((message) => AgentMessageSchema.parse(structuredClone(message)));
2266
+ },
2267
+ async loadById(transaction, input) {
2268
+ const active = (transaction.histories.get(input.conversationId) ?? []).find((message2) => message2.id === input.messageId);
2269
+ const message = active ?? transaction.archivedMessages.get(input.conversationId)?.get(input.messageId);
2270
+ return message ? AgentMessageSchema.parse(structuredClone(message)) : undefined;
2271
+ },
2272
+ async apply(transaction, rawMutation) {
2273
+ const mutation = AgentHistoryMutationSchema.parse(rawMutation);
2274
+ const conversationId = mutation.type === "admit" ? mutation.input.conversationId : mutation.type === "upsert-assistant" ? mutation.message.conversationId : mutation.summary.conversationId;
2275
+ const current = transaction.histories.get(conversationId) ?? [];
2276
+ if (mutation.type === "admit") {
2277
+ transaction.histories.set(conversationId, [...current, mutation.input]);
2278
+ return;
2279
+ }
2280
+ if (mutation.type === "upsert-assistant") {
2281
+ transaction.histories.set(conversationId, replaceMessage(current, mutation.message));
2282
+ return;
2283
+ }
2284
+ const replaced = new Set(mutation.replacedMessageIds);
2285
+ const positions = current.map((message, index) => replaced.has(message.id) ? index : undefined).filter((index) => index !== undefined);
2286
+ const first = positions[0];
2287
+ if (first === undefined)
2288
+ throw new Error("Compaction history range disappeared");
2289
+ const archive = transaction.archivedMessages.get(conversationId) ?? new Map;
2290
+ for (const message of current.filter((candidate) => replaced.has(candidate.id))) {
2291
+ archive.set(message.id, AgentMessageSchema.parse(structuredClone(message)));
2292
+ }
2293
+ transaction.archivedMessages.set(conversationId, archive);
2294
+ transaction.histories.set(conversationId, [
2295
+ ...current.slice(0, first),
2296
+ mutation.summary,
2297
+ ...current.slice(first + positions.length)
2298
+ ]);
1851
2299
  }
1852
- const nextRun = AgentRunSchema.parse({
1853
- schemaVersion: 1,
1854
- id: run.id,
1855
- conversationId: run.conversationId,
1856
- inputMessageIds: run.inputMessageIds,
1857
- assistantMessageId: run.assistantMessageId,
1858
- state: input.action === "requeue" ? "queued" : "abandoned",
1859
- revision: run.revision + 1,
1860
- ...input.action === "abandon" && { terminalReason: "abandoned" },
1861
- createdAt: run.createdAt,
1862
- updatedAt: new Date().toISOString()
1863
- });
1864
- return apply(entry, AgentSnapshotSchema.parse({
1865
- ...entry.snapshot,
1866
- version: entry.snapshot.version + 1,
1867
- runs: replaceRun(entry.snapshot.runs, nextRun)
1868
- }));
1869
2300
  },
1870
- async commitRunTerminal(rawInput) {
1871
- const input = CommitRunTerminalSchema.parse(rawInput);
1872
- const entry = get(input.conversationId);
1873
- const run = entry.snapshot.runs.find((candidate) => candidate.id === input.runId);
1874
- if (!run)
1875
- return { outcome: "not_found" };
1876
- if (run.revision !== input.expectedRevision || run.state !== "running" && run.state !== "interrupt_requested" || run.ownerId !== input.ownerId || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !== terminalMessageStatus(input.reason)) {
1877
- return conflict(run.revision);
1878
- }
1879
- const nextRun = AgentRunSchema.parse({
1880
- ...run,
1881
- state: terminalState(input.reason),
1882
- terminalReason: input.reason,
1883
- ...input.policyName && { terminalPolicyName: input.policyName },
1884
- revision: run.revision + 1,
1885
- updatedAt: new Date().toISOString()
2301
+ async scanRecoverable(input) {
2302
+ const descriptors = [...states.values()].flatMap((state) => state.runs.filter((run) => ["queued", "running", "interrupt_requested"].includes(run.state)).map((run) => ({ conversationId: state.conversationId, run }))).sort((left, right) => left.conversationId.localeCompare(right.conversationId) || left.run.id.localeCompare(right.run.id));
2303
+ const cursorTuple = input.cursor ? parseRecoverableCursor(input.cursor) : undefined;
2304
+ const start = cursorTuple ? descriptors.findIndex((item) => item.conversationId === cursorTuple[0] && item.run.id === cursorTuple[1]) + 1 : 0;
2305
+ const items = descriptors.slice(start, start + input.limit);
2306
+ const last = items.at(-1);
2307
+ const hasMore = start + items.length < descriptors.length;
2308
+ return AgentRecoverablePageSchema.parse({
2309
+ items,
2310
+ ...hasMore && last && { nextCursor: recoverableCursor(last) }
1886
2311
  });
1887
- return apply(entry, AgentSnapshotSchema.parse({
1888
- ...entry.snapshot,
1889
- version: entry.snapshot.version + 1,
1890
- messages: replaceMessage(entry.snapshot.messages, input.assistant),
1891
- runs: replaceRun(entry.snapshot.runs, nextRun)
1892
- }));
1893
- },
1894
- async replaceCompactedRange(rawInput) {
1895
- const input = ReplaceCompactedRangeSchema.parse(rawInput);
1896
- const entry = get(input.conversationId);
1897
- if (entry.snapshot.version !== input.expectedVersion) {
1898
- return conflict(entry.snapshot.version);
1899
- }
1900
- const replaced = new Set(input.replacedMessageIds);
1901
- if (!input.replacedMessageIds.every((id) => entry.snapshot.messages.some((m) => m.id === id))) {
1902
- return { outcome: "not_found" };
1903
- }
1904
- const positions = entry.snapshot.messages.map((message, index) => replaced.has(message.id) ? index : undefined).filter((index) => index !== undefined);
1905
- const first = positions[0];
1906
- if (first === undefined || positions.some((position, offset) => position !== first + offset) || input.summary.conversationId !== input.conversationId || input.summary.runId !== undefined || input.summary.role !== "summary" || input.summary.status !== "committed") {
1907
- throw new TypeError("Compaction replacement must be one valid contiguous history range");
1908
- }
1909
- const before = entry.snapshot.messages.slice(0, first);
1910
- const after = entry.snapshot.messages.slice(first + positions.length);
1911
- return apply(entry, AgentSnapshotSchema.parse({
1912
- ...entry.snapshot,
1913
- version: entry.snapshot.version + 1,
1914
- messages: [...before, input.summary, ...after]
1915
- }));
1916
- },
1917
- async scanRecoverable() {
1918
- return [...conversations.values()].filter((entry) => entry.snapshot.runs.some((run) => ["queued", "running", "interrupt_requested"].includes(run.state))).map((entry) => cloneSnapshot(entry.snapshot));
1919
2312
  }
1920
2313
  };
2314
+ return createAgentRuntimeStore(driver);
1921
2315
  }
1922
2316
  export {
1923
2317
  AcceptInputAndAssignRunSchema,
1924
2318
  AcquireAgentRunSchema,
2319
+ AgentAdmissionEventSchema,
2320
+ AgentAdmissionIdentitySchema,
2321
+ AgentAssistantPlaceholderSchema,
1925
2322
  AgentCheckpointEventSchema,
1926
2323
  AgentControlPartSchema,
1927
2324
  AgentCostValueSchema,
1928
2325
  AgentFilePartSchema,
2326
+ AgentHistoryMutationSchema,
1929
2327
  AgentJsonObjectSchema,
1930
2328
  AgentMessagePartSchema,
1931
2329
  AgentMessageRoleSchema,
@@ -1935,10 +2333,16 @@ export {
1935
2333
  AgentModelDescriptorSchema,
1936
2334
  AgentOpaquePartSchema,
1937
2335
  AgentProviderEnvelopeSchema,
2336
+ AgentReasoningDeltaEventSchema,
2337
+ AgentReasoningEndEventSchema,
1938
2338
  AgentReasoningPartSchema,
2339
+ AgentReasoningStartEventSchema,
1939
2340
  AgentRecordIdSchema,
1940
2341
  AgentRecordVersionSchema,
2342
+ AgentRecoverableDescriptorSchema,
2343
+ AgentRecoverablePageSchema,
1941
2344
  AgentRunEventSchema,
2345
+ AgentRunMetricsSchema,
1942
2346
  AgentRunSchema,
1943
2347
  AgentRunStateEventSchema,
1944
2348
  AgentRunStateSchema,
@@ -1950,6 +2354,7 @@ export {
1950
2354
  AgentStoreDuplicateSchema,
1951
2355
  AgentStoreMutationResultSchema,
1952
2356
  AgentStoreNotFoundSchema,
2357
+ AgentStoredStateSchema,
1953
2358
  AgentTerminalEventSchema,
1954
2359
  AgentTerminalReasonSchema,
1955
2360
  AgentTextPartSchema,
@@ -1969,6 +2374,7 @@ export {
1969
2374
  composeAgentPrompt,
1970
2375
  createAgentObservability,
1971
2376
  createAgentRuntime,
2377
+ createAgentRuntimeStore,
1972
2378
  createAgentSessionCoordinator,
1973
2379
  createAgentToolFenceLifecycle,
1974
2380
  createMemoryAgentRuntimeStore,