deepline 0.1.174 → 0.1.176
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/coordinator-entry.ts +3 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +17 -7
- package/dist/bundling-sources/sdk/src/client.ts +31 -1
- package/dist/bundling-sources/sdk/src/http.ts +19 -7
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +1 -0
- 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/context.ts +45 -15
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +6 -12
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +123 -32
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +2 -0
- package/dist/cli/index.js +256 -39
- package/dist/cli/index.mjs +256 -39
- package/dist/index.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +30 -12
- package/dist/index.mjs +30 -12
- package/package.json +1 -1
|
@@ -103,6 +103,7 @@ export type PlayWorkflowParams = {
|
|
|
103
103
|
executionPlan?: ExecutionPlan | null;
|
|
104
104
|
childPlayManifests?: PlayRuntimeManifestMap | null;
|
|
105
105
|
playCallGovernance?: PlayCallGovernanceSnapshot | null;
|
|
106
|
+
forceToolRefresh?: boolean | null;
|
|
106
107
|
preloadedDbSessions?: PreloadedRuntimeDbSession[] | null;
|
|
107
108
|
preloadedDbSessionRef?: {
|
|
108
109
|
runId: string;
|
|
@@ -2214,6 +2215,7 @@ function buildChildWorkflowParams(input: {
|
|
|
2214
2215
|
executorToken: childToken,
|
|
2215
2216
|
baseUrl,
|
|
2216
2217
|
integrationMode: normalizeIntegrationMode(body.integrationMode),
|
|
2218
|
+
forceToolRefresh: body.forceToolRefresh === true,
|
|
2217
2219
|
orgId,
|
|
2218
2220
|
userEmail: typeof body.userEmail === 'string' ? body.userEmail : '',
|
|
2219
2221
|
userId: typeof body.userId === 'string' ? body.userId : null,
|
|
@@ -2274,6 +2276,7 @@ function runRequestFromPlayWorkflowParams(
|
|
|
2274
2276
|
executionPlan: params.executionPlan ?? null,
|
|
2275
2277
|
childPlayManifests: params.childPlayManifests ?? null,
|
|
2276
2278
|
playCallGovernance: params.playCallGovernance ?? null,
|
|
2279
|
+
force: params.forceToolRefresh === true,
|
|
2277
2280
|
preloadedDbSessions: params.preloadedDbSessions ?? null,
|
|
2278
2281
|
inlineChildRunRegistered:
|
|
2279
2282
|
params.runtimeBackend === 'cf_workflows_dynamic_worker_inline_child',
|
|
@@ -270,6 +270,7 @@ type RunRequest = {
|
|
|
270
270
|
playName: string;
|
|
271
271
|
graphHash?: string | null;
|
|
272
272
|
userEmail: string | null;
|
|
273
|
+
force?: boolean | null;
|
|
273
274
|
runtimeInput: Record<string, unknown>;
|
|
274
275
|
/** Optional inline CSV rows (for plays where ctx.csv was passed inline data). */
|
|
275
276
|
inlineCsv?: { name: string; rows: Record<string, unknown>[] } | null;
|
|
@@ -1857,7 +1858,9 @@ class WorkerToolBatchScheduler {
|
|
|
1857
1858
|
id,
|
|
1858
1859
|
cacheKey: receiptKey,
|
|
1859
1860
|
receiptKey,
|
|
1860
|
-
force:
|
|
1861
|
+
force:
|
|
1862
|
+
options?.force === true ||
|
|
1863
|
+
!!this.req.force,
|
|
1861
1864
|
receiptWaitMaxAttempts: resolveRuntimeToolReceiptWaitMaxAttempts(
|
|
1862
1865
|
typeof runtimeOptions?.receiptWaitMs === 'number'
|
|
1863
1866
|
? { max_wait_ms: runtimeOptions.receiptWaitMs }
|
|
@@ -4088,6 +4091,7 @@ async function prepareMapRows(input: {
|
|
|
4088
4091
|
rows: Record<string, unknown>[];
|
|
4089
4092
|
inputOffset: number;
|
|
4090
4093
|
outputFields: string[];
|
|
4094
|
+
force?: boolean;
|
|
4091
4095
|
}): Promise<{
|
|
4092
4096
|
inserted: number;
|
|
4093
4097
|
skipped: number;
|
|
@@ -4109,6 +4113,7 @@ async function prepareMapRows(input: {
|
|
|
4109
4113
|
}),
|
|
4110
4114
|
rows,
|
|
4111
4115
|
inputOffset: input.inputOffset,
|
|
4116
|
+
...(input.force ? { force: true } : {}),
|
|
4112
4117
|
});
|
|
4113
4118
|
for (const timing of result.timings ?? []) {
|
|
4114
4119
|
const phase =
|
|
@@ -4682,9 +4687,7 @@ function createMinimalWorkerCtx(
|
|
|
4682
4687
|
return formatMapProgressMessage(completed, input.total);
|
|
4683
4688
|
};
|
|
4684
4689
|
const formatMapProcessingMessage = (rowsToExecute: number) =>
|
|
4685
|
-
rowsToExecute > 0
|
|
4686
|
-
? `Processing ${rowsToExecute.toLocaleString()} rows`
|
|
4687
|
-
: null;
|
|
4690
|
+
rowsToExecute > 0 ? `${rowsToExecute.toLocaleString()} rows` : null;
|
|
4688
4691
|
const formatMapExecutionHeartbeatMessage = (input: {
|
|
4689
4692
|
rowsToExecute: number;
|
|
4690
4693
|
startedRows: number;
|
|
@@ -4698,7 +4701,7 @@ function createMinimalWorkerCtx(
|
|
|
4698
4701
|
const waitingRows = Math.max(0, rowsToExecute - startedRows);
|
|
4699
4702
|
const parts = [
|
|
4700
4703
|
activeRows > 0 ? `${activeRows.toLocaleString()} active` : null,
|
|
4701
|
-
waitingRows > 0 ? `${waitingRows.toLocaleString()}
|
|
4704
|
+
waitingRows > 0 ? `${waitingRows.toLocaleString()} queued` : null,
|
|
4702
4705
|
completedRows > 0 ? `${completedRows.toLocaleString()} done` : null,
|
|
4703
4706
|
].filter((part): part is string => Boolean(part));
|
|
4704
4707
|
const base =
|
|
@@ -4889,6 +4892,7 @@ function createMinimalWorkerCtx(
|
|
|
4889
4892
|
...mapRowOutcomeRuntimeFields({ key: rowKey }),
|
|
4890
4893
|
})),
|
|
4891
4894
|
inputOffset: baseOffset + chunkStart,
|
|
4895
|
+
force: !!req.force,
|
|
4892
4896
|
});
|
|
4893
4897
|
recordRunnerPerfTrace({
|
|
4894
4898
|
req,
|
|
@@ -5366,7 +5370,9 @@ function createMinimalWorkerCtx(
|
|
|
5366
5370
|
request.input,
|
|
5367
5371
|
workflowStep,
|
|
5368
5372
|
{
|
|
5369
|
-
force:
|
|
5373
|
+
force:
|
|
5374
|
+
request.force === true ||
|
|
5375
|
+
!!req.force,
|
|
5370
5376
|
staleAfterSeconds: request.staleAfterSeconds,
|
|
5371
5377
|
},
|
|
5372
5378
|
);
|
|
@@ -6354,7 +6360,9 @@ function createMinimalWorkerCtx(
|
|
|
6354
6360
|
request.input,
|
|
6355
6361
|
workflowStep,
|
|
6356
6362
|
{
|
|
6357
|
-
force:
|
|
6363
|
+
force:
|
|
6364
|
+
request.force === true ||
|
|
6365
|
+
!!req.force,
|
|
6358
6366
|
staleAfterSeconds: request.staleAfterSeconds,
|
|
6359
6367
|
},
|
|
6360
6368
|
{
|
|
@@ -6500,6 +6508,7 @@ function createMinimalWorkerCtx(
|
|
|
6500
6508
|
callbackBaseUrl: req.callbackUrl,
|
|
6501
6509
|
baseUrl: req.baseUrl,
|
|
6502
6510
|
integrationMode: req.integrationMode ?? null,
|
|
6511
|
+
forceToolRefresh: req.force === true,
|
|
6503
6512
|
parentExecutorToken: req.executorToken,
|
|
6504
6513
|
userEmail: req.userEmail ?? '',
|
|
6505
6514
|
profile: 'workers_edge',
|
|
@@ -7956,6 +7965,7 @@ function runRequestFromWorkflowParams(
|
|
|
7956
7965
|
runtimeInput: isRecord(params.input)
|
|
7957
7966
|
? (params.input as Record<string, unknown>)
|
|
7958
7967
|
: {},
|
|
7968
|
+
force: params.forceToolRefresh === true,
|
|
7959
7969
|
inlineCsv: isInlineCsv(params.inlineCsv) ? params.inlineCsv : null,
|
|
7960
7970
|
inputFiles:
|
|
7961
7971
|
inputFile && inputStorageKey
|
|
@@ -90,6 +90,7 @@ const COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1_000];
|
|
|
90
90
|
const REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
|
|
91
91
|
const REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT = 3;
|
|
92
92
|
const REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES = 2_500_000;
|
|
93
|
+
const DEEPLINEAGENT_EXECUTE_TIMEOUT_MS = 15 * 60 * 1000;
|
|
93
94
|
|
|
94
95
|
function normalizePlayRunIntegrationMode(
|
|
95
96
|
value: unknown,
|
|
@@ -202,8 +203,21 @@ function chunkRegisterPlayArtifacts<T>(artifacts: T[]): T[][] {
|
|
|
202
203
|
type ExecuteToolRawOptions = {
|
|
203
204
|
includeToolMetadata?: boolean;
|
|
204
205
|
responseIntent?: 'raw' | 'row_artifact';
|
|
206
|
+
timeout?: number;
|
|
207
|
+
maxRetries?: number;
|
|
205
208
|
};
|
|
206
209
|
|
|
210
|
+
function resolveToolExecuteTimeoutMs(toolId: string): number | undefined {
|
|
211
|
+
const normalized = toolId.trim().toLowerCase();
|
|
212
|
+
return normalized === 'deeplineagent' ||
|
|
213
|
+
normalized === 'deeplineagent_deeplineagent' ||
|
|
214
|
+
normalized === 'ai_inference' ||
|
|
215
|
+
normalized === 'deeplineagent_ai_inference' ||
|
|
216
|
+
normalized === 'aiinference'
|
|
217
|
+
? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS
|
|
218
|
+
: undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
207
221
|
/**
|
|
208
222
|
* Standard provider/tool execution envelope returned by low-level SDK calls.
|
|
209
223
|
*
|
|
@@ -1212,7 +1226,12 @@ export class DeeplineClient {
|
|
|
1212
1226
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
1213
1227
|
{ payload: input },
|
|
1214
1228
|
headers,
|
|
1215
|
-
{
|
|
1229
|
+
{
|
|
1230
|
+
forbiddenAsApiError: true,
|
|
1231
|
+
timeout: options?.timeout ?? resolveToolExecuteTimeoutMs(toolId),
|
|
1232
|
+
maxRetries: options?.maxRetries ?? 0,
|
|
1233
|
+
exactUrlOnly: true,
|
|
1234
|
+
},
|
|
1216
1235
|
);
|
|
1217
1236
|
}
|
|
1218
1237
|
|
|
@@ -1285,6 +1304,7 @@ export class DeeplineClient {
|
|
|
1285
1304
|
*/
|
|
1286
1305
|
async startPlayRun(request: StartPlayRunRequest): Promise<PlayRunStart> {
|
|
1287
1306
|
const integrationMode = resolvePlayRunIntegrationMode(request);
|
|
1307
|
+
const forceToolRefresh = request.forceToolRefresh === true;
|
|
1288
1308
|
const response = await this.http.post<Record<string, unknown>>(
|
|
1289
1309
|
'/api/v2/plays/run',
|
|
1290
1310
|
{
|
|
@@ -1319,6 +1339,7 @@ export class DeeplineClient {
|
|
|
1319
1339
|
? { packagedFiles: request.packagedFiles }
|
|
1320
1340
|
: {}),
|
|
1321
1341
|
...(request.force ? { force: true } : {}),
|
|
1342
|
+
...(forceToolRefresh ? { forceToolRefresh: true } : {}),
|
|
1322
1343
|
...(typeof request.waitForCompletionMs === 'number'
|
|
1323
1344
|
? { waitForCompletionMs: request.waitForCompletionMs }
|
|
1324
1345
|
: {}),
|
|
@@ -1348,6 +1369,7 @@ export class DeeplineClient {
|
|
|
1348
1369
|
options?: { signal?: AbortSignal },
|
|
1349
1370
|
): AsyncGenerator<PlayLiveEvent> {
|
|
1350
1371
|
const integrationMode = resolvePlayRunIntegrationMode(request);
|
|
1372
|
+
const forceToolRefresh = request.forceToolRefresh === true;
|
|
1351
1373
|
const body = {
|
|
1352
1374
|
...(request.name ? { name: request.name } : {}),
|
|
1353
1375
|
...(request.revisionId ? { revisionId: request.revisionId } : {}),
|
|
@@ -1380,6 +1402,7 @@ export class DeeplineClient {
|
|
|
1380
1402
|
? { packagedFiles: request.packagedFiles }
|
|
1381
1403
|
: {}),
|
|
1382
1404
|
...(request.force ? { force: true } : {}),
|
|
1405
|
+
...(forceToolRefresh ? { forceToolRefresh: true } : {}),
|
|
1383
1406
|
...(typeof request.waitForCompletionMs === 'number'
|
|
1384
1407
|
? { waitForCompletionMs: request.waitForCompletionMs }
|
|
1385
1408
|
: {}),
|
|
@@ -1630,6 +1653,7 @@ export class DeeplineClient {
|
|
|
1630
1653
|
inputFile?: PlayStagedFileRef | null;
|
|
1631
1654
|
packagedFiles?: PlayStagedFileRef[];
|
|
1632
1655
|
force?: boolean;
|
|
1656
|
+
forceToolRefresh?: boolean;
|
|
1633
1657
|
}): Promise<PlayRunStart> {
|
|
1634
1658
|
const compilerManifest =
|
|
1635
1659
|
input.compilerManifest ??
|
|
@@ -1665,6 +1689,7 @@ export class DeeplineClient {
|
|
|
1665
1689
|
? { packagedFiles: input.packagedFiles }
|
|
1666
1690
|
: {}),
|
|
1667
1691
|
...(input.force ? { force: true } : {}),
|
|
1692
|
+
...(input.forceToolRefresh ? { forceToolRefresh: true } : {}),
|
|
1668
1693
|
});
|
|
1669
1694
|
}
|
|
1670
1695
|
|
|
@@ -1706,6 +1731,7 @@ export class DeeplineClient {
|
|
|
1706
1731
|
inputFile?: PlayStagedFileRef | null;
|
|
1707
1732
|
packagedFiles?: PlayStagedFileRef[];
|
|
1708
1733
|
force?: boolean;
|
|
1734
|
+
forceToolRefresh?: boolean;
|
|
1709
1735
|
},
|
|
1710
1736
|
): Promise<PlayRunStart> {
|
|
1711
1737
|
const runtimeInput = options?.input ? { ...options.input } : {};
|
|
@@ -1766,6 +1792,7 @@ export class DeeplineClient {
|
|
|
1766
1792
|
? { packagedFiles: options.packagedFiles }
|
|
1767
1793
|
: {}),
|
|
1768
1794
|
...(options?.force ? { force: true } : {}),
|
|
1795
|
+
...(options?.forceToolRefresh ? { forceToolRefresh: true } : {}),
|
|
1769
1796
|
});
|
|
1770
1797
|
}
|
|
1771
1798
|
|
|
@@ -2858,6 +2885,8 @@ export class DeeplineClient {
|
|
|
2858
2885
|
packagedFiles?: PlayStagedFileRef[];
|
|
2859
2886
|
/** Compatibility flag; active sibling runs are allowed. */
|
|
2860
2887
|
force?: boolean;
|
|
2888
|
+
/** Explicit cache-bypass flag for durable dataset and tool-call reuse. */
|
|
2889
|
+
forceToolRefresh?: boolean;
|
|
2861
2890
|
},
|
|
2862
2891
|
): Promise<PlayRunResult> {
|
|
2863
2892
|
const { workflowId } = await this.submitPlay(code, csvPath, name, {
|
|
@@ -2868,6 +2897,7 @@ export class DeeplineClient {
|
|
|
2868
2897
|
inputFile: options?.inputFile,
|
|
2869
2898
|
packagedFiles: options?.packagedFiles,
|
|
2870
2899
|
force: options?.force,
|
|
2900
|
+
forceToolRefresh: options?.forceToolRefresh,
|
|
2871
2901
|
});
|
|
2872
2902
|
const start = Date.now();
|
|
2873
2903
|
const state: PlayLiveStatusState = {
|
|
@@ -59,6 +59,10 @@ interface RequestOptions {
|
|
|
59
59
|
* most mutating API calls must fail loudly after the first server response.
|
|
60
60
|
*/
|
|
61
61
|
retryApiErrors?: boolean;
|
|
62
|
+
/** Per-request retry override. Use 0 for possibly delivered mutating calls. */
|
|
63
|
+
maxRetries?: number;
|
|
64
|
+
/** Disable localhost/127.0.0.1 failover for non-idempotent requests. */
|
|
65
|
+
exactUrlOnly?: boolean;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
interface StreamOptions {
|
|
@@ -222,10 +226,14 @@ export class HttpClient {
|
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
let lastError: Error | null = null;
|
|
225
|
-
const candidateUrls =
|
|
229
|
+
const candidateUrls = options?.exactUrlOnly
|
|
230
|
+
? [url]
|
|
231
|
+
: buildCandidateUrls(url);
|
|
226
232
|
let retryAfterDelayMs: number | null = null;
|
|
227
233
|
|
|
228
|
-
|
|
234
|
+
const maxRetries = options?.maxRetries ?? this.config.maxRetries;
|
|
235
|
+
|
|
236
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
229
237
|
if (attempt > 0) {
|
|
230
238
|
const backoffMs = Math.min(1000 * Math.pow(2, attempt - 1), 30_000);
|
|
231
239
|
const delayMs =
|
|
@@ -270,7 +278,7 @@ export class HttpClient {
|
|
|
270
278
|
if (response.status === 429) {
|
|
271
279
|
const retryAfter = parseRetryAfter(response);
|
|
272
280
|
lastError = new RateLimitError(retryAfter);
|
|
273
|
-
if (attempt <
|
|
281
|
+
if (attempt < maxRetries) {
|
|
274
282
|
retryAfterDelayMs = retryAfter;
|
|
275
283
|
break;
|
|
276
284
|
}
|
|
@@ -311,7 +319,7 @@ export class HttpClient {
|
|
|
311
319
|
: {}),
|
|
312
320
|
},
|
|
313
321
|
);
|
|
314
|
-
if (retryableApiError && attempt <
|
|
322
|
+
if (retryableApiError && attempt < maxRetries) {
|
|
315
323
|
retryAfterDelayMs = parseOptionalRetryAfter(response);
|
|
316
324
|
break;
|
|
317
325
|
}
|
|
@@ -350,7 +358,7 @@ export class HttpClient {
|
|
|
350
358
|
lastError = new DeeplineError(msg, response.status, apiErrorCode, {
|
|
351
359
|
response: parsed,
|
|
352
360
|
});
|
|
353
|
-
if (retryableApiError && attempt <
|
|
361
|
+
if (retryableApiError && attempt < maxRetries) {
|
|
354
362
|
retryAfterDelayMs = parseOptionalRetryAfter(response);
|
|
355
363
|
break;
|
|
356
364
|
}
|
|
@@ -371,7 +379,7 @@ export class HttpClient {
|
|
|
371
379
|
}
|
|
372
380
|
}
|
|
373
381
|
|
|
374
|
-
if (attempt <
|
|
382
|
+
if (attempt < maxRetries) continue;
|
|
375
383
|
}
|
|
376
384
|
|
|
377
385
|
if (lastError instanceof DeeplineError) {
|
|
@@ -487,7 +495,11 @@ export class HttpClient {
|
|
|
487
495
|
headers?: Record<string, string>,
|
|
488
496
|
options?: Pick<
|
|
489
497
|
RequestOptions,
|
|
490
|
-
|
|
498
|
+
| 'forbiddenAsApiError'
|
|
499
|
+
| 'retryApiErrors'
|
|
500
|
+
| 'timeout'
|
|
501
|
+
| 'maxRetries'
|
|
502
|
+
| 'exactUrlOnly'
|
|
491
503
|
>,
|
|
492
504
|
): Promise<T> {
|
|
493
505
|
return this.request<T>(path, {
|
|
@@ -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.176',
|
|
108
108
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
109
109
|
supportPolicy: {
|
|
110
|
-
latest: '0.1.
|
|
110
|
+
latest: '0.1.176',
|
|
111
111
|
minimumSupported: '0.1.53',
|
|
112
112
|
deprecatedBelow: '0.1.53',
|
|
113
113
|
commandMinimumSupported: [
|
|
@@ -998,6 +998,8 @@ export interface StartPlayRunRequest {
|
|
|
998
998
|
packagedFiles?: unknown[];
|
|
999
999
|
/** Compatibility flag; active sibling runs are allowed. */
|
|
1000
1000
|
force?: boolean;
|
|
1001
|
+
/** Explicit cache-bypass flag for durable dataset and tool-call reuse. */
|
|
1002
|
+
forceToolRefresh?: boolean;
|
|
1001
1003
|
/** Optionally let the start request wait briefly and return a terminal result. */
|
|
1002
1004
|
waitForCompletionMs?: number;
|
|
1003
1005
|
/**
|
|
@@ -190,11 +190,33 @@ const MAP_INCREMENTAL_PERSIST_INTERVAL_MS = 100;
|
|
|
190
190
|
const MAP_FRAME_FLUSH_INTERVAL_MS = 250;
|
|
191
191
|
const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
|
|
192
192
|
const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
193
|
+
const DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000;
|
|
193
194
|
const FETCH_TRANSPORT_MAX_ATTEMPTS = 3;
|
|
194
195
|
const FETCH_TRANSPORT_RETRY_DELAY_MS = 100;
|
|
195
196
|
type SafeFetchModule = typeof import('@shared_libs/security/safe-fetch');
|
|
196
197
|
let safeFetchModule: Promise<SafeFetchModule> | null = null;
|
|
197
198
|
|
|
199
|
+
export function resolveToolRuntimeTimeoutMs(
|
|
200
|
+
toolId: string,
|
|
201
|
+
requestedTimeoutMs?: number,
|
|
202
|
+
): number | undefined {
|
|
203
|
+
if (
|
|
204
|
+
typeof requestedTimeoutMs === 'number' &&
|
|
205
|
+
Number.isFinite(requestedTimeoutMs) &&
|
|
206
|
+
requestedTimeoutMs > 0
|
|
207
|
+
) {
|
|
208
|
+
return Math.max(1, Math.ceil(requestedTimeoutMs));
|
|
209
|
+
}
|
|
210
|
+
const normalized = toolId.trim().toLowerCase();
|
|
211
|
+
return normalized === 'deeplineagent' ||
|
|
212
|
+
normalized === 'deeplineagent_deeplineagent' ||
|
|
213
|
+
normalized === 'ai_inference' ||
|
|
214
|
+
normalized === 'deeplineagent_ai_inference' ||
|
|
215
|
+
normalized === 'aiinference'
|
|
216
|
+
? DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS
|
|
217
|
+
: undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
198
220
|
function loadSafeFetch(): Promise<SafeFetchModule> {
|
|
199
221
|
safeFetchModule ??= import('@shared_libs/security/safe-fetch');
|
|
200
222
|
return safeFetchModule;
|
|
@@ -1579,7 +1601,9 @@ export class PlayContextImpl {
|
|
|
1579
1601
|
staleAfterSeconds?: number | null;
|
|
1580
1602
|
} {
|
|
1581
1603
|
return {
|
|
1582
|
-
force:
|
|
1604
|
+
force:
|
|
1605
|
+
options?.force === true ||
|
|
1606
|
+
this.#options.cachePolicy?.forceToolRefresh === true,
|
|
1583
1607
|
staleAfterSeconds: options?.staleAfterSeconds ?? null,
|
|
1584
1608
|
};
|
|
1585
1609
|
}
|
|
@@ -2152,6 +2176,8 @@ export class PlayContextImpl {
|
|
|
2152
2176
|
playId: this.#options.playId,
|
|
2153
2177
|
runId: this.#options.runId,
|
|
2154
2178
|
staticPipeline: this.#options.staticPipeline,
|
|
2179
|
+
forceRefresh:
|
|
2180
|
+
this.#options.cachePolicy?.forceToolRefresh === true,
|
|
2155
2181
|
},
|
|
2156
2182
|
);
|
|
2157
2183
|
resolvedTableNamespace = normalizeTableNamespace(
|
|
@@ -3454,7 +3480,7 @@ export class PlayContextImpl {
|
|
|
3454
3480
|
? null
|
|
3455
3481
|
: this.getCachedToolResult(toolId, directCacheKey);
|
|
3456
3482
|
if (cached?.done) {
|
|
3457
|
-
this.log(`
|
|
3483
|
+
this.log(`Tool cache hit: ${toolId} exact payload`);
|
|
3458
3484
|
return await this.wrapToolExecutionResult({
|
|
3459
3485
|
toolId,
|
|
3460
3486
|
status: cached.result == null ? 'no_result' : 'completed',
|
|
@@ -3465,9 +3491,13 @@ export class PlayContextImpl {
|
|
|
3465
3491
|
}),
|
|
3466
3492
|
});
|
|
3467
3493
|
}
|
|
3468
|
-
this.log(
|
|
3494
|
+
this.log(
|
|
3495
|
+
toolCachePolicy.force
|
|
3496
|
+
? `Calling tool: ${toolId} (force)`
|
|
3497
|
+
: `Calling tool: ${toolId}`,
|
|
3498
|
+
);
|
|
3469
3499
|
const execution = await this.callToolExecutionAPI(toolId, input, {
|
|
3470
|
-
timeoutMs: options?.timeoutMs,
|
|
3500
|
+
timeoutMs: resolveToolRuntimeTimeoutMs(toolId, options?.timeoutMs),
|
|
3471
3501
|
});
|
|
3472
3502
|
const wrapped = await this.wrapToolExecutionResult({
|
|
3473
3503
|
toolId,
|
|
@@ -3513,7 +3543,7 @@ export class PlayContextImpl {
|
|
|
3513
3543
|
? null
|
|
3514
3544
|
: this.getCachedToolResult(toolId, toolResultCacheKey);
|
|
3515
3545
|
if (cached?.done) {
|
|
3516
|
-
this.log(` Row ${rowId} ${toolId}:
|
|
3546
|
+
this.log(` Row ${rowId} ${toolId}: cache hit exact payload`);
|
|
3517
3547
|
return await this.wrapToolExecutionResult({
|
|
3518
3548
|
toolId,
|
|
3519
3549
|
status: cached.result == null ? 'no_result' : 'completed',
|
|
@@ -3545,6 +3575,10 @@ export class PlayContextImpl {
|
|
|
3545
3575
|
},
|
|
3546
3576
|
dataPatch: {},
|
|
3547
3577
|
});
|
|
3578
|
+
const timeoutMs = resolveToolRuntimeTimeoutMs(
|
|
3579
|
+
toolId,
|
|
3580
|
+
options?.timeoutMs,
|
|
3581
|
+
);
|
|
3548
3582
|
this.toolCallQueue.push({
|
|
3549
3583
|
callId,
|
|
3550
3584
|
cacheKey: toolResultCacheKey,
|
|
@@ -3554,9 +3588,7 @@ export class PlayContextImpl {
|
|
|
3554
3588
|
fieldName,
|
|
3555
3589
|
toolId,
|
|
3556
3590
|
input,
|
|
3557
|
-
...(
|
|
3558
|
-
? { timeoutMs: options.timeoutMs }
|
|
3559
|
-
: {}),
|
|
3591
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
3560
3592
|
...(typeof options?.receiptWaitMs === 'number'
|
|
3561
3593
|
? { receiptWaitMs: options.receiptWaitMs }
|
|
3562
3594
|
: {}),
|
|
@@ -3582,7 +3614,7 @@ export class PlayContextImpl {
|
|
|
3582
3614
|
staleAfterSeconds: toolCachePolicy.staleAfterSeconds,
|
|
3583
3615
|
markSkipped: () => {
|
|
3584
3616
|
this.log(
|
|
3585
|
-
`
|
|
3617
|
+
`Tool cache hit: ${toolId} exact payload (${normalizedKey}:${toolRequestIdentity})`,
|
|
3586
3618
|
);
|
|
3587
3619
|
},
|
|
3588
3620
|
onClaimedResult: (output, receiptKey) =>
|
|
@@ -4303,7 +4335,9 @@ export class PlayContextImpl {
|
|
|
4303
4335
|
const pendingRequests: ToolCallRequest[] = [];
|
|
4304
4336
|
const recoveredRequests: ToolCallRequest[] = [];
|
|
4305
4337
|
for (const req of requests) {
|
|
4306
|
-
const cached =
|
|
4338
|
+
const cached = req.force
|
|
4339
|
+
? undefined
|
|
4340
|
+
: this.getCachedToolResult(toolId, req.cacheKey);
|
|
4307
4341
|
if (cached?.done) {
|
|
4308
4342
|
this.log(` Row ${req.rowId} ${toolId}: recovered from checkpoint`);
|
|
4309
4343
|
const resolver = this.toolCallResolvers.get(req.callId);
|
|
@@ -4906,11 +4940,7 @@ export class PlayContextImpl {
|
|
|
4906
4940
|
);
|
|
4907
4941
|
}
|
|
4908
4942
|
const url = `${this.#options.baseUrl}/api/v2/integrations/${encodeURIComponent(toolId)}/execute`;
|
|
4909
|
-
const timeoutMs =
|
|
4910
|
-
typeof options?.timeoutMs === 'number' &&
|
|
4911
|
-
Number.isFinite(options.timeoutMs)
|
|
4912
|
-
? Math.max(1, Math.ceil(options.timeoutMs))
|
|
4913
|
-
: undefined;
|
|
4943
|
+
const timeoutMs = resolveToolRuntimeTimeoutMs(toolId, options?.timeoutMs);
|
|
4914
4944
|
|
|
4915
4945
|
// The Governor's tool slot is the single seam for tool-call budget + the
|
|
4916
4946
|
// global tool-concurrency backstop + per-(org, provider) pacing. It blocks
|
|
@@ -410,6 +410,10 @@ export interface ContextOptions {
|
|
|
410
410
|
checkpoint?: PlayCheckpoint;
|
|
411
411
|
/** Enables durable boundary replay such as ctx.sleep() resumptions. */
|
|
412
412
|
durableBoundaries?: boolean;
|
|
413
|
+
/** Run-level cache policy. forceToolRefresh bypasses ctx.tools.execute receipts. */
|
|
414
|
+
cachePolicy?: {
|
|
415
|
+
forceToolRefresh?: boolean;
|
|
416
|
+
};
|
|
413
417
|
/** Called after each durable batch completes — for Temporal heartbeating. */
|
|
414
418
|
onBatchComplete?: (checkpoint: PlayCheckpoint) => void;
|
|
415
419
|
/** Called when the runtime emits a new execution log line. */
|
|
@@ -435,6 +439,7 @@ export interface ContextOptions {
|
|
|
435
439
|
playId?: string;
|
|
436
440
|
runId?: string;
|
|
437
441
|
staticPipeline?: PlayStaticPipeline | null;
|
|
442
|
+
forceRefresh?: boolean;
|
|
438
443
|
},
|
|
439
444
|
) => Promise<MapStartResult>;
|
|
440
445
|
/**
|
|
@@ -58,21 +58,15 @@ export function buildDurableToolCallCacheKey(input: {
|
|
|
58
58
|
const orgId = input.orgId?.trim() || 'org';
|
|
59
59
|
const playId = input.playId.trim();
|
|
60
60
|
if (!playId) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
'Durable tool call cache key requires a non-empty play id.',
|
|
63
|
-
);
|
|
61
|
+
throw new Error('Missing durable tool play id.');
|
|
64
62
|
}
|
|
65
63
|
const toolId = input.toolId.trim();
|
|
66
64
|
if (!toolId) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
'Durable tool call cache key requires a non-empty tool id.',
|
|
69
|
-
);
|
|
65
|
+
throw new Error('Missing durable tool id.');
|
|
70
66
|
}
|
|
71
|
-
const
|
|
72
|
-
if (!
|
|
73
|
-
throw new Error(
|
|
74
|
-
'Durable tool call cache key requires a provider action version.',
|
|
75
|
-
);
|
|
67
|
+
const p = input.providerActionVersion?.trim();
|
|
68
|
+
if (!p) {
|
|
69
|
+
throw new Error('Missing durable tool action version.');
|
|
76
70
|
}
|
|
77
71
|
const digest = sha256Hex(
|
|
78
72
|
stableStringify({
|
|
@@ -83,7 +77,7 @@ export function buildDurableToolCallCacheKey(input: {
|
|
|
83
77
|
normalizedToolId: normalizeTableNamespace(toolId),
|
|
84
78
|
requestInput: input.requestInput,
|
|
85
79
|
authScopeDigest: input.authScopeDigest ?? null,
|
|
86
|
-
providerActionVersion,
|
|
80
|
+
providerActionVersion: p,
|
|
87
81
|
cachePolicyVersion:
|
|
88
82
|
input.cachePolicyVersion ?? DURABLE_CALL_CACHE_POLICY_VERSION,
|
|
89
83
|
staleBucket: durableCacheStaleBucket({
|
|
@@ -23,6 +23,7 @@ export interface PlayRunnerContextConfig {
|
|
|
23
23
|
userEmail?: string;
|
|
24
24
|
convexUrl?: string;
|
|
25
25
|
staticPipeline?: PlayStaticPipeline | null;
|
|
26
|
+
forceToolRefresh?: boolean | null;
|
|
26
27
|
/**
|
|
27
28
|
* Controls how scoped Postgres sessions enter the runner. `preloaded` means
|
|
28
29
|
* the launch config carries short-lived encrypted sessions minted before
|