@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
@@ -1,5 +1,6 @@
1
1
  import type { AgentEvent } from "./agent.types.ts";
2
2
  import type { WorkflowEvent } from "./workflow.types.ts";
3
+ import type { WorkspaceCommitsEvent } from "./replay.types.ts";
3
4
  export interface ObservationScope {
4
5
  readonly executionId?: string;
5
6
  readonly taskKey?: string;
@@ -29,7 +30,11 @@ export type ObservationEvent = AgentEvent | OperationEvent | {
29
30
  readonly branch?: string;
30
31
  readonly commits?: readonly import("./workspace.types.ts").Commit[];
31
32
  readonly usage: import("./agent.types.ts").Usage;
32
- } | {
33
+ readonly error?: {
34
+ readonly code?: string;
35
+ readonly message: string;
36
+ };
37
+ } | WorkspaceCommitsEvent | {
33
38
  readonly kind: "command-output";
34
39
  readonly channel: "stdout" | "stderr";
35
40
  readonly text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"observation.types.js","sourceRoot":"","sources":["../../src/domain/observation.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentEvent } from \"./agent.types.ts\";\nimport type { WorkflowEvent } from \"./workflow.types.ts\";\n\nexport interface ObservationScope {\n readonly executionId?: string;\n readonly taskKey?: string;\n readonly attempt?: number;\n readonly dispatchId?: string;\n readonly pass?: number;\n readonly subagentId?: string;\n readonly candidate?: string;\n}\n\nexport type ObservationSource =\n | \"agent\"\n | \"harness\"\n | \"workflow\"\n | \"sandbox\"\n | \"git\"\n | \"hooks\"\n | \"transfer\"\n | \"conversation\"\n | \"recovery\";\n\nexport interface OperationEvent {\n readonly kind: \"operation\";\n readonly id: string;\n readonly name: string;\n readonly status: \"started\" | \"finished\" | \"failed\";\n readonly durationMs?: number;\n}\n\nexport type ObservationEvent =\n | AgentEvent\n | OperationEvent\n | { readonly kind: \"dispatch-start\" }\n | {\n readonly kind: \"workflow\";\n readonly event: WorkflowEvent;\n }\n | {\n readonly kind: \"dispatch-finished\";\n readonly status: \"done\" | \"failed\" | \"cancelled\";\n readonly completed: boolean;\n readonly branch?: string;\n readonly commits?: readonly import(\"./workspace.types.ts\").Commit[];\n readonly usage: import(\"./agent.types.ts\").Usage;\n }\n | {\n readonly kind: \"command-output\";\n readonly channel: \"stdout\" | \"stderr\";\n readonly text: string;\n }\n | {\n readonly kind: \"candidate\";\n readonly status: \"validated\" | \"accepted\" | \"rejected\" | \"cleanup\";\n }\n | {\n readonly kind: \"queue\";\n readonly id: string;\n readonly status: \"enqueued\" | \"polled\" | \"completed\" | \"failed\";\n };\n\nexport interface Observation {\n readonly seq: number;\n readonly at: string;\n readonly source: ObservationSource;\n readonly scope: ObservationScope;\n readonly event: ObservationEvent;\n}\n\nexport interface ObservationSink {\n observe(observation: Observation): void | Promise<void>;\n flush?(): void | Promise<void>;\n}\n\nexport interface ObservationHubOptions {\n readonly sinks?: readonly ObservationSink[];\n readonly scope?: ObservationScope;\n readonly capacity?: number;\n readonly deliveryTimeoutMs?: number;\n readonly verbose?: boolean;\n}\n\nexport interface ObservationHub {\n readonly scope: ObservationScope;\n readonly errors: readonly unknown[];\n readonly dropped: number;\n readonly verbose: boolean;\n emit(source: ObservationSource, event: ObservationEvent): void;\n child(\n scope: ObservationScope,\n sinks?: readonly ObservationSink[],\n ): ObservationHub;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport interface SinkDelivery {\n readonly sink: ObservationSink;\n readonly queue: Observation[];\n completedSeq?: number;\n pendingSeq?: number;\n disabled?: boolean;\n pending?: Promise<void>;\n dropped: number;\n}\n\nexport interface PendingObservation {\n readonly targets: readonly SinkDelivery[];\n readonly observation: Observation;\n}\n"]}
1
+ {"version":3,"file":"observation.types.js","sourceRoot":"","sources":["../../src/domain/observation.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentEvent } from \"./agent.types.ts\";\nimport type { WorkflowEvent } from \"./workflow.types.ts\";\nimport type { WorkspaceCommitsEvent } from \"./replay.types.ts\";\n\nexport interface ObservationScope {\n readonly executionId?: string;\n readonly taskKey?: string;\n readonly attempt?: number;\n readonly dispatchId?: string;\n readonly pass?: number;\n readonly subagentId?: string;\n readonly candidate?: string;\n}\n\nexport type ObservationSource =\n | \"agent\"\n | \"harness\"\n | \"workflow\"\n | \"sandbox\"\n | \"git\"\n | \"hooks\"\n | \"transfer\"\n | \"conversation\"\n | \"recovery\";\n\nexport interface OperationEvent {\n readonly kind: \"operation\";\n readonly id: string;\n readonly name: string;\n readonly status: \"started\" | \"finished\" | \"failed\";\n readonly durationMs?: number;\n}\n\nexport type ObservationEvent =\n | AgentEvent\n | OperationEvent\n | { readonly kind: \"dispatch-start\" }\n | {\n readonly kind: \"workflow\";\n readonly event: WorkflowEvent;\n }\n | {\n readonly kind: \"dispatch-finished\";\n readonly status: \"done\" | \"failed\" | \"cancelled\";\n readonly completed: boolean;\n readonly branch?: string;\n readonly commits?: readonly import(\"./workspace.types.ts\").Commit[];\n readonly usage: import(\"./agent.types.ts\").Usage;\n readonly error?: { readonly code?: string; readonly message: string };\n }\n | WorkspaceCommitsEvent\n | {\n readonly kind: \"command-output\";\n readonly channel: \"stdout\" | \"stderr\";\n readonly text: string;\n }\n | {\n readonly kind: \"candidate\";\n readonly status: \"validated\" | \"accepted\" | \"rejected\" | \"cleanup\";\n }\n | {\n readonly kind: \"queue\";\n readonly id: string;\n readonly status: \"enqueued\" | \"polled\" | \"completed\" | \"failed\";\n };\n\nexport interface Observation {\n readonly seq: number;\n readonly at: string;\n readonly source: ObservationSource;\n readonly scope: ObservationScope;\n readonly event: ObservationEvent;\n}\n\nexport interface ObservationSink {\n observe(observation: Observation): void | Promise<void>;\n flush?(): void | Promise<void>;\n}\n\nexport interface ObservationHubOptions {\n readonly sinks?: readonly ObservationSink[];\n readonly scope?: ObservationScope;\n readonly capacity?: number;\n readonly deliveryTimeoutMs?: number;\n readonly verbose?: boolean;\n}\n\nexport interface ObservationHub {\n readonly scope: ObservationScope;\n readonly errors: readonly unknown[];\n readonly dropped: number;\n readonly verbose: boolean;\n emit(source: ObservationSource, event: ObservationEvent): void;\n child(\n scope: ObservationScope,\n sinks?: readonly ObservationSink[],\n ): ObservationHub;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport interface SinkDelivery {\n readonly sink: ObservationSink;\n readonly queue: Observation[];\n completedSeq?: number;\n pendingSeq?: number;\n disabled?: boolean;\n pending?: Promise<void>;\n dropped: number;\n}\n\nexport interface PendingObservation {\n readonly targets: readonly SinkDelivery[];\n readonly observation: Observation;\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare const maxQuotaCauseDepth = 8;
@@ -0,0 +1,2 @@
1
+ export const maxQuotaCauseDepth = 8;
2
+ //# sourceMappingURL=quota.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.constants.js","sourceRoot":"","sources":["../../src/domain/quota.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC","sourcesContent":["export const maxQuotaCauseDepth = 8;\n"]}
@@ -0,0 +1,4 @@
1
+ import type { QuotaFault } from "./quota.types.ts";
2
+ export type { QuotaFault } from "./quota.types.ts";
3
+ export declare function quotaFault(error: unknown): QuotaFault | undefined;
4
+ export declare function resetTimestamp(delayMs: number, now?: number): string | undefined;
@@ -0,0 +1,28 @@
1
+ import { OutpostError } from "./errors.js";
2
+ import { maxQuotaCauseDepth } from "./quota.constants.js";
3
+ export function quotaFault(error) {
4
+ let current = error;
5
+ for (let depth = 0; depth < maxQuotaCauseDepth; depth++) {
6
+ if (current instanceof OutpostError && current.code === "quota") {
7
+ const { resetAt, conversation } = current.details;
8
+ return Object.freeze({
9
+ message: current.message,
10
+ ...(typeof resetAt === "string" && Number.isFinite(Date.parse(resetAt))
11
+ ? { resetAt }
12
+ : {}),
13
+ ...(typeof conversation === "string" && conversation
14
+ ? { conversation }
15
+ : {}),
16
+ });
17
+ }
18
+ if (!(current instanceof Error))
19
+ return undefined;
20
+ current = current.cause;
21
+ }
22
+ return undefined;
23
+ }
24
+ export function resetTimestamp(delayMs, now = Date.now()) {
25
+ const reset = new Date(now + delayMs);
26
+ return Number.isFinite(reset.getTime()) ? reset.toISOString() : undefined;
27
+ }
28
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../../src/domain/quota.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK1D,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,kBAAkB,EAAE,KAAK,EAAE,EAAE,CAAC;QACxD,IAAI,OAAO,YAAY,YAAY,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAChE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;YAClD,OAAO,MAAM,CAAC,MAAM,CAAC;gBACnB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,GAAG,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACrE,CAAC,CAAC,EAAE,OAAO,EAAE;oBACb,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY;oBAClD,CAAC,CAAC,EAAE,YAAY,EAAE;oBAClB,CAAC,CAAC,EAAE,CAAC;aACR,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,CAAC,OAAO,YAAY,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAClD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5E,CAAC","sourcesContent":["import { OutpostError } from \"./errors.ts\";\nimport { maxQuotaCauseDepth } from \"./quota.constants.ts\";\nimport type { QuotaFault } from \"./quota.types.ts\";\n\nexport type { QuotaFault } from \"./quota.types.ts\";\n\nexport function quotaFault(error: unknown): QuotaFault | undefined {\n let current = error;\n for (let depth = 0; depth < maxQuotaCauseDepth; depth++) {\n if (current instanceof OutpostError && current.code === \"quota\") {\n const { resetAt, conversation } = current.details;\n return Object.freeze({\n message: current.message,\n ...(typeof resetAt === \"string\" && Number.isFinite(Date.parse(resetAt))\n ? { resetAt }\n : {}),\n ...(typeof conversation === \"string\" && conversation\n ? { conversation }\n : {}),\n });\n }\n if (!(current instanceof Error)) return undefined;\n current = current.cause;\n }\n return undefined;\n}\n\nexport function resetTimestamp(\n delayMs: number,\n now = Date.now(),\n): string | undefined {\n const reset = new Date(now + delayMs);\n return Number.isFinite(reset.getTime()) ? reset.toISOString() : undefined;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export interface QuotaFault {
2
+ readonly message: string;
3
+ /** ISO timestamp when the provider reported that the limit resets. */
4
+ readonly resetAt?: string;
5
+ /** Agent conversation interrupted by the limit, when the CLI reported one. */
6
+ readonly conversation?: string;
7
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=quota.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.types.js","sourceRoot":"","sources":["../../src/domain/quota.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface QuotaFault {\n readonly message: string;\n /** ISO timestamp when the provider reported that the limit resets. */\n readonly resetAt?: string;\n /** Agent conversation interrupted by the limit, when the CLI reported one. */\n readonly conversation?: string;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import type { ReplayDivergenceDetails, ReplayDivergenceKind } from "./replay.types.ts";
2
+ export declare const replayDefaults: Readonly<{
3
+ name: "replay";
4
+ divergence: "fail";
5
+ unrecorded: "The journal was recorded without logging.replayable";
6
+ unfinished: "The recorded agent turn did not finish";
7
+ }>;
8
+ export declare const replayJournalFields: ReadonlySet<string>;
9
+ export declare const replayExecutionEvents: ReadonlySet<string>;
10
+ export declare const replayFaultCodes: ReadonlySet<string>;
11
+ export declare const replayDivergenceMessages: Readonly<Record<ReplayDivergenceKind, (details: ReplayDivergenceDetails) => string>>;
@@ -0,0 +1,42 @@
1
+ export const replayDefaults = Object.freeze({
2
+ name: "replay",
3
+ divergence: "fail",
4
+ unrecorded: "The journal was recorded without logging.replayable",
5
+ unfinished: "The recorded agent turn did not finish",
6
+ });
7
+ export const replayJournalFields = new Set([
8
+ "seq",
9
+ "at",
10
+ "source",
11
+ "scope",
12
+ "label",
13
+ "pass",
14
+ ]);
15
+ export const replayExecutionEvents = new Set([
16
+ "phase",
17
+ "prompt",
18
+ "summary",
19
+ ]);
20
+ export const replayFaultCodes = new Set([
21
+ "configuration",
22
+ "process",
23
+ "timeout",
24
+ "aborted",
25
+ "workspace",
26
+ "conflict",
27
+ "prompt",
28
+ "response",
29
+ "session",
30
+ "provider",
31
+ "limit",
32
+ "quota",
33
+ "replay",
34
+ ]);
35
+ export const replayDivergenceMessages = Object.freeze({
36
+ prompt: ({ turn }) => `Replay turn ${turn} received a prompt that differs from the recording`,
37
+ baseline: ({ turn }) => `Replay turn ${turn} started from a workspace tree that differs from the recording`,
38
+ tree: ({ turn, commit }) => `Replay turn ${turn} could not reproduce the tree of recorded commit ${commit}`,
39
+ exhausted: ({ turn }) => `The replay journal has no turn ${turn}`,
40
+ unrecorded: ({ turn, expected }) => `Replay turn ${turn} has no recorded workspace commits: ${expected}`,
41
+ });
42
+ //# sourceMappingURL=replay.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.constants.js","sourceRoot":"","sources":["../../src/domain/replay.constants.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,MAAM;IAClB,UAAU,EAAE,qDAAqD;IACjE,UAAU,EAAE,wCAAwC;CACrD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC;IAC9D,KAAK;IACL,IAAI;IACJ,QAAQ;IACR,OAAO;IACP,OAAO;IACP,MAAM;CACP,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IAChE,OAAO;IACP,QAAQ;IACR,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC;IAC3D,eAAe;IACf,SAAS;IACT,SAAS;IACT,SAAS;IACT,WAAW;IACX,UAAU;IACV,QAAQ;IACR,UAAU;IACV,SAAS;IACT,UAAU;IACV,OAAO;IACP,OAAO;IACP,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAEjC,MAAM,CAAC,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACnB,eAAe,IAAI,oDAAoD;IACzE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACrB,eAAe,IAAI,gEAAgE;IACrF,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CACzB,eAAe,IAAI,oDAAoD,MAAM,EAAE;IACjF,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,kCAAkC,IAAI,EAAE;IACjE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CACjC,eAAe,IAAI,uCAAuC,QAAQ,EAAE;CACvE,CAAC,CAAC","sourcesContent":["import type {\n ReplayDivergenceDetails,\n ReplayDivergenceKind,\n} from \"./replay.types.ts\";\n\nexport const replayDefaults = Object.freeze({\n name: \"replay\",\n divergence: \"fail\",\n unrecorded: \"The journal was recorded without logging.replayable\",\n unfinished: \"The recorded agent turn did not finish\",\n});\n\nexport const replayJournalFields: ReadonlySet<string> = new Set([\n \"seq\",\n \"at\",\n \"source\",\n \"scope\",\n \"label\",\n \"pass\",\n]);\n\nexport const replayExecutionEvents: ReadonlySet<string> = new Set([\n \"phase\",\n \"prompt\",\n \"summary\",\n]);\n\nexport const replayFaultCodes: ReadonlySet<string> = new Set([\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]);\n\nexport const replayDivergenceMessages: Readonly<\n Record<ReplayDivergenceKind, (details: ReplayDivergenceDetails) => string>\n> = Object.freeze({\n prompt: ({ turn }) =>\n `Replay turn ${turn} received a prompt that differs from the recording`,\n baseline: ({ turn }) =>\n `Replay turn ${turn} started from a workspace tree that differs from the recording`,\n tree: ({ turn, commit }) =>\n `Replay turn ${turn} could not reproduce the tree of recorded commit ${commit}`,\n exhausted: ({ turn }) => `The replay journal has no turn ${turn}`,\n unrecorded: ({ turn, expected }) =>\n `Replay turn ${turn} has no recorded workspace commits: ${expected}`,\n});\n"]}
@@ -0,0 +1,11 @@
1
+ import { OutpostError } from "./errors.ts";
2
+ import type { ReplayAgent, ReplayAgentOptions, ReplayDivergenceDetails, ReplayDivergenceKind } from "./replay.types.ts";
3
+ export declare class ReplayDivergence extends OutpostError {
4
+ readonly kind: ReplayDivergenceKind;
5
+ readonly turn: number;
6
+ readonly expected: string | undefined;
7
+ readonly actual: string | undefined;
8
+ readonly commit: string | undefined;
9
+ constructor(details: ReplayDivergenceDetails);
10
+ }
11
+ export declare function replayAgent(options: ReplayAgentOptions): ReplayAgent;
@@ -0,0 +1,231 @@
1
+ import { isAgentEvent } from "./agent-observation.js";
2
+ import { visitAgentEvent } from "./agent-events.js";
3
+ import { invariant, OutpostError } from "./errors.js";
4
+ import { replayDefaults, replayDivergenceMessages, replayExecutionEvents, replayFaultCodes, replayJournalFields, } from "./replay.constants.js";
5
+ export class ReplayDivergence extends OutpostError {
6
+ kind;
7
+ turn;
8
+ expected;
9
+ actual;
10
+ commit;
11
+ constructor(details) {
12
+ super("replay", replayDivergenceMessages[details.kind](details), {
13
+ ...details,
14
+ });
15
+ this.name = "ReplayDivergence";
16
+ this.kind = details.kind;
17
+ this.turn = details.turn;
18
+ this.expected = details.expected;
19
+ this.actual = details.actual;
20
+ this.commit = details.commit;
21
+ }
22
+ }
23
+ export function replayAgent(options) {
24
+ invariant(options && typeof options === "object", "Replay options must be an object");
25
+ invariant(Array.isArray(options.journal), "Provide the journal entries returned by readJournal()");
26
+ const divergence = options.divergence ?? replayDefaults.divergence;
27
+ invariant(divergence === "fail" || divergence === "warn", "Replay divergence must be fail or warn");
28
+ const { turns, source } = replayRecording(options.journal);
29
+ let position = 0;
30
+ return Object.freeze({
31
+ kind: "replay",
32
+ name: replayDefaults.name,
33
+ source,
34
+ divergence,
35
+ turns,
36
+ capture: false,
37
+ resumable: true,
38
+ forkable: false,
39
+ usage: "events",
40
+ get remainingTurns() {
41
+ return turns.length - position;
42
+ },
43
+ nextTurn() {
44
+ if (position >= turns.length)
45
+ return undefined;
46
+ return turns[position++];
47
+ },
48
+ });
49
+ }
50
+ function replayRecording(journal) {
51
+ const drafts = [];
52
+ let current;
53
+ let source = "agent";
54
+ let finished;
55
+ let replayable = false;
56
+ for (const [index, entry] of journal.entries()) {
57
+ const { origin, event } = journalEvent(entry, index);
58
+ if (event.kind === "workspace-commits") {
59
+ replayable = true;
60
+ const last = drafts.at(-1);
61
+ if (last)
62
+ last.changes = workspaceCommits(event, index);
63
+ current = undefined;
64
+ continue;
65
+ }
66
+ if (event.kind === "dispatch-finished") {
67
+ finished = dispatchFailure(event, index);
68
+ current = undefined;
69
+ continue;
70
+ }
71
+ if (origin !== "agent" && origin !== "harness")
72
+ continue;
73
+ if (origin === "harness")
74
+ source = "harness";
75
+ if (event.kind === "prompt") {
76
+ current = {
77
+ prompt: text(event, "text", index),
78
+ events: [],
79
+ texts: [],
80
+ raws: [],
81
+ };
82
+ drafts.push(current);
83
+ continue;
84
+ }
85
+ if (!current)
86
+ continue;
87
+ if (event.kind === "summary") {
88
+ current.usage = usage(event.tokens, index);
89
+ current = undefined;
90
+ continue;
91
+ }
92
+ const agentEvent = event;
93
+ if (replayExecutionEvents.has(event.kind) || !isAgentEvent(agentEvent))
94
+ continue;
95
+ collect(current, event, index);
96
+ current.events.push(agentEvent);
97
+ }
98
+ invariant(drafts.length > 0, "The replay journal contains no agent turns");
99
+ if (!replayable)
100
+ drafts.at(-1).changes = {
101
+ kind: "workspace-commits",
102
+ unavailable: replayDefaults.unrecorded,
103
+ };
104
+ return {
105
+ turns: Object.freeze(drafts.map((draft) => turn(draft, finished))),
106
+ source,
107
+ };
108
+ }
109
+ function turn(draft, finished) {
110
+ const failure = draft.usage
111
+ ? undefined
112
+ : (finished ?? {
113
+ code: "process",
114
+ message: draft.failure ?? replayDefaults.unfinished,
115
+ });
116
+ return Object.freeze({
117
+ prompt: draft.prompt,
118
+ events: Object.freeze(draft.events),
119
+ text: draft.result ??
120
+ (draft.texts.length ? draft.texts.join("") : draft.raws.join("\n")),
121
+ usage: draft.usage ?? { input: 0, cached: 0, output: 0 },
122
+ ...(draft.conversation ? { conversation: draft.conversation } : {}),
123
+ ...(failure ? { failure } : {}),
124
+ ...(draft.changes ? { changes: draft.changes } : {}),
125
+ });
126
+ }
127
+ function collect(draft, event, index) {
128
+ visitAgentEvent(event, {
129
+ text: () => draft.texts.push(text(event, "text", index)),
130
+ result: () => {
131
+ draft.result = text(event, "text", index);
132
+ },
133
+ conversation: () => {
134
+ draft.conversation = text(event, "id", index);
135
+ },
136
+ failure: () => {
137
+ draft.failure = text(event, "message", index);
138
+ },
139
+ raw: () => {
140
+ draft.raws.push(String(event.value));
141
+ },
142
+ });
143
+ }
144
+ function journalEvent(entry, index) {
145
+ const value = object(entry, index);
146
+ invariant(typeof value.kind === "string", `Replay journal entry ${index} has no event kind`);
147
+ const event = {};
148
+ for (const [key, field] of Object.entries(value))
149
+ if (!replayJournalFields.has(key))
150
+ event[key] = field;
151
+ return { origin: value.source, event: event };
152
+ }
153
+ function dispatchFailure(event, index) {
154
+ if (event.error === undefined)
155
+ return undefined;
156
+ const error = object(event.error, index);
157
+ const code = typeof error.code === "string" && replayFaultCodes.has(error.code)
158
+ ? error.code
159
+ : "process";
160
+ return { code, message: text(error, "message", index) };
161
+ }
162
+ function workspaceCommits(event, index) {
163
+ const baseline = event.baseline === undefined ? undefined : revision(event.baseline, index);
164
+ if (event.unavailable !== undefined)
165
+ return {
166
+ kind: "workspace-commits",
167
+ ...(baseline ? { baseline } : {}),
168
+ unavailable: text(event, "unavailable", index),
169
+ };
170
+ invariant(baseline && Array.isArray(event.commits), `Replay journal entry ${index} has malformed workspace commits`);
171
+ return {
172
+ kind: "workspace-commits",
173
+ baseline,
174
+ commits: event.commits.map((value) => commit(value, index)),
175
+ };
176
+ }
177
+ function commit(value, index) {
178
+ const recorded = object(value, index);
179
+ return {
180
+ oid: text(recorded, "oid", index),
181
+ tree: text(recorded, "tree", index),
182
+ author: identity(recorded.author, index),
183
+ committer: identity(recorded.committer, index),
184
+ message: text(recorded, "message", index),
185
+ patch: text(recorded, "patch", index),
186
+ };
187
+ }
188
+ function revision(value, index) {
189
+ const recorded = object(value, index);
190
+ return {
191
+ commit: text(recorded, "commit", index),
192
+ tree: text(recorded, "tree", index),
193
+ };
194
+ }
195
+ function identity(value, index) {
196
+ const recorded = object(value, index);
197
+ return {
198
+ name: text(recorded, "name", index),
199
+ email: text(recorded, "email", index),
200
+ date: text(recorded, "date", index),
201
+ };
202
+ }
203
+ function usage(value, index) {
204
+ const recorded = object(value, index);
205
+ const counts = ["input", "cached", "output", "cacheCreated"];
206
+ for (const key of counts)
207
+ invariant((key === "cacheCreated" && recorded[key] === undefined) ||
208
+ (Number.isSafeInteger(recorded[key]) && recorded[key] >= 0), `Replay journal entry ${index} has invalid ${key} usage`);
209
+ invariant(recorded.complete === undefined || typeof recorded.complete === "boolean", `Replay journal entry ${index} has invalid usage completeness`);
210
+ return {
211
+ input: recorded.input,
212
+ cached: recorded.cached,
213
+ output: recorded.output,
214
+ ...(recorded.cacheCreated === undefined
215
+ ? {}
216
+ : { cacheCreated: recorded.cacheCreated }),
217
+ ...(recorded.complete === undefined
218
+ ? {}
219
+ : { complete: recorded.complete }),
220
+ };
221
+ }
222
+ function object(value, index) {
223
+ invariant(value !== null && typeof value === "object" && !Array.isArray(value), `Replay journal entry ${index} is malformed`);
224
+ return value;
225
+ }
226
+ function text(value, key, index) {
227
+ const field = value[key];
228
+ invariant(typeof field === "string", `Replay journal entry ${index} requires a string ${key}`);
229
+ return field;
230
+ }
231
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/domain/replay.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAgentEvent } from \"./agent-observation.ts\";\nimport { visitAgentEvent } from \"./agent-events.ts\";\nimport type { AgentEvent, Usage } from \"./agent.types.ts\";\nimport { invariant, OutpostError } from \"./errors.ts\";\nimport type { FaultCode } from \"./errors.types.ts\";\nimport {\n replayDefaults,\n replayDivergenceMessages,\n replayExecutionEvents,\n replayFaultCodes,\n replayJournalFields,\n} from \"./replay.constants.ts\";\nimport type {\n RecordedCommit,\n RecordedIdentity,\n RecordedRevision,\n ReplayAgent,\n ReplayAgentOptions,\n ReplayDivergenceDetails,\n ReplayDivergenceKind,\n ReplayFailure,\n DraftTurn,\n JournalObject,\n ReplayJournalEvent,\n ReplayRecording,\n ReplayTurn,\n WorkspaceCommitsEvent,\n} from \"./replay.types.ts\";\n\nexport class ReplayDivergence extends OutpostError {\n readonly kind: ReplayDivergenceKind;\n readonly turn: number;\n readonly expected: string | undefined;\n readonly actual: string | undefined;\n readonly commit: string | undefined;\n\n constructor(details: ReplayDivergenceDetails) {\n super(\"replay\", replayDivergenceMessages[details.kind](details), {\n ...details,\n });\n this.name = \"ReplayDivergence\";\n this.kind = details.kind;\n this.turn = details.turn;\n this.expected = details.expected;\n this.actual = details.actual;\n this.commit = details.commit;\n }\n}\n\nexport function replayAgent(options: ReplayAgentOptions): ReplayAgent {\n invariant(\n options && typeof options === \"object\",\n \"Replay options must be an object\",\n );\n invariant(\n Array.isArray(options.journal),\n \"Provide the journal entries returned by readJournal()\",\n );\n const divergence = options.divergence ?? replayDefaults.divergence;\n invariant(\n divergence === \"fail\" || divergence === \"warn\",\n \"Replay divergence must be fail or warn\",\n );\n const { turns, source } = replayRecording(options.journal);\n let position = 0;\n return Object.freeze({\n kind: \"replay\",\n name: replayDefaults.name,\n source,\n divergence,\n turns,\n capture: false,\n resumable: true,\n forkable: false,\n usage: \"events\",\n get remainingTurns() {\n return turns.length - position;\n },\n nextTurn() {\n if (position >= turns.length) return undefined;\n return turns[position++];\n },\n });\n}\n\nfunction replayRecording(journal: readonly unknown[]): ReplayRecording {\n const drafts: DraftTurn[] = [];\n let current: DraftTurn | undefined;\n let source: ReplayAgent[\"source\"] = \"agent\";\n let finished: ReplayFailure | undefined;\n let replayable = false;\n for (const [index, entry] of journal.entries()) {\n const { origin, event } = journalEvent(entry, index);\n if (event.kind === \"workspace-commits\") {\n replayable = true;\n const last = drafts.at(-1);\n if (last) last.changes = workspaceCommits(event, index);\n current = undefined;\n continue;\n }\n if (event.kind === \"dispatch-finished\") {\n finished = dispatchFailure(event, index);\n current = undefined;\n continue;\n }\n if (origin !== \"agent\" && origin !== \"harness\") continue;\n if (origin === \"harness\") source = \"harness\";\n if (event.kind === \"prompt\") {\n current = {\n prompt: text(event, \"text\", index),\n events: [],\n texts: [],\n raws: [],\n };\n drafts.push(current);\n continue;\n }\n if (!current) continue;\n if (event.kind === \"summary\") {\n current.usage = usage(event.tokens, index);\n current = undefined;\n continue;\n }\n const agentEvent = event as unknown as AgentEvent;\n if (replayExecutionEvents.has(event.kind) || !isAgentEvent(agentEvent))\n continue;\n collect(current, event, index);\n current.events.push(agentEvent);\n }\n invariant(drafts.length > 0, \"The replay journal contains no agent turns\");\n if (!replayable)\n drafts.at(-1)!.changes = {\n kind: \"workspace-commits\",\n unavailable: replayDefaults.unrecorded,\n };\n return {\n turns: Object.freeze(drafts.map((draft) => turn(draft, finished))),\n source,\n };\n}\n\nfunction turn(\n draft: DraftTurn,\n finished: ReplayFailure | undefined,\n): ReplayTurn {\n const failure: ReplayFailure | undefined = draft.usage\n ? undefined\n : (finished ?? {\n code: \"process\",\n message: draft.failure ?? replayDefaults.unfinished,\n });\n return Object.freeze({\n prompt: draft.prompt,\n events: Object.freeze(draft.events),\n text:\n draft.result ??\n (draft.texts.length ? draft.texts.join(\"\") : draft.raws.join(\"\\n\")),\n usage: draft.usage ?? { input: 0, cached: 0, output: 0 },\n ...(draft.conversation ? { conversation: draft.conversation } : {}),\n ...(failure ? { failure } : {}),\n ...(draft.changes ? { changes: draft.changes } : {}),\n });\n}\n\nfunction collect(draft: DraftTurn, event: JournalObject, index: number): void {\n visitAgentEvent(event as unknown as AgentEvent, {\n text: () => draft.texts.push(text(event, \"text\", index)),\n result: () => {\n draft.result = text(event, \"text\", index);\n },\n conversation: () => {\n draft.conversation = text(event, \"id\", index);\n },\n failure: () => {\n draft.failure = text(event, \"message\", index);\n },\n raw: () => {\n draft.raws.push(String(event.value));\n },\n });\n}\n\nfunction journalEvent(entry: unknown, index: number): ReplayJournalEvent {\n const value = object(entry, index);\n invariant(\n typeof value.kind === \"string\",\n `Replay journal entry ${index} has no event kind`,\n );\n const event: Record<string, unknown> = {};\n for (const [key, field] of Object.entries(value))\n if (!replayJournalFields.has(key)) event[key] = field;\n return { origin: value.source, event: event as ReplayJournalEvent[\"event\"] };\n}\n\nfunction dispatchFailure(\n event: JournalObject,\n index: number,\n): ReplayFailure | undefined {\n if (event.error === undefined) return undefined;\n const error = object(event.error, index);\n const code =\n typeof error.code === \"string\" && replayFaultCodes.has(error.code)\n ? (error.code as FaultCode)\n : \"process\";\n return { code, message: text(error, \"message\", index) };\n}\n\nfunction workspaceCommits(\n event: JournalObject,\n index: number,\n): WorkspaceCommitsEvent {\n const baseline =\n event.baseline === undefined ? undefined : revision(event.baseline, index);\n if (event.unavailable !== undefined)\n return {\n kind: \"workspace-commits\",\n ...(baseline ? { baseline } : {}),\n unavailable: text(event, \"unavailable\", index),\n };\n invariant(\n baseline && Array.isArray(event.commits),\n `Replay journal entry ${index} has malformed workspace commits`,\n );\n return {\n kind: \"workspace-commits\",\n baseline,\n commits: event.commits.map((value: unknown) => commit(value, index)),\n };\n}\n\nfunction commit(value: unknown, index: number): RecordedCommit {\n const recorded = object(value, index);\n return {\n oid: text(recorded, \"oid\", index),\n tree: text(recorded, \"tree\", index),\n author: identity(recorded.author, index),\n committer: identity(recorded.committer, index),\n message: text(recorded, \"message\", index),\n patch: text(recorded, \"patch\", index),\n };\n}\n\nfunction revision(value: unknown, index: number): RecordedRevision {\n const recorded = object(value, index);\n return {\n commit: text(recorded, \"commit\", index),\n tree: text(recorded, \"tree\", index),\n };\n}\n\nfunction identity(value: unknown, index: number): RecordedIdentity {\n const recorded = object(value, index);\n return {\n name: text(recorded, \"name\", index),\n email: text(recorded, \"email\", index),\n date: text(recorded, \"date\", index),\n };\n}\n\nfunction usage(value: unknown, index: number): Usage {\n const recorded = object(value, index);\n const counts = [\"input\", \"cached\", \"output\", \"cacheCreated\"] as const;\n for (const key of counts)\n invariant(\n (key === \"cacheCreated\" && recorded[key] === undefined) ||\n (Number.isSafeInteger(recorded[key]) && (recorded[key] as number) >= 0),\n `Replay journal entry ${index} has invalid ${key} usage`,\n );\n invariant(\n recorded.complete === undefined || typeof recorded.complete === \"boolean\",\n `Replay journal entry ${index} has invalid usage completeness`,\n );\n return {\n input: recorded.input as number,\n cached: recorded.cached as number,\n output: recorded.output as number,\n ...(recorded.cacheCreated === undefined\n ? {}\n : { cacheCreated: recorded.cacheCreated as number }),\n ...(recorded.complete === undefined\n ? {}\n : { complete: recorded.complete as boolean }),\n };\n}\n\nfunction object(value: unknown, index: number): JournalObject {\n invariant(\n value !== null && typeof value === \"object\" && !Array.isArray(value),\n `Replay journal entry ${index} is malformed`,\n );\n return value as JournalObject;\n}\n\nfunction text(value: JournalObject, key: string, index: number): string {\n const field = value[key];\n invariant(\n typeof field === \"string\",\n `Replay journal entry ${index} requires a string ${key}`,\n );\n return field;\n}\n"]}
@@ -0,0 +1,84 @@
1
+ import type { AgentEvent, AgentFeatures, Usage } from "./agent.types.ts";
2
+ import type { FaultCode } from "./errors.types.ts";
3
+ export interface RecordedRevision {
4
+ readonly commit: string;
5
+ readonly tree: string;
6
+ }
7
+ export interface RecordedIdentity {
8
+ readonly name: string;
9
+ readonly email: string;
10
+ readonly date: string;
11
+ }
12
+ export interface RecordedCommit {
13
+ readonly oid: string;
14
+ readonly tree: string;
15
+ readonly author: RecordedIdentity;
16
+ readonly committer: RecordedIdentity;
17
+ readonly message: string;
18
+ readonly patch: string;
19
+ }
20
+ export type WorkspaceCommitsEvent = {
21
+ readonly kind: "workspace-commits";
22
+ readonly baseline: RecordedRevision;
23
+ readonly commits: readonly RecordedCommit[];
24
+ } | {
25
+ readonly kind: "workspace-commits";
26
+ readonly baseline?: RecordedRevision;
27
+ readonly unavailable: string;
28
+ };
29
+ export interface ReplayFailure {
30
+ readonly code: FaultCode;
31
+ readonly message: string;
32
+ }
33
+ export interface ReplayTurn {
34
+ readonly prompt: string;
35
+ readonly events: readonly AgentEvent[];
36
+ readonly text: string;
37
+ readonly usage: Usage;
38
+ readonly conversation?: string;
39
+ readonly failure?: ReplayFailure;
40
+ readonly changes?: WorkspaceCommitsEvent;
41
+ }
42
+ export type ReplayDivergencePolicy = "fail" | "warn";
43
+ export type ReplayDivergenceKind = "prompt" | "baseline" | "tree" | "exhausted" | "unrecorded";
44
+ export interface ReplayDivergenceDetails {
45
+ readonly kind: ReplayDivergenceKind;
46
+ readonly turn: number;
47
+ readonly expected?: string;
48
+ readonly actual?: string;
49
+ readonly commit?: string;
50
+ }
51
+ export interface ReplayAgentOptions {
52
+ readonly journal: readonly unknown[];
53
+ readonly divergence?: ReplayDivergencePolicy;
54
+ }
55
+ export interface ReplayAgent extends AgentFeatures {
56
+ readonly kind: "replay";
57
+ readonly source: "agent" | "harness";
58
+ readonly divergence: ReplayDivergencePolicy;
59
+ readonly turns: readonly ReplayTurn[];
60
+ readonly remainingTurns: number;
61
+ nextTurn(): ReplayTurn | undefined;
62
+ }
63
+ export type JournalObject = Readonly<Record<string, unknown>>;
64
+ export interface ReplayJournalEvent {
65
+ readonly origin: unknown;
66
+ readonly event: JournalObject & {
67
+ readonly kind: string;
68
+ };
69
+ }
70
+ export interface ReplayRecording {
71
+ readonly turns: readonly ReplayTurn[];
72
+ readonly source: ReplayAgent["source"];
73
+ }
74
+ export interface DraftTurn {
75
+ readonly prompt: string;
76
+ readonly events: AgentEvent[];
77
+ readonly texts: string[];
78
+ readonly raws: string[];
79
+ result?: string;
80
+ conversation?: string;
81
+ failure?: string;
82
+ usage?: Usage;
83
+ changes?: WorkspaceCommitsEvent;
84
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=replay.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.types.js","sourceRoot":"","sources":["../../src/domain/replay.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentEvent, AgentFeatures, Usage } from \"./agent.types.ts\";\nimport type { FaultCode } from \"./errors.types.ts\";\n\nexport interface RecordedRevision {\n readonly commit: string;\n readonly tree: string;\n}\n\nexport interface RecordedIdentity {\n readonly name: string;\n readonly email: string;\n readonly date: string;\n}\n\nexport interface RecordedCommit {\n readonly oid: string;\n readonly tree: string;\n readonly author: RecordedIdentity;\n readonly committer: RecordedIdentity;\n readonly message: string;\n readonly patch: string;\n}\n\nexport type WorkspaceCommitsEvent =\n | {\n readonly kind: \"workspace-commits\";\n readonly baseline: RecordedRevision;\n readonly commits: readonly RecordedCommit[];\n }\n | {\n readonly kind: \"workspace-commits\";\n readonly baseline?: RecordedRevision;\n readonly unavailable: string;\n };\n\nexport interface ReplayFailure {\n readonly code: FaultCode;\n readonly message: string;\n}\n\nexport interface ReplayTurn {\n readonly prompt: string;\n readonly events: readonly AgentEvent[];\n readonly text: string;\n readonly usage: Usage;\n readonly conversation?: string;\n readonly failure?: ReplayFailure;\n readonly changes?: WorkspaceCommitsEvent;\n}\n\nexport type ReplayDivergencePolicy = \"fail\" | \"warn\";\n\nexport type ReplayDivergenceKind =\n \"prompt\" | \"baseline\" | \"tree\" | \"exhausted\" | \"unrecorded\";\n\nexport interface ReplayDivergenceDetails {\n readonly kind: ReplayDivergenceKind;\n readonly turn: number;\n readonly expected?: string;\n readonly actual?: string;\n readonly commit?: string;\n}\n\nexport interface ReplayAgentOptions {\n readonly journal: readonly unknown[];\n readonly divergence?: ReplayDivergencePolicy;\n}\n\nexport interface ReplayAgent extends AgentFeatures {\n readonly kind: \"replay\";\n readonly source: \"agent\" | \"harness\";\n readonly divergence: ReplayDivergencePolicy;\n readonly turns: readonly ReplayTurn[];\n readonly remainingTurns: number;\n nextTurn(): ReplayTurn | undefined;\n}\n\nexport type JournalObject = Readonly<Record<string, unknown>>;\n\nexport interface ReplayJournalEvent {\n readonly origin: unknown;\n readonly event: JournalObject & { readonly kind: string };\n}\n\nexport interface ReplayRecording {\n readonly turns: readonly ReplayTurn[];\n readonly source: ReplayAgent[\"source\"];\n}\n\nexport interface DraftTurn {\n readonly prompt: string;\n readonly events: AgentEvent[];\n readonly texts: string[];\n readonly raws: string[];\n result?: string;\n conversation?: string;\n failure?: string;\n usage?: Usage;\n changes?: WorkspaceCommitsEvent;\n}\n"]}
@@ -35,6 +35,9 @@ export function queueRequest(value) {
35
35
  const data = queueObject(value);
36
36
  return {
37
37
  id: queueString(data.id),
38
+ ...(data.idempotencyKey === undefined
39
+ ? {}
40
+ : { idempotencyKey: queueString(data.idempotencyKey) }),
38
41
  handler: queueString(data.handler),
39
42
  input: queueJson(data.input),
40
43
  ...(data.deadline === undefined
@@ -62,12 +65,27 @@ export function queueLease(value) {
62
65
  fence: queueNumber(data.fence),
63
66
  };
64
67
  }
68
+ function queueQuota(value) {
69
+ const data = queueObject(value);
70
+ if (data.resetAt !== undefined &&
71
+ !Number.isFinite(Date.parse(queueString(data.resetAt))))
72
+ throw new Error("Invalid queue quota reset");
73
+ return {
74
+ ...(data.resetAt === undefined ? {} : { resetAt: String(data.resetAt) }),
75
+ ...(data.conversation === undefined
76
+ ? {}
77
+ : { conversation: queueString(data.conversation) }),
78
+ };
79
+ }
65
80
  export function queueResult(value) {
66
81
  const data = queueObject(value);
67
82
  const usage = data.usage === undefined ? undefined : queueObject(data.usage);
83
+ if (data.quota !== undefined && data.error === undefined)
84
+ throw new Error("Queue quota requires an error");
68
85
  return {
69
86
  value: queueJson(data.value),
70
87
  ...(data.error === undefined ? {} : { error: queueString(data.error) }),
88
+ ...(data.quota === undefined ? {} : { quota: queueQuota(data.quota) }),
71
89
  ...(usage === undefined
72
90
  ? {}
73
91
  : {
@@ -1 +1 @@
1
- {"version":3,"file":"task-queue.js","sourceRoot":"","sources":["../../src/domain/task-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n QueueClaim,\n QueueJob,\n QueueLease,\n QueueRequest,\n QueueResult,\n} from \"./task-queue.types.ts\";\nimport {\n queueMaxValueBytes,\n queueMaxLeaseMs,\n queueMaxStringLength,\n queueMinLeaseMs,\n queueMaxHandlers,\n} from \"./task-queue.constants.ts\";\nimport { checkpointValue } from \"./workflow/checkpoint-value.ts\";\n\nexport function queueObject(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n throw new Error(\"Invalid queue object\");\n return Object.fromEntries(Object.entries(value));\n}\nexport function queueString(value: unknown): string {\n if (\n typeof value !== \"string\" ||\n !value.length ||\n value.length > queueMaxStringLength\n )\n throw new Error(\"Invalid queue identifier\");\n return value;\n}\nexport function queueNumber(value: unknown): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0)\n throw new Error(\"Invalid queue number\");\n return value;\n}\nexport function queueLeaseMs(value: unknown): number {\n const ms = queueNumber(value);\n if (ms < queueMinLeaseMs || ms > queueMaxLeaseMs)\n throw new Error(\"Queue lease must be between 30 and 300000 milliseconds\");\n return ms;\n}\nexport function queueJson(value: unknown) {\n const checked = checkpointValue(value);\n if (checked.kind !== \"json\") throw new Error(\"Queue values must be JSON\");\n if (Buffer.byteLength(JSON.stringify(checked.value)) > queueMaxValueBytes)\n throw new Error(\"Queue value exceeds size limit\");\n return checked.value;\n}\nexport function queueRequest(value: unknown): QueueRequest {\n const data = queueObject(value);\n return {\n id: queueString(data.id),\n handler: queueString(data.handler),\n input: queueJson(data.input),\n ...(data.deadline === undefined\n ? {}\n : { deadline: queueNumber(data.deadline) }),\n };\n}\nexport function queueClaim(value: unknown): QueueClaim {\n const data = queueObject(value);\n if (\n !Array.isArray(data.handlers) ||\n !data.handlers.length ||\n data.handlers.length > queueMaxHandlers\n )\n throw new Error(\"Invalid queue handlers\");\n return {\n worker: queueString(data.worker),\n handlers: data.handlers.map(queueString),\n leaseMs: queueLeaseMs(data.leaseMs),\n };\n}\nexport function queueLease(value: unknown): QueueLease {\n const data = queueObject(value);\n return {\n id: queueString(data.id),\n worker: queueString(data.worker),\n fence: queueNumber(data.fence),\n };\n}\nexport function queueResult(value: unknown): QueueResult {\n const data = queueObject(value);\n const usage = data.usage === undefined ? undefined : queueObject(data.usage);\n return {\n value: queueJson(data.value),\n ...(data.error === undefined ? {} : { error: queueString(data.error) }),\n ...(usage === undefined\n ? {}\n : {\n usage: {\n input: queueNumber(usage.input),\n output: queueNumber(usage.output),\n cached: queueNumber(usage.cached),\n ...(usage.cacheCreated === undefined\n ? {}\n : { cacheCreated: queueNumber(usage.cacheCreated) }),\n },\n }),\n };\n}\nexport function queueJob(value: unknown): QueueJob {\n const data = queueObject(value);\n const status = data.status;\n if (\n status !== \"pending\" &&\n status !== \"active\" &&\n status !== \"done\" &&\n status !== \"failed\" &&\n status !== \"cancelled\"\n )\n throw new Error(\"Invalid queue status\");\n return {\n ...queueRequest(data),\n status,\n fence: queueNumber(data.fence),\n ...(data.worker === undefined ? {} : { worker: queueString(data.worker) }),\n ...(data.expires === undefined\n ? {}\n : { expires: queueNumber(data.expires) }),\n ...(data.result === undefined ? {} : { result: queueResult(data.result) }),\n };\n}\n"]}
1
+ {"version":3,"file":"task-queue.js","sourceRoot":"","sources":["../../src/domain/task-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n QueueClaim,\n QueueJob,\n QueueLease,\n QueueQuota,\n QueueRequest,\n QueueResult,\n} from \"./task-queue.types.ts\";\nimport {\n queueMaxValueBytes,\n queueMaxLeaseMs,\n queueMaxStringLength,\n queueMinLeaseMs,\n queueMaxHandlers,\n} from \"./task-queue.constants.ts\";\nimport { checkpointValue } from \"./workflow/checkpoint-value.ts\";\n\nexport function queueObject(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n throw new Error(\"Invalid queue object\");\n return Object.fromEntries(Object.entries(value));\n}\nexport function queueString(value: unknown): string {\n if (\n typeof value !== \"string\" ||\n !value.length ||\n value.length > queueMaxStringLength\n )\n throw new Error(\"Invalid queue identifier\");\n return value;\n}\nexport function queueNumber(value: unknown): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0)\n throw new Error(\"Invalid queue number\");\n return value;\n}\nexport function queueLeaseMs(value: unknown): number {\n const ms = queueNumber(value);\n if (ms < queueMinLeaseMs || ms > queueMaxLeaseMs)\n throw new Error(\"Queue lease must be between 30 and 300000 milliseconds\");\n return ms;\n}\nexport function queueJson(value: unknown) {\n const checked = checkpointValue(value);\n if (checked.kind !== \"json\") throw new Error(\"Queue values must be JSON\");\n if (Buffer.byteLength(JSON.stringify(checked.value)) > queueMaxValueBytes)\n throw new Error(\"Queue value exceeds size limit\");\n return checked.value;\n}\nexport function queueRequest(value: unknown): QueueRequest {\n const data = queueObject(value);\n return {\n id: queueString(data.id),\n ...(data.idempotencyKey === undefined\n ? {}\n : { idempotencyKey: queueString(data.idempotencyKey) }),\n handler: queueString(data.handler),\n input: queueJson(data.input),\n ...(data.deadline === undefined\n ? {}\n : { deadline: queueNumber(data.deadline) }),\n };\n}\nexport function queueClaim(value: unknown): QueueClaim {\n const data = queueObject(value);\n if (\n !Array.isArray(data.handlers) ||\n !data.handlers.length ||\n data.handlers.length > queueMaxHandlers\n )\n throw new Error(\"Invalid queue handlers\");\n return {\n worker: queueString(data.worker),\n handlers: data.handlers.map(queueString),\n leaseMs: queueLeaseMs(data.leaseMs),\n };\n}\nexport function queueLease(value: unknown): QueueLease {\n const data = queueObject(value);\n return {\n id: queueString(data.id),\n worker: queueString(data.worker),\n fence: queueNumber(data.fence),\n };\n}\nfunction queueQuota(value: unknown): QueueQuota {\n const data = queueObject(value);\n if (\n data.resetAt !== undefined &&\n !Number.isFinite(Date.parse(queueString(data.resetAt)))\n )\n throw new Error(\"Invalid queue quota reset\");\n return {\n ...(data.resetAt === undefined ? {} : { resetAt: String(data.resetAt) }),\n ...(data.conversation === undefined\n ? {}\n : { conversation: queueString(data.conversation) }),\n };\n}\nexport function queueResult(value: unknown): QueueResult {\n const data = queueObject(value);\n const usage = data.usage === undefined ? undefined : queueObject(data.usage);\n if (data.quota !== undefined && data.error === undefined)\n throw new Error(\"Queue quota requires an error\");\n return {\n value: queueJson(data.value),\n ...(data.error === undefined ? {} : { error: queueString(data.error) }),\n ...(data.quota === undefined ? {} : { quota: queueQuota(data.quota) }),\n ...(usage === undefined\n ? {}\n : {\n usage: {\n input: queueNumber(usage.input),\n output: queueNumber(usage.output),\n cached: queueNumber(usage.cached),\n ...(usage.cacheCreated === undefined\n ? {}\n : { cacheCreated: queueNumber(usage.cacheCreated) }),\n },\n }),\n };\n}\nexport function queueJob(value: unknown): QueueJob {\n const data = queueObject(value);\n const status = data.status;\n if (\n status !== \"pending\" &&\n status !== \"active\" &&\n status !== \"done\" &&\n status !== \"failed\" &&\n status !== \"cancelled\"\n )\n throw new Error(\"Invalid queue status\");\n return {\n ...queueRequest(data),\n status,\n fence: queueNumber(data.fence),\n ...(data.worker === undefined ? {} : { worker: queueString(data.worker) }),\n ...(data.expires === undefined\n ? {}\n : { expires: queueNumber(data.expires) }),\n ...(data.result === undefined ? {} : { result: queueResult(data.result) }),\n };\n}\n"]}