deepline 0.1.130 → 0.1.132
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/entry.ts +163 -97
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +22 -12
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +30 -23
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +277 -100
- package/dist/cli/index.js +51 -13
- package/dist/cli/index.mjs +51 -13
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -168,6 +168,9 @@ const MAP_FRAME_FLUSH_ROW_INTERVAL = 100;
|
|
|
168
168
|
/** Executed-row sheet persistence chunking: rows AND bytes, whichever first. */
|
|
169
169
|
const MAP_PERSIST_CHUNK_ROWS = 2_000;
|
|
170
170
|
const MAP_PERSIST_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
171
|
+
const MAP_INCREMENTAL_PERSIST_CHUNK_ROWS = 100;
|
|
172
|
+
const MAP_INCREMENTAL_PERSIST_CHUNK_BYTES = 1 * 1024 * 1024;
|
|
173
|
+
const MAP_INCREMENTAL_PERSIST_INTERVAL_MS = 100;
|
|
171
174
|
const MAP_FRAME_FLUSH_INTERVAL_MS = 250;
|
|
172
175
|
const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
|
|
173
176
|
const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
@@ -219,11 +222,143 @@ function comparePersistableMapRowsByInputIndex(
|
|
|
219
222
|
return leftIndex - rightIndex;
|
|
220
223
|
}
|
|
221
224
|
|
|
225
|
+
function persistableMapRowIdentity(row: PersistableMapRow): string | null {
|
|
226
|
+
if (row.key) return `key:${row.key}`;
|
|
227
|
+
return typeof row.inputIndex === 'number' && Number.isFinite(row.inputIndex)
|
|
228
|
+
? `index:${Math.floor(row.inputIndex)}`
|
|
229
|
+
: null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function persistableMapRowBytes(row: PersistableMapRow): number {
|
|
233
|
+
return JSON.stringify(row).length;
|
|
234
|
+
}
|
|
235
|
+
|
|
222
236
|
type FieldMapRunResult = {
|
|
223
237
|
completedRows: PersistableMapRow[];
|
|
224
238
|
failedRows: PersistableMapRow[];
|
|
225
239
|
};
|
|
226
240
|
|
|
241
|
+
type IncrementalMapRowPersistence = {
|
|
242
|
+
persistRows: (rows: PersistableMapRow[]) => Promise<void>;
|
|
243
|
+
isPersisted: (row: PersistableMapRow) => boolean;
|
|
244
|
+
flush: () => Promise<void>;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
function createIncrementalMapRowPersistence(
|
|
248
|
+
persistRows: (rows: PersistableMapRow[]) => Promise<void>,
|
|
249
|
+
): IncrementalMapRowPersistence {
|
|
250
|
+
const persisted = new Set<string>();
|
|
251
|
+
const queued = new Set<string>();
|
|
252
|
+
let pendingRows: PersistableMapRow[] = [];
|
|
253
|
+
let pendingBytes = 0;
|
|
254
|
+
let pendingResolvers: Array<{
|
|
255
|
+
resolve: () => void;
|
|
256
|
+
reject: (error: unknown) => void;
|
|
257
|
+
}> = [];
|
|
258
|
+
let scheduledTimer: ReturnType<typeof setTimeout> | null = null;
|
|
259
|
+
let flushChain: Promise<void> = Promise.resolve();
|
|
260
|
+
|
|
261
|
+
const clearScheduledTimer = (): void => {
|
|
262
|
+
if (scheduledTimer) {
|
|
263
|
+
clearTimeout(scheduledTimer);
|
|
264
|
+
scheduledTimer = null;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const flushPendingRows = (): Promise<void> => {
|
|
269
|
+
clearScheduledTimer();
|
|
270
|
+
const rows = pendingRows;
|
|
271
|
+
const resolvers = pendingResolvers;
|
|
272
|
+
pendingRows = [];
|
|
273
|
+
pendingBytes = 0;
|
|
274
|
+
pendingResolvers = [];
|
|
275
|
+
if (rows.length === 0) {
|
|
276
|
+
resolvers.forEach(({ resolve }) => resolve());
|
|
277
|
+
return flushChain;
|
|
278
|
+
}
|
|
279
|
+
flushChain = flushChain
|
|
280
|
+
.then(async () => {
|
|
281
|
+
await persistRows(rows);
|
|
282
|
+
for (const row of rows) {
|
|
283
|
+
const identity = persistableMapRowIdentity(row);
|
|
284
|
+
if (identity) {
|
|
285
|
+
persisted.add(identity);
|
|
286
|
+
queued.delete(identity);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
.then(
|
|
291
|
+
() => {
|
|
292
|
+
resolvers.forEach(({ resolve }) => resolve());
|
|
293
|
+
},
|
|
294
|
+
(error) => {
|
|
295
|
+
for (const row of rows) {
|
|
296
|
+
const identity = persistableMapRowIdentity(row);
|
|
297
|
+
if (identity) queued.delete(identity);
|
|
298
|
+
}
|
|
299
|
+
resolvers.forEach(({ reject }) => reject(error));
|
|
300
|
+
throw error;
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
return flushChain;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const scheduleFlush = (): void => {
|
|
307
|
+
if (scheduledTimer) return;
|
|
308
|
+
scheduledTimer = setTimeout(() => {
|
|
309
|
+
scheduledTimer = null;
|
|
310
|
+
void flushPendingRows().catch(() => {
|
|
311
|
+
// Each queued caller is rejected by flushPendingRows; this scheduled
|
|
312
|
+
// fire-and-forget path must not create a second unhandled rejection.
|
|
313
|
+
});
|
|
314
|
+
}, MAP_INCREMENTAL_PERSIST_INTERVAL_MS);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
persistRows: async (rows) => {
|
|
319
|
+
const freshRows: PersistableMapRow[] = [];
|
|
320
|
+
for (const row of rows) {
|
|
321
|
+
const identity = persistableMapRowIdentity(row);
|
|
322
|
+
if (identity && (persisted.has(identity) || queued.has(identity))) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (identity) queued.add(identity);
|
|
326
|
+
freshRows.push(row);
|
|
327
|
+
}
|
|
328
|
+
if (freshRows.length === 0) return;
|
|
329
|
+
await new Promise<void>((resolve, reject) => {
|
|
330
|
+
pendingRows.push(...freshRows);
|
|
331
|
+
pendingBytes += freshRows.reduce(
|
|
332
|
+
(total, row) => total + persistableMapRowBytes(row),
|
|
333
|
+
0,
|
|
334
|
+
);
|
|
335
|
+
pendingResolvers.push({ resolve, reject });
|
|
336
|
+
if (
|
|
337
|
+
pendingRows.length >= MAP_INCREMENTAL_PERSIST_CHUNK_ROWS ||
|
|
338
|
+
pendingBytes >= MAP_INCREMENTAL_PERSIST_CHUNK_BYTES
|
|
339
|
+
) {
|
|
340
|
+
void flushPendingRows().catch(() => {
|
|
341
|
+
// Each queued caller is rejected by flushPendingRows.
|
|
342
|
+
});
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
scheduleFlush();
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
isPersisted: (row) => {
|
|
349
|
+
const identity = persistableMapRowIdentity(row);
|
|
350
|
+
return identity ? persisted.has(identity) : false;
|
|
351
|
+
},
|
|
352
|
+
flush: async () => {
|
|
353
|
+
if (pendingRows.length > 0) {
|
|
354
|
+
clearScheduledTimer();
|
|
355
|
+
await flushPendingRows();
|
|
356
|
+
}
|
|
357
|
+
await flushChain;
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
227
362
|
class FailFastMapRowsError extends Error {
|
|
228
363
|
readonly completedRows: PersistableMapRow[];
|
|
229
364
|
readonly failedRows: PersistableMapRow[];
|
|
@@ -1819,6 +1954,7 @@ export class PlayContextImpl {
|
|
|
1819
1954
|
let totalInputCount = 0;
|
|
1820
1955
|
let rawItems: Record<string, unknown>[] = [];
|
|
1821
1956
|
let itemsToProcess: Array<Record<string, unknown>> = [];
|
|
1957
|
+
let itemOriginalIndexes: number[] = [];
|
|
1822
1958
|
let completedItemsByKey: Map<string, Record<string, unknown>> | null = null;
|
|
1823
1959
|
const datasetColumnNames = Object.keys(input);
|
|
1824
1960
|
const stripFieldOutputs = (row: Record<string, unknown>) => {
|
|
@@ -1923,6 +2059,7 @@ export class PlayContextImpl {
|
|
|
1923
2059
|
itemsToProcess = materializedItems.map((item) =>
|
|
1924
2060
|
this.toOutputRow(item as Record<string, unknown>),
|
|
1925
2061
|
);
|
|
2062
|
+
itemOriginalIndexes = materializedItems.map((_item, index) => index);
|
|
1926
2063
|
if (this.#options.onMapStart) {
|
|
1927
2064
|
const shouldPassRowKey = explicitKeyResolver != null;
|
|
1928
2065
|
// toSerializableCsvAliasedRow (not a plain spread): projected CSV
|
|
@@ -1968,7 +2105,7 @@ export class PlayContextImpl {
|
|
|
1968
2105
|
const rowKey = persistedRowIdentity(row, index);
|
|
1969
2106
|
if (rowKey) pendingRowsByKey.set(rowKey, row);
|
|
1970
2107
|
}
|
|
1971
|
-
|
|
2108
|
+
const pendingItems = materializedItems
|
|
1972
2109
|
.map((item, index) => ({
|
|
1973
2110
|
row: this.toOutputRow(item as Record<string, unknown>),
|
|
1974
2111
|
index,
|
|
@@ -1981,8 +2118,13 @@ export class PlayContextImpl {
|
|
|
1981
2118
|
// the sheet round-trip. Merge the persisted data/meta over the
|
|
1982
2119
|
// in-memory row so key functions and column resolvers keep seeing
|
|
1983
2120
|
// projected aliases.
|
|
1984
|
-
return
|
|
2121
|
+
return {
|
|
2122
|
+
row: persisted ? cloneCsvAliasedRow(row, persisted) : row,
|
|
2123
|
+
index,
|
|
2124
|
+
};
|
|
1985
2125
|
});
|
|
2126
|
+
itemsToProcess = pendingItems.map((item) => item.row);
|
|
2127
|
+
itemOriginalIndexes = pendingItems.map((item) => item.index);
|
|
1986
2128
|
if (mapStartResult.completedRows.length > 0) {
|
|
1987
2129
|
completedItemsByKey = new Map();
|
|
1988
2130
|
for (
|
|
@@ -2008,7 +2150,7 @@ export class PlayContextImpl {
|
|
|
2008
2150
|
const completedRowKeys =
|
|
2009
2151
|
completedItemsByKey != null ? [...completedItemsByKey.keys()] : [];
|
|
2010
2152
|
const pendingRowKeys = itemsToProcess.map((item, index) =>
|
|
2011
|
-
rowIdentity(this.toOutputRow(item), index),
|
|
2153
|
+
rowIdentity(this.toOutputRow(item), itemOriginalIndexes[index] ?? index),
|
|
2012
2154
|
);
|
|
2013
2155
|
this.setMapFrame({
|
|
2014
2156
|
mapInvocationId: mapScope.mapInvocationId,
|
|
@@ -2040,9 +2182,10 @@ export class PlayContextImpl {
|
|
|
2040
2182
|
>();
|
|
2041
2183
|
for (let index = 0; index < itemsToProcess.length; index += 1) {
|
|
2042
2184
|
const row = itemsToProcess[index]!;
|
|
2043
|
-
const
|
|
2185
|
+
const originalIndex = itemOriginalIndexes[index] ?? index;
|
|
2186
|
+
const rowKey = rowIdentity(row, originalIndex);
|
|
2044
2187
|
if (!rowsToExecuteByKey.has(rowKey)) {
|
|
2045
|
-
rowsToExecuteByKey.set(rowKey, { row, originalIndex
|
|
2188
|
+
rowsToExecuteByKey.set(rowKey, { row, originalIndex });
|
|
2046
2189
|
}
|
|
2047
2190
|
}
|
|
2048
2191
|
const rowsToExecuteEntries = [...rowsToExecuteByKey.entries()].map(
|
|
@@ -2090,6 +2233,9 @@ export class PlayContextImpl {
|
|
|
2090
2233
|
}
|
|
2091
2234
|
await flushChunk();
|
|
2092
2235
|
};
|
|
2236
|
+
const incrementalPersistence = this.#options.onMapRowsCompleted
|
|
2237
|
+
? createIncrementalMapRowPersistence(persistMapRows)
|
|
2238
|
+
: null;
|
|
2093
2239
|
|
|
2094
2240
|
let mapResult: FieldMapRunResult;
|
|
2095
2241
|
try {
|
|
@@ -2108,6 +2254,7 @@ export class PlayContextImpl {
|
|
|
2108
2254
|
executionRowIndexes: rowsToExecuteEntries.map(
|
|
2109
2255
|
(entry) => entry.originalIndex,
|
|
2110
2256
|
),
|
|
2257
|
+
incrementalPersistence,
|
|
2111
2258
|
},
|
|
2112
2259
|
);
|
|
2113
2260
|
} catch (error) {
|
|
@@ -2116,11 +2263,17 @@ export class PlayContextImpl {
|
|
|
2116
2263
|
error.completedRows.length > 0
|
|
2117
2264
|
? error.completedRows
|
|
2118
2265
|
: error.failedRows;
|
|
2266
|
+
await incrementalPersistence?.flush();
|
|
2267
|
+
const unpersistedRows = incrementalPersistence
|
|
2268
|
+
? rowsToPersist.filter(
|
|
2269
|
+
(row) => !incrementalPersistence.isPersisted(row),
|
|
2270
|
+
)
|
|
2271
|
+
: rowsToPersist;
|
|
2119
2272
|
const persistStartedAt = Date.now();
|
|
2120
|
-
await persistMapRows(
|
|
2121
|
-
if (
|
|
2273
|
+
await persistMapRows(unpersistedRows);
|
|
2274
|
+
if (unpersistedRows.length > 0) {
|
|
2122
2275
|
this.log(
|
|
2123
|
-
`Persisted ${
|
|
2276
|
+
`Persisted ${unpersistedRows.length} fail-fast rows to sheet ${resolvedTableNamespace} in ${Date.now() - persistStartedAt}ms`,
|
|
2124
2277
|
);
|
|
2125
2278
|
}
|
|
2126
2279
|
this.activeMapCellMeta = null;
|
|
@@ -2164,9 +2317,11 @@ export class PlayContextImpl {
|
|
|
2164
2317
|
// source of truth, not this in-memory results array. Chunked by rows AND
|
|
2165
2318
|
// bytes so large cells (scraped pages) never produce oversized writes.
|
|
2166
2319
|
if (resultsByKey.size > 0 || mapResult.failedRows.length > 0) {
|
|
2320
|
+
await incrementalPersistence?.flush();
|
|
2167
2321
|
const mapCellMeta = this.activeMapCellMeta;
|
|
2168
2322
|
const persistRows: PersistableMapRow[] = [];
|
|
2169
2323
|
for (const row of mapResult.completedRows) {
|
|
2324
|
+
if (incrementalPersistence?.isPersisted(row)) continue;
|
|
2170
2325
|
const rowKey = row.key;
|
|
2171
2326
|
const meta = mapCellMeta?.get(rowKey);
|
|
2172
2327
|
persistRows.push({
|
|
@@ -2178,12 +2333,18 @@ export class PlayContextImpl {
|
|
|
2178
2333
|
},
|
|
2179
2334
|
});
|
|
2180
2335
|
}
|
|
2181
|
-
persistRows.push(
|
|
2336
|
+
persistRows.push(
|
|
2337
|
+
...mapResult.failedRows.filter(
|
|
2338
|
+
(row) => !incrementalPersistence?.isPersisted(row),
|
|
2339
|
+
),
|
|
2340
|
+
);
|
|
2182
2341
|
const persistStartedAt = Date.now();
|
|
2183
2342
|
await persistMapRows(persistRows);
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2343
|
+
if (persistRows.length > 0) {
|
|
2344
|
+
this.log(
|
|
2345
|
+
`Persisted ${persistRows.length} executed rows to sheet ${resolvedTableNamespace} in ${Date.now() - persistStartedAt}ms`,
|
|
2346
|
+
);
|
|
2347
|
+
}
|
|
2187
2348
|
}
|
|
2188
2349
|
this.activeMapCellMeta = null;
|
|
2189
2350
|
|
|
@@ -2255,6 +2416,7 @@ export class PlayContextImpl {
|
|
|
2255
2416
|
* want to throttle a wide map.
|
|
2256
2417
|
*/
|
|
2257
2418
|
concurrency?: number;
|
|
2419
|
+
incrementalPersistence?: IncrementalMapRowPersistence | null;
|
|
2258
2420
|
},
|
|
2259
2421
|
): Promise<FieldMapRunResult> {
|
|
2260
2422
|
const fieldEntries = Object.entries(definition);
|
|
@@ -2299,6 +2461,14 @@ export class PlayContextImpl {
|
|
|
2299
2461
|
const failFastOnRowError = runtimeOptions?.onRowError === 'fail';
|
|
2300
2462
|
const completedRowsToPersist: PersistableMapRow[] = [];
|
|
2301
2463
|
const failedRowsToPersist: PersistableMapRow[] = [];
|
|
2464
|
+
const incrementalPersistence =
|
|
2465
|
+
runtimeOptions?.incrementalPersistence ?? null;
|
|
2466
|
+
const enqueueIncrementalPersist = (row: PersistableMapRow): void => {
|
|
2467
|
+
void incrementalPersistence?.persistRows([row]).catch(() => {
|
|
2468
|
+
// The final map-level flush awaits the same chain and surfaces the
|
|
2469
|
+
// persistence failure loudly without holding a completed row slot open.
|
|
2470
|
+
});
|
|
2471
|
+
};
|
|
2302
2472
|
|
|
2303
2473
|
if (completedRows > 0 || pendingRows !== totalRows) {
|
|
2304
2474
|
this.log(
|
|
@@ -2605,7 +2775,7 @@ export class PlayContextImpl {
|
|
|
2605
2775
|
: {},
|
|
2606
2776
|
});
|
|
2607
2777
|
if (failFastOnRowError) {
|
|
2608
|
-
|
|
2778
|
+
const failedRow: PersistableMapRow = {
|
|
2609
2779
|
key: rowKey,
|
|
2610
2780
|
inputIndex: rowIndex,
|
|
2611
2781
|
data: this.toPersistedOutputRow(
|
|
@@ -2616,21 +2786,23 @@ export class PlayContextImpl {
|
|
|
2616
2786
|
: {}),
|
|
2617
2787
|
status: 'failed',
|
|
2618
2788
|
error: formattedError,
|
|
2619
|
-
}
|
|
2789
|
+
};
|
|
2790
|
+
failedRowsToPersist.push(failedRow);
|
|
2620
2791
|
throw error;
|
|
2621
2792
|
}
|
|
2622
2793
|
const failedData = this.toPersistedOutputRow(
|
|
2623
2794
|
cloneCsvAliasedRow(baseRow, computedFields),
|
|
2624
2795
|
);
|
|
2625
2796
|
const cellMetaPatch = this.activeMapCellMeta?.get(rowKey);
|
|
2626
|
-
|
|
2797
|
+
const failedRow: PersistableMapRow = {
|
|
2627
2798
|
key: rowKey,
|
|
2628
2799
|
inputIndex: rowIndex,
|
|
2629
2800
|
data: failedData,
|
|
2630
2801
|
...(cellMetaPatch ? { cellMetaPatch } : {}),
|
|
2631
2802
|
status: 'failed',
|
|
2632
2803
|
error: formattedError,
|
|
2633
|
-
}
|
|
2804
|
+
};
|
|
2805
|
+
failedRowsToPersist.push(failedRow);
|
|
2634
2806
|
updateMapFrameProgress({
|
|
2635
2807
|
failedRowKey: rowKey,
|
|
2636
2808
|
});
|
|
@@ -2642,6 +2814,7 @@ export class PlayContextImpl {
|
|
|
2642
2814
|
error: formattedError,
|
|
2643
2815
|
dataPatch: {},
|
|
2644
2816
|
});
|
|
2817
|
+
enqueueIncrementalPersist(failedRow);
|
|
2645
2818
|
return FAILED_ROW;
|
|
2646
2819
|
}
|
|
2647
2820
|
const cellValue = this.serializeCellValue(value);
|
|
@@ -2682,14 +2855,16 @@ export class PlayContextImpl {
|
|
|
2682
2855
|
dataPatch: {},
|
|
2683
2856
|
});
|
|
2684
2857
|
const publicRow = this.toPublicOutputRow(merged);
|
|
2685
|
-
|
|
2858
|
+
const completedRow: PersistableMapRow = {
|
|
2686
2859
|
key: rowKey,
|
|
2687
2860
|
inputIndex: rowIndex,
|
|
2688
2861
|
data: this.toPersistedOutputRow(merged),
|
|
2689
2862
|
...(this.activeMapCellMeta?.get(rowKey)
|
|
2690
2863
|
? { cellMetaPatch: this.activeMapCellMeta.get(rowKey) }
|
|
2691
2864
|
: {}),
|
|
2692
|
-
}
|
|
2865
|
+
};
|
|
2866
|
+
completedRowsToPersist.push(completedRow);
|
|
2867
|
+
enqueueIncrementalPersist(completedRow);
|
|
2693
2868
|
return publicRow;
|
|
2694
2869
|
} catch (error) {
|
|
2695
2870
|
if (isPlayRowExecutionSuspendedError(error)) {
|
|
@@ -2807,6 +2982,7 @@ export class PlayContextImpl {
|
|
|
2807
2982
|
).values(),
|
|
2808
2983
|
];
|
|
2809
2984
|
this.pendingRowEventBoundaries = [];
|
|
2985
|
+
await incrementalPersistence?.flush();
|
|
2810
2986
|
this.#options.onBatchComplete?.(this.checkpoint);
|
|
2811
2987
|
throw new PlayExecutionSuspendedError({
|
|
2812
2988
|
kind: 'integration_event_batch',
|
|
@@ -4960,7 +5136,42 @@ export class PlayContextImpl {
|
|
|
4960
5136
|
[...byTool.entries()].map(async ([toolId, requests]) => {
|
|
4961
5137
|
this.log(`Executing tool batch ${toolId}: ${requests.length} calls`);
|
|
4962
5138
|
|
|
5139
|
+
const recordToolStep = (stepRequests: ToolCallRequest[]): void => {
|
|
5140
|
+
if (stepRequests.length === 0) return;
|
|
5141
|
+
const stepResults: PlayStepRowResult[] = stepRequests.map((req) => {
|
|
5142
|
+
const cachedResult = this.getCachedToolResult(
|
|
5143
|
+
toolId,
|
|
5144
|
+
this.buildToolResultCacheKey({
|
|
5145
|
+
rowId: req.rowId,
|
|
5146
|
+
tableNamespace: req.tableNamespace,
|
|
5147
|
+
rowKey: req.rowKey ?? undefined,
|
|
5148
|
+
callId: req.callId,
|
|
5149
|
+
}),
|
|
5150
|
+
);
|
|
5151
|
+
return {
|
|
5152
|
+
rowId: req.rowId,
|
|
5153
|
+
status: cachedResult?.result != null ? 'completed' : 'failed',
|
|
5154
|
+
success: cachedResult?.result != null,
|
|
5155
|
+
value: cachedResult?.result,
|
|
5156
|
+
error: cachedResult?.result != null ? null : 'Tool call failed',
|
|
5157
|
+
};
|
|
5158
|
+
});
|
|
5159
|
+
const toolStep = {
|
|
5160
|
+
type: 'tool' as const,
|
|
5161
|
+
toolId,
|
|
5162
|
+
// Keep the step trace preview-sized for large map pages.
|
|
5163
|
+
results: compactRowResultsPreview(stepResults),
|
|
5164
|
+
description: normalizeStepDescription(stepRequests[0]?.description),
|
|
5165
|
+
};
|
|
5166
|
+
if (this.activeDatasetStep) {
|
|
5167
|
+
this.activeDatasetStep.substeps.push(toolStep);
|
|
5168
|
+
} else {
|
|
5169
|
+
this.steps.push(toolStep);
|
|
5170
|
+
}
|
|
5171
|
+
};
|
|
5172
|
+
|
|
4963
5173
|
const pendingRequests: ToolCallRequest[] = [];
|
|
5174
|
+
const recoveredRequests: ToolCallRequest[] = [];
|
|
4964
5175
|
for (const req of requests) {
|
|
4965
5176
|
const cached = this.getCachedToolResult(
|
|
4966
5177
|
toolId,
|
|
@@ -4978,10 +5189,12 @@ export class PlayContextImpl {
|
|
|
4978
5189
|
resolver.resolve(cached.result);
|
|
4979
5190
|
this.toolCallResolvers.delete(req.callId);
|
|
4980
5191
|
}
|
|
5192
|
+
recoveredRequests.push(req);
|
|
4981
5193
|
} else {
|
|
4982
5194
|
pendingRequests.push(req);
|
|
4983
5195
|
}
|
|
4984
5196
|
}
|
|
5197
|
+
recordToolStep(recoveredRequests);
|
|
4985
5198
|
|
|
4986
5199
|
if (pendingRequests.length > 0) {
|
|
4987
5200
|
const strategy =
|
|
@@ -5001,49 +5214,47 @@ export class PlayContextImpl {
|
|
|
5001
5214
|
4,
|
|
5002
5215
|
)
|
|
5003
5216
|
: 4;
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
chunk.map((batch) =>
|
|
5012
|
-
this.callToolAPI(batch.batchOperation, batch.batchPayload),
|
|
5217
|
+
await executeChunkedRequests({
|
|
5218
|
+
requests: compiledBatches,
|
|
5219
|
+
batchSize,
|
|
5220
|
+
execute: async (batch) =>
|
|
5221
|
+
await this.callToolAPI(
|
|
5222
|
+
batch.batchOperation,
|
|
5223
|
+
batch.batchPayload,
|
|
5013
5224
|
),
|
|
5014
|
-
)
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5225
|
+
onChunkComplete: async (chunkResults) => {
|
|
5226
|
+
for (const entry of chunkResults) {
|
|
5227
|
+
if (entry.error !== undefined) {
|
|
5228
|
+
for (const request of entry.request.memberRequests) {
|
|
5229
|
+
this.rejectToolCall(toolId, request, entry.error);
|
|
5230
|
+
}
|
|
5231
|
+
continue;
|
|
5232
|
+
}
|
|
5020
5233
|
const splitResults =
|
|
5021
|
-
|
|
5022
|
-
?
|
|
5023
|
-
:
|
|
5234
|
+
entry.result != null
|
|
5235
|
+
? entry.request.splitResults(entry.result)
|
|
5236
|
+
: entry.request.memberRequests.map(() => null);
|
|
5024
5237
|
|
|
5025
5238
|
for (
|
|
5026
5239
|
let index = 0;
|
|
5027
|
-
index <
|
|
5240
|
+
index < entry.request.memberRequests.length;
|
|
5028
5241
|
index += 1
|
|
5029
5242
|
) {
|
|
5030
|
-
const request =
|
|
5243
|
+
const request = entry.request.memberRequests[index]!;
|
|
5031
5244
|
await this.resolveToolCall(
|
|
5032
5245
|
toolId,
|
|
5033
5246
|
request,
|
|
5034
5247
|
splitResults[index] ?? null,
|
|
5035
5248
|
);
|
|
5036
5249
|
}
|
|
5037
|
-
continue;
|
|
5038
5250
|
}
|
|
5039
5251
|
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
}
|
|
5252
|
+
recordToolStep(
|
|
5253
|
+
chunkResults.flatMap((entry) => entry.request.memberRequests),
|
|
5254
|
+
);
|
|
5255
|
+
this.#options.onBatchComplete?.(this.checkpoint);
|
|
5256
|
+
},
|
|
5257
|
+
});
|
|
5047
5258
|
} else {
|
|
5048
5259
|
const batchSize = await this.governor.suggestedParallelism(
|
|
5049
5260
|
toolId,
|
|
@@ -5055,66 +5266,32 @@ export class PlayContextImpl {
|
|
|
5055
5266
|
start += batchSize
|
|
5056
5267
|
) {
|
|
5057
5268
|
const chunk = pendingRequests.slice(start, start + batchSize);
|
|
5058
|
-
|
|
5059
|
-
chunk.map((request) =>
|
|
5060
|
-
|
|
5061
|
-
|
|
5269
|
+
await Promise.allSettled(
|
|
5270
|
+
chunk.map(async (request) => {
|
|
5271
|
+
try {
|
|
5272
|
+
const execution = await this.callToolExecutionAPI(
|
|
5273
|
+
toolId,
|
|
5274
|
+
request.input,
|
|
5275
|
+
);
|
|
5276
|
+
await this.resolveToolCall(
|
|
5277
|
+
toolId,
|
|
5278
|
+
request,
|
|
5279
|
+
execution?.result ?? null,
|
|
5280
|
+
execution?.metadata ?? null,
|
|
5281
|
+
execution?.jobId,
|
|
5282
|
+
execution?.meta,
|
|
5283
|
+
);
|
|
5284
|
+
} catch (error) {
|
|
5285
|
+
this.rejectToolCall(toolId, request, error);
|
|
5286
|
+
}
|
|
5287
|
+
}),
|
|
5062
5288
|
);
|
|
5063
5289
|
|
|
5064
|
-
|
|
5065
|
-
const request = chunk[index]!;
|
|
5066
|
-
const outcome = settled[index]!;
|
|
5067
|
-
if (outcome.status === 'fulfilled') {
|
|
5068
|
-
await this.resolveToolCall(
|
|
5069
|
-
toolId,
|
|
5070
|
-
request,
|
|
5071
|
-
outcome.value?.result ?? null,
|
|
5072
|
-
outcome.value?.metadata ?? null,
|
|
5073
|
-
outcome.value?.jobId,
|
|
5074
|
-
outcome.value?.meta,
|
|
5075
|
-
);
|
|
5076
|
-
continue;
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
|
-
this.rejectToolCall(toolId, request, outcome.reason);
|
|
5080
|
-
}
|
|
5081
|
-
|
|
5290
|
+
recordToolStep(chunk);
|
|
5082
5291
|
this.#options.onBatchComplete?.(this.checkpoint);
|
|
5083
5292
|
}
|
|
5084
5293
|
}
|
|
5085
5294
|
}
|
|
5086
|
-
|
|
5087
|
-
// Record step — nest under map if inside one
|
|
5088
|
-
const stepResults: PlayStepRowResult[] = requests.map((req) => {
|
|
5089
|
-
const cachedResult = this.getCachedToolResult(
|
|
5090
|
-
toolId,
|
|
5091
|
-
this.buildToolResultCacheKey({
|
|
5092
|
-
rowId: req.rowId,
|
|
5093
|
-
tableNamespace: req.tableNamespace,
|
|
5094
|
-
rowKey: req.rowKey ?? undefined,
|
|
5095
|
-
callId: req.callId,
|
|
5096
|
-
}),
|
|
5097
|
-
);
|
|
5098
|
-
return {
|
|
5099
|
-
rowId: req.rowId,
|
|
5100
|
-
status: cachedResult?.result != null ? 'completed' : 'failed',
|
|
5101
|
-
success: cachedResult?.result != null,
|
|
5102
|
-
value: cachedResult?.result,
|
|
5103
|
-
error: cachedResult?.result != null ? null : 'Tool call failed',
|
|
5104
|
-
};
|
|
5105
|
-
});
|
|
5106
|
-
const toolStep = {
|
|
5107
|
-
type: 'tool' as const,
|
|
5108
|
-
toolId,
|
|
5109
|
-
// Keep the step trace preview-sized for large map pages.
|
|
5110
|
-
results: compactRowResultsPreview(stepResults),
|
|
5111
|
-
description: normalizeStepDescription(requests[0]?.description),
|
|
5112
|
-
};
|
|
5113
|
-
if (this.activeDatasetStep) {
|
|
5114
|
-
this.activeDatasetStep.substeps.push(toolStep);
|
|
5115
|
-
} else {
|
|
5116
|
-
this.steps.push(toolStep);
|
|
5117
|
-
}
|
|
5118
5295
|
}),
|
|
5119
5296
|
);
|
|
5120
5297
|
}
|