deepline 0.1.200 → 0.1.202

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 (33) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +49 -13
  2. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +25 -0
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +139 -124
  4. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +17 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/bounded-dispatch.ts +52 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +152 -23
  8. package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +10 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +11 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +121 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/governor/adaptive-admission.ts +6 -1
  12. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-budget-state-backend.ts +22 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +86 -19
  14. package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +141 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/governor/budget-state-backend.ts +43 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +129 -41
  17. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +40 -2
  18. package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +92 -33
  19. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +13 -5
  20. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +43 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +122 -120
  22. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +10 -8
  23. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +140 -32
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +327 -31
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +26 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +21 -0
  27. package/dist/bundling-sources/shared_libs/plays/dataset.ts +32 -10
  28. package/dist/cli/index.js +198 -76
  29. package/dist/cli/index.mjs +204 -82
  30. package/dist/index.js +3 -2
  31. package/dist/index.mjs +3 -2
  32. package/package.json +1 -1
  33. package/dist/bundling-sources/shared_libs/play-runtime/adaptive-tool-dispatcher.ts +0 -355
@@ -1,355 +0,0 @@
1
- export type AdaptiveToolDispatchErrorKind = 'rate_limit' | 'other';
2
-
3
- export type AdaptiveToolDispatchError = {
4
- kind: AdaptiveToolDispatchErrorKind;
5
- retryAfterMs?: number | null;
6
- };
7
-
8
- export type AdaptiveToolDispatcherOptions = {
9
- initialRequestsPerSecond: number;
10
- maxRequestsPerSecond: number;
11
- maxConcurrency: number;
12
- minConcurrency?: number;
13
- additiveIncreasePerWindow?: number;
14
- cleanWindowMs?: number;
15
- defaultLatencyMs?: number;
16
- safetyFactor?: number;
17
- now?: () => number;
18
- sleep?: (ms: number) => Promise<void>;
19
- classifyError?: (error: unknown) => AdaptiveToolDispatchError | null;
20
- };
21
-
22
- export type AdaptiveToolDispatchResult<TJob, TResult> = {
23
- job: TJob;
24
- index: number;
25
- result: TResult | null;
26
- latencyMs: number | null;
27
- error?: unknown;
28
- };
29
-
30
- export type AdaptiveToolDispatcherSnapshot = {
31
- currentRequestsPerSecond: number;
32
- targetConcurrency: number;
33
- inFlight: number;
34
- queued: number;
35
- maxObservedInFlight: number;
36
- successCount: number;
37
- errorCount: number;
38
- rateLimitCount: number;
39
- latencyP95Ms: number | null;
40
- cooldownUntilMs: number | null;
41
- };
42
-
43
- type QueuedJob<TJob> = {
44
- job: TJob;
45
- index: number;
46
- };
47
-
48
- function positiveInteger(value: number, fallback: number): number {
49
- return Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
50
- }
51
-
52
- function clamp(value: number, min: number, max: number): number {
53
- return Math.max(min, Math.min(max, value));
54
- }
55
-
56
- function percentile(
57
- values: readonly number[],
58
- percentileValue: number,
59
- ): number {
60
- if (values.length === 0) return 0;
61
- const sorted = [...values].sort((a, b) => a - b);
62
- const index = clamp(
63
- Math.ceil(sorted.length * percentileValue) - 1,
64
- 0,
65
- sorted.length - 1,
66
- );
67
- return sorted[index] ?? 0;
68
- }
69
-
70
- export class AdaptiveToolDispatcher<TJob, TResult> {
71
- private readonly maxRequestsPerSecond: number;
72
- private readonly maxConcurrency: number;
73
- private readonly minConcurrency: number;
74
- private readonly additiveIncreasePerWindow: number;
75
- private readonly cleanWindowMs: number;
76
- private readonly defaultLatencyMs: number;
77
- private readonly safetyFactor: number;
78
- private readonly now: () => number;
79
- private readonly sleep: (ms: number) => Promise<void>;
80
- private readonly classifyError: (
81
- error: unknown,
82
- ) => AdaptiveToolDispatchError | null;
83
- private readonly latencySamples: number[] = [];
84
- private readonly launchTimestamps: number[] = [];
85
- private readonly progressWaiters: Array<() => void> = [];
86
- private currentRequestsPerSecond: number;
87
- private lastIncreaseAtMs: number;
88
- private successCountAtLastIncrease = 0;
89
- private successCount = 0;
90
- private errorCount = 0;
91
- private rateLimitCount = 0;
92
- private inFlight = 0;
93
- private queued = 0;
94
- private maxObservedInFlight = 0;
95
- private cooldownUntilMs: number | null = null;
96
-
97
- constructor(options: AdaptiveToolDispatcherOptions) {
98
- this.maxRequestsPerSecond = positiveInteger(
99
- options.maxRequestsPerSecond,
100
- 1,
101
- );
102
- this.minConcurrency = positiveInteger(options.minConcurrency ?? 1, 1);
103
- this.maxConcurrency = Math.max(
104
- this.minConcurrency,
105
- positiveInteger(options.maxConcurrency, this.minConcurrency),
106
- );
107
- this.currentRequestsPerSecond = clamp(
108
- positiveInteger(options.initialRequestsPerSecond, 1),
109
- 1,
110
- this.maxRequestsPerSecond,
111
- );
112
- this.additiveIncreasePerWindow = positiveInteger(
113
- options.additiveIncreasePerWindow ?? 5,
114
- 5,
115
- );
116
- this.cleanWindowMs = positiveInteger(options.cleanWindowMs ?? 1_000, 1_000);
117
- this.defaultLatencyMs = positiveInteger(
118
- options.defaultLatencyMs ?? 1_000,
119
- 1_000,
120
- );
121
- this.safetyFactor =
122
- Number.isFinite(options.safetyFactor) && options.safetyFactor! > 0
123
- ? options.safetyFactor!
124
- : 1.5;
125
- this.now = options.now ?? Date.now;
126
- this.sleep =
127
- options.sleep ??
128
- ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
129
- this.classifyError = options.classifyError ?? (() => null);
130
- this.lastIncreaseAtMs = this.now();
131
- }
132
-
133
- async dispatch(
134
- jobs: readonly TJob[],
135
- execute: (job: TJob) => Promise<TResult>,
136
- ): Promise<Array<AdaptiveToolDispatchResult<TJob, TResult>>> {
137
- const queue = jobs.map((job, index) => ({ job, index }));
138
- const results = new Array<AdaptiveToolDispatchResult<TJob, TResult>>(
139
- jobs.length,
140
- );
141
- this.queued = queue.length;
142
-
143
- while (queue.length > 0 || this.inFlight > 0) {
144
- let launched = false;
145
- while (queue.length > 0 && this.canLaunch()) {
146
- const next = queue.shift();
147
- if (!next) break;
148
- this.launch(next, execute, results);
149
- launched = true;
150
- }
151
- this.queued = queue.length;
152
- if (queue.length === 0 && this.inFlight === 0) break;
153
- if (!launched) {
154
- await this.waitForProgress(this.nextLaunchDelayMs());
155
- }
156
- }
157
-
158
- return results.filter(
159
- (result): result is AdaptiveToolDispatchResult<TJob, TResult> =>
160
- result !== undefined,
161
- );
162
- }
163
-
164
- snapshot(): AdaptiveToolDispatcherSnapshot {
165
- return {
166
- currentRequestsPerSecond: this.currentRequestsPerSecond,
167
- targetConcurrency: this.targetConcurrency(),
168
- inFlight: this.inFlight,
169
- queued: this.queued,
170
- maxObservedInFlight: this.maxObservedInFlight,
171
- successCount: this.successCount,
172
- errorCount: this.errorCount,
173
- rateLimitCount: this.rateLimitCount,
174
- latencyP95Ms: this.latencyP95Ms(),
175
- cooldownUntilMs: this.cooldownUntilMs,
176
- };
177
- }
178
-
179
- private canLaunch(): boolean {
180
- return (
181
- this.inFlight < this.targetConcurrency() &&
182
- this.now() >= (this.cooldownUntilMs ?? 0) &&
183
- this.startsAvailable() > 0
184
- );
185
- }
186
-
187
- private launch(
188
- queued: QueuedJob<TJob>,
189
- execute: (job: TJob) => Promise<TResult>,
190
- results: Array<AdaptiveToolDispatchResult<TJob, TResult> | undefined>,
191
- ): void {
192
- const startedAt = this.now();
193
- this.launchTimestamps.push(startedAt);
194
- this.inFlight += 1;
195
- this.maxObservedInFlight = Math.max(
196
- this.maxObservedInFlight,
197
- this.inFlight,
198
- );
199
-
200
- let execution: Promise<TResult>;
201
- try {
202
- execution = Promise.resolve(execute(queued.job));
203
- } catch (error) {
204
- execution = Promise.reject(error);
205
- }
206
-
207
- void execution
208
- .then((result) => {
209
- const latencyMs = Math.max(0, this.now() - startedAt);
210
- this.observeSuccess(latencyMs);
211
- results[queued.index] = {
212
- job: queued.job,
213
- index: queued.index,
214
- result,
215
- latencyMs,
216
- };
217
- })
218
- .catch((error) => {
219
- this.observeError(error);
220
- results[queued.index] = {
221
- job: queued.job,
222
- index: queued.index,
223
- result: null,
224
- latencyMs: Math.max(0, this.now() - startedAt),
225
- error,
226
- };
227
- })
228
- .finally(() => {
229
- this.inFlight = Math.max(0, this.inFlight - 1);
230
- this.signalProgress();
231
- });
232
- }
233
-
234
- private observeSuccess(latencyMs: number): void {
235
- this.successCount += 1;
236
- this.latencySamples.push(latencyMs);
237
- if (this.latencySamples.length > 128) {
238
- this.latencySamples.splice(0, this.latencySamples.length - 128);
239
- }
240
- const currentTime = this.now();
241
- if (this.cooldownUntilMs != null && this.cooldownUntilMs > currentTime) {
242
- this.successCountAtLastIncrease = this.successCount;
243
- return;
244
- }
245
- this.cooldownUntilMs = null;
246
- const successesSinceIncrease =
247
- this.successCount - this.successCountAtLastIncrease;
248
- if (
249
- currentTime - this.lastIncreaseAtMs >= this.cleanWindowMs &&
250
- successesSinceIncrease >= this.currentRequestsPerSecond
251
- ) {
252
- this.currentRequestsPerSecond = Math.min(
253
- this.maxRequestsPerSecond,
254
- this.currentRequestsPerSecond + this.additiveIncreasePerWindow,
255
- );
256
- this.lastIncreaseAtMs = currentTime;
257
- this.successCountAtLastIncrease = this.successCount;
258
- }
259
- }
260
-
261
- private observeError(error: unknown): void {
262
- this.errorCount += 1;
263
- let classified: AdaptiveToolDispatchError | null = null;
264
- try {
265
- classified = this.classifyError(error);
266
- } catch {
267
- classified = null;
268
- }
269
- if (classified?.kind !== 'rate_limit') return;
270
- this.rateLimitCount += 1;
271
- this.currentRequestsPerSecond = Math.max(
272
- 1,
273
- Math.floor(this.currentRequestsPerSecond / 2),
274
- );
275
- const retryAfterMs = Math.max(0, classified.retryAfterMs ?? 0);
276
- const currentTime = this.now();
277
- const cooldownUntilMs = currentTime + retryAfterMs;
278
- this.cooldownUntilMs =
279
- this.cooldownUntilMs == null
280
- ? cooldownUntilMs
281
- : Math.max(this.cooldownUntilMs, cooldownUntilMs);
282
- this.lastIncreaseAtMs = this.cooldownUntilMs;
283
- this.successCountAtLastIncrease = this.successCount;
284
- }
285
-
286
- private targetConcurrency(): number {
287
- const latencyMs = this.latencyP95Ms() ?? this.defaultLatencyMs;
288
- const target = Math.ceil(
289
- this.currentRequestsPerSecond *
290
- (Math.max(1, latencyMs) / 1_000) *
291
- this.safetyFactor,
292
- );
293
- return clamp(target, this.minConcurrency, this.maxConcurrency);
294
- }
295
-
296
- private latencyP95Ms(): number | null {
297
- return this.latencySamples.length > 0
298
- ? percentile(this.latencySamples, 0.95)
299
- : null;
300
- }
301
-
302
- private startsAvailable(): number {
303
- this.pruneLaunchTimestamps();
304
- return Math.max(
305
- 0,
306
- this.currentRequestsPerSecond - this.launchTimestamps.length,
307
- );
308
- }
309
-
310
- private nextLaunchDelayMs(): number {
311
- const currentTime = this.now();
312
- const cooldownWait =
313
- this.cooldownUntilMs != null
314
- ? Math.max(0, this.cooldownUntilMs - currentTime)
315
- : 0;
316
- this.pruneLaunchTimestamps();
317
- const oldest = this.launchTimestamps[0];
318
- const tokenWait =
319
- oldest == null ||
320
- this.launchTimestamps.length < this.currentRequestsPerSecond
321
- ? 0
322
- : Math.max(1, oldest + 1_000 - currentTime);
323
- return Math.max(1, cooldownWait, tokenWait);
324
- }
325
-
326
- private pruneLaunchTimestamps(): void {
327
- const cutoff = this.now() - 1_000;
328
- while (
329
- this.launchTimestamps.length > 0 &&
330
- (this.launchTimestamps[0] ?? 0) <= cutoff
331
- ) {
332
- this.launchTimestamps.shift();
333
- }
334
- }
335
-
336
- private async waitForProgress(delayMs: number): Promise<void> {
337
- let waiter: (() => void) | null = null;
338
- await Promise.race([
339
- new Promise<void>((resolve) => {
340
- waiter = resolve;
341
- this.progressWaiters.push(resolve);
342
- }),
343
- this.sleep(delayMs),
344
- ]);
345
- if (waiter) {
346
- const index = this.progressWaiters.indexOf(waiter);
347
- if (index >= 0) this.progressWaiters.splice(index, 1);
348
- }
349
- }
350
-
351
- private signalProgress(): void {
352
- const waiters = this.progressWaiters.splice(0);
353
- for (const waiter of waiters) waiter();
354
- }
355
- }