stitchkit 0.65.1 → 0.66.1

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.
Files changed (35) hide show
  1. package/dist/agent-runtime/coordinator.d.ts +8 -5
  2. package/dist/agent-runtime/coordinator.d.ts.map +1 -1
  3. package/dist/agent-runtime/events.d.ts +36 -30
  4. package/dist/agent-runtime/events.d.ts.map +1 -1
  5. package/dist/agent-runtime/injection.d.ts +28 -0
  6. package/dist/agent-runtime/injection.d.ts.map +1 -0
  7. package/dist/agent-runtime/observability.d.ts +22 -20
  8. package/dist/agent-runtime/observability.d.ts.map +1 -1
  9. package/dist/agent-runtime/prompt.d.ts +11 -1
  10. package/dist/agent-runtime/prompt.d.ts.map +1 -1
  11. package/dist/agent-runtime/run-execution.d.ts +11 -0
  12. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  13. package/dist/agent-runtime/runtime-internals.d.ts.map +1 -1
  14. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  15. package/dist/agent-runtime/schemas.d.ts +75 -21
  16. package/dist/agent-runtime/schemas.d.ts.map +1 -1
  17. package/dist/agent-runtime/store-driver.d.ts +21 -15
  18. package/dist/agent-runtime/store-driver.d.ts.map +1 -1
  19. package/dist/agent-runtime/store.d.ts +280 -46
  20. package/dist/agent-runtime/store.d.ts.map +1 -1
  21. package/dist/agent-runtime/terminal-commit.d.ts +33 -3
  22. package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
  23. package/dist/agent-runtime/terminal-status.d.ts.map +1 -1
  24. package/dist/agent-runtime-openrouter.js +1 -1
  25. package/dist/agent-runtime.d.ts +1 -1
  26. package/dist/agent-runtime.d.ts.map +1 -1
  27. package/dist/agent-runtime.js +384 -97
  28. package/dist/{index-sbkyvacf.js → index-fhsmrzj7.js} +45 -5
  29. package/dist/testing/agent-store-conformance.d.ts +34 -1
  30. package/dist/testing/agent-store-conformance.d.ts.map +1 -1
  31. package/dist/testing.d.ts +1 -1
  32. package/dist/testing.d.ts.map +1 -1
  33. package/dist/testing.js +175 -4
  34. package/llms-full.txt +281 -22
  35. package/package.json +1 -1
@@ -13,6 +13,7 @@ import {
13
13
  AgentMessageSchema,
14
14
  AgentMessageStatusSchema,
15
15
  AgentOpaquePartSchema,
16
+ AgentProvenanceSchema,
16
17
  AgentProviderEnvelopeSchema,
17
18
  AgentReasoningPartSchema,
18
19
  AgentRecordIdSchema,
@@ -30,7 +31,7 @@ import {
30
31
  AgentUsageSchema,
31
32
  AgentUsageValueSchema,
32
33
  runStateForTerminalReason
33
- } from "./index-sbkyvacf.js";
34
+ } from "./index-fhsmrzj7.js";
34
35
  import"./index-6djpbnda.js";
35
36
  import"./index-cby4ar3v.js";
36
37
  import {
@@ -56,6 +57,8 @@ function assistantStatus(reason) {
56
57
  }
57
58
  if (reason === "superseded")
58
59
  return "superseded";
60
+ if (reason === "absorbed")
61
+ return "superseded";
59
62
  if (reason === "interrupted" || reason === "cancelled" || reason === "shutdown") {
60
63
  return "interrupted";
61
64
  }
@@ -836,7 +839,12 @@ function createAgentObservability(config) {
836
839
  import { z as z4 } from "zod";
837
840
  var AgentTokenCountSchema = z4.object({
838
841
  value: z4.int().nonnegative().optional(),
839
- provenance: z4.enum(["measured", "estimated", "unavailable"])
842
+ provenance: AgentProvenanceSchema.extract([
843
+ "measured",
844
+ "computed",
845
+ "estimated",
846
+ "unavailable"
847
+ ])
840
848
  });
841
849
  function completeTurn(messages) {
842
850
  if (messages[0]?.role !== "user")
@@ -947,7 +955,7 @@ async function selectAgentHistory(options) {
947
955
  return {
948
956
  messages,
949
957
  decisions,
950
- totalTokens: { value: total, provenance: estimated ? "estimated" : "measured" },
958
+ totalTokens: { value: total, provenance: estimated ? "estimated" : "computed" },
951
959
  outcome: total > options.availableTokens ? "oversized" : removed.size > 0 ? "truncated" : "fits"
952
960
  };
953
961
  }
@@ -964,11 +972,11 @@ function composeAgentPrompt(sections) {
964
972
  const text = await section.render({ context: options.context, signal: options.signal });
965
973
  rendered.push({ name: section.name, stability: section.stability, text });
966
974
  let count;
967
- if (section.estimateTokens)
968
- count = await section.estimateTokens(text);
969
- else if (options.estimateFallback)
970
- count = await options.estimateFallback(text);
971
- else
975
+ if (section.estimateTokens) {
976
+ count = AgentTokenCountSchema.parse(await section.estimateTokens(text));
977
+ } else if (options.estimateFallback) {
978
+ count = AgentTokenCountSchema.parse(await options.estimateFallback(text));
979
+ } else
972
980
  count = { provenance: "unavailable" };
973
981
  const value = knownValue(count);
974
982
  if (value === undefined)
@@ -978,20 +986,23 @@ function composeAgentPrompt(sections) {
978
986
  if (count.provenance === "estimated")
979
987
  estimated = true;
980
988
  }
981
- const instructionTokens = unavailable ? { provenance: "unavailable" } : { value: total, provenance: estimated ? "estimated" : "measured" };
989
+ const instructionTokens = unavailable ? { provenance: "unavailable" } : { value: total, provenance: estimated ? "estimated" : "computed" };
982
990
  let availableHistoryTokens;
983
991
  let contextDecision = "unavailable";
984
992
  if (options.budget) {
993
+ if (!Number.isSafeInteger(options.budget.contextWindow) || options.budget.contextWindow < 0 || !Number.isSafeInteger(options.budget.reservedOutput) || options.budget.reservedOutput < 0) {
994
+ throw new TypeError("contextWindow and reservedOutput must be non-negative safe integers");
995
+ }
985
996
  const reserveValues = [
986
997
  options.budget.reservedOutput,
987
- knownValue(options.budget.toolSchemas),
988
- knownValue(options.budget.attachments),
989
- knownValue(options.budget.providerOverhead),
998
+ knownValue(AgentTokenCountSchema.parse(options.budget.toolSchemas)),
999
+ knownValue(AgentTokenCountSchema.parse(options.budget.attachments)),
1000
+ knownValue(AgentTokenCountSchema.parse(options.budget.providerOverhead)),
990
1001
  knownValue(instructionTokens)
991
1002
  ];
992
1003
  if (reserveValues.every((value) => value !== undefined)) {
993
1004
  availableHistoryTokens = Math.max(0, options.budget.contextWindow - reserveValues.reduce((sum, value) => sum + (value ?? 0), 0));
994
- const historyTokens = options.historyTokens ? knownValue(options.historyTokens) : undefined;
1005
+ const historyTokens = options.historyTokens ? knownValue(AgentTokenCountSchema.parse(options.historyTokens)) : undefined;
995
1006
  if (historyTokens !== undefined) {
996
1007
  if (historyTokens <= availableHistoryTokens)
997
1008
  contextDecision = "fits";
@@ -1075,6 +1086,48 @@ function createRuntimeAdmissionLanes() {
1075
1086
  };
1076
1087
  }
1077
1088
 
1089
+ // src/agent-runtime/injection.ts
1090
+ function createAgentInjectionRegistry() {
1091
+ const offered = new Map;
1092
+ return {
1093
+ offer(key, entry) {
1094
+ const existing = offered.get(key);
1095
+ if (!existing) {
1096
+ offered.set(key, [entry]);
1097
+ return;
1098
+ }
1099
+ if (existing.some((candidate) => candidate.input.id === entry.input.id))
1100
+ return;
1101
+ existing.push(entry);
1102
+ },
1103
+ take(key, excludeRunId) {
1104
+ const existing = offered.get(key);
1105
+ if (!existing)
1106
+ return [];
1107
+ const taken = existing.filter((candidate) => candidate.runId !== excludeRunId);
1108
+ const kept = existing.filter((candidate) => candidate.runId === excludeRunId);
1109
+ if (kept.length === 0)
1110
+ offered.delete(key);
1111
+ else
1112
+ offered.set(key, kept);
1113
+ return taken;
1114
+ },
1115
+ withdraw(key, runId) {
1116
+ const existing = offered.get(key);
1117
+ if (!existing)
1118
+ return;
1119
+ const kept = existing.filter((candidate) => candidate.runId !== runId);
1120
+ if (kept.length === 0)
1121
+ offered.delete(key);
1122
+ else
1123
+ offered.set(key, kept);
1124
+ },
1125
+ clear() {
1126
+ offered.clear();
1127
+ }
1128
+ };
1129
+ }
1130
+
1078
1131
  // src/agent-runtime/run-execution.ts
1079
1132
  import {
1080
1133
  stepCountIs,
@@ -1096,16 +1149,33 @@ function appliedSnapshot(result, operation) {
1096
1149
  return result.snapshot;
1097
1150
  throw new AgentRuntimeConflictError(operation);
1098
1151
  }
1099
- function canonicalTerminal(snapshot, runId, retainedAssistant) {
1152
+ function viewOfSnapshot(snapshot, runId, retainedAssistant) {
1100
1153
  const run = snapshot.runs.find((candidate) => candidate.id === runId);
1154
+ const assistant = snapshot.messages.find((message) => message.id === run?.assistantMessageId) ?? retainedAssistant;
1155
+ return {
1156
+ snapshotVersion: snapshot.version,
1157
+ conversationId: snapshot.conversationId,
1158
+ ...run && { run },
1159
+ ...assistant && { assistant }
1160
+ };
1161
+ }
1162
+ function viewOfRun(view, conversationId) {
1163
+ return {
1164
+ snapshotVersion: view.snapshotVersion,
1165
+ conversationId,
1166
+ run: view.run,
1167
+ ...view.assistant && { assistant: view.assistant }
1168
+ };
1169
+ }
1170
+ function canonicalTerminal(view) {
1171
+ const { run, assistant } = view;
1101
1172
  if (!run?.terminalReason)
1102
1173
  return;
1103
- const assistant = snapshot.messages.find((message) => message.id === run.assistantMessageId) ?? retainedAssistant;
1104
- if (snapshot.conversationId !== run.conversationId || !assistant || assistant.id !== run.assistantMessageId || assistant.conversationId !== run.conversationId || assistant.runId !== run.id || assistant.role !== "assistant" || assistant.status !== assistantStatus(run.terminalReason)) {
1174
+ if (view.conversationId !== run.conversationId || !assistant || assistant.id !== run.assistantMessageId || assistant.conversationId !== run.conversationId || assistant.runId !== run.id || assistant.role !== "assistant" || assistant.status !== assistantStatus(run.terminalReason)) {
1105
1175
  throw new AgentRuntimeConflictError("terminal result projection");
1106
1176
  }
1107
1177
  return {
1108
- snapshot,
1178
+ snapshotVersion: view.snapshotVersion,
1109
1179
  run,
1110
1180
  assistant,
1111
1181
  reason: run.terminalReason,
@@ -1136,9 +1206,10 @@ function interruptedCandidate(candidate, run, now) {
1136
1206
  function canRetryTerminal(current, previous, runtimeEpoch) {
1137
1207
  return (current.state === "running" || current.state === "interrupt_requested") && current.ownerId === runtimeEpoch && current.fencingToken === previous.fencingToken;
1138
1208
  }
1209
+ var TERMINAL_COMMIT_ATTEMPTS = 32;
1139
1210
  async function commitAgentRunTerminal(input) {
1140
1211
  let candidate = input.candidate;
1141
- while (true) {
1212
+ for (let attempt = 0;attempt < TERMINAL_COMMIT_ATTEMPTS; attempt += 1) {
1142
1213
  const committed = await input.store.commitRunTerminal({
1143
1214
  conversationId: candidate.run.conversationId,
1144
1215
  runId: candidate.run.id,
@@ -1150,16 +1221,22 @@ async function commitAgentRunTerminal(input) {
1150
1221
  assistant: candidate.assistant,
1151
1222
  reason: candidate.reason,
1152
1223
  ...candidate.policyName && { policyName: candidate.policyName },
1153
- ...candidate.usage && { usage: candidate.usage }
1224
+ ...candidate.usage && { usage: candidate.usage },
1225
+ ...candidate.absorb?.length && { absorb: candidate.absorb }
1154
1226
  });
1155
1227
  if (committed.outcome === "applied") {
1156
- const terminal2 = canonicalTerminal(committed.snapshot, candidate.run.id);
1228
+ const terminal2 = canonicalTerminal(viewOfSnapshot(committed.snapshot, candidate.run.id));
1157
1229
  if (!terminal2)
1158
1230
  throw new AgentRuntimeConflictError("terminal result projection");
1159
- return { ...terminal2, committedByCaller: true };
1231
+ const absorbed = committed.snapshot.runs.filter((run) => run.absorbedIntoRunId === candidate.run.id);
1232
+ return {
1233
+ ...terminal2,
1234
+ committedByCaller: true,
1235
+ ...absorbed.length > 0 && { absorbed }
1236
+ };
1160
1237
  }
1161
1238
  if (committed.outcome === "duplicate") {
1162
- const terminal2 = canonicalTerminal(committed.snapshot, candidate.run.id, committed.assistant);
1239
+ const terminal2 = canonicalTerminal(viewOfSnapshot(committed.snapshot, candidate.run.id, committed.assistant));
1163
1240
  if (!terminal2)
1164
1241
  throw new AgentRuntimeConflictError("terminal result projection");
1165
1242
  return terminal2;
@@ -1167,16 +1244,20 @@ async function commitAgentRunTerminal(input) {
1167
1244
  if (committed.outcome !== "conflict") {
1168
1245
  throw new AgentRuntimeConflictError("terminal commit");
1169
1246
  }
1170
- const latest = await input.store.loadSnapshot(candidate.run.conversationId);
1171
- const terminal = canonicalTerminal(latest, candidate.run.id);
1247
+ const latest = await input.store.loadRun({
1248
+ conversationId: candidate.run.conversationId,
1249
+ runId: candidate.run.id
1250
+ });
1251
+ const terminal = latest ? canonicalTerminal(viewOfRun(latest, candidate.run.conversationId)) : undefined;
1172
1252
  if (terminal)
1173
1253
  return terminal;
1174
- const current = latest.runs.find((run) => run.id === candidate.run.id);
1254
+ const current = latest?.run;
1175
1255
  if (!current || !canRetryTerminal(current, candidate.run, input.runtimeEpoch)) {
1176
1256
  throw new AgentRuntimeConflictError("terminal commit");
1177
1257
  }
1178
1258
  candidate = current.state === "interrupt_requested" ? interruptedCandidate(candidate, current, input.now) : { ...candidate, run: current };
1179
1259
  }
1260
+ throw new AgentRuntimeConflictError("terminal commit");
1180
1261
  }
1181
1262
 
1182
1263
  // src/agent-runtime/runtime-internals.ts
@@ -1285,7 +1366,7 @@ function unknownUsage() {
1285
1366
  };
1286
1367
  }
1287
1368
  function normalizeSdkUsage(value) {
1288
- const reported = (tokens) => tokens === undefined ? { provenance: "unavailable" } : { value: tokens, provenance: "provider-reported" };
1369
+ const reported = (tokens) => tokens === undefined || !Number.isSafeInteger(tokens) || tokens < 0 ? { provenance: "unavailable" } : { value: tokens, provenance: "provider-reported" };
1289
1370
  return {
1290
1371
  inputTokens: reported(value.inputTokens),
1291
1372
  outputTokens: reported(value.outputTokens),
@@ -1329,11 +1410,36 @@ function createRunExecutor(dependencies) {
1329
1410
  now,
1330
1411
  checkpointEveryEvents,
1331
1412
  maxSteps,
1332
- idleTimeoutMs
1413
+ idleTimeoutMs,
1414
+ injection
1333
1415
  } = dependencies;
1334
1416
  return async function executeRun(input) {
1335
- const queuedSnapshot = await config.store.loadSnapshot(input.acceptedRun.conversationId);
1336
- const queuedRun = findRun(queuedSnapshot.runs, input.acceptedRun.id);
1417
+ injection?.withdraw(input.key, input.acceptedRun.id);
1418
+ const queued = await config.store.loadRun({
1419
+ conversationId: input.acceptedRun.conversationId,
1420
+ runId: input.acceptedRun.id
1421
+ });
1422
+ if (!queued)
1423
+ throw new AgentRuntimeConflictError("run lookup");
1424
+ if (queued.run.terminalReason === "absorbed") {
1425
+ const absorbing = queued.run.absorbedIntoRunId ? await config.store.loadRun({
1426
+ conversationId: queued.run.conversationId,
1427
+ runId: queued.run.absorbedIntoRunId
1428
+ }) : undefined;
1429
+ if (!absorbing?.assistant || !absorbing.run.terminalReason) {
1430
+ throw new AgentRuntimeConflictError("absorbed run resolution");
1431
+ }
1432
+ return {
1433
+ run: absorbing.run,
1434
+ message: absorbing.assistant,
1435
+ reason: absorbing.run.terminalReason,
1436
+ snapshotVersion: absorbing.snapshotVersion,
1437
+ ...absorbing.run.terminalPolicyName && {
1438
+ policyName: absorbing.run.terminalPolicyName
1439
+ }
1440
+ };
1441
+ }
1442
+ const queuedRun = queued.run;
1337
1443
  const acquired = appliedSnapshot(await config.store.acquireRun({
1338
1444
  conversationId: queuedRun.conversationId,
1339
1445
  runId: queuedRun.id,
@@ -1385,7 +1491,9 @@ function createRunExecutor(dependencies) {
1385
1491
  assistant
1386
1492
  }), "assistant draft");
1387
1493
  run = findRun(snapshot.runs, run.id);
1494
+ let observedVersion = snapshot.version;
1388
1495
  const parts = [];
1496
+ const absorbed = new Map;
1389
1497
  let eventCount = 0;
1390
1498
  let sequence = 0;
1391
1499
  let terminalReason = "success";
@@ -1436,6 +1544,7 @@ function createRunExecutor(dependencies) {
1436
1544
  assistant,
1437
1545
  usage: statedUsage(usage)
1438
1546
  }), "assistant checkpoint");
1547
+ observedVersion = snapshot.version;
1439
1548
  run = findRun(snapshot.runs, run.id);
1440
1549
  const checkpointMetrics = {
1441
1550
  partial: true,
@@ -1445,10 +1554,10 @@ function createRunExecutor(dependencies) {
1445
1554
  };
1446
1555
  await publish({
1447
1556
  type: "assistant-checkpoint",
1448
- eventId: agentDurableEventId("assistant-checkpoint", run.id, snapshot.version),
1557
+ eventId: agentDurableEventId("assistant-checkpoint", run.id, observedVersion),
1449
1558
  conversationId: run.conversationId,
1450
1559
  runId: run.id,
1451
- snapshotVersion: snapshot.version,
1560
+ snapshotVersion: observedVersion,
1452
1561
  message: assistant,
1453
1562
  metrics: checkpointMetrics,
1454
1563
  emittedAt: now().toISOString()
@@ -1462,6 +1571,7 @@ function createRunExecutor(dependencies) {
1462
1571
  signal: executionSignal
1463
1572
  });
1464
1573
  snapshot = compacted.snapshot;
1574
+ observedVersion = snapshot.version;
1465
1575
  run = findRun(snapshot.runs, run.id);
1466
1576
  if (compacted.usage)
1467
1577
  usage = addUsage(usage, compacted.usage);
@@ -1469,8 +1579,11 @@ function createRunExecutor(dependencies) {
1469
1579
  const assertCurrent = async () => {
1470
1580
  if (executionSignal.aborted)
1471
1581
  return "run_interrupted";
1472
- const current = await config.store.loadSnapshot(run.conversationId);
1473
- const currentRun = current.runs.find((candidate) => candidate.id === run.id);
1582
+ const current = await config.store.loadRun({
1583
+ conversationId: run.conversationId,
1584
+ runId: run.id
1585
+ });
1586
+ const currentRun = current?.run;
1474
1587
  if (!currentRun || currentRun.ownerId !== runtimeEpoch)
1475
1588
  return "stale_run";
1476
1589
  if (currentRun.fencingToken !== run.fencingToken)
@@ -1531,6 +1644,20 @@ function createRunExecutor(dependencies) {
1531
1644
  carriedSystem = detailed.system;
1532
1645
  return [...detailed.messages];
1533
1646
  };
1647
+ const projectInputs = async (source) => {
1648
+ if (config.history?.project)
1649
+ return config.history.project(source);
1650
+ const detailed = await projectAgentHistoryDetailed(source, {
1651
+ ...config.history?.resolveFile && { resolveFile: config.history.resolveFile },
1652
+ ...config.history?.unresolvedFile && {
1653
+ unresolvedFile: config.history.unresolvedFile
1654
+ },
1655
+ ...config.history?.interruptedAssistant && {
1656
+ interruptedAssistant: config.history.interruptedAssistant
1657
+ }
1658
+ });
1659
+ return [...detailed.messages];
1660
+ };
1534
1661
  const history = await projectHistory(snapshot);
1535
1662
  const withCarriedSystem = (instructions) => {
1536
1663
  if (carriedSystem.length === 0)
@@ -1558,6 +1685,19 @@ function createRunExecutor(dependencies) {
1558
1685
  return stopped;
1559
1686
  });
1560
1687
  }
1688
+ const takeInjectedMessages = async () => {
1689
+ const taken = injection?.take(input.key, run.id) ?? [];
1690
+ if (taken.length === 0)
1691
+ return [];
1692
+ const messages = [];
1693
+ for (const entry of taken) {
1694
+ messages.push(...await projectInputs([entry.input]));
1695
+ const ids = absorbed.get(entry.runId) ?? [];
1696
+ ids.push(entry.input.id);
1697
+ absorbed.set(entry.runId, ids);
1698
+ }
1699
+ return messages;
1700
+ };
1561
1701
  const result = streamText({
1562
1702
  model: selectedModel.model,
1563
1703
  tools,
@@ -1566,8 +1706,18 @@ function createRunExecutor(dependencies) {
1566
1706
  abortSignal: executionSignal,
1567
1707
  maxRetries: 0,
1568
1708
  stopWhen: stopConditions,
1569
- ...config.loop?.prepareStep && {
1570
- prepareStep: (options) => config.loop?.prepareStep?.({ ...options, ...runtimeContext })
1709
+ ...(config.loop?.prepareStep || injection) && {
1710
+ prepareStep: async (options) => {
1711
+ const prepared = await config.loop?.prepareStep?.({
1712
+ ...options,
1713
+ ...runtimeContext
1714
+ });
1715
+ const injected = await takeInjectedMessages();
1716
+ if (injected.length === 0)
1717
+ return prepared;
1718
+ const base = prepared?.messages ?? options.messages;
1719
+ return { ...prepared, messages: [...base, ...injected] };
1720
+ }
1571
1721
  }
1572
1722
  });
1573
1723
  for await (const part of result.stream) {
@@ -1818,11 +1968,14 @@ function createRunExecutor(dependencies) {
1818
1968
  terminalReason = abortTerminalReason(executionSignal);
1819
1969
  } catch (error) {
1820
1970
  internalCause = error;
1821
- const latest = await config.store.loadSnapshot(run.conversationId);
1822
- const latestRun = latest.runs.find((candidate) => candidate.id === run.id);
1971
+ const latest = await config.store.loadRun({
1972
+ conversationId: run.conversationId,
1973
+ runId: run.id
1974
+ });
1975
+ const latestRun = latest?.run;
1823
1976
  const durableInterrupt = latestRun?.ownerId === runtimeEpoch && latestRun.state === "interrupt_requested";
1824
- if (durableInterrupt && latestRun) {
1825
- snapshot = latest;
1977
+ if (durableInterrupt && latest && latestRun) {
1978
+ observedVersion = latest.snapshotVersion;
1826
1979
  run = latestRun;
1827
1980
  }
1828
1981
  if (isToolExecutionControlError(error) || executionSignal.aborted || durableInterrupt) {
@@ -1875,19 +2028,25 @@ function createRunExecutor(dependencies) {
1875
2028
  assistant,
1876
2029
  reason: terminalReason,
1877
2030
  ...terminalPolicyName && { policyName: terminalPolicyName },
1878
- usage: spent
2031
+ usage: spent,
2032
+ ...absorbed.size > 0 && runStateForTerminalReason(terminalReason) === "completed" && {
2033
+ absorb: [...absorbed].map(([runId, inputMessageIds]) => ({
2034
+ runId,
2035
+ inputMessageIds
2036
+ }))
2037
+ }
1879
2038
  },
1880
2039
  now
1881
2040
  });
1882
2041
  } catch (error) {
1883
2042
  emitSpend({
1884
- eventId: unsettledEventId(snapshot.version),
2043
+ eventId: unsettledEventId(observedVersion),
1885
2044
  state: run.state,
1886
2045
  reason: terminalReason
1887
2046
  });
1888
2047
  throw error;
1889
2048
  }
1890
- snapshot = terminal.snapshot;
2049
+ observedVersion = terminal.snapshotVersion;
1891
2050
  run = terminal.run;
1892
2051
  assistant = terminal.assistant;
1893
2052
  terminalReason = terminal.reason;
@@ -1899,17 +2058,28 @@ function createRunExecutor(dependencies) {
1899
2058
  ...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt }
1900
2059
  } : undefined;
1901
2060
  emitSpend({
1902
- eventId: terminal.committedByCaller ? agentDurableEventId("terminal", run.id, snapshot.version) : unsettledEventId(snapshot.version),
2061
+ eventId: terminal.committedByCaller ? agentDurableEventId("terminal", run.id, observedVersion) : unsettledEventId(observedVersion),
1903
2062
  state: run.state,
1904
2063
  reason: terminalReason
1905
2064
  });
2065
+ for (const settled of terminal.absorbed ?? []) {
2066
+ await publish({
2067
+ type: "run-state",
2068
+ eventId: agentDurableEventId("run-state", settled.id, observedVersion),
2069
+ conversationId: settled.conversationId,
2070
+ runId: settled.id,
2071
+ snapshotVersion: observedVersion,
2072
+ state: settled.state,
2073
+ emittedAt: now().toISOString()
2074
+ });
2075
+ }
1906
2076
  if (terminalMetrics) {
1907
2077
  await publish({
1908
2078
  type: "terminal",
1909
- eventId: agentDurableEventId("terminal", run.id, snapshot.version),
2079
+ eventId: agentDurableEventId("terminal", run.id, observedVersion),
1910
2080
  conversationId: run.conversationId,
1911
2081
  runId: run.id,
1912
- snapshotVersion: snapshot.version,
2082
+ snapshotVersion: observedVersion,
1913
2083
  reason: terminalReason,
1914
2084
  ...terminalPolicyName && { policyName: terminalPolicyName },
1915
2085
  message: assistant,
@@ -1921,7 +2091,7 @@ function createRunExecutor(dependencies) {
1921
2091
  run,
1922
2092
  message: assistant,
1923
2093
  reason: terminalReason,
1924
- snapshotVersion: snapshot.version,
2094
+ snapshotVersion: observedVersion,
1925
2095
  ...terminalMetrics && { metrics: terminalMetrics },
1926
2096
  ...terminalPolicyName && { policyName: terminalPolicyName }
1927
2097
  };
@@ -1936,6 +2106,8 @@ function createAgentRuntime(config) {
1936
2106
  const now = config.now ?? (() => new Date);
1937
2107
  const runtimeEpoch = generateId();
1938
2108
  const admissionLanes = createRuntimeAdmissionLanes();
2109
+ const injectionPossible = typeof config.runs?.inputPolicy === "function" || config.runs?.inputPolicy === "inject";
2110
+ const injection = injectionPossible ? createAgentInjectionRegistry() : undefined;
1939
2111
  const reserveAdmission = admissionLanes.reserve;
1940
2112
  const settleAdmission = admissionLanes.settle;
1941
2113
  const waitForAdmissionAcceptances = admissionLanes.waitForAcceptances;
@@ -1976,7 +2148,8 @@ function createAgentRuntime(config) {
1976
2148
  now,
1977
2149
  checkpointEveryEvents,
1978
2150
  maxSteps,
1979
- ...idleTimeoutMs !== undefined && { idleTimeoutMs }
2151
+ ...idleTimeoutMs !== undefined && { idleTimeoutMs },
2152
+ ...injection && { injection }
1980
2153
  });
1981
2154
  let admissionClosed = false;
1982
2155
  const closedError = () => new Error("[stitchkit] agent runtime is closed and admits no further work");
@@ -2033,8 +2206,13 @@ function createAgentRuntime(config) {
2033
2206
  const handedOff = beginAdmission();
2034
2207
  (async () => {
2035
2208
  try {
2036
- const snapshot = await config.store.loadSnapshot(rawInput.conversationId);
2037
- const recoveredRun = findRun(snapshot.runs, rawInput.runId);
2209
+ const recovered = await config.store.loadRun({
2210
+ conversationId: rawInput.conversationId,
2211
+ runId: rawInput.runId
2212
+ });
2213
+ if (!recovered)
2214
+ throw new AgentRuntimeConflictError("run lookup");
2215
+ const recoveredRun = recovered.run;
2038
2216
  if (recoveredRun.state !== "queued") {
2039
2217
  throw new Error("Only a queued recovered agent run can be resumed");
2040
2218
  }
@@ -2044,7 +2222,12 @@ function createAgentRuntime(config) {
2044
2222
  policy: "queue",
2045
2223
  create: (signal) => ({
2046
2224
  runId: recoveredRun.id,
2047
- execute: () => executeRun({ acceptedRun: recoveredRun, context, signal })
2225
+ execute: () => executeRun({
2226
+ acceptedRun: recoveredRun,
2227
+ context,
2228
+ signal,
2229
+ key: rawInput.conversationKey ?? rawInput.conversationId
2230
+ })
2048
2231
  })
2049
2232
  });
2050
2233
  ticket.accepted.catch(() => {
@@ -2134,7 +2317,10 @@ function createAgentRuntime(config) {
2134
2317
  currentConversationTickets.set(input.idempotencyKey, publicTicket);
2135
2318
  if (!conversationTickets)
2136
2319
  tickets.set(input.conversationId, currentConversationTickets);
2320
+ let offeredRunId;
2137
2321
  const forgetTicket = () => {
2322
+ if (offeredRunId !== undefined)
2323
+ injection?.withdraw(key, offeredRunId);
2138
2324
  if (currentConversationTickets.get(input.idempotencyKey) !== publicTicket)
2139
2325
  return;
2140
2326
  currentConversationTickets.delete(input.idempotencyKey);
@@ -2246,6 +2432,10 @@ function createAgentRuntime(config) {
2246
2432
  }
2247
2433
  return;
2248
2434
  }
2435
+ if (policy === "inject") {
2436
+ offeredRunId = acceptedRun.id;
2437
+ injection?.offer(key, { runId: acceptedRun.id, input: acceptedInput });
2438
+ }
2249
2439
  if (reservation && !reservation.shouldSchedule) {
2250
2440
  reservation.admission.completion.promise.then(outerResult.resolve, outerResult.reject);
2251
2441
  return;
@@ -2258,7 +2448,7 @@ function createAgentRuntime(config) {
2258
2448
  await waitForAdmissionAcceptances(reservation.lane);
2259
2449
  return {
2260
2450
  runId: acceptedRun.id,
2261
- execute: () => executeRun({ acceptedRun, context, signal })
2451
+ execute: () => executeRun({ acceptedRun, context, signal, key })
2262
2452
  };
2263
2453
  }
2264
2454
  });
@@ -2294,12 +2484,16 @@ function createAgentRuntime(config) {
2294
2484
  },
2295
2485
  resume,
2296
2486
  async interrupt(input) {
2297
- const snapshot = await config.store.loadSnapshot(input.conversationId);
2298
- const run = findRun(snapshot.runs, input.runId);
2487
+ const view = await config.store.loadRun({
2488
+ conversationId: input.conversationId,
2489
+ runId: input.runId
2490
+ });
2491
+ if (!view)
2492
+ throw new AgentRuntimeConflictError("run lookup");
2299
2493
  const requested = await config.store.requestRunInterrupt({
2300
2494
  conversationId: input.conversationId,
2301
2495
  runId: input.runId,
2302
- expectedRevision: run.revision
2496
+ expectedRevision: view.run.revision
2303
2497
  });
2304
2498
  if (requested.outcome === "applied") {
2305
2499
  const interruptedRun = findRun(requested.snapshot.runs, input.runId);
@@ -2342,8 +2536,8 @@ function createAgentRuntime(config) {
2342
2536
  const handedOff = beginAdmission();
2343
2537
  try {
2344
2538
  if (item.run.state === "queued") {
2345
- const snapshot = await config.store.loadSnapshot(item.conversationId);
2346
- const blockedByAcquiredPredecessor = snapshot.runs.some((run) => run.id !== item.run.id && (run.state === "running" || run.state === "interrupt_requested"));
2539
+ const active = await config.store.listActiveRuns(item.conversationId);
2540
+ const blockedByAcquiredPredecessor = active.some((run) => run.id !== item.run.id && (run.state === "running" || run.state === "interrupt_requested"));
2347
2541
  if (blockedByAcquiredPredecessor) {
2348
2542
  outcomes.push({
2349
2543
  conversationId: item.conversationId,
@@ -2430,6 +2624,7 @@ function createAgentRuntime(config) {
2430
2624
  assertCloseBudgets(options);
2431
2625
  admissionClosed = true;
2432
2626
  const startedAt = performance.now();
2627
+ injection?.clear();
2433
2628
  const stranded = await drainAdmissions(options.forceTimeoutMs);
2434
2629
  const spent = Math.max(0, Math.round(performance.now() - startedAt));
2435
2630
  const remainingBudget = (value) => value === undefined ? undefined : Math.max(0, value - spent);
@@ -2472,6 +2667,11 @@ var AgentStoreMutationResultSchema = z6.discriminatedUnion("outcome", [
2472
2667
  AgentStoreConflictSchema,
2473
2668
  AgentStoreNotFoundSchema
2474
2669
  ]);
2670
+ var AgentRunViewSchema = z6.object({
2671
+ snapshotVersion: AgentRecordVersionSchema,
2672
+ run: AgentRunSchema,
2673
+ assistant: AgentMessageSchema.optional()
2674
+ });
2475
2675
  var AcceptInputAndAssignRunSchema = z6.object({
2476
2676
  idempotencyKey: z6.string().min(1),
2477
2677
  expectedVersion: AgentRecordVersionSchema.optional(),
@@ -2503,7 +2703,11 @@ var CommitRunTerminalSchema = z6.object({
2503
2703
  assistant: AgentMessageSchema,
2504
2704
  reason: AgentTerminalReasonSchema,
2505
2705
  policyName: z6.string().min(1).optional(),
2506
- usage: AgentUsageSchema.optional()
2706
+ usage: AgentUsageSchema.optional(),
2707
+ absorb: z6.array(z6.object({
2708
+ runId: AgentRecordIdSchema,
2709
+ inputMessageIds: z6.array(AgentRecordIdSchema).min(1)
2710
+ })).min(1).optional()
2507
2711
  });
2508
2712
  var RequestRunInterruptSchema = z6.object({
2509
2713
  conversationId: AgentRecordIdSchema,
@@ -2665,9 +2869,9 @@ function applied(current, input, effects) {
2665
2869
  runs: input.runs ?? current.runs,
2666
2870
  messages: input.messages ?? current.messages
2667
2871
  }),
2668
- ...effects?.runRecord && { runRecord: effects.runRecord },
2872
+ ...effects?.runRecords?.length && { runRecords: effects.runRecords },
2669
2873
  ...effects?.admissionReceipt && { admissionReceipt: effects.admissionReceipt },
2670
- ...effects?.historyMutation && { historyMutation: effects.historyMutation }
2874
+ ...effects?.historyMutations?.length && { historyMutations: effects.historyMutations }
2671
2875
  };
2672
2876
  }
2673
2877
  function reduceStore(current, operation) {
@@ -2701,12 +2905,9 @@ function reduceStore(current, operation) {
2701
2905
  messages: [...current.messages, input.input],
2702
2906
  runs: coalescedRun ? replaceRun(current.runs, assignedRun) : [...current.runs, assignedRun]
2703
2907
  }, {
2704
- runRecord: AgentStoredRunSchema.parse({
2705
- schemaVersion: 1,
2706
- run: assignedRun
2707
- }),
2908
+ runRecords: [AgentStoredRunSchema.parse({ schemaVersion: 1, run: assignedRun })],
2708
2909
  admissionReceipt,
2709
- historyMutation: { type: "admit", input: input.input }
2910
+ historyMutations: [{ type: "admit", input: input.input }]
2710
2911
  });
2711
2912
  }
2712
2913
  const conversationId = operation.input.conversationId;
@@ -2728,7 +2929,7 @@ function reduceStore(current, operation) {
2728
2929
  updatedAt: new Date().toISOString()
2729
2930
  });
2730
2931
  return applied(current, { runs: replaceRun(current.runs, next) }, {
2731
- runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })
2932
+ runRecords: [AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })]
2732
2933
  });
2733
2934
  }
2734
2935
  if (operation.type === "checkpoint" && run) {
@@ -2746,8 +2947,8 @@ function reduceStore(current, operation) {
2746
2947
  runs: replaceRun(current.runs, next),
2747
2948
  messages: replaceMessage(current.messages, input.assistant)
2748
2949
  }, {
2749
- runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next }),
2750
- historyMutation: { type: "upsert-assistant", message: input.assistant }
2950
+ runRecords: [AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })],
2951
+ historyMutations: [{ type: "upsert-assistant", message: input.assistant }]
2751
2952
  });
2752
2953
  }
2753
2954
  if (operation.type === "interrupt" && run) {
@@ -2761,7 +2962,7 @@ function reduceStore(current, operation) {
2761
2962
  updatedAt: new Date().toISOString()
2762
2963
  });
2763
2964
  return applied(current, { runs: replaceRun(current.runs, next) }, {
2764
- runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })
2965
+ runRecords: [AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })]
2765
2966
  });
2766
2967
  }
2767
2968
  if (operation.type === "recover" && run) {
@@ -2799,42 +3000,82 @@ function reduceStore(current, operation) {
2799
3000
  runs: replaceRun(current.runs, next),
2800
3001
  messages: replaceMessage(current.messages, assistant)
2801
3002
  }, {
2802
- runRecord: AgentStoredRunSchema.parse({
2803
- schemaVersion: 1,
2804
- run: next,
2805
- terminalAssistant: assistant
2806
- }),
2807
- historyMutation: { type: "upsert-assistant", message: assistant }
3003
+ runRecords: [
3004
+ AgentStoredRunSchema.parse({
3005
+ schemaVersion: 1,
3006
+ run: next,
3007
+ terminalAssistant: assistant
3008
+ })
3009
+ ],
3010
+ historyMutations: [{ type: "upsert-assistant", message: assistant }]
2808
3011
  });
2809
3012
  }
2810
3013
  return applied(current, { runs: replaceRun(current.runs, next) }, {
2811
- runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })
3014
+ runRecords: [AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })]
2812
3015
  });
2813
3016
  }
2814
3017
  if (operation.type === "terminal" && run) {
2815
3018
  const input = operation.input;
3019
+ if (input.reason === "absorbed") {
3020
+ throw new TypeError("A run is absorbed by another run, never terminalized as absorbed");
3021
+ }
2816
3022
  if (run.revision !== input.expectedRevision || run.state !== "running" && run.state !== "interrupt_requested" || run.ownerId !== input.ownerId || input.fencingToken !== undefined && run.fencingToken !== input.fencingToken || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !== assistantStatus(input.reason)) {
2817
3023
  return conflict(run.revision);
2818
3024
  }
3025
+ if (input.absorb && runStateForTerminalReason(input.reason) !== "completed") {
3026
+ throw new TypeError("Only a completing run may absorb a queued successor");
3027
+ }
3028
+ const named = new Set((input.absorb ?? []).map((entry) => entry.runId));
3029
+ if (named.size !== (input.absorb ?? []).length || named.has(run.id)) {
3030
+ throw new TypeError("An absorption names each successor once, and never the absorbing run");
3031
+ }
3032
+ const absorbable = (input.absorb ?? []).filter((entry) => {
3033
+ const candidate = current.runs.find((item) => item.id === entry.runId);
3034
+ return candidate !== undefined && candidate.id !== run.id && candidate.state === "queued" && candidate.conversationId === run.conversationId && candidate.inputMessageIds.length === entry.inputMessageIds.length && candidate.inputMessageIds.every((id, index) => id === entry.inputMessageIds[index]);
3035
+ });
3036
+ const absorbedIds = new Set(absorbable.flatMap((entry) => entry.inputMessageIds));
2819
3037
  const next = AgentRunSchema.parse({
2820
3038
  ...run,
2821
3039
  state: runStateForTerminalReason(input.reason),
2822
3040
  terminalReason: input.reason,
2823
3041
  ...input.policyName && { terminalPolicyName: input.policyName },
2824
3042
  ...input.usage && { usage: input.usage },
3043
+ ...absorbedIds.size > 0 && {
3044
+ inputMessageIds: [
3045
+ ...run.inputMessageIds,
3046
+ ...[...absorbedIds].filter((id) => !run.inputMessageIds.includes(id))
3047
+ ]
3048
+ },
2825
3049
  revision: run.revision + 1,
2826
3050
  updatedAt: new Date().toISOString()
2827
3051
  });
3052
+ const absorbedRuns = absorbable.map((entry) => {
3053
+ const candidate = current.runs.find((item) => item.id === entry.runId);
3054
+ if (!candidate)
3055
+ throw new TypeError("Absorbed run disappeared inside the reducer");
3056
+ return AgentRunSchema.parse({
3057
+ ...candidate,
3058
+ state: runStateForTerminalReason("absorbed"),
3059
+ terminalReason: "absorbed",
3060
+ absorbedIntoRunId: next.id,
3061
+ revision: candidate.revision + 1,
3062
+ updatedAt: new Date().toISOString()
3063
+ });
3064
+ });
3065
+ const runs = absorbedRuns.reduce((accumulated, absorbed) => replaceRun(accumulated, absorbed), replaceRun(current.runs, next));
2828
3066
  return applied(current, {
2829
- runs: replaceRun(current.runs, next),
3067
+ runs,
2830
3068
  messages: replaceMessage(current.messages, input.assistant)
2831
3069
  }, {
2832
- runRecord: AgentStoredRunSchema.parse({
2833
- schemaVersion: 1,
2834
- run: next,
2835
- terminalAssistant: input.assistant
2836
- }),
2837
- historyMutation: { type: "upsert-assistant", message: input.assistant }
3070
+ runRecords: [
3071
+ AgentStoredRunSchema.parse({
3072
+ schemaVersion: 1,
3073
+ run: next,
3074
+ terminalAssistant: input.assistant
3075
+ }),
3076
+ ...absorbedRuns.map((absorbed) => AgentStoredRunSchema.parse({ schemaVersion: 1, run: absorbed }))
3077
+ ],
3078
+ historyMutations: [{ type: "upsert-assistant", message: input.assistant }]
2838
3079
  });
2839
3080
  }
2840
3081
  if (operation.type === "compact") {
@@ -2862,11 +3103,13 @@ function reduceStore(current, operation) {
2862
3103
  ...current.messages.slice(first + positions.length)
2863
3104
  ];
2864
3105
  return applied(current, { messages }, {
2865
- historyMutation: {
2866
- type: "replace-compacted-range",
2867
- replacedMessageIds: input.replacedMessageIds,
2868
- summary: input.summary
2869
- }
3106
+ historyMutations: [
3107
+ {
3108
+ type: "replace-compacted-range",
3109
+ replacedMessageIds: input.replacedMessageIds,
3110
+ summary: input.summary
3111
+ }
3112
+ ]
2870
3113
  });
2871
3114
  }
2872
3115
  return { outcome: "not_found" };
@@ -2912,6 +3155,37 @@ function createAgentRuntimeStore(driver) {
2912
3155
  });
2913
3156
  return snapshotOf(head, messages, mergeRunRecords(activeRecords, referencedRecords));
2914
3157
  });
3158
+ const loadRun = (input) => driver.transaction(async (transaction) => {
3159
+ const [stored, record] = await Promise.all([
3160
+ driver.head.load(transaction, input.conversationId),
3161
+ driver.runs.load(transaction, input)
3162
+ ]);
3163
+ if (!record)
3164
+ return;
3165
+ const parsed = AgentStoredRunSchema.parse(record);
3166
+ if (parsed.run.conversationId !== input.conversationId || parsed.run.id !== input.runId) {
3167
+ throw new TypeError("Stored run does not match the identity it was loaded by");
3168
+ }
3169
+ const head = AgentRuntimeHeadSchema.parse(stored ?? emptyHead(input.conversationId));
3170
+ return AgentRunViewSchema.parse({
3171
+ snapshotVersion: head.version,
3172
+ run: parsed.run,
3173
+ ...parsed.terminalAssistant && { assistant: parsed.terminalAssistant }
3174
+ });
3175
+ });
3176
+ const listActiveRuns = (conversationId) => driver.transaction(async (transaction) => {
3177
+ const records = await driver.runs.listActive(transaction, conversationId);
3178
+ const runs = records.map((record) => AgentStoredRunSchema.parse(record).run);
3179
+ for (const run of runs) {
3180
+ if (run.conversationId !== conversationId) {
3181
+ throw new TypeError("Active run belongs to another conversation");
3182
+ }
3183
+ if (!isActiveRunState(run.state)) {
3184
+ throw new TypeError("Active run listing returned a terminal run");
3185
+ }
3186
+ }
3187
+ return runs.sort((left, right) => left.createdAt === right.createdAt ? left.id.localeCompare(right.id) : left.createdAt < right.createdAt ? -1 : 1);
3188
+ });
2915
3189
  const mutate = (operation) => driver.transaction(async (transaction) => {
2916
3190
  const conversationId = operationConversationId(operation);
2917
3191
  const operationRunId = operation.type === "accept" ? operation.input.coalesceIntoRunId : operation.type === "compact" ? undefined : operation.input.runId;
@@ -2941,17 +3215,25 @@ function createAgentRuntimeStore(driver) {
2941
3215
  throw new TypeError("Admission receipt points to a missing canonical run");
2942
3216
  }
2943
3217
  validateAdmissionReceipt(duplicateReceipt, duplicateRecord, conversationId);
3218
+ const answering = duplicateRecord.run.absorbedIntoRunId ? await driver.runs.load(transaction, {
3219
+ conversationId,
3220
+ runId: duplicateRecord.run.absorbedIntoRunId
3221
+ }) : undefined;
3222
+ if (duplicateRecord.run.absorbedIntoRunId && !answering) {
3223
+ throw new TypeError("Absorbed run points to a missing absorbing run");
3224
+ }
3225
+ const canonical = answering ?? duplicateRecord;
2944
3226
  return {
2945
3227
  outcome: "duplicate",
2946
3228
  input: duplicateReceipt.input,
2947
3229
  inputMessageId: duplicateReceipt.input.id,
2948
- runId: duplicateReceipt.runId,
2949
- assistantMessageId: duplicateReceipt.assistantMessageId,
2950
- run: duplicateRecord.run,
2951
- ...duplicateRecord.terminalAssistant && {
2952
- assistant: duplicateRecord.terminalAssistant
3230
+ runId: canonical.run.id,
3231
+ assistantMessageId: canonical.run.assistantMessageId,
3232
+ run: canonical.run,
3233
+ ...canonical.terminalAssistant && {
3234
+ assistant: canonical.terminalAssistant
2953
3235
  },
2954
- snapshot: snapshotOf(head, messages, mergeRunRecords(records, [duplicateRecord]))
3236
+ snapshot: snapshotOf(head, messages, mergeRunRecords(records, [duplicateRecord], answering ? [answering] : []))
2955
3237
  };
2956
3238
  }
2957
3239
  if (operation.type === "accept") {
@@ -2993,18 +3275,21 @@ function createAgentRuntimeStore(driver) {
2993
3275
  });
2994
3276
  if (outcome.outcome === "conflict")
2995
3277
  return conflict(outcome.actualVersion);
2996
- if (reduced.runRecord)
2997
- await driver.runs.save(transaction, reduced.runRecord);
3278
+ for (const record of reduced.runRecords ?? []) {
3279
+ await driver.runs.save(transaction, record);
3280
+ }
2998
3281
  if (reduced.admissionReceipt) {
2999
3282
  await driver.admissions.create(transaction, reduced.admissionReceipt);
3000
3283
  }
3001
- if (reduced.historyMutation) {
3002
- await driver.history.apply(transaction, reduced.historyMutation);
3284
+ for (const mutation of reduced.historyMutations ?? []) {
3285
+ await driver.history.apply(transaction, mutation);
3003
3286
  }
3004
3287
  return { outcome: "applied", snapshot: reduced.snapshot };
3005
3288
  });
3006
3289
  return {
3007
3290
  loadSnapshot,
3291
+ loadRun,
3292
+ listActiveRuns,
3008
3293
  acceptInputAndAssignRun: (input) => mutate({
3009
3294
  type: "accept",
3010
3295
  input: AcceptInputAndAssignRunSchema.parse(input)
@@ -3213,6 +3498,7 @@ export {
3213
3498
  AgentModelDescriptorSchema,
3214
3499
  AgentModelRegistrySnapshotSchema,
3215
3500
  AgentOpaquePartSchema,
3501
+ AgentProvenanceSchema,
3216
3502
  AgentProviderEnvelopeSchema,
3217
3503
  AgentReasoningDeltaEventSchema,
3218
3504
  AgentReasoningEndEventSchema,
@@ -3229,6 +3515,7 @@ export {
3229
3515
  AgentRunStateEventSchema,
3230
3516
  AgentRunStateSchema,
3231
3517
  AgentRunTerminalEventSchema,
3518
+ AgentRunViewSchema,
3232
3519
  AgentRuntimeConflictError,
3233
3520
  AgentRuntimeEventCursorSchema,
3234
3521
  AgentRuntimeEventSchema,