deepline 0.1.182 → 0.1.184
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.
- package/dist/bundling-sources/apps/play-runner-workers/src/child-play-await.ts +203 -6
- package/dist/bundling-sources/apps/play-runner-workers/src/child-play-submit.ts +8 -1
- package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +639 -109
- package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +3 -2
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +1752 -1899
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +116 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +542 -78
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +292 -11
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/run-work-dispatcher.ts +519 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +2381 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +18 -5
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/work-budget.ts +130 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/worker-platform-budget.ts +39 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +2 -0
- package/dist/bundling-sources/sdk/src/client.ts +41 -0
- package/dist/bundling-sources/sdk/src/http.ts +23 -8
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +56 -3
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/sdk/src/types.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +133 -10
- package/dist/bundling-sources/shared_libs/play-runtime/auth-scope-resolver.ts +92 -0
- package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +4 -4
- package/dist/bundling-sources/shared_libs/play-runtime/batching-types.ts +8 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-run-id.ts +101 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +1612 -287
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +105 -6
- package/dist/bundling-sources/shared_libs/play-runtime/dedup-backend.ts +0 -0
- package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durability-store.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +116 -16
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +186 -20
- package/dist/bundling-sources/shared_libs/play-runtime/dynamic-worker-version.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-ledger-store.ts +133 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +245 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -5
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +14 -0
- package/dist/bundling-sources/shared_libs/play-runtime/lease-policy.ts +52 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +41 -0
- package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +3 -2
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +124 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +6 -2
- package/dist/bundling-sources/shared_libs/play-runtime/row-isolation.ts +48 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +158 -15
- package/dist/bundling-sources/shared_libs/play-runtime/run-terminal-source.ts +45 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-paths.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +2038 -262
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +42 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-attempt-state-machine.ts +183 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-errors.ts +88 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +8 -1
- package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +19 -1
- package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +343 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +43 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +11 -0
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +437 -0
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +83 -6
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +28 -11
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +38 -6
- package/dist/bundling-sources/shared_libs/security/safe-outbound-fetch.ts +24 -17
- package/dist/cli/index.js +76 -17
- package/dist/cli/index.mjs +76 -17
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +63 -9
- package/dist/index.mjs +63 -9
- package/dist/plays/bundle-play-file.mjs +20 -6
- package/package.json +1 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
chooseMapChunkSize,
|
|
3
|
+
EXECUTION_PLAN_DEFAULTS,
|
|
3
4
|
type ExecutionPlan,
|
|
4
5
|
} from '../../../../shared_libs/play-runtime/execution-plan';
|
|
5
|
-
import { getPlayRuntimeBatchStrategy } from '../../../../shared_libs/play-runtime/play-runtime-batching-registry';
|
|
6
6
|
import { TOOL_CALLING_MAP_CHUNK_SIZE } from '../../../../shared_libs/play-runtime/map-chunk-limits';
|
|
7
|
+
import { getPlayRuntimeBatchStrategy } from '../../../../shared_libs/play-runtime/play-runtime-batching-registry';
|
|
8
|
+
import {
|
|
9
|
+
WORKER_PLATFORM_SUBREQUESTS_PER_UNBATCHED_TOOL_CALL,
|
|
10
|
+
WORKER_PLATFORM_SUBREQUEST_SOFT_LIMIT,
|
|
11
|
+
} from './worker-platform-budget';
|
|
7
12
|
import {
|
|
8
13
|
flattenStaticSubsteps,
|
|
9
14
|
getTopLevelPipelineSubsteps,
|
|
@@ -14,15 +19,61 @@ import {
|
|
|
14
19
|
|
|
15
20
|
export const CACHE_ENABLED_SIMPLE_MAP_CHUNK_SIZE = 10_000;
|
|
16
21
|
export { TOOL_CALLING_MAP_CHUNK_SIZE };
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
|
|
22
|
+
export const WORKER_SUBREQUEST_SAFE_TOOL_CALLS_PER_CHUNK =
|
|
23
|
+
TOOL_CALLING_MAP_CHUNK_SIZE;
|
|
24
|
+
export const UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET =
|
|
25
|
+
WORKER_PLATFORM_SUBREQUEST_SOFT_LIMIT;
|
|
26
|
+
export const SUBREQUESTS_PER_UNBATCHED_TOOL_CALL =
|
|
27
|
+
WORKER_PLATFORM_SUBREQUESTS_PER_UNBATCHED_TOOL_CALL;
|
|
28
|
+
|
|
29
|
+
// A batched tool over a chunk of N rows does not spend the unbatched provider
|
|
30
|
+
// budget for every row. Durable receipt claim/complete/fail are bulk RPCs for
|
|
31
|
+
// the whole drained tool group, but provider execution still happens once per
|
|
32
|
+
// compiled batch. Static planning cannot know input-dependent bucket keys, so
|
|
33
|
+
// it must assume worst-case provider fanout (one compiled batch per row) unless
|
|
34
|
+
// the batching registry grows a proof that all rows share a bucket.
|
|
35
|
+
export const BATCHED_TOOL_SUBREQUESTS_PER_BATCH = 2;
|
|
36
|
+
export const BULK_RECEIPT_SUBREQUESTS_PER_CHUNK = 3;
|
|
37
|
+
// Conservative batch size assumed only when a batchable tool's registry
|
|
38
|
+
// maxBatchSize is unknown. Smaller = more batches = more subrequests = safer.
|
|
39
|
+
export const ASSUMED_BATCH_SIZE_FLOOR = 100;
|
|
40
|
+
const MAX_BATCHABLE_SUBREQUEST_SAFE_ROWS = 1_000_000;
|
|
41
|
+
|
|
42
|
+
function assumedBatchSizeFor(minBatchableBatchSize: number): number {
|
|
43
|
+
return minBatchableBatchSize > 0
|
|
44
|
+
? minBatchableBatchSize
|
|
45
|
+
: ASSUMED_BATCH_SIZE_FLOOR;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Per-chunk subrequest cost of the batchable tool work in a map chunk. Shared
|
|
49
|
+
// by the chunk sizer (inverts it to find safe rows/chunk) and the live budget
|
|
50
|
+
// projection in entry.ts so the two never drift.
|
|
51
|
+
export function estimateBatchedToolChunkSubrequests(input: {
|
|
52
|
+
batchableToolCallsPerRow: number;
|
|
53
|
+
coalescedBatchableToolCallsPerRow?: number;
|
|
54
|
+
rows: number;
|
|
55
|
+
assumedBatchSize: number;
|
|
56
|
+
}): number {
|
|
57
|
+
if (input.batchableToolCallsPerRow <= 0 || input.rows <= 0) return 0;
|
|
58
|
+
const toolCallsPerRow = Math.max(1, input.batchableToolCallsPerRow);
|
|
59
|
+
const coalescedToolCallsPerRow = Math.min(
|
|
60
|
+
toolCallsPerRow,
|
|
61
|
+
Math.max(0, input.coalescedBatchableToolCallsPerRow ?? 0),
|
|
62
|
+
);
|
|
63
|
+
const worstCaseToolCallsPerRow = Math.max(
|
|
64
|
+
0,
|
|
65
|
+
toolCallsPerRow - coalescedToolCallsPerRow,
|
|
66
|
+
);
|
|
67
|
+
const coalescedCompiledBatches =
|
|
68
|
+
Math.ceil(input.rows / Math.max(1, input.assumedBatchSize)) *
|
|
69
|
+
coalescedToolCallsPerRow;
|
|
70
|
+
const worstCaseCompiledBatches = input.rows * worstCaseToolCallsPerRow;
|
|
71
|
+
return (
|
|
72
|
+
BATCHED_TOOL_SUBREQUESTS_PER_BATCH *
|
|
73
|
+
(coalescedCompiledBatches + worstCaseCompiledBatches) +
|
|
74
|
+
BULK_RECEIPT_SUBREQUESTS_PER_CHUNK * toolCallsPerRow
|
|
75
|
+
);
|
|
76
|
+
}
|
|
26
77
|
export type WorkerMapChunkPlanInput = {
|
|
27
78
|
mapName: string;
|
|
28
79
|
rowCountHint: number | null;
|
|
@@ -39,14 +90,61 @@ type ChunkSizingMap = Pick<
|
|
|
39
90
|
| 'defaultChunkSize'
|
|
40
91
|
| 'stepsPerChunk'
|
|
41
92
|
> &
|
|
42
|
-
Partial<
|
|
93
|
+
Partial<
|
|
94
|
+
Pick<PlanMap, 'externalStepFields' | 'stepFields' | 'waterfallStages'>
|
|
95
|
+
>;
|
|
43
96
|
type ChunkSizingPlan = {
|
|
44
97
|
maps: ChunkSizingMap[];
|
|
45
98
|
toolDeclarations?: ExecutionPlan['toolDeclarations'];
|
|
46
99
|
softWorkflowStepBudget?: number | null;
|
|
47
100
|
};
|
|
48
101
|
|
|
49
|
-
type MapToolStats = [
|
|
102
|
+
type MapToolStats = [
|
|
103
|
+
totalToolCount: number,
|
|
104
|
+
unbatchedToolCount: number,
|
|
105
|
+
unbatchedSubrequestCount: number,
|
|
106
|
+
// Smallest registry maxBatchSize across the batchable tools counted so far
|
|
107
|
+
// (0 when no batchable tool has been seen). Smallest = most batches = most
|
|
108
|
+
// subrequests, so it is the conservative choice for chunk sizing.
|
|
109
|
+
minBatchableBatchSize: number,
|
|
110
|
+
coalescedBatchableToolCount: number,
|
|
111
|
+
];
|
|
112
|
+
type MapControlWorkStats = {
|
|
113
|
+
childPlaySubmits: number;
|
|
114
|
+
eventWaits: number;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const EMPTY_CONTROL_WORK_STATS: MapControlWorkStats = {
|
|
118
|
+
childPlaySubmits: 0,
|
|
119
|
+
eventWaits: 0,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export type WorkerMapDispatchPlan = {
|
|
123
|
+
rowsPerChunk: number;
|
|
124
|
+
estimatedExternalStepsPerRow: number;
|
|
125
|
+
workEstimate: WorkerMapWorkEstimate;
|
|
126
|
+
reason:
|
|
127
|
+
| 'external-pressure'
|
|
128
|
+
| 'tool-free-large-cache'
|
|
129
|
+
| 'tool-free-plan'
|
|
130
|
+
| 'default-plan';
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type WorkerMapWorkEstimate = {
|
|
134
|
+
cpuRowsPerRow: number;
|
|
135
|
+
runtimeSheetReadsPerChunk: number;
|
|
136
|
+
runtimeSheetWritesPerChunk: number;
|
|
137
|
+
durableReceiptOpsPerRow: number;
|
|
138
|
+
providerToolCallsPerRow: number;
|
|
139
|
+
unbatchedProviderToolCallsPerRow: number;
|
|
140
|
+
// Registry batch size assumed for the batchable tools in this map (smallest
|
|
141
|
+
// maxBatchSize across them, or ASSUMED_BATCH_SIZE_FLOOR when unknown). Drives
|
|
142
|
+
// the batched-tool subrequest projection.
|
|
143
|
+
assumedBatchSize: number;
|
|
144
|
+
coalescedBatchableProviderToolCallsPerRow: number;
|
|
145
|
+
childPlaySubmitsPerRow: number;
|
|
146
|
+
eventWaitsPerRow: number;
|
|
147
|
+
};
|
|
50
148
|
|
|
51
149
|
function fieldRoot(field: string | null | undefined): string {
|
|
52
150
|
return String(field ?? '').split('.', 1)[0] ?? '';
|
|
@@ -71,22 +169,82 @@ function declarationBelongsToMapOutput(
|
|
|
71
169
|
);
|
|
72
170
|
}
|
|
73
171
|
|
|
74
|
-
function countTool(
|
|
75
|
-
|
|
76
|
-
|
|
172
|
+
function countTool(
|
|
173
|
+
toolId: string,
|
|
174
|
+
options?: { staticSingleBucket?: boolean },
|
|
175
|
+
): MapToolStats {
|
|
176
|
+
const batchStrategy = getPlayRuntimeBatchStrategy(toolId);
|
|
177
|
+
if (batchStrategy !== null) {
|
|
178
|
+
return [
|
|
179
|
+
1,
|
|
180
|
+
0,
|
|
181
|
+
0,
|
|
182
|
+
Math.max(1, Math.floor(batchStrategy.maxBatchSize)),
|
|
183
|
+
options?.staticSingleBucket === true ? 1 : 0,
|
|
184
|
+
];
|
|
185
|
+
}
|
|
186
|
+
return [1, 1, SUBREQUESTS_PER_UNBATCHED_TOOL_CALL, 0, 0];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function minPositiveBatchSize(a: number, b: number): number {
|
|
190
|
+
if (a <= 0) return Math.max(0, b);
|
|
191
|
+
if (b <= 0) return Math.max(0, a);
|
|
192
|
+
return Math.min(a, b);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function minProviderBranchCoalescedCount(
|
|
196
|
+
branchStats: readonly MapToolStats[],
|
|
197
|
+
): number {
|
|
198
|
+
let minCoalesced: number | null = null;
|
|
199
|
+
for (const [total, , , , coalesced] of branchStats) {
|
|
200
|
+
if (total <= 0) continue;
|
|
201
|
+
minCoalesced =
|
|
202
|
+
minCoalesced === null ? coalesced : Math.min(minCoalesced, coalesced);
|
|
203
|
+
}
|
|
204
|
+
return minCoalesced ?? 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function escapeRegExp(value: string): string {
|
|
208
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function hasStaticSingleBatchBucket(input: {
|
|
212
|
+
toolId: string;
|
|
213
|
+
paramsSource?: string | null;
|
|
214
|
+
sourceText?: string | null;
|
|
215
|
+
}): boolean {
|
|
216
|
+
const strategy = getPlayRuntimeBatchStrategy(input.toolId);
|
|
217
|
+
const bucketFields = strategy?.bucketKeyPayloadFields;
|
|
218
|
+
if (!bucketFields || bucketFields.length === 0) return false;
|
|
219
|
+
const source = [input.paramsSource, input.sourceText]
|
|
220
|
+
.filter((value): value is string => typeof value === 'string')
|
|
221
|
+
.join('\n');
|
|
222
|
+
if (!source) return false;
|
|
223
|
+
return bucketFields.every((field) => {
|
|
224
|
+
const pattern = new RegExp(
|
|
225
|
+
`(^|[^A-Za-z0-9_$])${escapeRegExp(field)}([^A-Za-z0-9_$]|$)`,
|
|
226
|
+
);
|
|
227
|
+
return !pattern.test(source);
|
|
228
|
+
});
|
|
77
229
|
}
|
|
78
230
|
|
|
79
231
|
function addStats(
|
|
80
|
-
[total, subrequests]: MapToolStats,
|
|
232
|
+
[total, unbatched, subrequests, batchSize, coalesced]: MapToolStats,
|
|
81
233
|
stats: MapToolStats,
|
|
82
234
|
): MapToolStats {
|
|
83
|
-
return [
|
|
235
|
+
return [
|
|
236
|
+
total + stats[0],
|
|
237
|
+
unbatched + stats[1],
|
|
238
|
+
subrequests + stats[2],
|
|
239
|
+
minPositiveBatchSize(batchSize, stats[3]),
|
|
240
|
+
coalesced + stats[4],
|
|
241
|
+
];
|
|
84
242
|
}
|
|
85
243
|
|
|
86
244
|
function countToolSubsteps(
|
|
87
245
|
substeps: readonly PlayStaticSubstep[],
|
|
88
246
|
): MapToolStats {
|
|
89
|
-
let stats: MapToolStats = [0, 0];
|
|
247
|
+
let stats: MapToolStats = [0, 0, 0, 0, 0];
|
|
90
248
|
|
|
91
249
|
for (const substep of substeps) {
|
|
92
250
|
stats = addStats(stats, countToolSubstep(substep));
|
|
@@ -97,14 +255,29 @@ function countToolSubsteps(
|
|
|
97
255
|
|
|
98
256
|
function countToolSubstep(substep: PlayStaticSubstep): MapToolStats {
|
|
99
257
|
if (substep.type === 'tool') {
|
|
100
|
-
return countTool(substep.toolId
|
|
258
|
+
return countTool(substep.toolId, {
|
|
259
|
+
staticSingleBucket: hasStaticSingleBatchBucket({
|
|
260
|
+
toolId: substep.toolId,
|
|
261
|
+
paramsSource: substep.paramsSource,
|
|
262
|
+
sourceText: substep.sourceText,
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
101
265
|
}
|
|
102
266
|
|
|
103
267
|
if (substep.type === 'waterfall') {
|
|
104
|
-
let stats: MapToolStats = [0, 0];
|
|
268
|
+
let stats: MapToolStats = [0, 0, 0, 0, 0];
|
|
105
269
|
for (const step of substep.steps ?? []) {
|
|
106
270
|
if (!step.toolId) continue;
|
|
107
|
-
stats = addStats(
|
|
271
|
+
stats = addStats(
|
|
272
|
+
stats,
|
|
273
|
+
countTool(step.toolId, {
|
|
274
|
+
staticSingleBucket: hasStaticSingleBatchBucket({
|
|
275
|
+
toolId: step.toolId,
|
|
276
|
+
paramsSource: step.paramsSource,
|
|
277
|
+
sourceText: substep.sourceText,
|
|
278
|
+
}),
|
|
279
|
+
}),
|
|
280
|
+
);
|
|
108
281
|
}
|
|
109
282
|
return stats;
|
|
110
283
|
}
|
|
@@ -118,13 +291,26 @@ function countToolSubstep(substep: PlayStaticSubstep): MapToolStats {
|
|
|
118
291
|
const branchStats = substep.branches.map((branch) =>
|
|
119
292
|
countToolSubsteps(branch.steps),
|
|
120
293
|
);
|
|
121
|
-
|
|
122
|
-
(
|
|
294
|
+
const maxBranchStats = branchStats.reduce<MapToolStats>(
|
|
295
|
+
(
|
|
296
|
+
[totalMax, unbatchedMax, subrequestsMax, batchSizeMin, coalescedMax],
|
|
297
|
+
[total, unbatched, subrequests, batchSize, coalesced],
|
|
298
|
+
) => [
|
|
123
299
|
Math.max(totalMax, total),
|
|
300
|
+
Math.max(unbatchedMax, unbatched),
|
|
124
301
|
Math.max(subrequestsMax, subrequests),
|
|
302
|
+
minPositiveBatchSize(batchSizeMin, batchSize),
|
|
303
|
+
Math.max(coalescedMax, coalesced),
|
|
125
304
|
],
|
|
126
|
-
[0, 0],
|
|
305
|
+
[0, 0, 0, 0, 0],
|
|
127
306
|
);
|
|
307
|
+
return [
|
|
308
|
+
maxBranchStats[0],
|
|
309
|
+
maxBranchStats[1],
|
|
310
|
+
maxBranchStats[2],
|
|
311
|
+
maxBranchStats[3],
|
|
312
|
+
minProviderBranchCoalescedCount(branchStats),
|
|
313
|
+
];
|
|
128
314
|
}
|
|
129
315
|
return countToolSubsteps(substep.steps);
|
|
130
316
|
}
|
|
@@ -133,7 +319,77 @@ function countToolSubstep(substep: PlayStaticSubstep): MapToolStats {
|
|
|
133
319
|
return countToolSubsteps(substep.steps ?? []);
|
|
134
320
|
}
|
|
135
321
|
|
|
136
|
-
return [0, 0];
|
|
322
|
+
return [0, 0, 0, 0, 0];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function addControlWorkStats(
|
|
326
|
+
left: MapControlWorkStats,
|
|
327
|
+
right: MapControlWorkStats,
|
|
328
|
+
): MapControlWorkStats {
|
|
329
|
+
return {
|
|
330
|
+
childPlaySubmits: left.childPlaySubmits + right.childPlaySubmits,
|
|
331
|
+
eventWaits: left.eventWaits + right.eventWaits,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function maxControlWorkStats(
|
|
336
|
+
left: MapControlWorkStats,
|
|
337
|
+
right: MapControlWorkStats,
|
|
338
|
+
): MapControlWorkStats {
|
|
339
|
+
return {
|
|
340
|
+
childPlaySubmits: Math.max(left.childPlaySubmits, right.childPlaySubmits),
|
|
341
|
+
eventWaits: Math.max(left.eventWaits, right.eventWaits),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function countControlWorkSubsteps(
|
|
346
|
+
substeps: readonly PlayStaticSubstep[],
|
|
347
|
+
): MapControlWorkStats {
|
|
348
|
+
return substeps.reduce<MapControlWorkStats>(
|
|
349
|
+
(acc, substep) =>
|
|
350
|
+
addControlWorkStats(acc, countControlWorkSubstep(substep)),
|
|
351
|
+
EMPTY_CONTROL_WORK_STATS,
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function countControlWorkSubstep(
|
|
356
|
+
substep: PlayStaticSubstep,
|
|
357
|
+
): MapControlWorkStats {
|
|
358
|
+
if (substep.type === 'play_call') {
|
|
359
|
+
return { childPlaySubmits: 1, eventWaits: 0 };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (substep.type === 'tool') {
|
|
363
|
+
return {
|
|
364
|
+
childPlaySubmits: 0,
|
|
365
|
+
eventWaits:
|
|
366
|
+
substep.isEventWait === true || substep.toolId === 'test_wait_for_event'
|
|
367
|
+
? 1
|
|
368
|
+
: 0,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (substep.type === 'step_suite') {
|
|
373
|
+
return countControlWorkSubsteps(substep.steps);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (substep.type === 'control_flow') {
|
|
377
|
+
if (substep.kind === 'conditional' && substep.branches?.length) {
|
|
378
|
+
return substep.branches
|
|
379
|
+
.map((branch) => countControlWorkSubsteps(branch.steps))
|
|
380
|
+
.reduce<MapControlWorkStats>(
|
|
381
|
+
(acc, stats) => maxControlWorkStats(acc, stats),
|
|
382
|
+
EMPTY_CONTROL_WORK_STATS,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
return countControlWorkSubsteps(substep.steps);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (substep.type === 'dataset') {
|
|
389
|
+
return countControlWorkSubsteps(substep.steps ?? []);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return EMPTY_CONTROL_WORK_STATS;
|
|
137
393
|
}
|
|
138
394
|
|
|
139
395
|
function countStepSuiteTools(
|
|
@@ -153,11 +409,8 @@ function countStepSuiteTools(
|
|
|
153
409
|
conditionalChildren.length < childStats.length / 2
|
|
154
410
|
) {
|
|
155
411
|
return childStats.reduce<MapToolStats>(
|
|
156
|
-
(
|
|
157
|
-
|
|
158
|
-
subrequestsSum + subrequests,
|
|
159
|
-
],
|
|
160
|
-
[0, 0],
|
|
412
|
+
(acc, { stats }) => addStats(acc, stats),
|
|
413
|
+
[0, 0, 0, 0, 0],
|
|
161
414
|
);
|
|
162
415
|
}
|
|
163
416
|
|
|
@@ -168,11 +421,8 @@ function countStepSuiteTools(
|
|
|
168
421
|
});
|
|
169
422
|
if (!sameRoot) {
|
|
170
423
|
return childStats.reduce<MapToolStats>(
|
|
171
|
-
(
|
|
172
|
-
|
|
173
|
-
subrequestsSum + subrequests,
|
|
174
|
-
],
|
|
175
|
-
[0, 0],
|
|
424
|
+
(acc, { stats }) => addStats(acc, stats),
|
|
425
|
+
[0, 0, 0, 0, 0],
|
|
176
426
|
);
|
|
177
427
|
}
|
|
178
428
|
|
|
@@ -183,18 +433,12 @@ function countStepSuiteTools(
|
|
|
183
433
|
!(step.type === 'control_flow' && step.kind === 'conditional'),
|
|
184
434
|
)
|
|
185
435
|
.reduce<MapToolStats>(
|
|
186
|
-
(
|
|
187
|
-
|
|
188
|
-
subrequestsSum + subrequests,
|
|
189
|
-
],
|
|
190
|
-
[0, 0],
|
|
436
|
+
(acc, { stats }) => addStats(acc, stats),
|
|
437
|
+
[0, 0, 0, 0, 0],
|
|
191
438
|
);
|
|
192
439
|
const conditionalStats = conditionalChildren.reduce<MapToolStats>(
|
|
193
|
-
(
|
|
194
|
-
|
|
195
|
-
subrequestsSum + subrequests,
|
|
196
|
-
],
|
|
197
|
-
[0, 0],
|
|
440
|
+
(acc, { stats }) => addStats(acc, stats),
|
|
441
|
+
[0, 0, 0, 0, 0],
|
|
198
442
|
);
|
|
199
443
|
|
|
200
444
|
return addStats(unconditionalStats, conditionalStats);
|
|
@@ -203,11 +447,26 @@ function countStepSuiteTools(
|
|
|
203
447
|
function countProducerTools(
|
|
204
448
|
producers: readonly PlayStaticColumnProducer[],
|
|
205
449
|
): MapToolStats {
|
|
206
|
-
let stats: MapToolStats = [0, 0];
|
|
450
|
+
let stats: MapToolStats = [0, 0, 0, 0, 0];
|
|
207
451
|
|
|
208
452
|
for (const producer of producers) {
|
|
209
453
|
if (producer.kind === 'tool' && producer.toolId) {
|
|
210
|
-
stats = addStats(
|
|
454
|
+
stats = addStats(
|
|
455
|
+
stats,
|
|
456
|
+
countTool(producer.toolId, {
|
|
457
|
+
staticSingleBucket: hasStaticSingleBatchBucket({
|
|
458
|
+
toolId: producer.toolId,
|
|
459
|
+
paramsSource:
|
|
460
|
+
producer.substep.type === 'tool'
|
|
461
|
+
? producer.substep.paramsSource
|
|
462
|
+
: undefined,
|
|
463
|
+
sourceText:
|
|
464
|
+
producer.substep.type === 'tool'
|
|
465
|
+
? producer.substep.sourceText
|
|
466
|
+
: undefined,
|
|
467
|
+
}),
|
|
468
|
+
}),
|
|
469
|
+
);
|
|
211
470
|
}
|
|
212
471
|
if (producer.substep.type === 'waterfall') {
|
|
213
472
|
stats = addStats(stats, countToolSubstep(producer.substep));
|
|
@@ -251,17 +510,42 @@ function countMapLocalTools(input: {
|
|
|
251
510
|
);
|
|
252
511
|
if (!dataset) return null;
|
|
253
512
|
|
|
254
|
-
if (dataset.steps?.length)
|
|
255
|
-
return countToolSubsteps(dataset.steps);
|
|
256
|
-
}
|
|
257
|
-
|
|
513
|
+
if (dataset.steps?.length) return countToolSubsteps(dataset.steps);
|
|
258
514
|
if (dataset.columns?.length) {
|
|
259
515
|
return countProducerTools(
|
|
260
516
|
dataset.columns.flatMap((column) => column.producers),
|
|
261
517
|
);
|
|
262
518
|
}
|
|
519
|
+
return [0, 0, 0, 0, 0];
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function countMapLocalControlWork(input: {
|
|
523
|
+
staticPipeline: PlayStaticPipeline | null | undefined;
|
|
524
|
+
planMap: ChunkSizingMap | null | undefined;
|
|
525
|
+
mapName: string;
|
|
526
|
+
}): MapControlWorkStats | null {
|
|
527
|
+
if (!input.staticPipeline || !input.planMap) return null;
|
|
528
|
+
const planMap = input.planMap;
|
|
529
|
+
const dataset = flattenStaticSubsteps(
|
|
530
|
+
getTopLevelPipelineSubsteps(input.staticPipeline),
|
|
531
|
+
).find(
|
|
532
|
+
(substep): substep is Extract<PlayStaticSubstep, { type: 'dataset' }> =>
|
|
533
|
+
substep.type === 'dataset' &&
|
|
534
|
+
datasetBelongsToPlanMap(substep, planMap, input.mapName),
|
|
535
|
+
);
|
|
536
|
+
if (!dataset) return null;
|
|
263
537
|
|
|
264
|
-
return
|
|
538
|
+
if (dataset.steps?.length) return countControlWorkSubsteps(dataset.steps);
|
|
539
|
+
if (dataset.columns?.length) {
|
|
540
|
+
return dataset.columns
|
|
541
|
+
.flatMap((column) => column.producers)
|
|
542
|
+
.reduce<MapControlWorkStats>(
|
|
543
|
+
(acc, producer) =>
|
|
544
|
+
addControlWorkStats(acc, countControlWorkSubstep(producer.substep)),
|
|
545
|
+
EMPTY_CONTROL_WORK_STATS,
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
return EMPTY_CONTROL_WORK_STATS;
|
|
265
549
|
}
|
|
266
550
|
|
|
267
551
|
function countFallbackDeclarationTools(input: {
|
|
@@ -269,7 +553,7 @@ function countFallbackDeclarationTools(input: {
|
|
|
269
553
|
outputFields: readonly string[];
|
|
270
554
|
externalStepFields?: readonly string[];
|
|
271
555
|
}): MapToolStats {
|
|
272
|
-
let stats: MapToolStats = [0, 0];
|
|
556
|
+
let stats: MapToolStats = [0, 0, 0, 0, 0];
|
|
273
557
|
|
|
274
558
|
for (const declaration of input.declarations) {
|
|
275
559
|
if (
|
|
@@ -292,7 +576,7 @@ function countDeclarationTools(
|
|
|
292
576
|
): MapToolStats {
|
|
293
577
|
return declarations.reduce<MapToolStats>(
|
|
294
578
|
(stats, declaration) => addStats(stats, countTool(declaration.toolId)),
|
|
295
|
-
[0, 0],
|
|
579
|
+
[0, 0, 0, 0, 0],
|
|
296
580
|
);
|
|
297
581
|
}
|
|
298
582
|
|
|
@@ -347,6 +631,12 @@ function buildStaticChunkSizingPlan(
|
|
|
347
631
|
export function chooseWorkerMapRowsPerChunk(
|
|
348
632
|
input: WorkerMapChunkPlanInput,
|
|
349
633
|
): number {
|
|
634
|
+
return chooseWorkerMapDispatchPlan(input).rowsPerChunk;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export function chooseWorkerMapDispatchPlan(
|
|
638
|
+
input: WorkerMapChunkPlanInput,
|
|
639
|
+
): WorkerMapDispatchPlan {
|
|
350
640
|
const plan: ChunkSizingPlan | null = input.executionPlan
|
|
351
641
|
? {
|
|
352
642
|
maps: input.executionPlan.maps,
|
|
@@ -365,6 +655,11 @@ export function chooseWorkerMapRowsPerChunk(
|
|
|
365
655
|
planMap,
|
|
366
656
|
mapName: input.mapName,
|
|
367
657
|
});
|
|
658
|
+
const staticMapControlWorkStats = countMapLocalControlWork({
|
|
659
|
+
staticPipeline: input.staticPipeline,
|
|
660
|
+
planMap,
|
|
661
|
+
mapName: input.mapName,
|
|
662
|
+
});
|
|
368
663
|
const mapToolStats =
|
|
369
664
|
staticMapToolStats ??
|
|
370
665
|
(plan && planMap
|
|
@@ -375,42 +670,211 @@ export function chooseWorkerMapRowsPerChunk(
|
|
|
375
670
|
})
|
|
376
671
|
: plan
|
|
377
672
|
? countDeclarationTools(plan.toolDeclarations ?? [])
|
|
378
|
-
: [0, 0]);
|
|
673
|
+
: [0, 0, 0, 0, 0]);
|
|
674
|
+
const estimatedExternalStepsPerRow = estimateExternalStepsForMap({
|
|
675
|
+
planMap,
|
|
676
|
+
mapToolStats,
|
|
677
|
+
});
|
|
678
|
+
const workEstimate = estimateMapWork({
|
|
679
|
+
estimatedExternalStepsPerRow,
|
|
680
|
+
mapToolStats,
|
|
681
|
+
controlWorkStats: staticMapControlWorkStats ?? EMPTY_CONTROL_WORK_STATS,
|
|
682
|
+
});
|
|
683
|
+
const controlSubrequestsPerRow =
|
|
684
|
+
workEstimate.childPlaySubmitsPerRow + workEstimate.eventWaitsPerRow;
|
|
685
|
+
const allProviderCallsAreCoalescedBatchable =
|
|
686
|
+
workEstimate.providerToolCallsPerRow > 0 &&
|
|
687
|
+
workEstimate.unbatchedProviderToolCallsPerRow === 0 &&
|
|
688
|
+
workEstimate.coalescedBatchableProviderToolCallsPerRow >=
|
|
689
|
+
workEstimate.providerToolCallsPerRow &&
|
|
690
|
+
controlSubrequestsPerRow === 0;
|
|
691
|
+
const preferredChunkSize = allProviderCallsAreCoalescedBatchable
|
|
692
|
+
? Math.max(
|
|
693
|
+
planMap?.defaultChunkSize ?? 0,
|
|
694
|
+
EXECUTION_PLAN_DEFAULTS.largeMapChunkSize,
|
|
695
|
+
)
|
|
696
|
+
: planMap?.defaultChunkSize;
|
|
379
697
|
const rowsPerChunk = chooseMapChunkSize({
|
|
380
698
|
totalRows: input.rowCountHint,
|
|
381
699
|
mapCount: Math.max(1, plan?.maps.length ?? 1),
|
|
382
|
-
stepsPerChunk:
|
|
383
|
-
|
|
700
|
+
stepsPerChunk:
|
|
701
|
+
estimatedExternalStepsPerRow > 0
|
|
702
|
+
? Math.max(estimatedExternalStepsPerRow, planMap?.stepsPerChunk ?? 1)
|
|
703
|
+
: 1,
|
|
704
|
+
preferredChunkSize,
|
|
384
705
|
softWorkflowStepBudget: plan?.softWorkflowStepBudget,
|
|
385
706
|
});
|
|
707
|
+
if (estimatedExternalStepsPerRow > 0 || controlSubrequestsPerRow > 0) {
|
|
708
|
+
const subrequestSafeRows = subrequestSafeRowsForMap({
|
|
709
|
+
planMap,
|
|
710
|
+
mapToolStats,
|
|
711
|
+
staticMapToolStats,
|
|
712
|
+
estimatedExternalStepsPerRow,
|
|
713
|
+
workEstimate,
|
|
714
|
+
});
|
|
715
|
+
if (subrequestSafeRows < rowsPerChunk) {
|
|
716
|
+
const externalPressurePlan: WorkerMapDispatchPlan = {
|
|
717
|
+
rowsPerChunk: subrequestSafeRows,
|
|
718
|
+
estimatedExternalStepsPerRow,
|
|
719
|
+
workEstimate,
|
|
720
|
+
reason: 'external-pressure',
|
|
721
|
+
};
|
|
722
|
+
return externalPressurePlan;
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
rowsPerChunk,
|
|
726
|
+
estimatedExternalStepsPerRow,
|
|
727
|
+
workEstimate,
|
|
728
|
+
reason: 'external-pressure',
|
|
729
|
+
};
|
|
730
|
+
}
|
|
386
731
|
|
|
387
|
-
const
|
|
388
|
-
|
|
732
|
+
const toolFreeMap = !!planMap && mapToolStats[0] === 0;
|
|
733
|
+
const toolFreeSimpleMap = toolFreeMap && planMap.stepsPerChunk === 1;
|
|
389
734
|
if (
|
|
390
735
|
toolFreeSimpleMap &&
|
|
391
736
|
(input.rowCountHint === null ||
|
|
392
737
|
input.rowCountHint >= CACHE_ENABLED_SIMPLE_MAP_CHUNK_SIZE)
|
|
393
738
|
) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (mapToolStats[1] > 0) {
|
|
398
|
-
const unbatchedSubrequestsPerRow =
|
|
399
|
-
staticMapToolStats !== null
|
|
400
|
-
? mapToolStats[1]
|
|
401
|
-
: Math.max(
|
|
402
|
-
(planMap?.stepsPerChunk ?? 1) * SUBREQUESTS_PER_UNBATCHED_TOOL_CALL,
|
|
403
|
-
mapToolStats[1],
|
|
404
|
-
);
|
|
405
|
-
const unbatchedToolRowsPerChunk = Math.max(
|
|
406
|
-
1,
|
|
407
|
-
Math.floor(
|
|
408
|
-
UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET /
|
|
409
|
-
unbatchedSubrequestsPerRow,
|
|
410
|
-
),
|
|
739
|
+
const largeRowsPerChunk = Math.max(
|
|
740
|
+
rowsPerChunk,
|
|
741
|
+
CACHE_ENABLED_SIMPLE_MAP_CHUNK_SIZE,
|
|
411
742
|
);
|
|
412
|
-
return
|
|
743
|
+
return {
|
|
744
|
+
rowsPerChunk: largeRowsPerChunk,
|
|
745
|
+
estimatedExternalStepsPerRow: 0,
|
|
746
|
+
workEstimate,
|
|
747
|
+
reason: 'tool-free-large-cache',
|
|
748
|
+
};
|
|
413
749
|
}
|
|
414
750
|
|
|
415
|
-
return
|
|
751
|
+
return {
|
|
752
|
+
rowsPerChunk,
|
|
753
|
+
estimatedExternalStepsPerRow: 0,
|
|
754
|
+
workEstimate,
|
|
755
|
+
reason: toolFreeMap ? 'tool-free-plan' : 'default-plan',
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function estimateMapWork(input: {
|
|
760
|
+
estimatedExternalStepsPerRow: number;
|
|
761
|
+
mapToolStats: MapToolStats;
|
|
762
|
+
controlWorkStats: MapControlWorkStats;
|
|
763
|
+
}): WorkerMapWorkEstimate {
|
|
764
|
+
return {
|
|
765
|
+
cpuRowsPerRow: 1,
|
|
766
|
+
runtimeSheetReadsPerChunk: 1,
|
|
767
|
+
runtimeSheetWritesPerChunk: 1,
|
|
768
|
+
durableReceiptOpsPerRow: input.estimatedExternalStepsPerRow,
|
|
769
|
+
providerToolCallsPerRow: input.mapToolStats[0],
|
|
770
|
+
unbatchedProviderToolCallsPerRow: input.mapToolStats[1],
|
|
771
|
+
assumedBatchSize: assumedBatchSizeFor(input.mapToolStats[3]),
|
|
772
|
+
coalescedBatchableProviderToolCallsPerRow: input.mapToolStats[4],
|
|
773
|
+
childPlaySubmitsPerRow: input.controlWorkStats.childPlaySubmits,
|
|
774
|
+
eventWaitsPerRow: input.controlWorkStats.eventWaits,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function estimateExternalStepsForMap(input: {
|
|
779
|
+
planMap: ChunkSizingMap | undefined;
|
|
780
|
+
mapToolStats: MapToolStats;
|
|
781
|
+
}): number {
|
|
782
|
+
if (!input.planMap) return input.mapToolStats[0];
|
|
783
|
+
const explicitExternalSteps = Array.isArray(input.planMap.externalStepFields)
|
|
784
|
+
? input.planMap.externalStepFields.length
|
|
785
|
+
: 0;
|
|
786
|
+
return Math.max(explicitExternalSteps, input.mapToolStats[0]);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function subrequestSafeRowsForMap(input: {
|
|
790
|
+
planMap: ChunkSizingMap | undefined;
|
|
791
|
+
mapToolStats: MapToolStats;
|
|
792
|
+
staticMapToolStats: MapToolStats | null;
|
|
793
|
+
estimatedExternalStepsPerRow: number;
|
|
794
|
+
workEstimate: WorkerMapWorkEstimate;
|
|
795
|
+
}): number {
|
|
796
|
+
const hasToolWork = input.mapToolStats[0] > 0;
|
|
797
|
+
const unbatchedToolCount = input.mapToolStats[1];
|
|
798
|
+
const unbatchedSubrequestCount = input.mapToolStats[2];
|
|
799
|
+
const controlSubrequestsPerRow =
|
|
800
|
+
input.workEstimate.childPlaySubmitsPerRow +
|
|
801
|
+
input.workEstimate.eventWaitsPerRow;
|
|
802
|
+
const controlRows =
|
|
803
|
+
controlSubrequestsPerRow > 0
|
|
804
|
+
? Math.max(
|
|
805
|
+
1,
|
|
806
|
+
Math.floor(
|
|
807
|
+
(UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET -
|
|
808
|
+
input.workEstimate.runtimeSheetReadsPerChunk -
|
|
809
|
+
input.workEstimate.runtimeSheetWritesPerChunk) /
|
|
810
|
+
controlSubrequestsPerRow,
|
|
811
|
+
),
|
|
812
|
+
)
|
|
813
|
+
: Number.POSITIVE_INFINITY;
|
|
814
|
+
// Largest chunk whose batched tool work stays under the subrequest ceiling.
|
|
815
|
+
// Invert estimateBatchedToolChunkSubrequests. Static planning does not know
|
|
816
|
+
// bucket cardinality, so it assumes worst-case provider fanout (one compiled
|
|
817
|
+
// batch per row per batchable tool call) while keeping durable receipt RPCs
|
|
818
|
+
// fixed per drained tool group.
|
|
819
|
+
const batchableToolRows =
|
|
820
|
+
hasToolWork && unbatchedToolCount <= 0
|
|
821
|
+
? (() => {
|
|
822
|
+
const batchableToolCallsPerRow = input.mapToolStats[0];
|
|
823
|
+
const costForRows = (rows: number) =>
|
|
824
|
+
estimateBatchedToolChunkSubrequests({
|
|
825
|
+
batchableToolCallsPerRow,
|
|
826
|
+
coalescedBatchableToolCallsPerRow:
|
|
827
|
+
input.workEstimate.coalescedBatchableProviderToolCallsPerRow,
|
|
828
|
+
rows,
|
|
829
|
+
assumedBatchSize: input.workEstimate.assumedBatchSize,
|
|
830
|
+
}) +
|
|
831
|
+
input.workEstimate.runtimeSheetReadsPerChunk +
|
|
832
|
+
input.workEstimate.runtimeSheetWritesPerChunk;
|
|
833
|
+
if (costForRows(1) > UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET) {
|
|
834
|
+
return 1;
|
|
835
|
+
}
|
|
836
|
+
let low = 1;
|
|
837
|
+
let high = MAX_BATCHABLE_SUBREQUEST_SAFE_ROWS;
|
|
838
|
+
while (low < high) {
|
|
839
|
+
const mid = Math.ceil((low + high) / 2);
|
|
840
|
+
if (
|
|
841
|
+
costForRows(mid) <= UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET
|
|
842
|
+
) {
|
|
843
|
+
low = mid;
|
|
844
|
+
} else {
|
|
845
|
+
high = mid - 1;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
return low;
|
|
849
|
+
})()
|
|
850
|
+
: Number.POSITIVE_INFINITY;
|
|
851
|
+
if (hasToolWork && unbatchedToolCount <= 0) {
|
|
852
|
+
return Math.min(batchableToolRows, controlRows);
|
|
853
|
+
}
|
|
854
|
+
const genericRows =
|
|
855
|
+
input.estimatedExternalStepsPerRow > 0
|
|
856
|
+
? Math.max(
|
|
857
|
+
1,
|
|
858
|
+
Math.floor(
|
|
859
|
+
WORKER_SUBREQUEST_SAFE_TOOL_CALLS_PER_CHUNK /
|
|
860
|
+
input.estimatedExternalStepsPerRow,
|
|
861
|
+
),
|
|
862
|
+
)
|
|
863
|
+
: Number.POSITIVE_INFINITY;
|
|
864
|
+
if (unbatchedToolCount <= 0) return Math.min(genericRows, controlRows);
|
|
865
|
+
const unbatchedSubrequestsPerRow =
|
|
866
|
+
input.staticMapToolStats !== null
|
|
867
|
+
? unbatchedSubrequestCount
|
|
868
|
+
: Math.max(
|
|
869
|
+
(input.planMap?.stepsPerChunk ?? 1) *
|
|
870
|
+
SUBREQUESTS_PER_UNBATCHED_TOOL_CALL,
|
|
871
|
+
unbatchedSubrequestCount,
|
|
872
|
+
);
|
|
873
|
+
const unbatchedRows = Math.max(
|
|
874
|
+
1,
|
|
875
|
+
Math.floor(
|
|
876
|
+
UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET / unbatchedSubrequestsPerRow,
|
|
877
|
+
),
|
|
878
|
+
);
|
|
879
|
+
return Math.min(unbatchedRows, controlRows);
|
|
416
880
|
}
|