deepline 0.3.127 → 0.3.129

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 (128) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +34 -9
  2. package/dist/bundling-sources/sdk/src/http.ts +22 -0
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +22 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +265 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/bounded-batch-function.ts +682 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +21 -5
  8. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5390 -1732
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +107 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +7 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +229 -7
  12. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +25 -4
  13. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-capacity.ts +71 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +1 -1
  15. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +4 -1
  16. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +694 -28
  17. package/dist/bundling-sources/shared_libs/play-runtime/egress-bandwidth-probe.ts +167 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +103 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-receipt-output-reference.ts +34 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-response-size.ts +27 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +66 -1
  22. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +425 -71
  23. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +210 -32
  24. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +27 -13
  25. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +19 -6
  26. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +61 -2
  27. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +33 -1
  28. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +42 -1
  29. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +11 -11
  30. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +49 -16
  31. package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +1653 -98
  32. package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +807 -0
  33. package/dist/bundling-sources/shared_libs/play-runtime/memory-pressure-signal.ts +138 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +85 -3
  35. package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +60 -2
  36. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +46 -1
  37. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +2 -0
  38. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +1 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +1 -0
  40. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +1 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +70 -27
  42. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +56 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/adaptive-provider-capacity-controller.ts +192 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/epoch-aimd-rate-controller.ts +194 -0
  45. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/fixture-capacity-simulator.ts +220 -0
  46. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/gradient2-concurrency-controller.ts +214 -0
  47. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-capacity-policy.ts +43 -0
  48. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-concurrency-policy.ts +30 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-rate-policy.ts +95 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-throttle-classifier.ts +40 -0
  51. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +1535 -11
  52. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +49 -2
  53. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +6 -1
  54. package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +55 -0
  55. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +221 -0
  56. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +339 -29
  57. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +28 -1
  58. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +192 -165
  59. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +6 -0
  60. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +90 -5
  61. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +281 -6
  62. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +27 -1
  63. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +19 -0
  64. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +108 -0
  65. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +40 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +11 -5
  67. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +30 -0
  68. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-compression.ts +276 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +723 -115
  70. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +98 -2
  71. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +3 -2
  72. package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +41 -4
  73. package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +448 -0
  74. package/dist/bundling-sources/shared_libs/play-runtime/runtime-map-row-feed.ts +215 -0
  75. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +11 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +161 -14
  77. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-value.ts +184 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +607 -121
  79. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +4 -0
  80. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +21 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +15 -2
  82. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +71 -14
  83. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +2 -2
  84. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +288 -119
  85. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -6
  86. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +28 -3
  87. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/canonical-integration-operation-store.ts +179 -0
  88. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +80 -2
  89. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +31 -2
  90. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-store-contract.ts +104 -0
  91. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-reference.ts +47 -0
  92. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +193 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-storage.ts +420 -0
  94. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +41 -0
  95. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +134 -3
  96. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +1657 -95
  97. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +885 -73
  98. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-completion-coalescer.ts +452 -0
  99. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +601 -42
  100. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +1 -0
  101. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +371 -0
  102. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +86 -7
  103. package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +153 -22
  104. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
  105. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +188 -38
  106. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +28 -13
  107. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +44 -1
  108. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +56 -4
  109. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +2 -0
  110. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +16 -10
  111. package/dist/bundling-sources/shared_libs/plays/dataset.ts +4 -1
  112. package/dist/cli/index.js +254 -38
  113. package/dist/cli/index.mjs +254 -38
  114. package/dist/{compiler-manifest-DfSnbCTW.d.mts → compiler-manifest-BIqRyj5m.d.mts} +1 -1
  115. package/dist/{compiler-manifest-DfSnbCTW.d.ts → compiler-manifest-BIqRyj5m.d.ts} +1 -1
  116. package/dist/index.d.mts +4 -2
  117. package/dist/index.d.ts +4 -2
  118. package/dist/index.js +231 -35
  119. package/dist/index.mjs +231 -35
  120. package/dist/install-integrity.json +31 -2
  121. package/dist/plays/bundle-play-file.d.mts +2 -2
  122. package/dist/plays/bundle-play-file.d.ts +2 -2
  123. package/dist/plays/bundle-play-file.mjs +65 -1
  124. package/dist/release.d.mts +1 -1
  125. package/dist/release.d.ts +1 -1
  126. package/dist/release.js +1 -1
  127. package/dist/release.mjs +1 -1
  128. package/package.json +1 -1
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Hands source pages to one running map worker pool so the pool never drains
3
+ * between pages. Workers that outrun the appended rows wait here; the page
4
+ * pump appends the next page as soon as the previous one is fully dispatched,
5
+ * so at most one undispatched page and one prepared page are resident.
6
+ */
7
+ export type RuntimeMapRowFeedSnapshot = {
8
+ appendedRows: number;
9
+ dispatchedRows: number;
10
+ pagesAppended: number;
11
+ closed: boolean;
12
+ failed: boolean;
13
+ workersWaiting: number;
14
+ pumpWaitingForDrain: boolean;
15
+ };
16
+
17
+ export const RUNTIME_MAP_ROW_FEED_MAX_WAIT_MS = 30 * 60 * 1000;
18
+
19
+ export class RuntimeMapRowFeedStalledError extends Error {
20
+ readonly snapshot: RuntimeMapRowFeedSnapshot;
21
+
22
+ constructor(input: {
23
+ waiter: 'worker' | 'pump';
24
+ waitMs: number;
25
+ snapshot: RuntimeMapRowFeedSnapshot;
26
+ }) {
27
+ super(
28
+ `Runtime map row feed stalled: ${input.waiter} waited ${input.waitMs} ms ` +
29
+ `(${JSON.stringify(input.snapshot)}).`,
30
+ );
31
+ this.name = 'RuntimeMapRowFeedStalledError';
32
+ this.snapshot = input.snapshot;
33
+ }
34
+ }
35
+
36
+ type Waiter<T> = {
37
+ resolve: (value: T) => void;
38
+ reject: (error: unknown) => void;
39
+ timer: ReturnType<typeof setTimeout>;
40
+ };
41
+
42
+ export class RuntimeMapRowFeed {
43
+ #appended = 0;
44
+ #dispatched = 0;
45
+ #pages = 0;
46
+ #closed = false;
47
+ #failure: unknown = null;
48
+ #failed = false;
49
+ readonly #rowWaiters = new Map<Waiter<boolean>, number>();
50
+ #drainWaiter: Waiter<void> | null = null;
51
+ #onAppended: ((fromIndex: number, toIndex: number) => void) | null = null;
52
+ readonly #maxWaitMs: number;
53
+
54
+ constructor(input?: { maxWaitMs?: number }) {
55
+ this.#maxWaitMs =
56
+ input?.maxWaitMs !== undefined &&
57
+ Number.isFinite(input.maxWaitMs) &&
58
+ input.maxWaitMs > 0
59
+ ? input.maxWaitMs
60
+ : RUNTIME_MAP_ROW_FEED_MAX_WAIT_MS;
61
+ }
62
+
63
+ onAppended(listener: (fromIndex: number, toIndex: number) => void): void {
64
+ this.#onAppended = listener;
65
+ }
66
+
67
+ append(rowCount: number): void {
68
+ if (this.#failed) throw this.#failure;
69
+ if (this.#closed) {
70
+ throw new Error('Runtime map row feed is closed; cannot append rows.');
71
+ }
72
+ if (!Number.isInteger(rowCount) || rowCount < 0) {
73
+ throw new Error(`Runtime map row feed append count must be a non-negative integer, got ${String(rowCount)}.`);
74
+ }
75
+ const fromIndex = this.#appended;
76
+ this.#appended += rowCount;
77
+ this.#pages += 1;
78
+ this.#onAppended?.(fromIndex, this.#appended);
79
+ this.#wakeRowWaiters();
80
+ }
81
+
82
+ close(): void {
83
+ if (this.#closed || this.#failed) return;
84
+ this.#closed = true;
85
+ this.#wakeRowWaiters();
86
+ this.#settleDrainWaiter();
87
+ }
88
+
89
+ fail(error: unknown): void {
90
+ if (this.#failed) return;
91
+ this.#failed = true;
92
+ this.#failure = error;
93
+ for (const [waiter] of this.#rowWaiters) {
94
+ clearTimeout(waiter.timer);
95
+ waiter.reject(error);
96
+ }
97
+ this.#rowWaiters.clear();
98
+ if (this.#drainWaiter) {
99
+ clearTimeout(this.#drainWaiter.timer);
100
+ this.#drainWaiter.reject(error);
101
+ this.#drainWaiter = null;
102
+ }
103
+ }
104
+
105
+ get failed(): boolean {
106
+ return this.#failed;
107
+ }
108
+
109
+ get closed(): boolean {
110
+ return this.#closed;
111
+ }
112
+
113
+ markDispatched(count = 1): void {
114
+ this.#dispatched += count;
115
+ if (this.#dispatched > this.#appended) {
116
+ throw new Error(
117
+ `Runtime map row feed dispatched ${this.#dispatched} rows but only ${this.#appended} were appended.`,
118
+ );
119
+ }
120
+ this.#settleDrainWaiter();
121
+ }
122
+
123
+ /**
124
+ * Resolves true once row `index` has been appended, false once the feed is
125
+ * closed with no such row. Rejects with the feed's failure.
126
+ */
127
+ waitForRows(index: number): Promise<boolean> {
128
+ if (this.#failed) return Promise.reject(this.#failure);
129
+ if (index < this.#appended) return Promise.resolve(true);
130
+ if (this.#closed) return Promise.resolve(false);
131
+ return new Promise<boolean>((resolve, reject) => {
132
+ const startedAt = Date.now();
133
+ const waiter: Waiter<boolean> = {
134
+ resolve,
135
+ reject,
136
+ timer: setTimeout(() => {
137
+ this.#rowWaiters.delete(waiter);
138
+ reject(
139
+ new RuntimeMapRowFeedStalledError({
140
+ waiter: 'worker',
141
+ waitMs: Date.now() - startedAt,
142
+ snapshot: this.snapshot(),
143
+ }),
144
+ );
145
+ }, this.#maxWaitMs),
146
+ };
147
+ waiter.timer.unref?.();
148
+ this.#rowWaiters.set(waiter, index);
149
+ });
150
+ }
151
+
152
+ /** Resolves once every appended row has been dispatched to a worker. */
153
+ waitUntilDrained(): Promise<void> {
154
+ if (this.#failed) return Promise.reject(this.#failure);
155
+ if (this.#dispatched >= this.#appended) return Promise.resolve();
156
+ if (this.#drainWaiter) {
157
+ return Promise.reject(
158
+ new Error('Runtime map row feed already has a pump waiting to drain.'),
159
+ );
160
+ }
161
+ return new Promise<void>((resolve, reject) => {
162
+ const startedAt = Date.now();
163
+ this.#drainWaiter = {
164
+ resolve,
165
+ reject,
166
+ timer: setTimeout(() => {
167
+ this.#drainWaiter = null;
168
+ reject(
169
+ new RuntimeMapRowFeedStalledError({
170
+ waiter: 'pump',
171
+ waitMs: Date.now() - startedAt,
172
+ snapshot: this.snapshot(),
173
+ }),
174
+ );
175
+ }, this.#maxWaitMs),
176
+ };
177
+ this.#drainWaiter.timer.unref?.();
178
+ });
179
+ }
180
+
181
+ snapshot(): RuntimeMapRowFeedSnapshot {
182
+ return {
183
+ appendedRows: this.#appended,
184
+ dispatchedRows: this.#dispatched,
185
+ pagesAppended: this.#pages,
186
+ closed: this.#closed,
187
+ failed: this.#failed,
188
+ workersWaiting: this.#rowWaiters.size,
189
+ pumpWaitingForDrain: this.#drainWaiter !== null,
190
+ };
191
+ }
192
+
193
+ #wakeRowWaiters(): void {
194
+ for (const [waiter, index] of this.#rowWaiters) {
195
+ if (index < this.#appended) {
196
+ this.#rowWaiters.delete(waiter);
197
+ clearTimeout(waiter.timer);
198
+ waiter.resolve(true);
199
+ } else if (this.#closed) {
200
+ this.#rowWaiters.delete(waiter);
201
+ clearTimeout(waiter.timer);
202
+ waiter.resolve(false);
203
+ }
204
+ }
205
+ }
206
+
207
+ #settleDrainWaiter(): void {
208
+ if (!this.#drainWaiter) return;
209
+ if (this.#dispatched < this.#appended && !this.#closed) return;
210
+ const waiter = this.#drainWaiter;
211
+ this.#drainWaiter = null;
212
+ clearTimeout(waiter.timer);
213
+ waiter.resolve();
214
+ }
215
+ }
@@ -24,6 +24,7 @@ export const RUNTIME_OPERATION_CAPABILITIES = {
24
24
  mark_runtime_step_receipts_queued: 'receipt.write',
25
25
  complete_runtime_step_receipt: 'receipt.write',
26
26
  complete_runtime_step_receipts: 'receipt.write',
27
+ complete_runtime_step_receipts_by_reference: 'receipt.write',
27
28
  release_runtime_step_receipt: 'receipt.write',
28
29
  fail_runtime_step_receipt: 'receipt.write',
29
30
  fail_runtime_step_receipts: 'receipt.write',
@@ -54,6 +55,16 @@ export const RUNTIME_OPERATION_CONTRACT: DeployedOperationContract =
54
55
  deployed.operation({
55
56
  id: 'runtime-api-actions',
56
57
  actions: RUNTIME_OPERATION_CAPABILITIES,
58
+ olderReceiver: {
59
+ // The runner retains the complete result before attempting this
60
+ // compact completion. An older app receiver reports the action as
61
+ // unsupported, and the adapter retries the established full-payload
62
+ // completion without re-executing the provider call.
63
+ complete_runtime_step_receipts_by_reference: {
64
+ kind: 'equivalent-fallback',
65
+ action: 'complete_runtime_step_receipts',
66
+ },
67
+ },
57
68
  });
58
69
 
59
70
  export function runtimeOperationCapability(
@@ -2,6 +2,7 @@ import type {
2
2
  AcquireRuntimeReceiptExecutionLockInput,
3
3
  ClaimRuntimeStepReceiptInput,
4
4
  CompleteRuntimeStepReceiptInput,
5
+ CompleteRuntimeStepReceiptsByReferenceInput,
5
6
  ContextOptions,
6
7
  FailRuntimeStepReceiptInput,
7
8
  ReleaseRuntimeReceiptExecutionLockInput,
@@ -18,6 +19,7 @@ import {
18
19
  AppRuntimeApiResponseError,
19
20
  AppRuntimeApiTransportError,
20
21
  claimRuntimeStepReceiptsViaAppRuntime,
22
+ completeRuntimeStepReceiptsByReferenceViaAppRuntime,
21
23
  completeRuntimeStepReceiptsViaAppRuntime,
22
24
  failRuntimeStepReceiptsViaAppRuntime,
23
25
  getRuntimeStepReceiptsViaAppRuntime,
@@ -31,6 +33,7 @@ import {
31
33
  import {
32
34
  RuntimeReceiptWriter,
33
35
  RuntimeReceiptWriterResultCountError,
36
+ writeRuntimeReceiptWithBackpressure,
34
37
  } from './runtime-receipt-writer';
35
38
 
36
39
  type ReceiptOutput =
@@ -42,7 +45,7 @@ type ReceiptOutput =
42
45
  type ReceiptCommand =
43
46
  | {
44
47
  kind: 'get';
45
- input: { key: string; runId: string };
48
+ input: { key: string; runId: string; hydrateOutput?: boolean };
46
49
  }
47
50
  | {
48
51
  kind: 'claim';
@@ -53,6 +56,11 @@ type ReceiptCommand =
53
56
  outcome: 'complete';
54
57
  input: CompleteRuntimeStepReceiptInput;
55
58
  }
59
+ | {
60
+ kind: 'settle';
61
+ outcome: 'complete_reference';
62
+ input: CompleteRuntimeStepReceiptsByReferenceInput['receipts'][number];
63
+ }
56
64
  | {
57
65
  kind: 'settle';
58
66
  outcome: 'fail';
@@ -99,11 +107,13 @@ type ReceiptHandlerName =
99
107
  | 'claimRuntimeStepReceipts'
100
108
  | 'completeRuntimeStepReceipt'
101
109
  | 'completeRuntimeStepReceipts'
110
+ | 'completeRuntimeStepReceiptsByReference'
102
111
  | 'releaseRuntimeStepReceipt'
103
112
  | 'failRuntimeStepReceipt'
104
113
  | 'failRuntimeStepReceipts'
105
114
  | 'heartbeatRuntimeStepReceipts'
106
- | 'skipRuntimeStepReceipt';
115
+ | 'skipRuntimeStepReceipt'
116
+ | 'lastRuntimeStepReceiptCompletionRequestId';
107
117
 
108
118
  export type RuntimeReceiptStoreHandlers = Required<
109
119
  Pick<ContextOptions, ReceiptHandlerName>
@@ -119,15 +129,17 @@ export const RUNTIME_RECEIPT_STORE_RETRY_BUDGET_MS = 5 * 60_000;
119
129
  * The runner's single Work Receipt Adapter.
120
130
  *
121
131
  * Receipt-domain batching and gateway transport stay behind this seam. Every
122
- * command shares one writer, so heterogeneous operations cannot produce
123
- * concurrent gateway requests. The low-level runtime client is explicitly
124
- * one-attempt; this Adapter is the sole retry owner.
132
+ * command shares one writer: operations for one receipt key stay ordered,
133
+ * while independent keys can use its bounded transport pool. The low-level
134
+ * runtime client is explicitly one-attempt; this Adapter is the sole retry
135
+ * owner.
125
136
  */
126
137
  export class RuntimeReceiptStoreAdapter {
127
138
  readonly handlers: RuntimeReceiptStoreHandlers;
128
139
  readonly claimsEstablishExecutionFence = true;
129
140
  readonly #writer: RuntimeReceiptWriter<ReceiptCommand, ReceiptOutput>;
130
141
  #serial = 0;
142
+ #lastCompletionRequestId: string | null = null;
131
143
 
132
144
  constructor(options: {
133
145
  context: WorkerRuntimeApiContext;
@@ -137,21 +149,76 @@ export class RuntimeReceiptStoreAdapter {
137
149
  maxBatchBytes?: number;
138
150
  targetBatchBytes?: number;
139
151
  maxFlushMs?: number;
152
+ maxBufferedItems?: number;
140
153
  maxBufferedBytes?: number;
154
+ maxInFlightBatches?: number;
155
+ /** Completion flights may use this many concurrent transports. */
156
+ maxCompletionInFlightBatches?: number;
157
+ /** Control traffic retains this many flights during a completion burst. */
158
+ maxControlInFlightBatches?: number;
159
+ maxCompletionBufferedItems?: number;
160
+ maxCompletionBufferedBytes?: number;
161
+ maxControlBufferedItems?: number;
162
+ maxControlBufferedBytes?: number;
141
163
  onRetryTelemetry?: (line: string) => void;
142
164
  }) {
143
165
  const context: WorkerRuntimeApiContext = {
144
166
  ...options.context,
145
167
  retryPolicy: 'none',
168
+ onResponseMeta: (meta) => {
169
+ if (
170
+ meta.action === 'complete_runtime_step_receipt' ||
171
+ meta.action === 'complete_runtime_step_receipts' ||
172
+ meta.action === 'complete_runtime_step_receipts_by_reference'
173
+ ) {
174
+ this.#lastCompletionRequestId = meta.requestId;
175
+ }
176
+ options.context.onResponseMeta?.(meta);
177
+ },
146
178
  };
179
+ const usesDedicatedLanes =
180
+ options.maxCompletionInFlightBatches !== undefined ||
181
+ options.maxControlInFlightBatches !== undefined;
182
+ const completionFlights = Math.max(
183
+ 1,
184
+ Math.floor(
185
+ options.maxCompletionInFlightBatches ?? options.maxInFlightBatches ?? 1,
186
+ ),
187
+ );
188
+ const controlFlights = Math.max(
189
+ 1,
190
+ Math.floor(options.maxControlInFlightBatches ?? 1),
191
+ );
147
192
  this.#writer = new RuntimeReceiptWriter({
148
193
  batchKey: receiptCommandBatchKey,
194
+ ...(usesDedicatedLanes
195
+ ? {
196
+ batchLane: receiptCommandBatchLane,
197
+ maxInFlightBatches: completionFlights + controlFlights,
198
+ maxInFlightBatchesByLane: {
199
+ completion: completionFlights,
200
+ control: controlFlights,
201
+ },
202
+ maxBufferedByLane: {
203
+ completion: {
204
+ items: options.maxCompletionBufferedItems,
205
+ bytes: options.maxCompletionBufferedBytes,
206
+ },
207
+ control: {
208
+ items: options.maxControlBufferedItems,
209
+ bytes: options.maxControlBufferedBytes,
210
+ },
211
+ },
212
+ }
213
+ : { maxInFlightBatches: options.maxInFlightBatches }),
214
+ orderingKeys: receiptCommandOrderingKeys,
149
215
  maxBatchSize: options.maxBatchSize,
150
216
  maxBatchBytes:
151
217
  options.maxBatchBytes ?? RUNTIME_RECEIPT_GATEWAY_BATCH_MAX_BYTES,
152
218
  targetBatchBytes:
153
219
  options.targetBatchBytes ?? RUNTIME_RECEIPT_WRITER_TARGET_BATCH_BYTES,
154
220
  maxFlushMs: options.maxFlushMs,
221
+ maxBufferedItems: options.maxBufferedItems,
155
222
  maxBufferedBytes: options.maxBufferedBytes,
156
223
  maxRetryElapsedMs: RUNTIME_RECEIPT_STORE_RETRY_BUDGET_MS,
157
224
  classifyRetryableError: classifyReceiptRetry,
@@ -171,12 +238,12 @@ export class RuntimeReceiptStoreAdapter {
171
238
  }),
172
239
  });
173
240
 
174
- const write = <Output extends ReceiptOutput>(
241
+ const write = async <Output extends ReceiptOutput>(
175
242
  command: ReceiptCommand,
176
243
  ): Promise<Output> =>
177
- this.#writer.write(command, {
244
+ (await writeRuntimeReceiptWithBackpressure(this.#writer, command, {
178
245
  signal: options.context.signal,
179
- }) as Promise<Output>;
246
+ })) as Output;
180
247
  const writeMany = <Output extends ReceiptOutput>(
181
248
  commands: readonly ReceiptCommand[],
182
249
  ): Promise<Output[]> =>
@@ -195,16 +262,24 @@ export class RuntimeReceiptStoreAdapter {
195
262
  input,
196
263
  serial: this.#nextSerial(),
197
264
  }),
198
- getRuntimeStepReceipt: ({ key }) =>
265
+ getRuntimeStepReceipt: ({ key, hydrateOutput }) =>
199
266
  write({
200
267
  kind: 'get',
201
- input: { key, runId: options.runId },
268
+ input: {
269
+ key,
270
+ runId: options.runId,
271
+ ...(hydrateOutput === false ? { hydrateOutput: false } : {}),
272
+ },
202
273
  }),
203
- getRuntimeStepReceipts: ({ keys }) =>
274
+ getRuntimeStepReceipts: ({ keys, hydrateOutput }) =>
204
275
  writeMany(
205
276
  keys.map((key) => ({
206
277
  kind: 'get' as const,
207
- input: { key, runId: options.runId },
278
+ input: {
279
+ key,
280
+ runId: options.runId,
281
+ ...(hydrateOutput === false ? { hydrateOutput: false } : {}),
282
+ },
208
283
  })),
209
284
  ),
210
285
  claimRuntimeStepReceipt: (input) => write({ kind: 'claim', input }),
@@ -220,6 +295,9 @@ export class RuntimeReceiptStoreAdapter {
220
295
  reclaimRunning: input.reclaimRunning,
221
296
  forceRefresh: input.forceRefresh,
222
297
  forceFailedRefresh: input.forceFailedRefresh,
298
+ ...(input.hydrateOutput === false
299
+ ? { hydrateOutput: false }
300
+ : {}),
223
301
  ...(input.leaseIds ? { leaseId: input.leaseIds[index] } : {}),
224
302
  },
225
303
  })),
@@ -234,6 +312,14 @@ export class RuntimeReceiptStoreAdapter {
234
312
  input,
235
313
  })),
236
314
  ),
315
+ completeRuntimeStepReceiptsByReference: ({ receipts }) =>
316
+ writeMany(
317
+ receipts.map((input) => ({
318
+ kind: 'settle' as const,
319
+ outcome: 'complete_reference' as const,
320
+ input,
321
+ })),
322
+ ),
237
323
  releaseRuntimeStepReceipt: (input) =>
238
324
  write({
239
325
  kind: 'settle',
@@ -270,6 +356,8 @@ export class RuntimeReceiptStoreAdapter {
270
356
  input,
271
357
  serial: this.#nextSerial(),
272
358
  }),
359
+ lastRuntimeStepReceiptCompletionRequestId: () =>
360
+ this.#lastCompletionRequestId,
273
361
  };
274
362
  }
275
363
 
@@ -363,7 +451,7 @@ function emitReceiptWriterRetryTelemetry(input: {
363
451
  elapsedMs: event.elapsedMs,
364
452
  retryAfterMs: event.retryAfterMs,
365
453
  queued: event.queued,
366
- blocked: event.blocked,
454
+ bufferedItems: event.bufferedItems,
367
455
  bufferedBytes: event.bufferedBytes,
368
456
  ...(event.error === undefined
369
457
  ? { failureKind: null }
@@ -398,7 +486,9 @@ function receiptCommandBatchKey(command: ReceiptCommand): string {
398
486
  command.input.leaseId !== undefined,
399
487
  ]);
400
488
  case 'settle':
401
- return command.outcome === 'complete' || command.outcome === 'fail'
489
+ return command.outcome === 'complete' ||
490
+ command.outcome === 'complete_reference' ||
491
+ command.outcome === 'fail'
402
492
  ? JSON.stringify([command.kind, command.outcome, command.input.runId])
403
493
  : `${command.kind}:${command.outcome}:${command.serial}`;
404
494
  case 'heartbeat':
@@ -413,6 +503,37 @@ function receiptCommandBatchKey(command: ReceiptCommand): string {
413
503
  }
414
504
  }
415
505
 
506
+ function receiptCommandBatchLane(
507
+ command: ReceiptCommand,
508
+ ): 'completion' | 'control' {
509
+ return command.kind === 'settle' &&
510
+ (command.outcome === 'complete' ||
511
+ command.outcome === 'complete_reference' ||
512
+ command.outcome === 'fail')
513
+ ? 'completion'
514
+ : 'control';
515
+ }
516
+
517
+ /**
518
+ * The gateway conditionally owns every receipt transition, but same-receipt
519
+ * commands still travel in program order. Different receipt keys are
520
+ * independent and can safely occupy the shared bounded transport pool.
521
+ */
522
+ function receiptCommandOrderingKeys(
523
+ command: ReceiptCommand,
524
+ ): readonly string[] {
525
+ switch (command.kind) {
526
+ case 'get':
527
+ case 'claim':
528
+ case 'heartbeat':
529
+ case 'acquire_execution_lock':
530
+ case 'release_execution_lock':
531
+ return [command.input.key];
532
+ case 'settle':
533
+ return [command.input.key];
534
+ }
535
+ }
536
+
416
537
  function classifyReceiptRetry(error: unknown): { retryAfterMs: number } | null {
417
538
  if (isAppRuntimeApiCapacityError(error)) {
418
539
  return { retryAfterMs: error.retryAfterMs };
@@ -443,6 +564,12 @@ async function sendReceiptCommands(input: {
443
564
  playName: input.playName,
444
565
  runId: first.input.runId,
445
566
  keys: commands.map((command) => command.input.key),
567
+ // A mixed writer batch must preserve normal full reads. The manifest
568
+ // probe safely falls back to its byte-admitted path when it receives a
569
+ // body, so never omit an output a concurrent caller requested.
570
+ ...(commands.every((command) => command.input.hydrateOutput === false)
571
+ ? { hydrateOutput: false }
572
+ : {}),
446
573
  });
447
574
  }
448
575
  case 'claim': {
@@ -463,6 +590,12 @@ async function sendReceiptCommands(input: {
463
590
  reclaimRunning: first.input.reclaimRunning,
464
591
  forceRefresh: first.input.forceRefresh,
465
592
  forceFailedRefresh: first.input.forceFailedRefresh,
593
+ // A mixed writer batch must retain a full body for callers that
594
+ // requested one. Manifest callers detect such a body and re-enter the
595
+ // byte-admitted hydration path before using it.
596
+ ...(commands.every((command) => command.input.hydrateOutput === false)
597
+ ? { hydrateOutput: false }
598
+ : {}),
466
599
  });
467
600
  }
468
601
  case 'settle':
@@ -478,6 +611,20 @@ async function sendReceiptCommands(input: {
478
611
  receipts: commands.map((command) => command.input),
479
612
  });
480
613
  }
614
+ case 'complete_reference': {
615
+ const commands = input.commands as readonly Extract<
616
+ ReceiptCommand,
617
+ { kind: 'settle'; outcome: 'complete_reference' }
618
+ >[];
619
+ return await completeRuntimeStepReceiptsByReferenceViaAppRuntime(
620
+ input.context,
621
+ {
622
+ playName: input.playName,
623
+ runId: first.input.runId,
624
+ receipts: commands.map((command) => command.input),
625
+ },
626
+ );
627
+ }
481
628
  case 'fail': {
482
629
  const commands = input.commands as readonly Extract<
483
630
  ReceiptCommand,