@elie-laloum/outpost 7.0.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +2 -0
  3. package/dist/adapters/agents/antigravity-adapter.js +3 -0
  4. package/dist/adapters/agents/antigravity-adapter.js.map +1 -1
  5. package/dist/adapters/agents/claude-adapter.js +3 -0
  6. package/dist/adapters/agents/claude-adapter.js.map +1 -1
  7. package/dist/adapters/agents/claude-events.js +25 -1
  8. package/dist/adapters/agents/claude-events.js.map +1 -1
  9. package/dist/adapters/agents/codex-adapter.js +3 -0
  10. package/dist/adapters/agents/codex-adapter.js.map +1 -1
  11. package/dist/adapters/agents/copilot-adapter.js +3 -0
  12. package/dist/adapters/agents/copilot-adapter.js.map +1 -1
  13. package/dist/adapters/agents/copilot-events.js +7 -3
  14. package/dist/adapters/agents/copilot-events.js.map +1 -1
  15. package/dist/adapters/agents/kimi-adapter.js +3 -0
  16. package/dist/adapters/agents/kimi-adapter.js.map +1 -1
  17. package/dist/adapters/agents/quota.constants.d.ts +7 -0
  18. package/dist/adapters/agents/quota.constants.js +31 -0
  19. package/dist/adapters/agents/quota.constants.js.map +1 -0
  20. package/dist/adapters/agents/quota.d.ts +1 -0
  21. package/dist/adapters/agents/quota.js +4 -0
  22. package/dist/adapters/agents/quota.js.map +1 -0
  23. package/dist/adapters/models/http-provider.js +8 -2
  24. package/dist/adapters/models/http-provider.js.map +1 -1
  25. package/dist/adapters/models/model.constants.d.ts +2 -0
  26. package/dist/adapters/models/model.constants.js +6 -0
  27. package/dist/adapters/models/model.constants.js.map +1 -1
  28. package/dist/adapters/models/stream-events.js +11 -7
  29. package/dist/adapters/models/stream-events.js.map +1 -1
  30. package/dist/application/agent-output.js +10 -1
  31. package/dist/application/agent-output.js.map +1 -1
  32. package/dist/application/agent-quota.d.ts +7 -0
  33. package/dist/application/agent-quota.js +33 -0
  34. package/dist/application/agent-quota.js.map +1 -0
  35. package/dist/application/agent-turn.js +25 -9
  36. package/dist/application/agent-turn.js.map +1 -1
  37. package/dist/application/dispatch-observation.js +10 -1
  38. package/dist/application/dispatch-observation.js.map +1 -1
  39. package/dist/application/execution.types.d.ts +2 -0
  40. package/dist/application/execution.types.js.map +1 -1
  41. package/dist/application/interactive-task-execution.d.ts +3 -0
  42. package/dist/application/interactive-task-execution.js +76 -0
  43. package/dist/application/interactive-task-execution.js.map +1 -0
  44. package/dist/application/interactive-task-protocol.d.ts +4 -0
  45. package/dist/application/interactive-task-protocol.js +56 -0
  46. package/dist/application/interactive-task-protocol.js.map +1 -0
  47. package/dist/application/interactive-task.constants.d.ts +4 -0
  48. package/dist/application/interactive-task.constants.js +7 -0
  49. package/dist/application/interactive-task.constants.js.map +1 -0
  50. package/dist/application/interactive-task.d.ts +3 -0
  51. package/dist/application/interactive-task.js +84 -0
  52. package/dist/application/interactive-task.js.map +1 -0
  53. package/dist/application/interactive-task.types.d.ts +44 -0
  54. package/dist/application/interactive-task.types.js +2 -0
  55. package/dist/application/interactive-task.types.js.map +1 -0
  56. package/dist/application/queue-worker.js +19 -1
  57. package/dist/application/queue-worker.js.map +1 -1
  58. package/dist/application/queued-task.js +17 -2
  59. package/dist/application/queued-task.js.map +1 -1
  60. package/dist/application/quota-resume.constants.d.ts +1 -0
  61. package/dist/application/quota-resume.constants.js +2 -0
  62. package/dist/application/quota-resume.constants.js.map +1 -0
  63. package/dist/application/quota-resume.d.ts +9 -0
  64. package/dist/application/quota-resume.js +34 -0
  65. package/dist/application/quota-resume.js.map +1 -0
  66. package/dist/application/quota-resume.types.d.ts +1 -0
  67. package/dist/application/quota-resume.types.js +2 -0
  68. package/dist/application/quota-resume.types.js.map +1 -0
  69. package/dist/application/recovery-retention-policy.js +1 -1
  70. package/dist/application/recovery-retention-policy.js.map +1 -1
  71. package/dist/application/recovery-retention.js +3 -3
  72. package/dist/application/recovery-retention.js.map +1 -1
  73. package/dist/application/recovery-retention.types.d.ts +1 -1
  74. package/dist/application/recovery-retention.types.js.map +1 -1
  75. package/dist/application/remote-workspace.js +2 -1
  76. package/dist/application/remote-workspace.js.map +1 -1
  77. package/dist/application/replay-recording.d.ts +2 -0
  78. package/dist/application/replay-recording.js +22 -0
  79. package/dist/application/replay-recording.js.map +1 -0
  80. package/dist/application/replay-turn.d.ts +4 -0
  81. package/dist/application/replay-turn.js +47 -0
  82. package/dist/application/replay-turn.js.map +1 -0
  83. package/dist/application/replay-workspace.d.ts +4 -0
  84. package/dist/application/replay-workspace.js +71 -0
  85. package/dist/application/replay-workspace.js.map +1 -0
  86. package/dist/application/replay-workspace.types.d.ts +6 -0
  87. package/dist/application/replay-workspace.types.js +2 -0
  88. package/dist/application/replay-workspace.types.js.map +1 -0
  89. package/dist/application/repository-fingerprint.d.ts +1 -0
  90. package/dist/application/repository-fingerprint.js +18 -0
  91. package/dist/application/repository-fingerprint.js.map +1 -0
  92. package/dist/application/sandbox-dispatch.js +2 -0
  93. package/dist/application/sandbox-dispatch.js.map +1 -1
  94. package/dist/application/speculation-checkpoint.js +19 -2
  95. package/dist/application/speculation-checkpoint.js.map +1 -1
  96. package/dist/application/speculation-checkpoint.types.d.ts +1 -1
  97. package/dist/application/speculation-checkpoint.types.js.map +1 -1
  98. package/dist/application/speculation-resume.js +21 -0
  99. package/dist/application/speculation-resume.js.map +1 -1
  100. package/dist/application/speculation-run.js +18 -1
  101. package/dist/application/speculation-run.js.map +1 -1
  102. package/dist/application/speculation.types.d.ts +7 -2
  103. package/dist/application/speculation.types.js.map +1 -1
  104. package/dist/application/tasks.d.ts +2 -2
  105. package/dist/application/tasks.js +11 -4
  106. package/dist/application/tasks.js.map +1 -1
  107. package/dist/application/tasks.types.d.ts +5 -0
  108. package/dist/application/tasks.types.js.map +1 -1
  109. package/dist/application/transport-inspection.constants.js +1 -0
  110. package/dist/application/transport-inspection.constants.js.map +1 -1
  111. package/dist/application/transport-retention.js +33 -1
  112. package/dist/application/transport-retention.js.map +1 -1
  113. package/dist/domain/agent-observation.js +1 -0
  114. package/dist/domain/agent-observation.js.map +1 -1
  115. package/dist/domain/agent.types.d.ts +8 -1
  116. package/dist/domain/agent.types.js.map +1 -1
  117. package/dist/domain/errors.types.d.ts +1 -1
  118. package/dist/domain/errors.types.js.map +1 -1
  119. package/dist/domain/observation.types.d.ts +6 -1
  120. package/dist/domain/observation.types.js.map +1 -1
  121. package/dist/domain/quota.constants.d.ts +1 -0
  122. package/dist/domain/quota.constants.js +2 -0
  123. package/dist/domain/quota.constants.js.map +1 -0
  124. package/dist/domain/quota.d.ts +4 -0
  125. package/dist/domain/quota.js +28 -0
  126. package/dist/domain/quota.js.map +1 -0
  127. package/dist/domain/quota.types.d.ts +7 -0
  128. package/dist/domain/quota.types.js +2 -0
  129. package/dist/domain/quota.types.js.map +1 -0
  130. package/dist/domain/replay.constants.d.ts +11 -0
  131. package/dist/domain/replay.constants.js +42 -0
  132. package/dist/domain/replay.constants.js.map +1 -0
  133. package/dist/domain/replay.d.ts +11 -0
  134. package/dist/domain/replay.js +231 -0
  135. package/dist/domain/replay.js.map +1 -0
  136. package/dist/domain/replay.types.d.ts +84 -0
  137. package/dist/domain/replay.types.js +2 -0
  138. package/dist/domain/replay.types.js.map +1 -0
  139. package/dist/domain/task-queue.js +18 -0
  140. package/dist/domain/task-queue.js.map +1 -1
  141. package/dist/domain/task-queue.types.d.ts +9 -0
  142. package/dist/domain/task-queue.types.js.map +1 -1
  143. package/dist/domain/workflow/checkpoint-validation.js +14 -1
  144. package/dist/domain/workflow/checkpoint-validation.js.map +1 -1
  145. package/dist/domain/workflow/checkpoint.js +13 -2
  146. package/dist/domain/workflow/checkpoint.js.map +1 -1
  147. package/dist/domain/workflow/gate-validation.js +2 -1
  148. package/dist/domain/workflow/gate-validation.js.map +1 -1
  149. package/dist/domain/workflow/input-validation.d.ts +7 -0
  150. package/dist/domain/workflow/input-validation.js +82 -0
  151. package/dist/domain/workflow/input-validation.js.map +1 -0
  152. package/dist/domain/workflow/input.d.ts +10 -0
  153. package/dist/domain/workflow/input.js +93 -0
  154. package/dist/domain/workflow/input.js.map +1 -0
  155. package/dist/domain/workflow/input.types.d.ts +37 -0
  156. package/dist/domain/workflow/input.types.js +2 -0
  157. package/dist/domain/workflow/input.types.js.map +1 -0
  158. package/dist/domain/workflow/loop-runner.d.ts +3 -0
  159. package/dist/domain/workflow/loop-runner.js +91 -0
  160. package/dist/domain/workflow/loop-runner.js.map +1 -0
  161. package/dist/domain/workflow/loop-task.d.ts +10 -0
  162. package/dist/domain/workflow/loop-task.js +39 -0
  163. package/dist/domain/workflow/loop-task.js.map +1 -0
  164. package/dist/domain/workflow/loop-task.types.d.ts +28 -0
  165. package/dist/domain/workflow/loop-task.types.js +2 -0
  166. package/dist/domain/workflow/loop-task.types.js.map +1 -0
  167. package/dist/domain/workflow/loop-validation.d.ts +4 -0
  168. package/dist/domain/workflow/loop-validation.js +62 -0
  169. package/dist/domain/workflow/loop-validation.js.map +1 -0
  170. package/dist/domain/workflow/quota-pause.d.ts +7 -0
  171. package/dist/domain/workflow/quota-pause.js +83 -0
  172. package/dist/domain/workflow/quota-pause.js.map +1 -0
  173. package/dist/domain/workflow/quota-pause.types.d.ts +14 -0
  174. package/dist/domain/workflow/quota-pause.types.js +2 -0
  175. package/dist/domain/workflow/quota-pause.types.js.map +1 -0
  176. package/dist/domain/workflow/quota-validation.d.ts +2 -0
  177. package/dist/domain/workflow/quota-validation.js +30 -0
  178. package/dist/domain/workflow/quota-validation.js.map +1 -0
  179. package/dist/domain/workflow/task-cache-entry.d.ts +3 -0
  180. package/dist/domain/workflow/task-cache-entry.js +57 -0
  181. package/dist/domain/workflow/task-cache-entry.js.map +1 -0
  182. package/dist/domain/workflow/task-cache.constants.d.ts +3 -0
  183. package/dist/domain/workflow/task-cache.constants.js +3 -0
  184. package/dist/domain/workflow/task-cache.constants.js.map +1 -0
  185. package/dist/domain/workflow/task-cache.d.ts +6 -0
  186. package/dist/domain/workflow/task-cache.js +92 -0
  187. package/dist/domain/workflow/task-cache.js.map +1 -0
  188. package/dist/domain/workflow/task-cache.types.d.ts +35 -0
  189. package/dist/domain/workflow/task-cache.types.js +2 -0
  190. package/dist/domain/workflow/task-cache.types.js.map +1 -0
  191. package/dist/domain/workflow/task-runner.js +100 -34
  192. package/dist/domain/workflow/task-runner.js.map +1 -1
  193. package/dist/domain/workflow/task.js +21 -0
  194. package/dist/domain/workflow/task.js.map +1 -1
  195. package/dist/domain/workflow/validation.js +13 -2
  196. package/dist/domain/workflow/validation.js.map +1 -1
  197. package/dist/domain/workflow/workflow-scheduler.js +27 -2
  198. package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
  199. package/dist/domain/workflow/workflow-state.js +20 -3
  200. package/dist/domain/workflow/workflow-state.js.map +1 -1
  201. package/dist/domain/workflow.types.d.ts +26 -3
  202. package/dist/domain/workflow.types.js.map +1 -1
  203. package/dist/index.d.ts +16 -1
  204. package/dist/index.js +6 -0
  205. package/dist/index.js.map +1 -1
  206. package/dist/infrastructure/git/command.d.ts +2 -1
  207. package/dist/infrastructure/git/command.js +2 -2
  208. package/dist/infrastructure/git/command.js.map +1 -1
  209. package/dist/infrastructure/git/replay-commits.constants.d.ts +5 -0
  210. package/dist/infrastructure/git/replay-commits.constants.js +6 -0
  211. package/dist/infrastructure/git/replay-commits.constants.js.map +1 -0
  212. package/dist/infrastructure/git/replay-commits.d.ts +2 -0
  213. package/dist/infrastructure/git/replay-commits.js +92 -0
  214. package/dist/infrastructure/git/replay-commits.js.map +1 -0
  215. package/dist/infrastructure/journal.types.d.ts +1 -0
  216. package/dist/infrastructure/journal.types.js.map +1 -1
  217. package/dist/infrastructure/reporter.js +3 -0
  218. package/dist/infrastructure/reporter.js.map +1 -1
  219. package/dist/infrastructure/storage-inventory.types.d.ts +1 -1
  220. package/dist/infrastructure/storage-inventory.types.js.map +1 -1
  221. package/dist/infrastructure/transport-task-cache.constants.d.ts +2 -0
  222. package/dist/infrastructure/transport-task-cache.constants.js +3 -0
  223. package/dist/infrastructure/transport-task-cache.constants.js.map +1 -0
  224. package/dist/infrastructure/transport-task-cache.d.ts +3 -0
  225. package/dist/infrastructure/transport-task-cache.js +56 -0
  226. package/dist/infrastructure/transport-task-cache.js.map +1 -0
  227. package/dist/infrastructure/transport-task-cache.types.d.ts +4 -0
  228. package/dist/infrastructure/transport-task-cache.types.js +2 -0
  229. package/dist/infrastructure/transport-task-cache.types.js.map +1 -0
  230. package/package.json +1 -1
@@ -5,6 +5,7 @@ import { speculationTimeout } from "./speculation-timeout.js";
5
5
  import { git } from "../infrastructure/git/command.js";
6
6
  import { taskObservation } from "./task-observation.js";
7
7
  import { invariant, recoveryDetails } from "../domain/errors.js";
8
+ import { quotaFault } from "../domain/quota.js";
8
9
  import { workflowAccounting } from "../domain/workflow/budget.js";
9
10
  import { speculativeHostSnapshot } from "./speculation-host.js";
10
11
  import { createSandbox } from "./sandbox.js";
@@ -189,13 +190,18 @@ export async function runSpeculation(options, state, session, concurrency, clean
189
190
  : undefined;
190
191
  const directory = sandbox?.workspace.directory ?? recoveredDirectory;
191
192
  retainedDirectory ??= recoveredDirectory;
193
+ const fault = quotaFault(error);
194
+ const quota = fault && {
195
+ message: fault.message,
196
+ ...(fault.resetAt ? { resetAt: fault.resetAt } : {}),
197
+ };
192
198
  function candidateStatus() {
193
199
  if (cleanupFailed)
194
200
  return "failed";
195
201
  if (signal.aborted)
196
202
  return "cancelled";
197
203
  if (error !== undefined)
198
- return "failed";
204
+ return quota ? "quota" : "failed";
199
205
  if (accepted && !winner)
200
206
  return "winner";
201
207
  return "rejected";
@@ -216,6 +222,7 @@ export async function runSpeculation(options, state, session, concurrency, clean
216
222
  ...(retainedDirectory ? { retainedDirectory } : {}),
217
223
  ...(result ? { result } : {}),
218
224
  ...(error !== undefined ? { error } : {}),
225
+ ...(status === "quota" ? { quota: quota } : {}),
219
226
  };
220
227
  records[index] = record;
221
228
  attempt.record = record;
@@ -274,6 +281,8 @@ export async function runSpeculation(options, state, session, concurrency, clean
274
281
  return "aborted";
275
282
  if (budgetError !== undefined)
276
283
  return "budget-exhausted";
284
+ if (records.some((record) => record.status === "quota"))
285
+ return "quota";
277
286
  return "no-winner";
278
287
  }
279
288
  sealed = true;
@@ -311,10 +320,18 @@ export async function runSpeculation(options, state, session, concurrency, clean
311
320
  }
312
321
  : {}),
313
322
  usage: accounting.snapshot(),
323
+ ...(status === "quota" ? { quota: earliestQuota(records) } : {}),
314
324
  ...(winner ? { winner } : {}),
315
325
  ...(budgetError !== undefined || state.error
316
326
  ? { error: budgetError ?? state.error }
317
327
  : {}),
318
328
  };
319
329
  }
330
+ function earliestQuota(records) {
331
+ const faults = records.flatMap((record) => record.status === "quota" && record.quota ? [record.quota] : []);
332
+ const known = faults
333
+ .filter((fault) => fault.resetAt !== undefined)
334
+ .sort((a, b) => Date.parse(a.resetAt) - Date.parse(b.resetAt));
335
+ return known[0] ?? faults[0];
336
+ }
320
337
  //# sourceMappingURL=speculation-run.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"speculation-run.js","sourceRoot":"","sources":["../../src/application/speculation-run.ts"],"names":[],"mappings":"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","sourcesContent":["import { resumeSpeculation } from \"./speculation-resume.ts\";\nimport { encodeSpeculation } from \"./speculation-checkpoint.ts\";\nimport { checkSpeculationIntegration } from \"./speculation-integration.ts\";\nimport { speculationTimeout } from \"./speculation-timeout.ts\";\nimport type { SpeculationCheckpoint } from \"./speculation-checkpoint.types.ts\";\nimport type { SpeculationStoreSession } from \"../infrastructure/speculation-store.types.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { taskObservation } from \"./task-observation.ts\";\nimport { invariant, recoveryDetails } from \"../domain/errors.ts\";\nimport { workflowAccounting } from \"../domain/workflow/budget.ts\";\nimport { speculativeHostSnapshot } from \"./speculation-host.ts\";\nimport type { Sandbox } from \"./outpost.types.ts\";\nimport { createSandbox } from \"./sandbox.ts\";\nimport type {\n SpeculationOptions,\n SpeculationResult,\n SpeculativeCandidateResult,\n SpeculativeOutput,\n} from \"./speculation.types.ts\";\nimport { taskUsage } from \"./task-usage.ts\";\n\nexport async function runSpeculation<T>(\n options: SpeculationOptions<T>,\n state: SpeculationCheckpoint<T>,\n session: SpeculationStoreSession | undefined,\n concurrency: number,\n cleanupMs: number,\n): Promise<SpeculationResult<T>> {\n const { candidates } = options;\n const stop = new AbortController();\n const signal = options.signal\n ? AbortSignal.any([options.signal, stop.signal])\n : stop.signal;\n let budgetError: unknown;\n let sealed = false;\n const accounting = workflowAccounting(\n options.budget,\n (error) => {\n budgetError = error;\n // Attempt limits stop admissions; already admitted candidates may finish.\n if (error.dimension !== \"attempts\") stop.abort(error);\n },\n state.usage,\n );\n const before = state.before;\n const baseline = before.head;\n const id = state.id;\n const save = async () => {\n if (sealed) return;\n state.usage = accounting.snapshot();\n try {\n await session?.save(encodeSpeculation(state));\n } catch (error) {\n stop.abort(error);\n throw error;\n }\n };\n const latest = await resumeSpeculation(\n options,\n state,\n accounting,\n save,\n cleanupMs,\n );\n const records: SpeculativeCandidateResult<T>[] = candidates.map(\n (candidate) => {\n const attempt = latest.get(candidate.key)!;\n return (\n attempt.record ?? {\n key: candidate.key,\n branch: attempt.branch,\n attempt: attempt.attempt,\n status: \"skipped\",\n }\n );\n },\n );\n let winner = records.find((record) => record.status === \"winner\");\n await save();\n let next = 0;\n async function worker(): Promise<void> {\n while (!signal.aborted && !winner && !accounting.exhausted) {\n const index = next++;\n const candidate = candidates[index];\n if (!candidate) return;\n const attempt = latest.get(candidate.key)!;\n if (attempt.phase === \"settled\" || state.finished) continue;\n try {\n accounting.admit();\n attempt.phase = \"running\";\n attempt.cleanup = \"pending\";\n await save();\n } catch (error) {\n if (!accounting.exhausted) throw error;\n return;\n }\n const observation = taskObservation(\n options.observation ?? candidate.request.observation,\n candidate.request.observe,\n { candidate: candidate.key },\n );\n const initial = records[index]!;\n let sandbox: Sandbox | undefined;\n let result: SpeculativeOutput<T> | undefined;\n let error: unknown;\n let accepted = false;\n let cleanupFailed = false;\n let retainedDirectory: string | undefined;\n const usage = taskUsage(\n {\n reportUsage: (value) => {\n if (sealed) return;\n accounting.report(value);\n void save().catch((error) => stop.abort(error));\n },\n },\n undefined,\n );\n try {\n sandbox = await createSandbox({\n ...options.sandbox,\n ...(observation ? { observation } : {}),\n repository: options.repository,\n sandboxProvider: {\n ...options.sandboxProvider,\n async acquire(context) {\n attempt.directory = context.directory;\n await save();\n const lease = await options.sandboxProvider.acquire({\n ...context,\n ...(session\n ? {\n async registerRecovery(resourceId: string) {\n invariant(\n !sealed && !signal.aborted,\n \"Speculation allocation cancelled\",\n );\n invariant(\n resourceId.length > 0 && resourceId.length <= 1024,\n \"Invalid speculation resource identity\",\n );\n invariant(\n !attempt.resourceId,\n \"Provider registered more than one speculation resource\",\n );\n attempt.resourceId = resourceId;\n await save();\n signal.throwIfAborted();\n },\n }\n : {}),\n });\n if (session && !attempt.resourceId) {\n await lease.release();\n throw new Error(\n \"Durable provider did not register its resource before allocation\",\n );\n }\n return lease;\n },\n },\n branch: { mode: \"named\", name: initial.branch, from: baseline },\n agent: candidate.agent,\n signal,\n });\n signal.throwIfAborted();\n invariant(\n sandbox.workspace.baseline === baseline,\n \"Speculative workspace does not match the pinned baseline\",\n );\n const {\n resume: _resume,\n fork: _fork,\n ...output\n } = await sandbox.dispatch({\n ...candidate.request,\n ...(observation ? { observation } : {}),\n signal,\n observe: usage.observe,\n });\n result = output;\n usage.reconcile(output.usage);\n signal.throwIfAborted();\n accepted = await options.validate({\n key: candidate.key,\n result,\n sandbox,\n signal,\n });\n observation?.emit(\"workflow\", {\n kind: \"candidate\",\n status: \"validated\",\n });\n signal.throwIfAborted();\n const commit = (\n await git(sandbox.workspace.directory, [\"rev-parse\", \"HEAD\"])\n ).trim();\n signal.throwIfAborted();\n attempt.accepted = accepted;\n attempt.phase = \"validated\";\n attempt.record = {\n ...initial,\n status: \"rejected\",\n result,\n directory: sandbox.workspace.directory,\n commit,\n };\n await save();\n } catch (cause) {\n error = cause;\n }\n if (sandbox) {\n try {\n const disposal = await speculationTimeout(\n sandbox.close({\n preserve: !!session || error !== undefined,\n }),\n cleanupMs,\n );\n if (!sealed) attempt.cleanup = \"done\";\n retainedDirectory = disposal.retainedDirectory;\n } catch (cause) {\n cleanupFailed = true;\n error =\n error === undefined\n ? cause\n : new AggregateError(\n [error, cause],\n \"Speculative execution and cleanup failed\",\n );\n retainedDirectory = sandbox.workspace.directory;\n }\n }\n if (sealed) return;\n if (!sandbox && !attempt.resourceId) attempt.cleanup = \"done\";\n const recovery = recoveryDetails(error);\n const recoveredDirectory =\n typeof recovery?.directory === \"string\"\n ? recovery.directory\n : undefined;\n const directory = sandbox?.workspace.directory ?? recoveredDirectory;\n retainedDirectory ??= recoveredDirectory;\n function candidateStatus(): SpeculativeCandidateResult<T>[\"status\"] {\n if (cleanupFailed) return \"failed\";\n if (signal.aborted) return \"cancelled\";\n if (error !== undefined) return \"failed\";\n if (accepted && !winner) return \"winner\";\n return \"rejected\";\n }\n observation?.emit(\"workflow\", { kind: \"candidate\", status: \"cleanup\" });\n const status = candidateStatus();\n observation?.emit(\"workflow\", {\n kind: \"candidate\",\n status: status === \"winner\" ? \"accepted\" : \"rejected\",\n });\n const record: SpeculativeCandidateResult<T> = {\n ...initial,\n status,\n ...(attempt.record?.commit ? { commit: attempt.record.commit } : {}),\n cleanup: attempt.cleanup,\n ...(attempt.resourceId ? { resourceId: attempt.resourceId } : {}),\n ...(directory ? { directory } : {}),\n ...(retainedDirectory ? { retainedDirectory } : {}),\n ...(result ? { result } : {}),\n ...(error !== undefined ? { error } : {}),\n };\n records[index] = record;\n attempt.record = record;\n attempt.phase = \"settled\";\n if (status === \"winner\") {\n winner = record;\n stop.abort(\n new Error(`Speculative candidate ${candidate.key} selected`),\n );\n }\n await save();\n await observation.close();\n }\n }\n const workers = Promise.all(\n Array.from({ length: Math.min(concurrency, candidates.length) }, worker),\n );\n let removeAbort = () => {};\n const cancelled = new Promise<void>((resolve) => {\n if (signal.aborted) return resolve();\n const listener = () => resolve();\n signal.addEventListener(\"abort\", listener, { once: true });\n removeAbort = () => signal.removeEventListener(\"abort\", listener);\n });\n try {\n await Promise.race([workers, cancelled]);\n await speculationTimeout(workers, cleanupMs);\n } catch (error) {\n stop.abort(error);\n for (const attempt of latest.values()) {\n if (attempt.phase === \"settled\" || attempt.phase === \"waiting\") continue;\n const index = candidates.findIndex(\n (candidate) => candidate.key === attempt.key,\n );\n const record: SpeculativeCandidateResult<T> = {\n ...(attempt.record ?? records[index]!),\n status: \"cancelled\",\n cleanup: \"pending\",\n error,\n ...(attempt.resourceId ? { resourceId: attempt.resourceId } : {}),\n ...(attempt.directory\n ? {\n directory: attempt.directory,\n retainedDirectory: attempt.directory,\n }\n : {}),\n };\n records[index] = record;\n attempt.record = record;\n }\n } finally {\n removeAbort();\n }\n function outcome(): SpeculationResult<T>[\"status\"] {\n if (winner) return \"winner\";\n if (options.signal?.aborted) return \"aborted\";\n if (budgetError !== undefined) return \"budget-exhausted\";\n return \"no-winner\";\n }\n sealed = true;\n const status = state.finished && state.status ? state.status : outcome();\n const host = await speculativeHostSnapshot(options.repository).then(\n (after) => ({\n before,\n after,\n changed:\n before.head !== after.head ||\n before.dirty !== after.dirty ||\n before.fingerprint !== after.fingerprint ||\n before.branch !== after.branch,\n }),\n (error: unknown) => ({ before, changed: true, error }),\n );\n state.finished = state.attempts.every(\n (attempt) => attempt.phase === \"waiting\" || attempt.phase === \"settled\",\n );\n state.status = status;\n if (budgetError !== undefined) state.error = String(budgetError);\n state.usage = accounting.snapshot();\n await session?.save(encodeSpeculation(state));\n const integration = winner\n ? await checkSpeculationIntegration(\n options.repository,\n winner.branch,\n winner.commit,\n )\n : undefined;\n await options.observation?.flush();\n return {\n id,\n baseline,\n host,\n status,\n candidates: records,\n ...(integration ? { integration } : {}),\n ...(session\n ? {\n previousAttempts: state.attempts\n .filter((attempt) => latest.get(attempt.key) !== attempt)\n .flatMap((attempt) => (attempt.record ? [attempt.record] : [])),\n }\n : {}),\n usage: accounting.snapshot(),\n ...(winner ? { winner } : {}),\n ...(budgetError !== undefined || state.error\n ? { error: budgetError ?? state.error }\n : {}),\n };\n}\n"]}
1
+ {"version":3,"file":"speculation-run.js","sourceRoot":"","sources":["../../src/application/speculation-run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAG9D,OAAO,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA8B,EAC9B,KAA+B,EAC/B,OAA4C,EAC5C,WAAmB,EACnB,SAAiB;IAEjB,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;QAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAChB,IAAI,WAAoB,CAAC;IACzB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,MAAM,UAAU,GAAG,kBAAkB,CACnC,OAAO,CAAC,MAAM,EACd,CAAC,KAAK,EAAE,EAAE;QACR,WAAW,GAAG,KAAK,CAAC;QACpB,0EAA0E;QAC1E,IAAI,KAAK,CAAC,SAAS,KAAK,UAAU;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC,EACD,KAAK,CAAC,KAAK,CACZ,CAAC;IACF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;IAC7B,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;IACpB,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,IAAI,MAAM;YAAE,OAAO;QACnB,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAClB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CACpC,OAAO,EACP,KAAK,EACL,UAAU,EACV,IAAI,EACJ,SAAS,CACV,CAAC;IACF,MAAM,OAAO,GAAoC,UAAU,CAAC,GAAG,CAC7D,CAAC,SAAS,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAE,CAAC;QAC3C,OAAO,CACL,OAAO,CAAC,MAAM,IAAI;YAChB,GAAG,EAAE,SAAS,CAAC,GAAG;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM,EAAE,SAAS;SAClB,CACF,CAAC;IACJ,CAAC,CACF,CAAC;IACF,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;IAClE,MAAM,IAAI,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,UAAU,MAAM;QACnB,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;YACrB,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,CAAC,SAAS;gBAAE,OAAO;YACvB,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAE,CAAC;YAC3C,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ;gBAAE,SAAS;YAC5D,IAAI,CAAC;gBACH,UAAU,CAAC,KAAK,EAAE,CAAC;gBACnB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;gBAC1B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;gBAC5B,MAAM,IAAI,EAAE,CAAC;YACf,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,UAAU,CAAC,SAAS;oBAAE,MAAM,KAAK,CAAC;gBACvC,OAAO;YACT,CAAC;YACD,MAAM,WAAW,GAAG,eAAe,CACjC,OAAO,CAAC,WAAW,IAAI,SAAS,CAAC,OAAO,CAAC,WAAW,EACpD,SAAS,CAAC,OAAO,CAAC,OAAO,EACzB,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,EAAE,CAC7B,CAAC;YACF,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAE,CAAC;YAChC,IAAI,OAA4B,CAAC;YACjC,IAAI,MAAwC,CAAC;YAC7C,IAAI,KAAc,CAAC;YACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,aAAa,GAAG,KAAK,CAAC;YAC1B,IAAI,iBAAqC,CAAC;YAC1C,MAAM,KAAK,GAAG,SAAS,CACrB;gBACE,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;oBACrB,IAAI,MAAM;wBAAE,OAAO;oBACnB,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACzB,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;gBAClD,CAAC;aACF,EACD,SAAS,CACV,CAAC;YACF,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,aAAa,CAAC;oBAC5B,GAAG,OAAO,CAAC,OAAO;oBAClB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvC,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,eAAe,EAAE;wBACf,GAAG,OAAO,CAAC,eAAe;wBAC1B,KAAK,CAAC,OAAO,CAAC,OAAO;4BACnB,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;4BACtC,MAAM,IAAI,EAAE,CAAC;4BACb,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC;gCAClD,GAAG,OAAO;gCACV,GAAG,CAAC,OAAO;oCACT,CAAC,CAAC;wCACE,KAAK,CAAC,gBAAgB,CAAC,UAAkB;4CACvC,SAAS,CACP,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAC1B,kCAAkC,CACnC,CAAC;4CACF,SAAS,CACP,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI,EAClD,uCAAuC,CACxC,CAAC;4CACF,SAAS,CACP,CAAC,OAAO,CAAC,UAAU,EACnB,wDAAwD,CACzD,CAAC;4CACF,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;4CAChC,MAAM,IAAI,EAAE,CAAC;4CACb,MAAM,CAAC,cAAc,EAAE,CAAC;wCAC1B,CAAC;qCACF;oCACH,CAAC,CAAC,EAAE,CAAC;6BACR,CAAC,CAAC;4BACH,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gCACnC,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;gCACtB,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;4BACJ,CAAC;4BACD,OAAO,KAAK,CAAC;wBACf,CAAC;qBACF;oBACD,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC/D,KAAK,EAAE,SAAS,CAAC,KAAK;oBACtB,MAAM;iBACP,CAAC,CAAC;gBACH,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,SAAS,CACP,OAAO,CAAC,SAAS,CAAC,QAAQ,KAAK,QAAQ,EACvC,0DAA0D,CAC3D,CAAC;gBACF,MAAM,EACJ,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,KAAK,EACX,GAAG,MAAM,EACV,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC;oBACzB,GAAG,SAAS,CAAC,OAAO;oBACpB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvC,MAAM;oBACN,OAAO,EAAE,KAAK,CAAC,OAAO;iBACvB,CAAC,CAAC;gBACH,MAAM,GAAG,MAAM,CAAC;gBAChB,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC9B,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC;oBAChC,GAAG,EAAE,SAAS,CAAC,GAAG;oBAClB,MAAM;oBACN,OAAO;oBACP,MAAM;iBACP,CAAC,CAAC;gBACH,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE;oBAC5B,IAAI,EAAE,WAAW;oBACjB,MAAM,EAAE,WAAW;iBACpB,CAAC,CAAC;gBACH,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,CACb,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAC9D,CAAC,IAAI,EAAE,CAAC;gBACT,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBAC5B,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC;gBAC5B,OAAO,CAAC,MAAM,GAAG;oBACf,GAAG,OAAO;oBACV,MAAM,EAAE,UAAU;oBAClB,MAAM;oBACN,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,SAAS;oBACtC,MAAM;iBACP,CAAC;gBACF,MAAM,IAAI,EAAE,CAAC;YACf,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,KAAK,GAAG,KAAK,CAAC;YAChB,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CACvC,OAAO,CAAC,KAAK,CAAC;wBACZ,QAAQ,EAAE,CAAC,CAAC,OAAO,IAAI,KAAK,KAAK,SAAS;qBAC3C,CAAC,EACF,SAAS,CACV,CAAC;oBACF,IAAI,CAAC,MAAM;wBAAE,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC;oBACtC,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;gBACjD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,aAAa,GAAG,IAAI,CAAC;oBACrB,KAAK;wBACH,KAAK,KAAK,SAAS;4BACjB,CAAC,CAAC,KAAK;4BACP,CAAC,CAAC,IAAI,cAAc,CAChB,CAAC,KAAK,EAAE,KAAK,CAAC,EACd,0CAA0C,CAC3C,CAAC;oBACR,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC;gBAClD,CAAC;YACH,CAAC;YACD,IAAI,MAAM;gBAAE,OAAO;YACnB,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU;gBAAE,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC;YAC9D,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,kBAAkB,GACtB,OAAO,QAAQ,EAAE,SAAS,KAAK,QAAQ;gBACrC,CAAC,CAAC,QAAQ,CAAC,SAAS;gBACpB,CAAC,CAAC,SAAS,CAAC;YAChB,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,CAAC,SAAS,IAAI,kBAAkB,CAAC;YACrE,iBAAiB,KAAK,kBAAkB,CAAC;YACzC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAChC,MAAM,KAAK,GAA2B,KAAK,IAAI;gBAC7C,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD,CAAC;YACF,SAAS,eAAe;gBACtB,IAAI,aAAa;oBAAE,OAAO,QAAQ,CAAC;gBACnC,IAAI,MAAM,CAAC,OAAO;oBAAE,OAAO,WAAW,CAAC;gBACvC,IAAI,KAAK,KAAK,SAAS;oBAAE,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAC3D,IAAI,QAAQ,IAAI,CAAC,MAAM;oBAAE,OAAO,QAAQ,CAAC;gBACzC,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YACxE,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;YACjC,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE;gBAC5B,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;aACtD,CAAC,CAAC;YACH,MAAM,MAAM,GAAkC;gBAC5C,GAAG,OAAO;gBACV,MAAM;gBACN,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7B,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjD,CAAC;YACF,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;YACxB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;YACxB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;YAC1B,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACxB,MAAM,GAAG,MAAM,CAAC;gBAChB,IAAI,CAAC,KAAK,CACR,IAAI,KAAK,CAAC,yBAAyB,SAAS,CAAC,GAAG,WAAW,CAAC,CAC7D,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,EAAE,CAAC;YACb,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CACzB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CACzE,CAAC;IACF,IAAI,WAAW,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IAC3B,MAAM,SAAS,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC9C,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,OAAO,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,WAAW,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;QACzC,MAAM,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACtC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;gBAAE,SAAS;YACzE,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAChC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAC7C,CAAC;YACF,MAAM,MAAM,GAAkC;gBAC5C,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAE,CAAC;gBACtC,MAAM,EAAE,WAAW;gBACnB,OAAO,EAAE,SAAS;gBAClB,KAAK;gBACL,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,GAAG,CAAC,OAAO,CAAC,SAAS;oBACnB,CAAC,CAAC;wBACE,SAAS,EAAE,OAAO,CAAC,SAAS;wBAC5B,iBAAiB,EAAE,OAAO,CAAC,SAAS;qBACrC;oBACH,CAAC,CAAC,EAAE,CAAC;aACR,CAAC;YACF,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;YACxB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;QAC1B,CAAC;IACH,CAAC;YAAS,CAAC;QACT,WAAW,EAAE,CAAC;IAChB,CAAC;IACD,SAAS,OAAO;QACd,IAAI,MAAM;YAAE,OAAO,QAAQ,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,OAAO,SAAS,CAAC;QAC9C,IAAI,WAAW,KAAK,SAAS;YAAE,OAAO,kBAAkB,CAAC;QACzD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QACxE,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,GAAG,IAAI,CAAC;IACd,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACzE,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CACjE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACV,MAAM;QACN,KAAK;QACL,OAAO,EACL,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;YAC1B,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;YAC5B,MAAM,CAAC,WAAW,KAAK,KAAK,CAAC,WAAW;YACxC,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;KACjC,CAAC,EACF,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CACvD,CAAC;IACF,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CACnC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,CACxE,CAAC;IACF,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACjE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,MAAM,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM;QACxB,CAAC,CAAC,MAAM,2BAA2B,CAC/B,OAAO,CAAC,UAAU,EAClB,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,MAAM,CACd;QACH,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC;IACnC,OAAO;QACL,EAAE;QACF,QAAQ;QACR,IAAI;QACJ,MAAM;QACN,UAAU,EAAE,OAAO;QACnB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,OAAO;YACT,CAAC,CAAC;gBACE,gBAAgB,EAAE,KAAK,CAAC,QAAQ;qBAC7B,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC;qBACxD,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aAClE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE;QAC5B,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK;YAC1C,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,IAAI,KAAK,CAAC,KAAK,EAAE;YACvC,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,OAAuD;IAEvD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CACxC,MAAM,CAAC,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAChE,CAAC;IACF,MAAM,KAAK,GAAG,MAAM;SACjB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC;SAC9C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAQ,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAQ,CAAC,CAAC,CAAC;IACnE,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAE,CAAC;AAChC,CAAC","sourcesContent":["import { resumeSpeculation } from \"./speculation-resume.ts\";\nimport { encodeSpeculation } from \"./speculation-checkpoint.ts\";\nimport { checkSpeculationIntegration } from \"./speculation-integration.ts\";\nimport { speculationTimeout } from \"./speculation-timeout.ts\";\nimport type { SpeculationCheckpoint } from \"./speculation-checkpoint.types.ts\";\nimport type { SpeculationStoreSession } from \"../infrastructure/speculation-store.types.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { taskObservation } from \"./task-observation.ts\";\nimport { invariant, recoveryDetails } from \"../domain/errors.ts\";\nimport { quotaFault } from \"../domain/quota.ts\";\nimport type { QuotaFault } from \"../domain/quota.types.ts\";\nimport { workflowAccounting } from \"../domain/workflow/budget.ts\";\nimport { speculativeHostSnapshot } from \"./speculation-host.ts\";\nimport type { Sandbox } from \"./outpost.types.ts\";\nimport { createSandbox } from \"./sandbox.ts\";\nimport type {\n SpeculationOptions,\n SpeculationResult,\n SpeculativeCandidateResult,\n SpeculativeOutput,\n} from \"./speculation.types.ts\";\nimport { taskUsage } from \"./task-usage.ts\";\n\nexport async function runSpeculation<T>(\n options: SpeculationOptions<T>,\n state: SpeculationCheckpoint<T>,\n session: SpeculationStoreSession | undefined,\n concurrency: number,\n cleanupMs: number,\n): Promise<SpeculationResult<T>> {\n const { candidates } = options;\n const stop = new AbortController();\n const signal = options.signal\n ? AbortSignal.any([options.signal, stop.signal])\n : stop.signal;\n let budgetError: unknown;\n let sealed = false;\n const accounting = workflowAccounting(\n options.budget,\n (error) => {\n budgetError = error;\n // Attempt limits stop admissions; already admitted candidates may finish.\n if (error.dimension !== \"attempts\") stop.abort(error);\n },\n state.usage,\n );\n const before = state.before;\n const baseline = before.head;\n const id = state.id;\n const save = async () => {\n if (sealed) return;\n state.usage = accounting.snapshot();\n try {\n await session?.save(encodeSpeculation(state));\n } catch (error) {\n stop.abort(error);\n throw error;\n }\n };\n const latest = await resumeSpeculation(\n options,\n state,\n accounting,\n save,\n cleanupMs,\n );\n const records: SpeculativeCandidateResult<T>[] = candidates.map(\n (candidate) => {\n const attempt = latest.get(candidate.key)!;\n return (\n attempt.record ?? {\n key: candidate.key,\n branch: attempt.branch,\n attempt: attempt.attempt,\n status: \"skipped\",\n }\n );\n },\n );\n let winner = records.find((record) => record.status === \"winner\");\n await save();\n let next = 0;\n async function worker(): Promise<void> {\n while (!signal.aborted && !winner && !accounting.exhausted) {\n const index = next++;\n const candidate = candidates[index];\n if (!candidate) return;\n const attempt = latest.get(candidate.key)!;\n if (attempt.phase === \"settled\" || state.finished) continue;\n try {\n accounting.admit();\n attempt.phase = \"running\";\n attempt.cleanup = \"pending\";\n await save();\n } catch (error) {\n if (!accounting.exhausted) throw error;\n return;\n }\n const observation = taskObservation(\n options.observation ?? candidate.request.observation,\n candidate.request.observe,\n { candidate: candidate.key },\n );\n const initial = records[index]!;\n let sandbox: Sandbox | undefined;\n let result: SpeculativeOutput<T> | undefined;\n let error: unknown;\n let accepted = false;\n let cleanupFailed = false;\n let retainedDirectory: string | undefined;\n const usage = taskUsage(\n {\n reportUsage: (value) => {\n if (sealed) return;\n accounting.report(value);\n void save().catch((error) => stop.abort(error));\n },\n },\n undefined,\n );\n try {\n sandbox = await createSandbox({\n ...options.sandbox,\n ...(observation ? { observation } : {}),\n repository: options.repository,\n sandboxProvider: {\n ...options.sandboxProvider,\n async acquire(context) {\n attempt.directory = context.directory;\n await save();\n const lease = await options.sandboxProvider.acquire({\n ...context,\n ...(session\n ? {\n async registerRecovery(resourceId: string) {\n invariant(\n !sealed && !signal.aborted,\n \"Speculation allocation cancelled\",\n );\n invariant(\n resourceId.length > 0 && resourceId.length <= 1024,\n \"Invalid speculation resource identity\",\n );\n invariant(\n !attempt.resourceId,\n \"Provider registered more than one speculation resource\",\n );\n attempt.resourceId = resourceId;\n await save();\n signal.throwIfAborted();\n },\n }\n : {}),\n });\n if (session && !attempt.resourceId) {\n await lease.release();\n throw new Error(\n \"Durable provider did not register its resource before allocation\",\n );\n }\n return lease;\n },\n },\n branch: { mode: \"named\", name: initial.branch, from: baseline },\n agent: candidate.agent,\n signal,\n });\n signal.throwIfAborted();\n invariant(\n sandbox.workspace.baseline === baseline,\n \"Speculative workspace does not match the pinned baseline\",\n );\n const {\n resume: _resume,\n fork: _fork,\n ...output\n } = await sandbox.dispatch({\n ...candidate.request,\n ...(observation ? { observation } : {}),\n signal,\n observe: usage.observe,\n });\n result = output;\n usage.reconcile(output.usage);\n signal.throwIfAborted();\n accepted = await options.validate({\n key: candidate.key,\n result,\n sandbox,\n signal,\n });\n observation?.emit(\"workflow\", {\n kind: \"candidate\",\n status: \"validated\",\n });\n signal.throwIfAborted();\n const commit = (\n await git(sandbox.workspace.directory, [\"rev-parse\", \"HEAD\"])\n ).trim();\n signal.throwIfAborted();\n attempt.accepted = accepted;\n attempt.phase = \"validated\";\n attempt.record = {\n ...initial,\n status: \"rejected\",\n result,\n directory: sandbox.workspace.directory,\n commit,\n };\n await save();\n } catch (cause) {\n error = cause;\n }\n if (sandbox) {\n try {\n const disposal = await speculationTimeout(\n sandbox.close({\n preserve: !!session || error !== undefined,\n }),\n cleanupMs,\n );\n if (!sealed) attempt.cleanup = \"done\";\n retainedDirectory = disposal.retainedDirectory;\n } catch (cause) {\n cleanupFailed = true;\n error =\n error === undefined\n ? cause\n : new AggregateError(\n [error, cause],\n \"Speculative execution and cleanup failed\",\n );\n retainedDirectory = sandbox.workspace.directory;\n }\n }\n if (sealed) return;\n if (!sandbox && !attempt.resourceId) attempt.cleanup = \"done\";\n const recovery = recoveryDetails(error);\n const recoveredDirectory =\n typeof recovery?.directory === \"string\"\n ? recovery.directory\n : undefined;\n const directory = sandbox?.workspace.directory ?? recoveredDirectory;\n retainedDirectory ??= recoveredDirectory;\n const fault = quotaFault(error);\n const quota: QuotaFault | undefined = fault && {\n message: fault.message,\n ...(fault.resetAt ? { resetAt: fault.resetAt } : {}),\n };\n function candidateStatus(): SpeculativeCandidateResult<T>[\"status\"] {\n if (cleanupFailed) return \"failed\";\n if (signal.aborted) return \"cancelled\";\n if (error !== undefined) return quota ? \"quota\" : \"failed\";\n if (accepted && !winner) return \"winner\";\n return \"rejected\";\n }\n observation?.emit(\"workflow\", { kind: \"candidate\", status: \"cleanup\" });\n const status = candidateStatus();\n observation?.emit(\"workflow\", {\n kind: \"candidate\",\n status: status === \"winner\" ? \"accepted\" : \"rejected\",\n });\n const record: SpeculativeCandidateResult<T> = {\n ...initial,\n status,\n ...(attempt.record?.commit ? { commit: attempt.record.commit } : {}),\n cleanup: attempt.cleanup,\n ...(attempt.resourceId ? { resourceId: attempt.resourceId } : {}),\n ...(directory ? { directory } : {}),\n ...(retainedDirectory ? { retainedDirectory } : {}),\n ...(result ? { result } : {}),\n ...(error !== undefined ? { error } : {}),\n ...(status === \"quota\" ? { quota: quota! } : {}),\n };\n records[index] = record;\n attempt.record = record;\n attempt.phase = \"settled\";\n if (status === \"winner\") {\n winner = record;\n stop.abort(\n new Error(`Speculative candidate ${candidate.key} selected`),\n );\n }\n await save();\n await observation.close();\n }\n }\n const workers = Promise.all(\n Array.from({ length: Math.min(concurrency, candidates.length) }, worker),\n );\n let removeAbort = () => {};\n const cancelled = new Promise<void>((resolve) => {\n if (signal.aborted) return resolve();\n const listener = () => resolve();\n signal.addEventListener(\"abort\", listener, { once: true });\n removeAbort = () => signal.removeEventListener(\"abort\", listener);\n });\n try {\n await Promise.race([workers, cancelled]);\n await speculationTimeout(workers, cleanupMs);\n } catch (error) {\n stop.abort(error);\n for (const attempt of latest.values()) {\n if (attempt.phase === \"settled\" || attempt.phase === \"waiting\") continue;\n const index = candidates.findIndex(\n (candidate) => candidate.key === attempt.key,\n );\n const record: SpeculativeCandidateResult<T> = {\n ...(attempt.record ?? records[index]!),\n status: \"cancelled\",\n cleanup: \"pending\",\n error,\n ...(attempt.resourceId ? { resourceId: attempt.resourceId } : {}),\n ...(attempt.directory\n ? {\n directory: attempt.directory,\n retainedDirectory: attempt.directory,\n }\n : {}),\n };\n records[index] = record;\n attempt.record = record;\n }\n } finally {\n removeAbort();\n }\n function outcome(): SpeculationResult<T>[\"status\"] {\n if (winner) return \"winner\";\n if (options.signal?.aborted) return \"aborted\";\n if (budgetError !== undefined) return \"budget-exhausted\";\n if (records.some((record) => record.status === \"quota\")) return \"quota\";\n return \"no-winner\";\n }\n sealed = true;\n const status = state.finished && state.status ? state.status : outcome();\n const host = await speculativeHostSnapshot(options.repository).then(\n (after) => ({\n before,\n after,\n changed:\n before.head !== after.head ||\n before.dirty !== after.dirty ||\n before.fingerprint !== after.fingerprint ||\n before.branch !== after.branch,\n }),\n (error: unknown) => ({ before, changed: true, error }),\n );\n state.finished = state.attempts.every(\n (attempt) => attempt.phase === \"waiting\" || attempt.phase === \"settled\",\n );\n state.status = status;\n if (budgetError !== undefined) state.error = String(budgetError);\n state.usage = accounting.snapshot();\n await session?.save(encodeSpeculation(state));\n const integration = winner\n ? await checkSpeculationIntegration(\n options.repository,\n winner.branch,\n winner.commit,\n )\n : undefined;\n await options.observation?.flush();\n return {\n id,\n baseline,\n host,\n status,\n candidates: records,\n ...(integration ? { integration } : {}),\n ...(session\n ? {\n previousAttempts: state.attempts\n .filter((attempt) => latest.get(attempt.key) !== attempt)\n .flatMap((attempt) => (attempt.record ? [attempt.record] : [])),\n }\n : {}),\n usage: accounting.snapshot(),\n ...(status === \"quota\" ? { quota: earliestQuota(records) } : {}),\n ...(winner ? { winner } : {}),\n ...(budgetError !== undefined || state.error\n ? { error: budgetError ?? state.error }\n : {}),\n };\n}\n\nfunction earliestQuota(\n records: readonly SpeculativeCandidateResult<unknown>[],\n): QuotaFault {\n const faults = records.flatMap((record) =>\n record.status === \"quota\" && record.quota ? [record.quota] : [],\n );\n const known = faults\n .filter((fault) => fault.resetAt !== undefined)\n .sort((a, b) => Date.parse(a.resetAt!) - Date.parse(b.resetAt!));\n return known[0] ?? faults[0]!;\n}\n"]}
@@ -2,6 +2,7 @@ import type { Transport } from "../domain/transport.types.ts";
2
2
  import type { Agent } from "../domain/agent.types.ts";
3
3
  import type { WorkflowBudget, WorkflowUsage } from "../domain/workflow/budget.types.ts";
4
4
  import type { DispatchOptions } from "./execution.types.ts";
5
+ import type { QuotaFault } from "../domain/quota.types.ts";
5
6
  import type { Sandbox, SandboxOptions, WarmDispatchResult } from "./outpost.types.ts";
6
7
  export interface SpeculativeCandidate<T = undefined> {
7
8
  readonly key: string;
@@ -48,7 +49,9 @@ export interface SpeculativeCandidateResult<T = undefined> {
48
49
  readonly cleanup?: "pending" | "done";
49
50
  readonly resourceId?: string;
50
51
  readonly branch: string;
51
- readonly status: "winner" | "rejected" | "failed" | "cancelled" | "skipped";
52
+ readonly status: "winner" | "rejected" | "failed" | "quota" | "cancelled" | "skipped";
53
+ /** Usage or rate limit that stopped this candidate. */
54
+ readonly quota?: QuotaFault;
52
55
  readonly directory?: string;
53
56
  readonly retainedDirectory?: string;
54
57
  readonly result?: SpeculativeOutput<T>;
@@ -65,7 +68,9 @@ export interface SpeculationResult<T = undefined> {
65
68
  readonly changed: boolean;
66
69
  readonly error?: unknown;
67
70
  };
68
- readonly status: "winner" | "no-winner" | "aborted" | "budget-exhausted";
71
+ readonly status: "winner" | "no-winner" | "quota" | "aborted" | "budget-exhausted";
72
+ /** Earliest known reset among candidates stopped by a usage or rate limit. */
73
+ readonly quota?: QuotaFault;
69
74
  readonly winner?: SpeculativeCandidateResult<T>;
70
75
  readonly candidates: readonly SpeculativeCandidateResult<T>[];
71
76
  readonly usage: WorkflowUsage;
@@ -1 +1 @@
1
- {"version":3,"file":"speculation.types.js","sourceRoot":"","sources":["../../src/application/speculation.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Transport } from \"../domain/transport.types.ts\";\nimport type { Agent } from \"../domain/agent.types.ts\";\nimport type {\n WorkflowBudget,\n WorkflowUsage,\n} from \"../domain/workflow/budget.types.ts\";\nimport type { DispatchOptions } from \"./execution.types.ts\";\nimport type {\n Sandbox,\n SandboxOptions,\n WarmDispatchResult,\n} from \"./outpost.types.ts\";\n\nexport interface SpeculativeCandidate<T = undefined> {\n readonly key: string;\n readonly agent: Agent;\n readonly request: Omit<\n DispatchOptions<T>,\n \"agent\" | \"signal\" | \"continuation\"\n >;\n}\n\nexport type SpeculativeOutput<T> = Omit<\n WarmDispatchResult<T>,\n \"resume\" | \"fork\"\n>;\n\nexport interface SpeculativeValidation<T> {\n readonly key: string;\n readonly result: SpeculativeOutput<T>;\n readonly sandbox: Sandbox;\n readonly signal: AbortSignal;\n}\n\nexport interface SpeculationDurability {\n readonly transporter: Transport;\n readonly runId: string;\n readonly version: string;\n readonly resume?: \"retry-incomplete\";\n}\n\nexport interface SpeculationIntegration {\n readonly status: \"clean\" | \"conflict\" | \"blocked\";\n readonly host: SpeculativeHostSnapshot;\n readonly candidateCommit?: string;\n readonly conflicts: readonly string[];\n readonly reason?: string;\n}\n\nexport interface SpeculationOptions<T = undefined> {\n readonly durability?: SpeculationDurability;\n readonly cleanupMs?: number;\n readonly observation?: import(\"../domain/observation.types.ts\").ObservationHub;\n readonly repository: string;\n readonly sandboxProvider: NonNullable<SandboxOptions[\"sandboxProvider\"]>;\n readonly candidates: readonly SpeculativeCandidate<T>[];\n readonly concurrency?: number;\n readonly budget: WorkflowBudget;\n readonly signal?: AbortSignal;\n readonly sandbox?: Pick<\n SandboxOptions,\n | \"hooks\"\n | \"bootstrap\"\n | \"logging\"\n | \"limits\"\n | \"storageQuota\"\n | \"conversationHome\"\n >;\n readonly validate: (\n candidate: SpeculativeValidation<T>,\n ) => boolean | Promise<boolean>;\n}\n\nexport interface SpeculativeCandidateResult<T = undefined> {\n readonly key: string;\n readonly commit?: string;\n readonly attempt?: number;\n readonly cleanup?: \"pending\" | \"done\";\n readonly resourceId?: string;\n readonly branch: string;\n readonly status: \"winner\" | \"rejected\" | \"failed\" | \"cancelled\" | \"skipped\";\n readonly directory?: string;\n readonly retainedDirectory?: string;\n readonly result?: SpeculativeOutput<T>;\n readonly error?: unknown;\n}\n\nexport interface SpeculationResult<T = undefined> {\n readonly integration?: SpeculationIntegration;\n readonly previousAttempts?: readonly SpeculativeCandidateResult<T>[];\n readonly id: string;\n readonly baseline: string;\n readonly host: {\n readonly before: SpeculativeHostSnapshot;\n readonly after?: SpeculativeHostSnapshot;\n readonly changed: boolean;\n readonly error?: unknown;\n };\n readonly status: \"winner\" | \"no-winner\" | \"aborted\" | \"budget-exhausted\";\n readonly winner?: SpeculativeCandidateResult<T>;\n readonly candidates: readonly SpeculativeCandidateResult<T>[];\n readonly usage: WorkflowUsage;\n readonly error?: unknown;\n}\n\nexport interface SpeculativeHostSnapshot {\n readonly head: string;\n readonly branch: string;\n readonly fingerprint: string;\n readonly dirty: boolean;\n}\n"]}
1
+ {"version":3,"file":"speculation.types.js","sourceRoot":"","sources":["../../src/application/speculation.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Transport } from \"../domain/transport.types.ts\";\nimport type { Agent } from \"../domain/agent.types.ts\";\nimport type {\n WorkflowBudget,\n WorkflowUsage,\n} from \"../domain/workflow/budget.types.ts\";\nimport type { DispatchOptions } from \"./execution.types.ts\";\nimport type { QuotaFault } from \"../domain/quota.types.ts\";\nimport type {\n Sandbox,\n SandboxOptions,\n WarmDispatchResult,\n} from \"./outpost.types.ts\";\n\nexport interface SpeculativeCandidate<T = undefined> {\n readonly key: string;\n readonly agent: Agent;\n readonly request: Omit<\n DispatchOptions<T>,\n \"agent\" | \"signal\" | \"continuation\"\n >;\n}\n\nexport type SpeculativeOutput<T> = Omit<\n WarmDispatchResult<T>,\n \"resume\" | \"fork\"\n>;\n\nexport interface SpeculativeValidation<T> {\n readonly key: string;\n readonly result: SpeculativeOutput<T>;\n readonly sandbox: Sandbox;\n readonly signal: AbortSignal;\n}\n\nexport interface SpeculationDurability {\n readonly transporter: Transport;\n readonly runId: string;\n readonly version: string;\n readonly resume?: \"retry-incomplete\";\n}\n\nexport interface SpeculationIntegration {\n readonly status: \"clean\" | \"conflict\" | \"blocked\";\n readonly host: SpeculativeHostSnapshot;\n readonly candidateCommit?: string;\n readonly conflicts: readonly string[];\n readonly reason?: string;\n}\n\nexport interface SpeculationOptions<T = undefined> {\n readonly durability?: SpeculationDurability;\n readonly cleanupMs?: number;\n readonly observation?: import(\"../domain/observation.types.ts\").ObservationHub;\n readonly repository: string;\n readonly sandboxProvider: NonNullable<SandboxOptions[\"sandboxProvider\"]>;\n readonly candidates: readonly SpeculativeCandidate<T>[];\n readonly concurrency?: number;\n readonly budget: WorkflowBudget;\n readonly signal?: AbortSignal;\n readonly sandbox?: Pick<\n SandboxOptions,\n | \"hooks\"\n | \"bootstrap\"\n | \"logging\"\n | \"limits\"\n | \"storageQuota\"\n | \"conversationHome\"\n >;\n readonly validate: (\n candidate: SpeculativeValidation<T>,\n ) => boolean | Promise<boolean>;\n}\n\nexport interface SpeculativeCandidateResult<T = undefined> {\n readonly key: string;\n readonly commit?: string;\n readonly attempt?: number;\n readonly cleanup?: \"pending\" | \"done\";\n readonly resourceId?: string;\n readonly branch: string;\n readonly status:\n \"winner\" | \"rejected\" | \"failed\" | \"quota\" | \"cancelled\" | \"skipped\";\n /** Usage or rate limit that stopped this candidate. */\n readonly quota?: QuotaFault;\n readonly directory?: string;\n readonly retainedDirectory?: string;\n readonly result?: SpeculativeOutput<T>;\n readonly error?: unknown;\n}\n\nexport interface SpeculationResult<T = undefined> {\n readonly integration?: SpeculationIntegration;\n readonly previousAttempts?: readonly SpeculativeCandidateResult<T>[];\n readonly id: string;\n readonly baseline: string;\n readonly host: {\n readonly before: SpeculativeHostSnapshot;\n readonly after?: SpeculativeHostSnapshot;\n readonly changed: boolean;\n readonly error?: unknown;\n };\n readonly status:\n \"winner\" | \"no-winner\" | \"quota\" | \"aborted\" | \"budget-exhausted\";\n /** Earliest known reset among candidates stopped by a usage or rate limit. */\n readonly quota?: QuotaFault;\n readonly winner?: SpeculativeCandidateResult<T>;\n readonly candidates: readonly SpeculativeCandidateResult<T>[];\n readonly usage: WorkflowUsage;\n readonly error?: unknown;\n}\n\nexport interface SpeculativeHostSnapshot {\n readonly head: string;\n readonly branch: string;\n readonly fingerprint: string;\n readonly dirty: boolean;\n}\n"]}
@@ -2,6 +2,6 @@ import type { CommandResult } from "../domain/ports.ts";
2
2
  import { type Task, type TaskOptions } from "../domain/workflow.ts";
3
3
  import type { DispatchResult } from "./outpost.ts";
4
4
  import type { AgentTaskOptions, CommandTaskOptions, IsolatedTaskOptions } from "./tasks.types.ts";
5
- export declare function agentTask<T>(options: Omit<TaskOptions<DispatchResult<T>>, "perform"> & AgentTaskOptions<T>): Task<DispatchResult<T>>;
6
- export declare function isolatedTask<T>(options: Omit<TaskOptions<DispatchResult<T>>, "perform"> & IsolatedTaskOptions<T>): Task<DispatchResult<T>>;
5
+ export declare function agentTask<T>(options: Omit<TaskOptions<DispatchResult<T>>, "perform" | "cache"> & AgentTaskOptions<T>): Task<DispatchResult<T>>;
6
+ export declare function isolatedTask<T>(options: Omit<TaskOptions<DispatchResult<T>>, "perform" | "cache"> & IsolatedTaskOptions<T>): Task<DispatchResult<T>>;
7
7
  export declare function commandTask(options: Omit<TaskOptions<CommandResult>, "perform"> & CommandTaskOptions): Task<CommandResult>;
@@ -3,13 +3,19 @@ import { taskObservation } from "./task-observation.js";
3
3
  import { taskUsage } from "./task-usage.js";
4
4
  import { OutpostError } from "../domain/errors.js";
5
5
  import { task } from "../domain/workflow.js";
6
+ import { quotaContinuation, quotaWorkspace } from "./quota-resume.js";
6
7
  import { dispatch } from "./outpost.js";
8
+ function uncached(options) {
9
+ if ("cache" in options && options.cache !== undefined)
10
+ throw new Error("Dispatch results are not JSON; cache a task that returns a JSON projection");
11
+ }
7
12
  export function agentTask(options) {
8
- const { sandbox, request, ...definition } = options;
13
+ uncached(options);
14
+ const { sandbox, request, quotaResume, ...definition } = options;
9
15
  return task({
10
16
  ...definition,
11
17
  async perform(context) {
12
- const options = request(context);
18
+ const options = quotaContinuation(context, request(context), quotaResume);
13
19
  const usage = taskUsage(context, undefined);
14
20
  const observation = taskObservation(context.observation ?? options.observation, options.observe);
15
21
  try {
@@ -29,11 +35,12 @@ export function agentTask(options) {
29
35
  });
30
36
  }
31
37
  export function isolatedTask(options) {
32
- const { request, ...definition } = options;
38
+ uncached(options);
39
+ const { request, quotaResume, ...definition } = options;
33
40
  return task({
34
41
  ...definition,
35
42
  async perform(context) {
36
- const options = await request(context);
43
+ const options = quotaWorkspace(context, quotaContinuation(context, await request(context), quotaResume));
37
44
  const usage = taskUsage(context, undefined);
38
45
  const observation = taskObservation(context.observation ?? options.observation, options.observe);
39
46
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/application/tasks.ts"],"names":[],"mappings":"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","sourcesContent":["import { observationDefaults } from \"../domain/observation.constants.ts\";\nimport { taskObservation } from \"./task-observation.ts\";\nimport { taskUsage } from \"./task-usage.ts\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { CommandResult } from \"../domain/ports.ts\";\nimport { task, type Task, type TaskOptions } from \"../domain/workflow.ts\";\nimport type { DispatchResult } from \"./outpost.ts\";\nimport { dispatch } from \"./outpost.ts\";\nimport type {\n AgentTaskOptions,\n CommandTaskOptions,\n IsolatedTaskOptions,\n} from \"./tasks.types.ts\";\n\nexport function agentTask<T>(\n options: Omit<TaskOptions<DispatchResult<T>>, \"perform\"> &\n AgentTaskOptions<T>,\n): Task<DispatchResult<T>> {\n const { sandbox, request, ...definition } = options;\n return task({\n ...definition,\n async perform(context) {\n const options = request(context);\n const usage = taskUsage(context, undefined);\n const observation = taskObservation(\n context.observation ?? options.observation,\n options.observe,\n );\n try {\n const result = await sandbox.dispatch({\n ...options,\n observation,\n signal: context.signal,\n observe: usage.observe,\n });\n usage.reconcile(result.usage);\n return result;\n } finally {\n await observation.close();\n }\n },\n });\n}\n\nexport function isolatedTask<T>(\n options: Omit<TaskOptions<DispatchResult<T>>, \"perform\"> &\n IsolatedTaskOptions<T>,\n): Task<DispatchResult<T>> {\n const { request, ...definition } = options;\n return task({\n ...definition,\n async perform(context) {\n const options = await request(context);\n const usage = taskUsage(context, undefined);\n const observation = taskObservation(\n context.observation ?? options.observation,\n options.observe,\n );\n try {\n const result = await dispatch({\n ...options,\n observation,\n signal: context.signal,\n observe: usage.observe,\n });\n usage.reconcile(result.usage);\n return result;\n } finally {\n await observation.close();\n }\n },\n });\n}\n\nexport function commandTask(\n options: Omit<TaskOptions<CommandResult>, \"perform\"> & CommandTaskOptions,\n): Task<CommandResult> {\n const { sandbox, command, ...definition } = options;\n return task({\n ...definition,\n async perform(context) {\n const invocation =\n typeof command === \"function\" ? command(context) : command;\n const result = await sandbox.command({\n ...invocation,\n observe(channel, text) {\n for (\n let offset = 0;\n offset < text.length;\n offset += observationDefaults.outputCharacters\n )\n context.observation?.emit(\"sandbox\", {\n kind: \"command-output\",\n channel,\n text: text.slice(\n offset,\n offset + observationDefaults.outputCharacters,\n ),\n });\n invocation.observe?.(channel, text);\n },\n signal: context.signal,\n });\n if (result.status !== 0)\n throw new OutpostError(\"process\", \"Workflow command failed\", {\n ...result,\n });\n return result;\n },\n });\n}\n"]}
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/application/tasks.ts"],"names":[],"mappings":"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","sourcesContent":["import { observationDefaults } from \"../domain/observation.constants.ts\";\nimport { taskObservation } from \"./task-observation.ts\";\nimport { taskUsage } from \"./task-usage.ts\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { CommandResult } from \"../domain/ports.ts\";\nimport { task, type Task, type TaskOptions } from \"../domain/workflow.ts\";\nimport type { DispatchResult } from \"./outpost.ts\";\nimport { quotaContinuation, quotaWorkspace } from \"./quota-resume.ts\";\nimport { dispatch } from \"./outpost.ts\";\nimport type {\n AgentTaskOptions,\n CommandTaskOptions,\n IsolatedTaskOptions,\n} from \"./tasks.types.ts\";\n\nfunction uncached(options: object): void {\n if (\"cache\" in options && options.cache !== undefined)\n throw new Error(\n \"Dispatch results are not JSON; cache a task that returns a JSON projection\",\n );\n}\n\nexport function agentTask<T>(\n options: Omit<TaskOptions<DispatchResult<T>>, \"perform\" | \"cache\"> &\n AgentTaskOptions<T>,\n): Task<DispatchResult<T>> {\n uncached(options);\n const { sandbox, request, quotaResume, ...definition } = options;\n return task({\n ...definition,\n async perform(context) {\n const options = quotaContinuation(context, request(context), quotaResume);\n const usage = taskUsage(context, undefined);\n const observation = taskObservation(\n context.observation ?? options.observation,\n options.observe,\n );\n try {\n const result = await sandbox.dispatch({\n ...options,\n observation,\n signal: context.signal,\n observe: usage.observe,\n });\n usage.reconcile(result.usage);\n return result;\n } finally {\n await observation.close();\n }\n },\n });\n}\n\nexport function isolatedTask<T>(\n options: Omit<TaskOptions<DispatchResult<T>>, \"perform\" | \"cache\"> &\n IsolatedTaskOptions<T>,\n): Task<DispatchResult<T>> {\n uncached(options);\n const { request, quotaResume, ...definition } = options;\n return task({\n ...definition,\n async perform(context) {\n const options = quotaWorkspace(\n context,\n quotaContinuation(context, await request(context), quotaResume),\n );\n const usage = taskUsage(context, undefined);\n const observation = taskObservation(\n context.observation ?? options.observation,\n options.observe,\n );\n try {\n const result = await dispatch({\n ...options,\n observation,\n signal: context.signal,\n observe: usage.observe,\n });\n usage.reconcile(result.usage);\n return result;\n } finally {\n await observation.close();\n }\n },\n });\n}\n\nexport function commandTask(\n options: Omit<TaskOptions<CommandResult>, \"perform\"> & CommandTaskOptions,\n): Task<CommandResult> {\n const { sandbox, command, ...definition } = options;\n return task({\n ...definition,\n async perform(context) {\n const invocation =\n typeof command === \"function\" ? command(context) : command;\n const result = await sandbox.command({\n ...invocation,\n observe(channel, text) {\n for (\n let offset = 0;\n offset < text.length;\n offset += observationDefaults.outputCharacters\n )\n context.observation?.emit(\"sandbox\", {\n kind: \"command-output\",\n channel,\n text: text.slice(\n offset,\n offset + observationDefaults.outputCharacters,\n ),\n });\n invocation.observe?.(channel, text);\n },\n signal: context.signal,\n });\n if (result.status !== 0)\n throw new OutpostError(\"process\", \"Workflow command failed\", {\n ...result,\n });\n return result;\n },\n });\n}\n"]}
@@ -3,16 +3,21 @@ import type { Command } from "../domain/command.types.ts";
3
3
  import type { TaskContext } from "../domain/workflow.types.ts";
4
4
  import type { DispatchOptions } from "./execution.types.ts";
5
5
  import type { Sandbox, SandboxOptions } from "./outpost.types.ts";
6
+ import type { QuotaResumePolicy } from "./quota-resume.types.ts";
6
7
  export type CommandTaskOptions = {
7
8
  sandbox: Sandbox;
8
9
  command: Command | ((context: TaskContext) => Command);
9
10
  };
10
11
  export type IsolatedTaskOptions<T> = {
11
12
  request: (context: TaskContext) => IsolatedTaskRequest<T> | Promise<IsolatedTaskRequest<T>>;
13
+ /** After a quota pause, continue the captured conversation or start a new one. */
14
+ quotaResume?: QuotaResumePolicy;
12
15
  };
13
16
  export type AgentTaskOptions<T> = {
14
17
  sandbox: Sandbox;
15
18
  request: (context: TaskContext) => DispatchOptions<T>;
19
+ /** After a quota pause, continue the captured conversation or start a new one. */
20
+ quotaResume?: QuotaResumePolicy;
16
21
  };
17
22
  export type IsolatedTaskRequest<T> = SandboxOptions & DispatchOptions<T> & {
18
23
  readonly agent: Agent;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks.types.js","sourceRoot":"","sources":["../../src/application/tasks.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Agent } from \"../domain/agent.types.ts\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport type { TaskContext } from \"../domain/workflow.types.ts\";\nimport type { DispatchOptions } from \"./execution.types.ts\";\nimport type { Sandbox, SandboxOptions } from \"./outpost.types.ts\";\n\nexport type CommandTaskOptions = {\n sandbox: Sandbox;\n command: Command | ((context: TaskContext) => Command);\n};\n\nexport type IsolatedTaskOptions<T> = {\n request: (\n context: TaskContext,\n ) => IsolatedTaskRequest<T> | Promise<IsolatedTaskRequest<T>>;\n};\n\nexport type AgentTaskOptions<T> = {\n sandbox: Sandbox;\n request: (context: TaskContext) => DispatchOptions<T>;\n};\n\nexport type IsolatedTaskRequest<T> = SandboxOptions &\n DispatchOptions<T> & { readonly agent: Agent };\n"]}
1
+ {"version":3,"file":"tasks.types.js","sourceRoot":"","sources":["../../src/application/tasks.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Agent } from \"../domain/agent.types.ts\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport type { TaskContext } from \"../domain/workflow.types.ts\";\nimport type { DispatchOptions } from \"./execution.types.ts\";\nimport type { Sandbox, SandboxOptions } from \"./outpost.types.ts\";\nimport type { QuotaResumePolicy } from \"./quota-resume.types.ts\";\n\nexport type CommandTaskOptions = {\n sandbox: Sandbox;\n command: Command | ((context: TaskContext) => Command);\n};\n\nexport type IsolatedTaskOptions<T> = {\n request: (\n context: TaskContext,\n ) => IsolatedTaskRequest<T> | Promise<IsolatedTaskRequest<T>>;\n /** After a quota pause, continue the captured conversation or start a new one. */\n quotaResume?: QuotaResumePolicy;\n};\n\nexport type AgentTaskOptions<T> = {\n sandbox: Sandbox;\n request: (context: TaskContext) => DispatchOptions<T>;\n /** After a quota pause, continue the captured conversation or start a new one. */\n quotaResume?: QuotaResumePolicy;\n};\n\nexport type IsolatedTaskRequest<T> = SandboxOptions &\n DispatchOptions<T> & { readonly agent: Agent };\n"]}
@@ -6,5 +6,6 @@ export const transportCategories = [
6
6
  "logs",
7
7
  "reservations",
8
8
  "resources",
9
+ "task-cache",
9
10
  ];
10
11
  //# sourceMappingURL=transport-inspection.constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport-inspection.constants.js","sourceRoot":"","sources":["../../src/application/transport-inspection.constants.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,mBAAmB,GAAmC;IACjE,WAAW;IACX,aAAa;IACb,eAAe;IACf,UAAU;IACV,MAAM;IACN,cAAc;IACd,WAAW;CACZ,CAAC","sourcesContent":["import type { StorageCategoryName } from \"../infrastructure/storage-inventory.types.ts\";\nexport const transportCategories: readonly StorageCategoryName[] = [\n \"artifacts\",\n \"checkpoints\",\n \"conversations\",\n \"recovery\",\n \"logs\",\n \"reservations\",\n \"resources\",\n];\n"]}
1
+ {"version":3,"file":"transport-inspection.constants.js","sourceRoot":"","sources":["../../src/application/transport-inspection.constants.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,mBAAmB,GAAmC;IACjE,WAAW;IACX,aAAa;IACb,eAAe;IACf,UAAU;IACV,MAAM;IACN,cAAc;IACd,WAAW;IACX,YAAY;CACb,CAAC","sourcesContent":["import type { StorageCategoryName } from \"../infrastructure/storage-inventory.types.ts\";\nexport const transportCategories: readonly StorageCategoryName[] = [\n \"artifacts\",\n \"checkpoints\",\n \"conversations\",\n \"recovery\",\n \"logs\",\n \"reservations\",\n \"resources\",\n \"task-cache\",\n];\n"]}
@@ -3,6 +3,34 @@ import { inspectTransportRecovery } from "./transport-inspection.js";
3
3
  import { journalSnapshot } from "../infrastructure/transport-journal.js";
4
4
  import { jsonObject } from "../infrastructure/transport-json.js";
5
5
  import { retentionPolicy } from "./recovery-retention-policy.js";
6
+ function cacheEntry(entry, policy, complete, inspectedAt) {
7
+ invariant(entry.revision && entry.modifiedAt, "Missing transport entry version");
8
+ const object = {
9
+ key: entry.path,
10
+ revision: entry.revision,
11
+ size: entry.bytes,
12
+ modifiedAt: entry.modifiedAt,
13
+ };
14
+ const selected = policy.scopes.includes("task-cache");
15
+ const eligible = selected &&
16
+ complete &&
17
+ Date.parse(inspectedAt) - Date.parse(entry.modifiedAt) >= policy.minAgeMs;
18
+ let reason = selected
19
+ ? "RETENTION_AGE_OR_INCOMPLETE_INVENTORY"
20
+ : "TASK_CACHE_NOT_SELECTED";
21
+ if (eligible)
22
+ reason = "ELIGIBLE";
23
+ return {
24
+ path: entry.path,
25
+ category: "task-cache",
26
+ bytes: entry.bytes,
27
+ eligible,
28
+ reason,
29
+ objects: [object],
30
+ revision: entry.revision,
31
+ modifiedAt: entry.modifiedAt,
32
+ };
33
+ }
6
34
  export async function planTransportRetention(options) {
7
35
  const transporter = options.transporter;
8
36
  invariant(transporter, "Transport is required");
@@ -70,6 +98,10 @@ export async function planTransportRetention(options) {
70
98
  });
71
99
  continue;
72
100
  }
101
+ if (category.name === "task-cache") {
102
+ entries.push(cacheEntry(entry, options.policy, inspection.complete, inspectedAt));
103
+ continue;
104
+ }
73
105
  entries.push({
74
106
  path: entry.path,
75
107
  category: category.name,
@@ -121,7 +153,7 @@ export async function pruneTransportRetention(plan, options) {
121
153
  continue;
122
154
  }
123
155
  try {
124
- invariant(entry.revision && entry.objects, "Missing log revisions");
156
+ invariant(entry.revision && entry.objects, "Missing entry revisions");
125
157
  await options.transporter.remove(entry.path, {
126
158
  ifRevision: entry.revision,
127
159
  });
@@ -1 +1 @@
1
- {"version":3,"file":"transport-retention.js","sourceRoot":"","sources":["../../src/application/transport-retention.ts"],"names":[],"mappings":"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","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport type {\n TransportStoreOptions,\n TransportEntry,\n} from \"../domain/transport.types.ts\";\nimport type {\n RecoveryRetentionOptions,\n RecoveryRetentionPlan,\n RecoveryRetentionEntry,\n RecoveryPruneResult,\n} from \"./recovery-retention.types.ts\";\nimport { inspectTransportRecovery } from \"./transport-inspection.ts\";\nimport { journalSnapshot } from \"../infrastructure/transport-journal.ts\";\nimport { jsonObject } from \"../infrastructure/transport-json.ts\";\nimport { retentionPolicy } from \"./recovery-retention-policy.ts\";\n\nexport async function planTransportRetention(\n options: RecoveryRetentionOptions,\n): Promise<RecoveryRetentionPlan> {\n const transporter = options.transporter;\n invariant(transporter, \"Transport is required\");\n retentionPolicy(options.policy);\n invariant(\n !options.policy.scopes.includes(\"clean-workspaces\") &&\n options.policy.maxWorkspaces === undefined,\n \"Transport retention cannot inspect local workspaces\",\n );\n const inspection = await inspectTransportRecovery(options);\n const inspectedAt = new Date().toISOString();\n const entries: RecoveryRetentionEntry[] = [];\n const handled = new Set<string>();\n for (const category of inspection.categories) {\n for (const entry of category.entries) {\n if (handled.has(entry.path)) continue;\n let eligible = false,\n reason = \"RECOVERY_DATA_PROTECTED\";\n let objects: TransportEntry[] = [];\n if (category.name === \"logs\") {\n const prefix = entry.path.slice(0, entry.path.lastIndexOf(\"/\") + 1);\n const group = category.entries.filter((value) =>\n value.path.startsWith(prefix),\n );\n objects = group.map((value) => {\n invariant(\n value.revision && value.modifiedAt,\n \"Missing transport entry version\",\n );\n return {\n key: value.path,\n revision: value.revision,\n size: value.bytes,\n modifiedAt: value.modifiedAt,\n };\n });\n for (const object of objects) handled.add(object.key);\n const index = group.find((value) => value.path === prefix + \"index\");\n reason = \"LOG_ACTIVITY_OR_CONTENT_UNKNOWN\";\n if (index && options.policy.scopes.includes(\"closed-logs\")) {\n try {\n const current = await transporter.read(index.path);\n if (\n current?.revision === index.revision &&\n journalSnapshot(jsonObject(current)).closed\n ) {\n eligible =\n inspection.complete &&\n objects.every(\n (value) =>\n Date.parse(inspectedAt) - Date.parse(value.modifiedAt) >=\n options.policy.minAgeMs,\n );\n reason = eligible\n ? \"ELIGIBLE\"\n : \"RETENTION_AGE_OR_INCOMPLETE_INVENTORY\";\n }\n } catch {\n reason = \"LOG_ACTIVITY_OR_CONTENT_UNKNOWN\";\n }\n }\n const indexObject = objects.find(\n (value) => value.key === prefix + \"index\",\n );\n entries.push({\n path: prefix + \"index\",\n category: category.name,\n bytes: objects.reduce((sum, value) => sum + value.size, 0),\n eligible,\n reason,\n objects,\n ...(indexObject\n ? {\n revision: indexObject.revision,\n modifiedAt: indexObject.modifiedAt,\n }\n : {}),\n });\n continue;\n }\n entries.push({\n path: entry.path,\n category: category.name,\n bytes: entry.bytes,\n eligible,\n reason,\n ...(entry.revision ? { revision: entry.revision } : {}),\n ...(entry.modifiedAt ? { modifiedAt: entry.modifiedAt } : {}),\n });\n }\n }\n const projectedBytes =\n inspection.usage.bytes -\n entries\n .filter((entry) => entry.eligible)\n .reduce((sum, entry) => sum + entry.bytes, 0);\n return {\n repository: inspection.repository,\n source: \"transport\",\n policy: structuredClone(options.policy),\n inspectedAt,\n inspection,\n entries,\n complete: inspection.complete,\n usageBytes: inspection.usage.bytes,\n projectedBytes,\n quota: !inspection.complete\n ? \"unknown\"\n : options.policy.maxBytes !== undefined &&\n projectedBytes > options.policy.maxBytes\n ? \"exceeded\"\n : \"within\",\n };\n}\n\nexport async function pruneTransportRetention(\n plan: RecoveryRetentionPlan,\n options: TransportStoreOptions,\n): Promise<RecoveryPruneResult> {\n invariant(plan.complete, \"Cannot prune an incomplete retention plan\");\n retentionPolicy(plan.policy);\n const removed: string[] = [],\n retained = [];\n for (const candidate of plan.entries.filter((entry) => entry.eligible)) {\n const fresh = await planTransportRetention({\n transporter: options.transporter,\n policy: plan.policy,\n repository: plan.repository,\n });\n const entry = fresh.entries.find((entry) => entry.path === candidate.path);\n if (\n !entry?.eligible ||\n entry.revision !== candidate.revision ||\n JSON.stringify(entry.objects) !== JSON.stringify(candidate.objects)\n ) {\n retained.push({ path: candidate.path, reason: \"PLAN_CHANGED\" });\n continue;\n }\n try {\n invariant(entry.revision && entry.objects, \"Missing log revisions\");\n await options.transporter.remove(entry.path, {\n ifRevision: entry.revision,\n });\n for (const object of entry.objects) {\n if (object.key !== entry.path)\n await options.transporter.remove(object.key, {\n ifRevision: object.revision,\n });\n }\n removed.push(entry.path);\n } catch {\n retained.push({\n path: entry.path,\n reason: \"REVALIDATION_OR_REMOVAL_FAILED\",\n });\n }\n }\n return {\n removed,\n retained,\n after: await planTransportRetention({\n transporter: options.transporter,\n policy: plan.policy,\n repository: plan.repository,\n }),\n };\n}\n"]}
1
+ {"version":3,"file":"transport-retention.js","sourceRoot":"","sources":["../../src/application/transport-retention.ts"],"names":[],"mappings":"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","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport type {\n TransportStoreOptions,\n TransportEntry,\n} from \"../domain/transport.types.ts\";\nimport type { StorageEntry } from \"../infrastructure/storage-inventory.types.ts\";\nimport type {\n RecoveryRetentionPolicy,\n RecoveryRetentionOptions,\n RecoveryRetentionPlan,\n RecoveryRetentionEntry,\n RecoveryPruneResult,\n} from \"./recovery-retention.types.ts\";\nimport { inspectTransportRecovery } from \"./transport-inspection.ts\";\nimport { journalSnapshot } from \"../infrastructure/transport-journal.ts\";\nimport { jsonObject } from \"../infrastructure/transport-json.ts\";\nimport { retentionPolicy } from \"./recovery-retention-policy.ts\";\n\nfunction cacheEntry(\n entry: StorageEntry,\n policy: RecoveryRetentionPolicy,\n complete: boolean,\n inspectedAt: string,\n): RecoveryRetentionEntry {\n invariant(\n entry.revision && entry.modifiedAt,\n \"Missing transport entry version\",\n );\n const object = {\n key: entry.path,\n revision: entry.revision,\n size: entry.bytes,\n modifiedAt: entry.modifiedAt,\n };\n const selected = policy.scopes.includes(\"task-cache\");\n const eligible =\n selected &&\n complete &&\n Date.parse(inspectedAt) - Date.parse(entry.modifiedAt) >= policy.minAgeMs;\n let reason = selected\n ? \"RETENTION_AGE_OR_INCOMPLETE_INVENTORY\"\n : \"TASK_CACHE_NOT_SELECTED\";\n if (eligible) reason = \"ELIGIBLE\";\n return {\n path: entry.path,\n category: \"task-cache\",\n bytes: entry.bytes,\n eligible,\n reason,\n objects: [object],\n revision: entry.revision,\n modifiedAt: entry.modifiedAt,\n };\n}\n\nexport async function planTransportRetention(\n options: RecoveryRetentionOptions,\n): Promise<RecoveryRetentionPlan> {\n const transporter = options.transporter;\n invariant(transporter, \"Transport is required\");\n retentionPolicy(options.policy);\n invariant(\n !options.policy.scopes.includes(\"clean-workspaces\") &&\n options.policy.maxWorkspaces === undefined,\n \"Transport retention cannot inspect local workspaces\",\n );\n const inspection = await inspectTransportRecovery(options);\n const inspectedAt = new Date().toISOString();\n const entries: RecoveryRetentionEntry[] = [];\n const handled = new Set<string>();\n for (const category of inspection.categories) {\n for (const entry of category.entries) {\n if (handled.has(entry.path)) continue;\n let eligible = false,\n reason = \"RECOVERY_DATA_PROTECTED\";\n let objects: TransportEntry[] = [];\n if (category.name === \"logs\") {\n const prefix = entry.path.slice(0, entry.path.lastIndexOf(\"/\") + 1);\n const group = category.entries.filter((value) =>\n value.path.startsWith(prefix),\n );\n objects = group.map((value) => {\n invariant(\n value.revision && value.modifiedAt,\n \"Missing transport entry version\",\n );\n return {\n key: value.path,\n revision: value.revision,\n size: value.bytes,\n modifiedAt: value.modifiedAt,\n };\n });\n for (const object of objects) handled.add(object.key);\n const index = group.find((value) => value.path === prefix + \"index\");\n reason = \"LOG_ACTIVITY_OR_CONTENT_UNKNOWN\";\n if (index && options.policy.scopes.includes(\"closed-logs\")) {\n try {\n const current = await transporter.read(index.path);\n if (\n current?.revision === index.revision &&\n journalSnapshot(jsonObject(current)).closed\n ) {\n eligible =\n inspection.complete &&\n objects.every(\n (value) =>\n Date.parse(inspectedAt) - Date.parse(value.modifiedAt) >=\n options.policy.minAgeMs,\n );\n reason = eligible\n ? \"ELIGIBLE\"\n : \"RETENTION_AGE_OR_INCOMPLETE_INVENTORY\";\n }\n } catch {\n reason = \"LOG_ACTIVITY_OR_CONTENT_UNKNOWN\";\n }\n }\n const indexObject = objects.find(\n (value) => value.key === prefix + \"index\",\n );\n entries.push({\n path: prefix + \"index\",\n category: category.name,\n bytes: objects.reduce((sum, value) => sum + value.size, 0),\n eligible,\n reason,\n objects,\n ...(indexObject\n ? {\n revision: indexObject.revision,\n modifiedAt: indexObject.modifiedAt,\n }\n : {}),\n });\n continue;\n }\n if (category.name === \"task-cache\") {\n entries.push(\n cacheEntry(entry, options.policy, inspection.complete, inspectedAt),\n );\n continue;\n }\n entries.push({\n path: entry.path,\n category: category.name,\n bytes: entry.bytes,\n eligible,\n reason,\n ...(entry.revision ? { revision: entry.revision } : {}),\n ...(entry.modifiedAt ? { modifiedAt: entry.modifiedAt } : {}),\n });\n }\n }\n const projectedBytes =\n inspection.usage.bytes -\n entries\n .filter((entry) => entry.eligible)\n .reduce((sum, entry) => sum + entry.bytes, 0);\n return {\n repository: inspection.repository,\n source: \"transport\",\n policy: structuredClone(options.policy),\n inspectedAt,\n inspection,\n entries,\n complete: inspection.complete,\n usageBytes: inspection.usage.bytes,\n projectedBytes,\n quota: !inspection.complete\n ? \"unknown\"\n : options.policy.maxBytes !== undefined &&\n projectedBytes > options.policy.maxBytes\n ? \"exceeded\"\n : \"within\",\n };\n}\n\nexport async function pruneTransportRetention(\n plan: RecoveryRetentionPlan,\n options: TransportStoreOptions,\n): Promise<RecoveryPruneResult> {\n invariant(plan.complete, \"Cannot prune an incomplete retention plan\");\n retentionPolicy(plan.policy);\n const removed: string[] = [],\n retained = [];\n for (const candidate of plan.entries.filter((entry) => entry.eligible)) {\n const fresh = await planTransportRetention({\n transporter: options.transporter,\n policy: plan.policy,\n repository: plan.repository,\n });\n const entry = fresh.entries.find((entry) => entry.path === candidate.path);\n if (\n !entry?.eligible ||\n entry.revision !== candidate.revision ||\n JSON.stringify(entry.objects) !== JSON.stringify(candidate.objects)\n ) {\n retained.push({ path: candidate.path, reason: \"PLAN_CHANGED\" });\n continue;\n }\n try {\n invariant(entry.revision && entry.objects, \"Missing entry revisions\");\n await options.transporter.remove(entry.path, {\n ifRevision: entry.revision,\n });\n for (const object of entry.objects) {\n if (object.key !== entry.path)\n await options.transporter.remove(object.key, {\n ifRevision: object.revision,\n });\n }\n removed.push(entry.path);\n } catch {\n retained.push({\n path: entry.path,\n reason: \"REVALIDATION_OR_REMOVAL_FAILED\",\n });\n }\n }\n return {\n removed,\n retained,\n after: await planTransportRetention({\n transporter: options.transporter,\n policy: plan.policy,\n repository: plan.repository,\n }),\n };\n}\n"]}
@@ -4,6 +4,7 @@ export function isAgentEvent(event) {
4
4
  case "operation":
5
5
  case "dispatch-start":
6
6
  case "dispatch-finished":
7
+ case "workspace-commits":
7
8
  case "command-output":
8
9
  case "candidate":
9
10
  case "queue":
@@ -1 +1 @@
1
- {"version":3,"file":"agent-observation.js","sourceRoot":"","sources":["../../src/domain/agent-observation.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,YAAY,CAAC,KAAuB;IAClD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,UAAU,CAAC;QAChB,KAAK,WAAW,CAAC;QACjB,KAAK,gBAAgB,CAAC;QACtB,KAAK,mBAAmB,CAAC;QACzB,KAAK,gBAAgB,CAAC;QACtB,KAAK,WAAW,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;QACf;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAkB;IAElB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACjD,OAAO;QACL,GAAG,KAAK,CAAC,KAAK;QACd,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;QAC3B,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC","sourcesContent":["import type { AgentEvent, AgentObservation } from \"./agent.types.ts\";\nimport type { Observation, ObservationEvent } from \"./observation.types.ts\";\n\nexport function isAgentEvent(event: ObservationEvent): event is AgentEvent {\n switch (event.kind) {\n case \"workflow\":\n case \"operation\":\n case \"dispatch-start\":\n case \"dispatch-finished\":\n case \"command-output\":\n case \"candidate\":\n case \"queue\":\n return false;\n default:\n return true;\n }\n}\n\nexport function agentObservation(\n value: Observation,\n): AgentObservation | undefined {\n if (!isAgentEvent(value.event)) return undefined;\n return {\n ...value.event,\n pass: value.scope.pass ?? 1,\n at: value.at,\n seq: value.seq,\n source: value.source,\n scope: value.scope,\n };\n}\n"]}
1
+ {"version":3,"file":"agent-observation.js","sourceRoot":"","sources":["../../src/domain/agent-observation.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,YAAY,CAAC,KAAuB;IAClD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,UAAU,CAAC;QAChB,KAAK,WAAW,CAAC;QACjB,KAAK,gBAAgB,CAAC;QACtB,KAAK,mBAAmB,CAAC;QACzB,KAAK,mBAAmB,CAAC;QACzB,KAAK,gBAAgB,CAAC;QACtB,KAAK,WAAW,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;QACf;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAkB;IAElB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACjD,OAAO;QACL,GAAG,KAAK,CAAC,KAAK;QACd,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;QAC3B,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC","sourcesContent":["import type { AgentEvent, AgentObservation } from \"./agent.types.ts\";\nimport type { Observation, ObservationEvent } from \"./observation.types.ts\";\n\nexport function isAgentEvent(event: ObservationEvent): event is AgentEvent {\n switch (event.kind) {\n case \"workflow\":\n case \"operation\":\n case \"dispatch-start\":\n case \"dispatch-finished\":\n case \"workspace-commits\":\n case \"command-output\":\n case \"candidate\":\n case \"queue\":\n return false;\n default:\n return true;\n }\n}\n\nexport function agentObservation(\n value: Observation,\n): AgentObservation | undefined {\n if (!isAgentEvent(value.event)) return undefined;\n return {\n ...value.event,\n pass: value.scope.pass ?? 1,\n at: value.at,\n seq: value.seq,\n source: value.source,\n scope: value.scope,\n };\n}\n"]}
@@ -2,6 +2,7 @@ import type { Harness } from "./harness.types.ts";
2
2
  import type { AgentModel, ModelSpec } from "./model.types.ts";
3
3
  import type { Command, CommandResult, Variables } from "./command.types.ts";
4
4
  import type { ConversationStore } from "./conversation.types.ts";
5
+ import type { ReplayAgent } from "./replay.types.ts";
5
6
  export interface Usage {
6
7
  readonly complete?: boolean;
7
8
  readonly input: number;
@@ -132,6 +133,10 @@ export type AgentEventDetails = {
132
133
  } | {
133
134
  readonly kind: "failure";
134
135
  readonly message: string;
136
+ } | {
137
+ readonly kind: "quota";
138
+ readonly message: string;
139
+ readonly resetAt?: string;
135
140
  } | {
136
141
  readonly kind: "finished";
137
142
  } | {
@@ -178,6 +183,8 @@ export interface AgentAdapter extends AgentFeatures {
178
183
  credentials?(variables: Variables): CredentialPlan;
179
184
  request(input: AgentInput): Command;
180
185
  events(line: string): readonly AgentEvent[];
186
+ /** Recognizes a usage-limit or rate-limit message in failure or stderr text. */
187
+ quota?(text: string): boolean;
181
188
  usageCommand?(conversation: string): Command | undefined;
182
189
  usageResult?(text: string): Usage | undefined;
183
190
  }
@@ -201,7 +208,7 @@ export interface CustomAgent extends AgentFeatures {
201
208
  readonly harness: Harness;
202
209
  readonly model: AgentModel;
203
210
  }
204
- export type Agent = CliAgent | CustomAgent;
211
+ export type Agent = CliAgent | CustomAgent | ReplayAgent;
205
212
  export interface CliAgentOptions {
206
213
  readonly harness: CliHarness;
207
214
  readonly model?: ModelSpec;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.types.js","sourceRoot":"","sources":["../../src/domain/agent.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Harness } from \"./harness.types.ts\";\nimport type { AgentModel, ModelSpec } from \"./model.types.ts\";\nimport type { Command, CommandResult, Variables } from \"./command.types.ts\";\nimport type { ConversationStore } from \"./conversation.types.ts\";\n\nexport interface Usage {\n readonly complete?: boolean;\n readonly input: number;\n readonly cached: number;\n readonly cacheCreated?: number;\n readonly output: number;\n}\n\nexport type AgentEvent = AgentEventDetails & {\n readonly subagentId?: string;\n};\n\nexport type AgentEventDetails =\n | {\n readonly kind: \"subagent\";\n readonly id: string;\n readonly callId: string;\n readonly name: string;\n readonly status: \"started\" | \"finished\" | \"failed\";\n readonly conversation?: string;\n }\n | {\n readonly kind: \"message-usage\";\n readonly tokens: Usage;\n readonly messageId?: string;\n readonly parentCallId?: string;\n }\n | {\n readonly kind: \"stderr\";\n readonly text: string;\n readonly truncated?: boolean;\n }\n | {\n readonly kind: \"stopped\";\n readonly reason:\n | \"completion\"\n | \"idle-timeout\"\n | \"deadline\"\n | \"aborted\"\n | \"oversized-event\";\n }\n | {\n readonly kind: \"reasoning\";\n readonly text: string;\n readonly parentCallId?: string;\n }\n | {\n readonly kind: \"file-change\";\n readonly changes: unknown;\n readonly callId?: string;\n }\n | { readonly kind: \"model-request\"; readonly request: unknown }\n | { readonly kind: \"model-response\"; readonly response: unknown }\n | {\n readonly kind: \"model-retry\";\n readonly attempt: number;\n readonly message?: string;\n }\n | { readonly kind: \"model-error\"; readonly message: string }\n | { readonly kind: \"hook\"; readonly phase: string; readonly changed: boolean }\n | { readonly kind: \"instructions-loaded\"; readonly count: number }\n | { readonly kind: \"skills-loaded\"; readonly names: readonly string[] }\n | {\n readonly kind: \"tool-output\";\n readonly callId: string;\n readonly channel: \"stdout\" | \"stderr\";\n readonly text: string;\n }\n | {\n readonly kind: \"phase\";\n readonly name: string;\n readonly agent?: string;\n readonly branch?: string;\n readonly directory?: string;\n }\n | {\n readonly kind: \"summary\";\n readonly durationMs: number;\n readonly status: number;\n readonly tokens: Usage;\n }\n | { readonly kind: \"warning\"; readonly message: string }\n | { readonly kind: \"text\"; readonly text: string }\n | { readonly kind: \"text-delta\"; readonly text: string }\n | { readonly kind: \"result\"; readonly text: string }\n | { readonly kind: \"prompt\"; readonly text: string }\n | {\n readonly kind: \"tool\";\n readonly name: string;\n readonly input: unknown;\n readonly callId?: string;\n readonly parentCallId?: string;\n }\n | {\n readonly kind: \"tool-result\";\n readonly callId: string;\n readonly name: string;\n readonly isError: boolean;\n readonly preview: string;\n readonly characters: number;\n readonly parentCallId?: string;\n }\n | { readonly kind: \"step\"; readonly index: number }\n | {\n readonly kind: \"tool-denied\";\n readonly callId: string;\n readonly name: string;\n readonly reason: string;\n }\n | { readonly kind: \"stop-prevented\"; readonly message: string }\n | {\n readonly kind: \"compaction\";\n readonly strategy: string;\n readonly messages: number;\n }\n | { readonly kind: \"conversation\"; readonly id: string }\n | {\n readonly kind: \"usage\";\n readonly tokens: Usage;\n readonly cumulative?: boolean;\n }\n | { readonly kind: \"failure\"; readonly message: string }\n | { readonly kind: \"finished\" }\n | {\n readonly kind: \"raw\";\n readonly value: unknown;\n readonly bytes?: number;\n readonly truncated?: boolean;\n };\n\nexport type AgentObservation = AgentEvent & {\n readonly pass: number;\n readonly at: string;\n readonly seq?: number;\n readonly source?: import(\"./observation.types.ts\").ObservationSource;\n readonly scope?: import(\"./observation.types.ts\").ObservationScope;\n};\n\nexport type AgentEventHandlers = {\n readonly [Kind in AgentEvent[\"kind\"]]?: (\n event: Extract<AgentEvent, { kind: Kind }>,\n ) => void;\n};\n\nexport interface AgentInput {\n readonly text?: string;\n readonly interactive?: boolean;\n readonly continuation?: { readonly id: string; readonly fork?: boolean };\n}\n\nexport interface AgentFeatures {\n readonly name: string;\n readonly bootstrap?: string;\n readonly requiresFinishedEvent?: boolean;\n readonly usage?: \"events\" | \"session\" | \"unavailable\";\n readonly variables?: Variables;\n readonly conversations?: \"claude\" | \"codex\" | \"copilot\" | \"kimi\";\n readonly storage?: ConversationStore;\n readonly capture?: boolean;\n readonly resumable?: boolean;\n readonly forkable?: boolean;\n transcriptUsage?(text: string): Usage | undefined;\n}\n\nexport interface AgentAdapter extends AgentFeatures {\n fork?(\n id: string,\n invoke: (command: Command) => Promise<CommandResult>,\n ): Promise<string>;\n credentials?(variables: Variables): CredentialPlan;\n request(input: AgentInput): Command;\n events(line: string): readonly AgentEvent[];\n usageCommand?(conversation: string): Command | undefined;\n usageResult?(text: string): Usage | undefined;\n}\n\nexport interface RequiredAgent {\n readonly agent: Agent;\n}\n\nexport interface CliHarness {\n readonly kind: \"cli\";\n bind(model?: AgentModel): AgentAdapter;\n}\n\nexport type AgentHarness = CliHarness | Harness;\n\nexport interface CliAgent extends AgentAdapter {\n readonly kind: \"cli\";\n readonly harness: CliHarness;\n readonly model?: AgentModel;\n}\n\nexport interface CustomAgent extends AgentFeatures {\n readonly resumable: boolean;\n readonly capture: boolean;\n readonly kind: \"custom\";\n readonly harness: Harness;\n readonly model: AgentModel;\n}\n\nexport type Agent = CliAgent | CustomAgent;\n\nexport interface CliAgentOptions {\n readonly harness: CliHarness;\n readonly model?: ModelSpec;\n}\nexport interface CustomAgentOptions {\n readonly harness: Harness;\n readonly model: ModelSpec;\n}\nexport type AgentOptions = CliAgentOptions | CustomAgentOptions;\n\nexport type AccountCredential =\n | { readonly file: string }\n | { readonly key: string }\n | { readonly variable: string };\n\nexport type UsageCredential =\n { readonly key: string } | { readonly variable: string };\n\nexport type AgentAuthentication =\n | \"account\"\n | \"usage\"\n | { readonly account: AccountCredential }\n | { readonly usage: UsageCredential };\n\nexport interface HostCredentialPath {\n readonly path: string;\n readonly home?: { readonly variable: string; readonly path: string };\n}\n\nexport interface HostCredential {\n readonly source: HostCredentialPath;\n readonly destination:\n { readonly file: string } | { readonly variable: string };\n readonly login: string;\n readonly alternative?: string;\n select?(content: string): string;\n}\n\nexport interface GeneratedCredential {\n readonly path: string;\n readonly content: string;\n}\n\nexport interface CredentialPlan {\n readonly variables: Variables;\n readonly host: readonly HostCredential[];\n readonly files: readonly GeneratedCredential[];\n readonly commands: readonly Command[];\n}\n"]}
1
+ {"version":3,"file":"agent.types.js","sourceRoot":"","sources":["../../src/domain/agent.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Harness } from \"./harness.types.ts\";\nimport type { AgentModel, ModelSpec } from \"./model.types.ts\";\nimport type { Command, CommandResult, Variables } from \"./command.types.ts\";\nimport type { ConversationStore } from \"./conversation.types.ts\";\nimport type { ReplayAgent } from \"./replay.types.ts\";\n\nexport interface Usage {\n readonly complete?: boolean;\n readonly input: number;\n readonly cached: number;\n readonly cacheCreated?: number;\n readonly output: number;\n}\n\nexport type AgentEvent = AgentEventDetails & {\n readonly subagentId?: string;\n};\n\nexport type AgentEventDetails =\n | {\n readonly kind: \"subagent\";\n readonly id: string;\n readonly callId: string;\n readonly name: string;\n readonly status: \"started\" | \"finished\" | \"failed\";\n readonly conversation?: string;\n }\n | {\n readonly kind: \"message-usage\";\n readonly tokens: Usage;\n readonly messageId?: string;\n readonly parentCallId?: string;\n }\n | {\n readonly kind: \"stderr\";\n readonly text: string;\n readonly truncated?: boolean;\n }\n | {\n readonly kind: \"stopped\";\n readonly reason:\n | \"completion\"\n | \"idle-timeout\"\n | \"deadline\"\n | \"aborted\"\n | \"oversized-event\";\n }\n | {\n readonly kind: \"reasoning\";\n readonly text: string;\n readonly parentCallId?: string;\n }\n | {\n readonly kind: \"file-change\";\n readonly changes: unknown;\n readonly callId?: string;\n }\n | { readonly kind: \"model-request\"; readonly request: unknown }\n | { readonly kind: \"model-response\"; readonly response: unknown }\n | {\n readonly kind: \"model-retry\";\n readonly attempt: number;\n readonly message?: string;\n }\n | { readonly kind: \"model-error\"; readonly message: string }\n | { readonly kind: \"hook\"; readonly phase: string; readonly changed: boolean }\n | { readonly kind: \"instructions-loaded\"; readonly count: number }\n | { readonly kind: \"skills-loaded\"; readonly names: readonly string[] }\n | {\n readonly kind: \"tool-output\";\n readonly callId: string;\n readonly channel: \"stdout\" | \"stderr\";\n readonly text: string;\n }\n | {\n readonly kind: \"phase\";\n readonly name: string;\n readonly agent?: string;\n readonly branch?: string;\n readonly directory?: string;\n }\n | {\n readonly kind: \"summary\";\n readonly durationMs: number;\n readonly status: number;\n readonly tokens: Usage;\n }\n | { readonly kind: \"warning\"; readonly message: string }\n | { readonly kind: \"text\"; readonly text: string }\n | { readonly kind: \"text-delta\"; readonly text: string }\n | { readonly kind: \"result\"; readonly text: string }\n | { readonly kind: \"prompt\"; readonly text: string }\n | {\n readonly kind: \"tool\";\n readonly name: string;\n readonly input: unknown;\n readonly callId?: string;\n readonly parentCallId?: string;\n }\n | {\n readonly kind: \"tool-result\";\n readonly callId: string;\n readonly name: string;\n readonly isError: boolean;\n readonly preview: string;\n readonly characters: number;\n readonly parentCallId?: string;\n }\n | { readonly kind: \"step\"; readonly index: number }\n | {\n readonly kind: \"tool-denied\";\n readonly callId: string;\n readonly name: string;\n readonly reason: string;\n }\n | { readonly kind: \"stop-prevented\"; readonly message: string }\n | {\n readonly kind: \"compaction\";\n readonly strategy: string;\n readonly messages: number;\n }\n | { readonly kind: \"conversation\"; readonly id: string }\n | {\n readonly kind: \"usage\";\n readonly tokens: Usage;\n readonly cumulative?: boolean;\n }\n | { readonly kind: \"failure\"; readonly message: string }\n | {\n readonly kind: \"quota\";\n readonly message: string;\n readonly resetAt?: string;\n }\n | { readonly kind: \"finished\" }\n | {\n readonly kind: \"raw\";\n readonly value: unknown;\n readonly bytes?: number;\n readonly truncated?: boolean;\n };\n\nexport type AgentObservation = AgentEvent & {\n readonly pass: number;\n readonly at: string;\n readonly seq?: number;\n readonly source?: import(\"./observation.types.ts\").ObservationSource;\n readonly scope?: import(\"./observation.types.ts\").ObservationScope;\n};\n\nexport type AgentEventHandlers = {\n readonly [Kind in AgentEvent[\"kind\"]]?: (\n event: Extract<AgentEvent, { kind: Kind }>,\n ) => void;\n};\n\nexport interface AgentInput {\n readonly text?: string;\n readonly interactive?: boolean;\n readonly continuation?: { readonly id: string; readonly fork?: boolean };\n}\n\nexport interface AgentFeatures {\n readonly name: string;\n readonly bootstrap?: string;\n readonly requiresFinishedEvent?: boolean;\n readonly usage?: \"events\" | \"session\" | \"unavailable\";\n readonly variables?: Variables;\n readonly conversations?: \"claude\" | \"codex\" | \"copilot\" | \"kimi\";\n readonly storage?: ConversationStore;\n readonly capture?: boolean;\n readonly resumable?: boolean;\n readonly forkable?: boolean;\n transcriptUsage?(text: string): Usage | undefined;\n}\n\nexport interface AgentAdapter extends AgentFeatures {\n fork?(\n id: string,\n invoke: (command: Command) => Promise<CommandResult>,\n ): Promise<string>;\n credentials?(variables: Variables): CredentialPlan;\n request(input: AgentInput): Command;\n events(line: string): readonly AgentEvent[];\n /** Recognizes a usage-limit or rate-limit message in failure or stderr text. */\n quota?(text: string): boolean;\n usageCommand?(conversation: string): Command | undefined;\n usageResult?(text: string): Usage | undefined;\n}\n\nexport interface RequiredAgent {\n readonly agent: Agent;\n}\n\nexport interface CliHarness {\n readonly kind: \"cli\";\n bind(model?: AgentModel): AgentAdapter;\n}\n\nexport type AgentHarness = CliHarness | Harness;\n\nexport interface CliAgent extends AgentAdapter {\n readonly kind: \"cli\";\n readonly harness: CliHarness;\n readonly model?: AgentModel;\n}\n\nexport interface CustomAgent extends AgentFeatures {\n readonly resumable: boolean;\n readonly capture: boolean;\n readonly kind: \"custom\";\n readonly harness: Harness;\n readonly model: AgentModel;\n}\n\nexport type Agent = CliAgent | CustomAgent | ReplayAgent;\n\nexport interface CliAgentOptions {\n readonly harness: CliHarness;\n readonly model?: ModelSpec;\n}\nexport interface CustomAgentOptions {\n readonly harness: Harness;\n readonly model: ModelSpec;\n}\nexport type AgentOptions = CliAgentOptions | CustomAgentOptions;\n\nexport type AccountCredential =\n | { readonly file: string }\n | { readonly key: string }\n | { readonly variable: string };\n\nexport type UsageCredential =\n { readonly key: string } | { readonly variable: string };\n\nexport type AgentAuthentication =\n | \"account\"\n | \"usage\"\n | { readonly account: AccountCredential }\n | { readonly usage: UsageCredential };\n\nexport interface HostCredentialPath {\n readonly path: string;\n readonly home?: { readonly variable: string; readonly path: string };\n}\n\nexport interface HostCredential {\n readonly source: HostCredentialPath;\n readonly destination:\n { readonly file: string } | { readonly variable: string };\n readonly login: string;\n readonly alternative?: string;\n select?(content: string): string;\n}\n\nexport interface GeneratedCredential {\n readonly path: string;\n readonly content: string;\n}\n\nexport interface CredentialPlan {\n readonly variables: Variables;\n readonly host: readonly HostCredential[];\n readonly files: readonly GeneratedCredential[];\n readonly commands: readonly Command[];\n}\n"]}
@@ -1 +1 @@
1
- export type FaultCode = "configuration" | "process" | "timeout" | "aborted" | "workspace" | "conflict" | "prompt" | "response" | "session" | "provider" | "limit";
1
+ export type FaultCode = "configuration" | "process" | "timeout" | "aborted" | "workspace" | "conflict" | "prompt" | "response" | "session" | "provider" | "limit" | "quota" | "replay";
@@ -1 +1 @@
1
- {"version":3,"file":"errors.types.js","sourceRoot":"","sources":["../../src/domain/errors.types.ts"],"names":[],"mappings":"","sourcesContent":["export type FaultCode =\n | \"configuration\"\n | \"process\"\n | \"timeout\"\n | \"aborted\"\n | \"workspace\"\n | \"conflict\"\n | \"prompt\"\n | \"response\"\n | \"session\"\n | \"provider\"\n | \"limit\";\n"]}
1
+ {"version":3,"file":"errors.types.js","sourceRoot":"","sources":["../../src/domain/errors.types.ts"],"names":[],"mappings":"","sourcesContent":["export type FaultCode =\n | \"configuration\"\n | \"process\"\n | \"timeout\"\n | \"aborted\"\n | \"workspace\"\n | \"conflict\"\n | \"prompt\"\n | \"response\"\n | \"session\"\n | \"provider\"\n | \"limit\"\n | \"quota\"\n | \"replay\";\n"]}