deepline 0.1.171 → 0.1.172
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/README.md +1 -1
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +70 -51
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +46 -61
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +58 -23
- package/dist/cli/index.js +42 -2
- package/dist/cli/index.mjs +42 -2
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -195,7 +195,7 @@ Full sequence from zero to hitting + surviving rate limits via v2 plays.
|
|
|
195
195
|
|
|
196
196
|
```bash
|
|
197
197
|
# Production
|
|
198
|
-
bash <(curl -
|
|
198
|
+
bash <(curl -fsSL https://deepline.com/api/v2/sdk/install)
|
|
199
199
|
|
|
200
200
|
# Local dev (no install needed)
|
|
201
201
|
bun run dev # start server
|
|
@@ -1719,7 +1719,10 @@ class RuntimeReceiptPersistenceError extends Error {
|
|
|
1719
1719
|
function isRuntimeReceiptPersistenceError(error: unknown): boolean {
|
|
1720
1720
|
if (!error || typeof error !== 'object') return false;
|
|
1721
1721
|
if (error instanceof RuntimeReceiptPersistenceError) return true;
|
|
1722
|
-
if (
|
|
1722
|
+
if (
|
|
1723
|
+
error instanceof Error &&
|
|
1724
|
+
error.name === 'RuntimeReceiptPersistenceError'
|
|
1725
|
+
) {
|
|
1723
1726
|
return true;
|
|
1724
1727
|
}
|
|
1725
1728
|
const nestedErrors = (error as { errors?: unknown }).errors;
|
|
@@ -2559,8 +2562,7 @@ class WorkerToolBatchScheduler {
|
|
|
2559
2562
|
{ id: request.id, toolId, input: request.input },
|
|
2560
2563
|
request.workflowStep,
|
|
2561
2564
|
this.callbacks,
|
|
2562
|
-
(retryAfterMs) =>
|
|
2563
|
-
this.reportBackpressure(toolId, retryAfterMs),
|
|
2565
|
+
(retryAfterMs) => this.reportBackpressure(toolId, retryAfterMs),
|
|
2564
2566
|
() => this.governor.chargeBudget('retry'),
|
|
2565
2567
|
toolContract?.retrySafeTransientHttp === true,
|
|
2566
2568
|
this.abortSignal,
|
|
@@ -4559,18 +4561,15 @@ function createMinimalWorkerCtx(
|
|
|
4559
4561
|
if (!workflowStep) {
|
|
4560
4562
|
return await executeWithRuntimeReceipt(name, execute);
|
|
4561
4563
|
}
|
|
4562
|
-
return await executeWithRuntimeReceipt(
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
return deserializeDurableStepValue(serialized) as T;
|
|
4572
|
-
},
|
|
4573
|
-
);
|
|
4564
|
+
return await executeWithRuntimeReceipt(name, async () => {
|
|
4565
|
+
const serialized = await (
|
|
4566
|
+
workflowStep.do as unknown as (
|
|
4567
|
+
name: string,
|
|
4568
|
+
callback: () => Promise<unknown>,
|
|
4569
|
+
) => Promise<unknown>
|
|
4570
|
+
)(name, async () => serializeDurableStepValue(await execute()));
|
|
4571
|
+
return deserializeDurableStepValue(serialized) as T;
|
|
4572
|
+
});
|
|
4574
4573
|
};
|
|
4575
4574
|
const nextCtxStepReceiptKey = (
|
|
4576
4575
|
name: string,
|
|
@@ -4653,7 +4652,6 @@ function createMinimalWorkerCtx(
|
|
|
4653
4652
|
nodeId: mapNodeId,
|
|
4654
4653
|
progress: {
|
|
4655
4654
|
artifactTableNamespace: name,
|
|
4656
|
-
failed: 0,
|
|
4657
4655
|
...progress,
|
|
4658
4656
|
updatedAt: progress.updatedAt ?? nowMs(),
|
|
4659
4657
|
},
|
|
@@ -5037,6 +5035,7 @@ function createMinimalWorkerCtx(
|
|
|
5037
5035
|
{
|
|
5038
5036
|
completed,
|
|
5039
5037
|
total: progressTotalRows,
|
|
5038
|
+
failed: failedExecutedRows,
|
|
5040
5039
|
startedAt: mapStartedAt,
|
|
5041
5040
|
message: formatMapProgressMessage(completed, progressTotalRows),
|
|
5042
5041
|
},
|
|
@@ -5081,7 +5080,7 @@ function createMinimalWorkerCtx(
|
|
|
5081
5080
|
let stepCellsCompleted = 0;
|
|
5082
5081
|
let stepCellsSkipped = 0;
|
|
5083
5082
|
const generatedOutputFields = new Set<string>();
|
|
5084
|
-
const
|
|
5083
|
+
const pendingLiveUpdates: Array<
|
|
5085
5084
|
Omit<PlayRowUpdate, 'rowId'> & { runId?: string }
|
|
5086
5085
|
> = [];
|
|
5087
5086
|
const persistedExecutedIndexes = new Set<number>();
|
|
@@ -5091,9 +5090,9 @@ function createMinimalWorkerCtx(
|
|
|
5091
5090
|
let scheduledPersistTimer: ReturnType<typeof setTimeout> | null = null;
|
|
5092
5091
|
let persistFlushChain: Promise<void> = Promise.resolve();
|
|
5093
5092
|
let persistFailure: unknown = null;
|
|
5094
|
-
let
|
|
5095
|
-
let
|
|
5096
|
-
let
|
|
5093
|
+
let liveUpdateTimer: ReturnType<typeof setTimeout> | null = null;
|
|
5094
|
+
let liveFlushChain: Promise<void> = Promise.resolve();
|
|
5095
|
+
let liveUpdateFailures = 0;
|
|
5097
5096
|
|
|
5098
5097
|
const clearScheduledPersistTimer = () => {
|
|
5099
5098
|
if (scheduledPersistTimer) {
|
|
@@ -5102,10 +5101,10 @@ function createMinimalWorkerCtx(
|
|
|
5102
5101
|
}
|
|
5103
5102
|
};
|
|
5104
5103
|
|
|
5105
|
-
const
|
|
5106
|
-
if (
|
|
5107
|
-
clearTimeout(
|
|
5108
|
-
|
|
5104
|
+
const clearLiveUpdateTimer = () => {
|
|
5105
|
+
if (liveUpdateTimer) {
|
|
5106
|
+
clearTimeout(liveUpdateTimer);
|
|
5107
|
+
liveUpdateTimer = null;
|
|
5109
5108
|
}
|
|
5110
5109
|
};
|
|
5111
5110
|
|
|
@@ -5223,14 +5222,36 @@ function createMinimalWorkerCtx(
|
|
|
5223
5222
|
return task;
|
|
5224
5223
|
};
|
|
5225
5224
|
|
|
5225
|
+
const coalesceLiveUpdates = (
|
|
5226
|
+
updates: Array<Omit<PlayRowUpdate, 'rowId'> & { runId?: string }>,
|
|
5227
|
+
): Array<Omit<PlayRowUpdate, 'rowId'> & { runId?: string }> => {
|
|
5228
|
+
const mergedByKey = new Map<
|
|
5229
|
+
string,
|
|
5230
|
+
Omit<PlayRowUpdate, 'rowId'> & { runId?: string }
|
|
5231
|
+
>();
|
|
5232
|
+
for (const update of updates) {
|
|
5233
|
+
const existing = mergedByKey.get(update.key);
|
|
5234
|
+
mergedByKey.set(update.key, {
|
|
5235
|
+
...existing,
|
|
5236
|
+
...update,
|
|
5237
|
+
dataPatch: { ...existing?.dataPatch, ...update.dataPatch },
|
|
5238
|
+
cellMetaPatch: {
|
|
5239
|
+
...existing?.cellMetaPatch,
|
|
5240
|
+
...update.cellMetaPatch,
|
|
5241
|
+
},
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
return [...mergedByKey.values()];
|
|
5245
|
+
};
|
|
5246
|
+
|
|
5226
5247
|
const flushLiveRowUpdates = (): Promise<void> => {
|
|
5227
|
-
|
|
5228
|
-
if (
|
|
5229
|
-
return
|
|
5248
|
+
clearLiveUpdateTimer();
|
|
5249
|
+
if (pendingLiveUpdates.length === 0) {
|
|
5250
|
+
return liveFlushChain;
|
|
5230
5251
|
}
|
|
5231
|
-
const updates =
|
|
5252
|
+
const updates = coalesceLiveUpdates(pendingLiveUpdates.splice(0));
|
|
5232
5253
|
const extraOutputFields = Array.from(generatedOutputFields);
|
|
5233
|
-
const task =
|
|
5254
|
+
const task = liveFlushChain.then(async () => {
|
|
5234
5255
|
try {
|
|
5235
5256
|
await applyLiveMapRowUpdates({
|
|
5236
5257
|
req,
|
|
@@ -5240,33 +5261,29 @@ function createMinimalWorkerCtx(
|
|
|
5240
5261
|
updates,
|
|
5241
5262
|
});
|
|
5242
5263
|
} catch (error) {
|
|
5243
|
-
|
|
5244
|
-
if (
|
|
5264
|
+
liveUpdateFailures += 1;
|
|
5265
|
+
if (liveUpdateFailures <= MAP_ROW_FAILURE_SAMPLE_LIMIT) {
|
|
5245
5266
|
emitEvent({
|
|
5246
5267
|
type: 'log',
|
|
5247
5268
|
level: 'warn',
|
|
5248
|
-
message:
|
|
5249
|
-
`Live row update flush failed for ctx.dataset("${name}") ` +
|
|
5250
|
-
`(non-fatal; terminal rows still persist): ${formatWorkerRowFailureMessage(error)}`,
|
|
5269
|
+
message: formatWorkerRowFailureMessage(error),
|
|
5251
5270
|
ts: nowMs(),
|
|
5252
5271
|
});
|
|
5253
5272
|
}
|
|
5254
5273
|
}
|
|
5255
5274
|
});
|
|
5256
|
-
|
|
5275
|
+
liveFlushChain = task.catch(() => undefined);
|
|
5257
5276
|
return task;
|
|
5258
5277
|
};
|
|
5259
5278
|
|
|
5260
5279
|
const scheduleLiveRowUpdates = () => {
|
|
5261
|
-
if (
|
|
5262
|
-
pendingLiveRowUpdates.length >= MAP_LIVE_UPDATE_FLUSH_CHUNK_ROWS
|
|
5263
|
-
) {
|
|
5280
|
+
if (pendingLiveUpdates.length >= MAP_LIVE_UPDATE_FLUSH_CHUNK_ROWS) {
|
|
5264
5281
|
void flushLiveRowUpdates().catch(() => undefined);
|
|
5265
5282
|
return;
|
|
5266
5283
|
}
|
|
5267
|
-
if (
|
|
5268
|
-
|
|
5269
|
-
|
|
5284
|
+
if (liveUpdateTimer) return;
|
|
5285
|
+
liveUpdateTimer = setTimeout(() => {
|
|
5286
|
+
liveUpdateTimer = null;
|
|
5270
5287
|
void flushLiveRowUpdates().catch(() => undefined);
|
|
5271
5288
|
}, MAP_INCREMENTAL_PERSIST_INTERVAL_MS);
|
|
5272
5289
|
};
|
|
@@ -5274,10 +5291,8 @@ function createMinimalWorkerCtx(
|
|
|
5274
5291
|
const enqueueLiveRowUpdate = (
|
|
5275
5292
|
update: Omit<PlayRowUpdate, 'rowId'> & { runId?: string },
|
|
5276
5293
|
): Promise<void> => {
|
|
5277
|
-
|
|
5278
|
-
if (
|
|
5279
|
-
pendingLiveRowUpdates.length >= MAP_LIVE_UPDATE_FLUSH_CHUNK_ROWS
|
|
5280
|
-
) {
|
|
5294
|
+
pendingLiveUpdates.push(update);
|
|
5295
|
+
if (pendingLiveUpdates.length >= MAP_LIVE_UPDATE_FLUSH_CHUNK_ROWS) {
|
|
5281
5296
|
void flushLiveRowUpdates().catch(() => undefined);
|
|
5282
5297
|
return Promise.resolve();
|
|
5283
5298
|
}
|
|
@@ -5402,10 +5417,6 @@ function createMinimalWorkerCtx(
|
|
|
5402
5417
|
else stepCellsCompleted += 1;
|
|
5403
5418
|
await enqueueLiveRowUpdate({
|
|
5404
5419
|
key: entry.rowKey,
|
|
5405
|
-
tableNamespace: name,
|
|
5406
|
-
runId: req.runId,
|
|
5407
|
-
status: 'running',
|
|
5408
|
-
stage: stepOutput.stepId,
|
|
5409
5420
|
dataPatch: {
|
|
5410
5421
|
[stepOutput.columnName]: stepOutput.value,
|
|
5411
5422
|
},
|
|
@@ -5436,6 +5447,12 @@ function createMinimalWorkerCtx(
|
|
|
5436
5447
|
completedAt: nowMs(),
|
|
5437
5448
|
};
|
|
5438
5449
|
}
|
|
5450
|
+
if (fieldEntries.length > 1) {
|
|
5451
|
+
await enqueueLiveRowUpdate({
|
|
5452
|
+
key: entry.rowKey,
|
|
5453
|
+
dataPatch: { [key]: resolved.value },
|
|
5454
|
+
});
|
|
5455
|
+
}
|
|
5439
5456
|
activeField = null;
|
|
5440
5457
|
}
|
|
5441
5458
|
for (const stepOutput of stepProgramOutputs) {
|
|
@@ -5612,7 +5629,7 @@ function createMinimalWorkerCtx(
|
|
|
5612
5629
|
});
|
|
5613
5630
|
try {
|
|
5614
5631
|
await flushLiveRowUpdates();
|
|
5615
|
-
await
|
|
5632
|
+
await liveFlushChain;
|
|
5616
5633
|
await enqueuePersistExecutedRows();
|
|
5617
5634
|
await persistFlushChain;
|
|
5618
5635
|
if (persistFailure) throw persistFailure;
|
|
@@ -7864,7 +7881,9 @@ function extractMaxCreditsPerRun(contractSnapshot: unknown): number | null {
|
|
|
7864
7881
|
}
|
|
7865
7882
|
|
|
7866
7883
|
function shouldSkipWorkerComputeBilling(req: RunRequest): boolean {
|
|
7867
|
-
return
|
|
7884
|
+
return (
|
|
7885
|
+
req.integrationMode === 'fixture' || req.integrationMode === 'eval_stub'
|
|
7886
|
+
);
|
|
7868
7887
|
}
|
|
7869
7888
|
|
|
7870
7889
|
async function finalizeWorkerComputeBilling(input: {
|
|
@@ -21,7 +21,6 @@ export const UNBATCHED_TOOL_SUBREQUESTS_PER_CHUNK_BUDGET = 200;
|
|
|
21
21
|
// Fresh unbatched tool calls use one RUNTIME_API integration execute RPC and
|
|
22
22
|
// one HARNESS durable-receipt completion RPC. Batch-cap rows by both.
|
|
23
23
|
export const SUBREQUESTS_PER_UNBATCHED_TOOL_CALL = 2;
|
|
24
|
-
|
|
25
24
|
export type WorkerMapChunkPlanInput = {
|
|
26
25
|
mapName: string;
|
|
27
26
|
rowCountHint: number | null;
|
|
@@ -45,7 +44,7 @@ type ChunkSizingPlan = {
|
|
|
45
44
|
softWorkflowStepBudget?: number | null;
|
|
46
45
|
};
|
|
47
46
|
|
|
48
|
-
type MapToolStats = [totalToolCount: number,
|
|
47
|
+
type MapToolStats = [totalToolCount: number, unbatchedSubrequestCount: number];
|
|
49
48
|
|
|
50
49
|
function fieldRoot(field: string | null | undefined): string {
|
|
51
50
|
return String(field ?? '').split('.', 1)[0] ?? '';
|
|
@@ -70,41 +69,42 @@ function declarationBelongsToMapOutput(
|
|
|
70
69
|
);
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
function
|
|
74
|
-
|
|
72
|
+
function countTool(toolId: string): MapToolStats {
|
|
73
|
+
if (getPlayRuntimeBatchStrategy(toolId) !== null) return [1, 0];
|
|
74
|
+
return [1, toolId === 'test_high_single' ? 5 : 2];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function addStats(
|
|
78
|
+
[total, subrequests]: MapToolStats,
|
|
79
|
+
stats: MapToolStats,
|
|
80
|
+
): MapToolStats {
|
|
81
|
+
return [total + stats[0], subrequests + stats[1]];
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
function countToolSubsteps(
|
|
78
85
|
substeps: readonly PlayStaticSubstep[],
|
|
79
86
|
): MapToolStats {
|
|
80
|
-
let
|
|
81
|
-
let unbatchedToolCount = 0;
|
|
87
|
+
let stats: MapToolStats = [0, 0];
|
|
82
88
|
|
|
83
89
|
for (const substep of substeps) {
|
|
84
|
-
|
|
85
|
-
totalToolCount += nestedTotal;
|
|
86
|
-
unbatchedToolCount += nestedUnbatched;
|
|
90
|
+
stats = addStats(stats, countToolSubstep(substep));
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
return
|
|
93
|
+
return stats;
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
function countToolSubstep(substep: PlayStaticSubstep): MapToolStats {
|
|
93
97
|
if (substep.type === 'tool') {
|
|
94
|
-
return
|
|
98
|
+
return countTool(substep.toolId);
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
if (substep.type === 'waterfall') {
|
|
98
|
-
let
|
|
99
|
-
let unbatchedToolCount = 0;
|
|
102
|
+
let stats: MapToolStats = [0, 0];
|
|
100
103
|
for (const step of substep.steps ?? []) {
|
|
101
104
|
if (!step.toolId) continue;
|
|
102
|
-
|
|
103
|
-
if (isUnbatchedTool(step.toolId)) {
|
|
104
|
-
unbatchedToolCount += 1;
|
|
105
|
-
}
|
|
105
|
+
stats = addStats(stats, countTool(step.toolId));
|
|
106
106
|
}
|
|
107
|
-
return
|
|
107
|
+
return stats;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
if (substep.type === 'step_suite') {
|
|
@@ -117,9 +117,9 @@ function countToolSubstep(substep: PlayStaticSubstep): MapToolStats {
|
|
|
117
117
|
countToolSubsteps(branch.steps),
|
|
118
118
|
);
|
|
119
119
|
return branchStats.reduce<MapToolStats>(
|
|
120
|
-
([totalMax,
|
|
120
|
+
([totalMax, subrequestsMax], [total, subrequests]) => [
|
|
121
121
|
Math.max(totalMax, total),
|
|
122
|
-
Math.max(
|
|
122
|
+
Math.max(subrequestsMax, subrequests),
|
|
123
123
|
],
|
|
124
124
|
[0, 0],
|
|
125
125
|
);
|
|
@@ -151,9 +151,9 @@ function countStepSuiteTools(
|
|
|
151
151
|
conditionalChildren.length < childStats.length / 2
|
|
152
152
|
) {
|
|
153
153
|
return childStats.reduce<MapToolStats>(
|
|
154
|
-
([totalSum,
|
|
154
|
+
([totalSum, subrequestsSum], { stats: [total, subrequests] }) => [
|
|
155
155
|
totalSum + total,
|
|
156
|
-
|
|
156
|
+
subrequestsSum + subrequests,
|
|
157
157
|
],
|
|
158
158
|
[0, 0],
|
|
159
159
|
);
|
|
@@ -166,9 +166,9 @@ function countStepSuiteTools(
|
|
|
166
166
|
});
|
|
167
167
|
if (!sameRoot) {
|
|
168
168
|
return childStats.reduce<MapToolStats>(
|
|
169
|
-
([totalSum,
|
|
169
|
+
([totalSum, subrequestsSum], { stats: [total, subrequests] }) => [
|
|
170
170
|
totalSum + total,
|
|
171
|
-
|
|
171
|
+
subrequestsSum + subrequests,
|
|
172
172
|
],
|
|
173
173
|
[0, 0],
|
|
174
174
|
);
|
|
@@ -181,52 +181,41 @@ function countStepSuiteTools(
|
|
|
181
181
|
!(step.type === 'control_flow' && step.kind === 'conditional'),
|
|
182
182
|
)
|
|
183
183
|
.reduce<MapToolStats>(
|
|
184
|
-
([totalSum,
|
|
184
|
+
([totalSum, subrequestsSum], { stats: [total, subrequests] }) => [
|
|
185
185
|
totalSum + total,
|
|
186
|
-
|
|
186
|
+
subrequestsSum + subrequests,
|
|
187
187
|
],
|
|
188
188
|
[0, 0],
|
|
189
189
|
);
|
|
190
190
|
const conditionalStats = conditionalChildren.reduce<MapToolStats>(
|
|
191
|
-
([totalSum,
|
|
191
|
+
([totalSum, subrequestsSum], { stats: [total, subrequests] }) => [
|
|
192
192
|
totalSum + total,
|
|
193
|
-
|
|
193
|
+
subrequestsSum + subrequests,
|
|
194
194
|
],
|
|
195
195
|
[0, 0],
|
|
196
196
|
);
|
|
197
197
|
|
|
198
|
-
return
|
|
199
|
-
unconditionalStats[0] + conditionalStats[0],
|
|
200
|
-
unconditionalStats[1] + conditionalStats[1],
|
|
201
|
-
];
|
|
198
|
+
return addStats(unconditionalStats, conditionalStats);
|
|
202
199
|
}
|
|
203
200
|
|
|
204
201
|
function countProducerTools(
|
|
205
202
|
producers: readonly PlayStaticColumnProducer[],
|
|
206
203
|
): MapToolStats {
|
|
207
|
-
let
|
|
208
|
-
let unbatchedToolCount = 0;
|
|
204
|
+
let stats: MapToolStats = [0, 0];
|
|
209
205
|
|
|
210
206
|
for (const producer of producers) {
|
|
211
207
|
if (producer.kind === 'tool' && producer.toolId) {
|
|
212
|
-
|
|
213
|
-
if (isUnbatchedTool(producer.toolId)) {
|
|
214
|
-
unbatchedToolCount += 1;
|
|
215
|
-
}
|
|
208
|
+
stats = addStats(stats, countTool(producer.toolId));
|
|
216
209
|
}
|
|
217
210
|
if (producer.substep.type === 'waterfall') {
|
|
218
|
-
|
|
219
|
-
totalToolCount += nestedTotal;
|
|
220
|
-
unbatchedToolCount += nestedUnbatched;
|
|
211
|
+
stats = addStats(stats, countToolSubstep(producer.substep));
|
|
221
212
|
}
|
|
222
213
|
if (producer.steps?.length) {
|
|
223
|
-
|
|
224
|
-
totalToolCount += nestedTotal;
|
|
225
|
-
unbatchedToolCount += nestedUnbatched;
|
|
214
|
+
stats = addStats(stats, countProducerTools(producer.steps));
|
|
226
215
|
}
|
|
227
216
|
}
|
|
228
217
|
|
|
229
|
-
return
|
|
218
|
+
return stats;
|
|
230
219
|
}
|
|
231
220
|
|
|
232
221
|
function datasetBelongsToPlanMap(
|
|
@@ -278,8 +267,7 @@ function countFallbackDeclarationTools(input: {
|
|
|
278
267
|
outputFields: readonly string[];
|
|
279
268
|
externalStepFields?: readonly string[];
|
|
280
269
|
}): MapToolStats {
|
|
281
|
-
let
|
|
282
|
-
let unbatchedToolCount = 0;
|
|
270
|
+
let stats: MapToolStats = [0, 0];
|
|
283
271
|
|
|
284
272
|
for (const declaration of input.declarations) {
|
|
285
273
|
if (
|
|
@@ -291,23 +279,19 @@ function countFallbackDeclarationTools(input: {
|
|
|
291
279
|
) {
|
|
292
280
|
continue;
|
|
293
281
|
}
|
|
294
|
-
|
|
295
|
-
if (isUnbatchedTool(declaration.toolId)) {
|
|
296
|
-
unbatchedToolCount += 1;
|
|
297
|
-
}
|
|
282
|
+
stats = addStats(stats, countTool(declaration.toolId));
|
|
298
283
|
}
|
|
299
284
|
|
|
300
|
-
return
|
|
285
|
+
return stats;
|
|
301
286
|
}
|
|
302
287
|
|
|
303
288
|
function countDeclarationTools(
|
|
304
289
|
declarations: readonly { toolId: string; field?: string | null }[],
|
|
305
290
|
): MapToolStats {
|
|
306
|
-
return
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
];
|
|
291
|
+
return declarations.reduce<MapToolStats>(
|
|
292
|
+
(stats, declaration) => addStats(stats, countTool(declaration.toolId)),
|
|
293
|
+
[0, 0],
|
|
294
|
+
);
|
|
311
295
|
}
|
|
312
296
|
|
|
313
297
|
function countNestedExecutionSteps(
|
|
@@ -409,12 +393,13 @@ export function chooseWorkerMapRowsPerChunk(
|
|
|
409
393
|
}
|
|
410
394
|
|
|
411
395
|
if (mapToolStats[1] > 0) {
|
|
412
|
-
const
|
|
396
|
+
const unbatchedSubrequestsPerRow =
|
|
413
397
|
staticMapToolStats !== null
|
|
414
398
|
? mapToolStats[1]
|
|
415
|
-
: Math.max(
|
|
416
|
-
|
|
417
|
-
|
|
399
|
+
: Math.max(
|
|
400
|
+
(planMap?.stepsPerChunk ?? 1) * SUBREQUESTS_PER_UNBATCHED_TOOL_CALL,
|
|
401
|
+
mapToolStats[1],
|
|
402
|
+
);
|
|
418
403
|
const unbatchedToolRowsPerChunk = Math.max(
|
|
419
404
|
1,
|
|
420
405
|
Math.floor(
|
|
@@ -104,10 +104,10 @@ export const SDK_RELEASE = {
|
|
|
104
104
|
// 0.1.111 ships dataset-native tool list getters and result row datasets.
|
|
105
105
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
106
106
|
// fields shipped in 0.1.153.
|
|
107
|
-
version: '0.1.
|
|
107
|
+
version: '0.1.172',
|
|
108
108
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
109
109
|
supportPolicy: {
|
|
110
|
-
latest: '0.1.
|
|
110
|
+
latest: '0.1.172',
|
|
111
111
|
minimumSupported: '0.1.53',
|
|
112
112
|
deprecatedBelow: '0.1.53',
|
|
113
113
|
commandMinimumSupported: [
|
|
@@ -114,6 +114,9 @@ const RUNTIME_DB_SESSION_ROW_LIMIT_FLOOR = DIRECT_POSTGRES_BATCH_SIZE;
|
|
|
114
114
|
const APPEND_KEY_SUFFIX_LENGTH = 12;
|
|
115
115
|
const RUNTIME_DB_SESSION_TTL_SECONDS = 10 * 60;
|
|
116
116
|
const RUNTIME_SHEET_ENSURE_CACHE_TTL_MS = 10 * 60_000;
|
|
117
|
+
const RUNTIME_SHEET_READY_AFTER_ENSURE_RETRY_DELAYS_MS = [
|
|
118
|
+
100, 250, 500, 1_000, 2_000,
|
|
119
|
+
] as const;
|
|
117
120
|
const RUNTIME_DB_SESSION_RENEWAL_WINDOW_MS = 60_000;
|
|
118
121
|
const RUNTIME_API_RETRY_DELAYS_MS = [
|
|
119
122
|
250, 500, 1_000, 2_000, 4_000, 8_000, 8_000,
|
|
@@ -529,6 +532,41 @@ async function isRuntimeSheetSchemaReady(
|
|
|
529
532
|
}
|
|
530
533
|
}
|
|
531
534
|
|
|
535
|
+
async function waitForRuntimeSheetSchemaReadyAfterEnsure(
|
|
536
|
+
session: RuntimePostgresSession,
|
|
537
|
+
input: {
|
|
538
|
+
sheetContract: PlaySheetContract;
|
|
539
|
+
timings?: RuntimeSheetTiming[];
|
|
540
|
+
},
|
|
541
|
+
): Promise<boolean> {
|
|
542
|
+
for (
|
|
543
|
+
let attempt = 0;
|
|
544
|
+
attempt <= RUNTIME_SHEET_READY_AFTER_ENSURE_RETRY_DELAYS_MS.length;
|
|
545
|
+
attempt += 1
|
|
546
|
+
) {
|
|
547
|
+
const recheckStartedAt = Date.now();
|
|
548
|
+
const ready = await isRuntimeSheetSchemaReady(session, {
|
|
549
|
+
sheetContract: input.sheetContract,
|
|
550
|
+
});
|
|
551
|
+
input.timings?.push({
|
|
552
|
+
phase: 'schema_check_after_preloaded_session_ensure',
|
|
553
|
+
ms: Date.now() - recheckStartedAt,
|
|
554
|
+
ready,
|
|
555
|
+
retried: attempt > 0,
|
|
556
|
+
});
|
|
557
|
+
if (ready) {
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
const delay =
|
|
561
|
+
RUNTIME_SHEET_READY_AFTER_ENSURE_RETRY_DELAYS_MS[attempt] ?? null;
|
|
562
|
+
if (delay === null) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
await sleep(delay);
|
|
566
|
+
}
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
|
|
532
570
|
async function ensureRuntimeSheetForPreloadedSession(
|
|
533
571
|
context: RuntimeApiContext & { playName: string },
|
|
534
572
|
input: {
|
|
@@ -597,38 +635,35 @@ async function ensureRuntimeSheetForPreloadedSession(
|
|
|
597
635
|
return;
|
|
598
636
|
}
|
|
599
637
|
const ensureStartedAt = Date.now();
|
|
600
|
-
const promise =
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
});
|
|
605
|
-
runtimeSheetEnsureCache.set(cacheKey, {
|
|
606
|
-
expiresAt: now + RUNTIME_SHEET_ENSURE_CACHE_TTL_MS,
|
|
607
|
-
promise,
|
|
608
|
-
});
|
|
609
|
-
try {
|
|
610
|
-
await promise;
|
|
611
|
-
input.timings?.push({
|
|
612
|
-
phase: 'ensure_sheet_for_preloaded_session',
|
|
613
|
-
ms: Date.now() - ensureStartedAt,
|
|
614
|
-
});
|
|
615
|
-
const recheckStartedAt = Date.now();
|
|
616
|
-
const readyAfterEnsure = await isRuntimeSheetSchemaReady(input.session, {
|
|
638
|
+
const promise = (async () => {
|
|
639
|
+
await ensureRuntimeSheet(context, {
|
|
640
|
+
playName: context.playName,
|
|
641
|
+
tableNamespace: input.tableNamespace,
|
|
617
642
|
sheetContract: input.sheetContract,
|
|
618
643
|
});
|
|
619
644
|
input.timings?.push({
|
|
620
|
-
phase: '
|
|
621
|
-
ms: Date.now() -
|
|
622
|
-
ready: readyAfterEnsure,
|
|
645
|
+
phase: 'ensure_sheet_for_preloaded_session',
|
|
646
|
+
ms: Date.now() - ensureStartedAt,
|
|
623
647
|
});
|
|
648
|
+
const readyAfterEnsure = await waitForRuntimeSheetSchemaReadyAfterEnsure(
|
|
649
|
+
input.session,
|
|
650
|
+
{
|
|
651
|
+
sheetContract: input.sheetContract,
|
|
652
|
+
timings: input.timings,
|
|
653
|
+
},
|
|
654
|
+
);
|
|
624
655
|
if (!readyAfterEnsure) {
|
|
625
|
-
if (runtimeSheetEnsureCache.get(cacheKey)?.promise === promise) {
|
|
626
|
-
runtimeSheetEnsureCache.delete(cacheKey);
|
|
627
|
-
}
|
|
628
656
|
throw new Error(
|
|
629
657
|
`Runtime sheet schema for ctx.dataset("${input.tableNamespace}") is still not ready after ensure_sheet.`,
|
|
630
658
|
);
|
|
631
659
|
}
|
|
660
|
+
})();
|
|
661
|
+
runtimeSheetEnsureCache.set(cacheKey, {
|
|
662
|
+
expiresAt: now + RUNTIME_SHEET_ENSURE_CACHE_TTL_MS,
|
|
663
|
+
promise,
|
|
664
|
+
});
|
|
665
|
+
try {
|
|
666
|
+
await promise;
|
|
632
667
|
} catch (error) {
|
|
633
668
|
if (runtimeSheetEnsureCache.get(cacheKey)?.promise === promise) {
|
|
634
669
|
runtimeSheetEnsureCache.delete(cacheKey);
|
package/dist/cli/index.js
CHANGED
|
@@ -622,10 +622,10 @@ var SDK_RELEASE = {
|
|
|
622
622
|
// 0.1.111 ships dataset-native tool list getters and result row datasets.
|
|
623
623
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
624
624
|
// fields shipped in 0.1.153.
|
|
625
|
-
version: "0.1.
|
|
625
|
+
version: "0.1.172",
|
|
626
626
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
627
627
|
supportPolicy: {
|
|
628
|
-
latest: "0.1.
|
|
628
|
+
latest: "0.1.172",
|
|
629
629
|
minimumSupported: "0.1.53",
|
|
630
630
|
deprecatedBelow: "0.1.53",
|
|
631
631
|
commandMinimumSupported: [
|
|
@@ -4389,10 +4389,50 @@ end run
|
|
|
4389
4389
|
`;
|
|
4390
4390
|
return runAppleScript(script, [targetUrl, host], runner);
|
|
4391
4391
|
}
|
|
4392
|
+
function hasOnlyHeadlessMacosBrowserInstances(appName, runner = defaultBrowserCommandRunner) {
|
|
4393
|
+
try {
|
|
4394
|
+
const output2 = runner.execFileSync("ps", ["-axo", "args="], {
|
|
4395
|
+
encoding: "utf-8",
|
|
4396
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4397
|
+
});
|
|
4398
|
+
const executableSuffix = `/Contents/MacOS/${appName}`;
|
|
4399
|
+
const lines = String(output2).split(/\r?\n/).map((line) => line.trim()).filter((line) => {
|
|
4400
|
+
const executableIndex = line.indexOf(executableSuffix);
|
|
4401
|
+
if (executableIndex < 0 || !line.includes(".app/Contents/MacOS/")) {
|
|
4402
|
+
return false;
|
|
4403
|
+
}
|
|
4404
|
+
const rest = line.slice(executableIndex + executableSuffix.length);
|
|
4405
|
+
return rest === "" || /^\s+-/.test(rest);
|
|
4406
|
+
});
|
|
4407
|
+
if (lines.length === 0) return false;
|
|
4408
|
+
return lines.every(
|
|
4409
|
+
(line) => line.includes("--headless") || line.includes("--no-startup-window")
|
|
4410
|
+
);
|
|
4411
|
+
} catch {
|
|
4412
|
+
return false;
|
|
4413
|
+
}
|
|
4414
|
+
}
|
|
4415
|
+
function openNewVisibleMacosBrowserInstance(appName, targetUrl, runner = defaultBrowserCommandRunner) {
|
|
4416
|
+
try {
|
|
4417
|
+
runner.execFileSync(
|
|
4418
|
+
"open",
|
|
4419
|
+
["-na", appName, "--args", "--new-window", targetUrl],
|
|
4420
|
+
{
|
|
4421
|
+
stdio: "ignore"
|
|
4422
|
+
}
|
|
4423
|
+
);
|
|
4424
|
+
return true;
|
|
4425
|
+
} catch {
|
|
4426
|
+
return false;
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4392
4429
|
function openUrlMacos(targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
4393
4430
|
const defaultBundleId = readDefaultMacBrowserBundleId(runner);
|
|
4394
4431
|
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
4395
4432
|
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
4433
|
+
if (allowFocus && appName && strategy === "chromium" && hasOnlyHeadlessMacosBrowserInstances(appName, runner) && openNewVisibleMacosBrowserInstance(appName, targetUrl, runner)) {
|
|
4434
|
+
return true;
|
|
4435
|
+
}
|
|
4396
4436
|
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus, runner)) {
|
|
4397
4437
|
return true;
|
|
4398
4438
|
}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -607,10 +607,10 @@ var SDK_RELEASE = {
|
|
|
607
607
|
// 0.1.111 ships dataset-native tool list getters and result row datasets.
|
|
608
608
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
609
609
|
// fields shipped in 0.1.153.
|
|
610
|
-
version: "0.1.
|
|
610
|
+
version: "0.1.172",
|
|
611
611
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
612
612
|
supportPolicy: {
|
|
613
|
-
latest: "0.1.
|
|
613
|
+
latest: "0.1.172",
|
|
614
614
|
minimumSupported: "0.1.53",
|
|
615
615
|
deprecatedBelow: "0.1.53",
|
|
616
616
|
commandMinimumSupported: [
|
|
@@ -4386,10 +4386,50 @@ end run
|
|
|
4386
4386
|
`;
|
|
4387
4387
|
return runAppleScript(script, [targetUrl, host], runner);
|
|
4388
4388
|
}
|
|
4389
|
+
function hasOnlyHeadlessMacosBrowserInstances(appName, runner = defaultBrowserCommandRunner) {
|
|
4390
|
+
try {
|
|
4391
|
+
const output2 = runner.execFileSync("ps", ["-axo", "args="], {
|
|
4392
|
+
encoding: "utf-8",
|
|
4393
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4394
|
+
});
|
|
4395
|
+
const executableSuffix = `/Contents/MacOS/${appName}`;
|
|
4396
|
+
const lines = String(output2).split(/\r?\n/).map((line) => line.trim()).filter((line) => {
|
|
4397
|
+
const executableIndex = line.indexOf(executableSuffix);
|
|
4398
|
+
if (executableIndex < 0 || !line.includes(".app/Contents/MacOS/")) {
|
|
4399
|
+
return false;
|
|
4400
|
+
}
|
|
4401
|
+
const rest = line.slice(executableIndex + executableSuffix.length);
|
|
4402
|
+
return rest === "" || /^\s+-/.test(rest);
|
|
4403
|
+
});
|
|
4404
|
+
if (lines.length === 0) return false;
|
|
4405
|
+
return lines.every(
|
|
4406
|
+
(line) => line.includes("--headless") || line.includes("--no-startup-window")
|
|
4407
|
+
);
|
|
4408
|
+
} catch {
|
|
4409
|
+
return false;
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
function openNewVisibleMacosBrowserInstance(appName, targetUrl, runner = defaultBrowserCommandRunner) {
|
|
4413
|
+
try {
|
|
4414
|
+
runner.execFileSync(
|
|
4415
|
+
"open",
|
|
4416
|
+
["-na", appName, "--args", "--new-window", targetUrl],
|
|
4417
|
+
{
|
|
4418
|
+
stdio: "ignore"
|
|
4419
|
+
}
|
|
4420
|
+
);
|
|
4421
|
+
return true;
|
|
4422
|
+
} catch {
|
|
4423
|
+
return false;
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4389
4426
|
function openUrlMacos(targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
4390
4427
|
const defaultBundleId = readDefaultMacBrowserBundleId(runner);
|
|
4391
4428
|
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
4392
4429
|
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
4430
|
+
if (allowFocus && appName && strategy === "chromium" && hasOnlyHeadlessMacosBrowserInstances(appName, runner) && openNewVisibleMacosBrowserInstance(appName, targetUrl, runner)) {
|
|
4431
|
+
return true;
|
|
4432
|
+
}
|
|
4393
4433
|
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus, runner)) {
|
|
4394
4434
|
return true;
|
|
4395
4435
|
}
|
package/dist/index.js
CHANGED
|
@@ -421,10 +421,10 @@ var SDK_RELEASE = {
|
|
|
421
421
|
// 0.1.111 ships dataset-native tool list getters and result row datasets.
|
|
422
422
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
423
423
|
// fields shipped in 0.1.153.
|
|
424
|
-
version: "0.1.
|
|
424
|
+
version: "0.1.172",
|
|
425
425
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
426
426
|
supportPolicy: {
|
|
427
|
-
latest: "0.1.
|
|
427
|
+
latest: "0.1.172",
|
|
428
428
|
minimumSupported: "0.1.53",
|
|
429
429
|
deprecatedBelow: "0.1.53",
|
|
430
430
|
commandMinimumSupported: [
|
package/dist/index.mjs
CHANGED
|
@@ -351,10 +351,10 @@ var SDK_RELEASE = {
|
|
|
351
351
|
// 0.1.111 ships dataset-native tool list getters and result row datasets.
|
|
352
352
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
353
353
|
// fields shipped in 0.1.153.
|
|
354
|
-
version: "0.1.
|
|
354
|
+
version: "0.1.172",
|
|
355
355
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
356
356
|
supportPolicy: {
|
|
357
|
-
latest: "0.1.
|
|
357
|
+
latest: "0.1.172",
|
|
358
358
|
minimumSupported: "0.1.53",
|
|
359
359
|
deprecatedBelow: "0.1.53",
|
|
360
360
|
commandMinimumSupported: [
|