deepline 0.1.109 → 0.1.111
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/cli/index.js +2634 -1532
- package/dist/cli/index.mjs +2547 -1451
- package/dist/index.d.mts +21 -14
- package/dist/index.d.ts +21 -14
- package/dist/index.js +97 -23
- package/dist/index.mjs +97 -23
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +192 -121
- package/dist/repo/apps/play-runner-workers/src/entry.ts +254 -65
- package/dist/repo/apps/play-runner-workers/src/runtime/receipts.ts +18 -27
- package/dist/repo/apps/play-runner-workers/src/workflow-instance-create.ts +44 -0
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +7 -11
- package/dist/repo/sdk/src/client.ts +35 -12
- package/dist/repo/sdk/src/errors.ts +2 -2
- package/dist/repo/sdk/src/http.ts +87 -7
- package/dist/repo/sdk/src/play.ts +1 -1
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +5 -1
- package/dist/repo/sdk/src/release.ts +13 -10
- package/dist/repo/sdk/src/tool-output.ts +2 -2
- package/dist/repo/sdk/src/types.ts +9 -6
- package/dist/repo/shared_libs/play-runtime/fullenrich-batching.ts +229 -0
- package/dist/repo/shared_libs/play-runtime/governor/policy.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/play-runtime-batching-registry.ts +20 -0
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +20 -12
- package/dist/repo/shared_libs/play-runtime/run-ledger.ts +147 -70
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +6 -2
- package/dist/repo/shared_libs/play-runtime/secret-redaction.ts +15 -0
- package/dist/repo/shared_libs/play-runtime/work-receipts.ts +1 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +193 -21
- package/dist/repo/shared_libs/plays/static-pipeline.ts +1 -3
- package/dist/repo/shared_libs/security/outbound-url-policy.ts +238 -0
- package/dist/repo/shared_libs/security/safe-fetch.ts +118 -0
- package/dist/viewer/viewer.css +617 -0
- package/dist/viewer/viewer.js +1496 -0
- package/package.json +5 -1
package/dist/index.mjs
CHANGED
|
@@ -196,10 +196,10 @@ var SDK_RELEASE = {
|
|
|
196
196
|
// skill on the sdk sync surface, and the people-search-to-email prebuilt.
|
|
197
197
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
198
198
|
// the SDK enrich generator's one-second stale policy.
|
|
199
|
-
version: "0.1.
|
|
199
|
+
version: "0.1.111",
|
|
200
200
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
201
201
|
supportPolicy: {
|
|
202
|
-
latest: "0.1.
|
|
202
|
+
latest: "0.1.111",
|
|
203
203
|
minimumSupported: "0.1.53",
|
|
204
204
|
deprecatedBelow: "0.1.53",
|
|
205
205
|
commandMinimumSupported: [
|
|
@@ -226,6 +226,7 @@ var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
|
|
|
226
226
|
|
|
227
227
|
// src/http.ts
|
|
228
228
|
var MAX_DIAGNOSTIC_HEADER_LENGTH = 120;
|
|
229
|
+
var COWORK_NETWORK_HINT = "Claude Cowork appears to be running Deepline in a network-restricted sandbox. In Claude Desktop, open Settings > Capabilities, turn on Allow network egress, and set Domain allowlist to All domains for the Cowork session.";
|
|
229
230
|
var HttpClient = class {
|
|
230
231
|
constructor(config) {
|
|
231
232
|
this.config = config;
|
|
@@ -261,6 +262,7 @@ var HttpClient = class {
|
|
|
261
262
|
"User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
|
|
262
263
|
"X-Deepline-Client-Family": "sdk",
|
|
263
264
|
"X-Deepline-CLI-Family": "sdk",
|
|
265
|
+
"X-Deepline-Agent-Runtime": detectAgentRuntime(),
|
|
264
266
|
"X-Deepline-CLI-Version": SDK_VERSION,
|
|
265
267
|
"X-Deepline-SDK-Version": SDK_VERSION,
|
|
266
268
|
"X-Deepline-API-Contract": SDK_API_CONTRACT,
|
|
@@ -363,12 +365,13 @@ var HttpClient = class {
|
|
|
363
365
|
parsed = body;
|
|
364
366
|
}
|
|
365
367
|
if (!response.ok) {
|
|
368
|
+
const retryableApiError = options?.retryApiErrors === true && isRetryableApiErrorResponse(response.status);
|
|
366
369
|
const htmlError = detectHtmlErrorBody(
|
|
367
370
|
body,
|
|
368
371
|
response.headers.get("content-type")
|
|
369
372
|
);
|
|
370
373
|
if (htmlError) {
|
|
371
|
-
|
|
374
|
+
lastError = new DeeplineError(
|
|
372
375
|
htmlError.message(response.status),
|
|
373
376
|
response.status,
|
|
374
377
|
"API_ERROR",
|
|
@@ -378,12 +381,23 @@ var HttpClient = class {
|
|
|
378
381
|
...htmlError.workerThrewException ? { workerThrewException: true } : {}
|
|
379
382
|
}
|
|
380
383
|
);
|
|
384
|
+
if (retryableApiError && attempt < this.config.maxRetries) {
|
|
385
|
+
retryAfterDelayMs = parseOptionalRetryAfter(response);
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
throw lastError;
|
|
381
389
|
}
|
|
382
390
|
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
383
391
|
const msg = typeof errorValue === "string" ? errorValue : errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string" ? errorValue.message : typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `HTTP ${response.status}`;
|
|
384
|
-
|
|
392
|
+
const apiErrorCode = errorValue && typeof errorValue === "object" && typeof errorValue.code === "string" ? errorValue.code : "API_ERROR";
|
|
393
|
+
lastError = new DeeplineError(msg, response.status, apiErrorCode, {
|
|
385
394
|
response: parsed
|
|
386
395
|
});
|
|
396
|
+
if (retryableApiError && attempt < this.config.maxRetries) {
|
|
397
|
+
retryAfterDelayMs = parseOptionalRetryAfter(response);
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
throw lastError;
|
|
387
401
|
}
|
|
388
402
|
return parsed;
|
|
389
403
|
} catch (error) {
|
|
@@ -404,7 +418,7 @@ var HttpClient = class {
|
|
|
404
418
|
throw lastError;
|
|
405
419
|
}
|
|
406
420
|
const errorMessage = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
|
|
407
|
-
throw new DeeplineError(errorMessage);
|
|
421
|
+
throw new DeeplineError(withCoworkNetworkHint(errorMessage));
|
|
408
422
|
}
|
|
409
423
|
/**
|
|
410
424
|
* Send a GET request.
|
|
@@ -476,7 +490,9 @@ var HttpClient = class {
|
|
|
476
490
|
}
|
|
477
491
|
}
|
|
478
492
|
throw new DeeplineError(
|
|
479
|
-
|
|
493
|
+
withCoworkNetworkHint(
|
|
494
|
+
lastError?.message ? `Unable to stream from ${this.config.baseUrl}. ${lastError.message}` : `Unable to stream from ${this.config.baseUrl}.`
|
|
495
|
+
)
|
|
480
496
|
);
|
|
481
497
|
}
|
|
482
498
|
/**
|
|
@@ -486,11 +502,12 @@ var HttpClient = class {
|
|
|
486
502
|
* @param path - API path
|
|
487
503
|
* @param body - Request body (will be JSON-serialized)
|
|
488
504
|
*/
|
|
489
|
-
async post(path, body, headers) {
|
|
505
|
+
async post(path, body, headers, options) {
|
|
490
506
|
return this.request(path, {
|
|
491
507
|
method: "POST",
|
|
492
508
|
body,
|
|
493
|
-
headers
|
|
509
|
+
headers,
|
|
510
|
+
...options
|
|
494
511
|
});
|
|
495
512
|
}
|
|
496
513
|
async postFormData(path, formData, headers) {
|
|
@@ -531,6 +548,9 @@ function parseResponseBody(body) {
|
|
|
531
548
|
return body;
|
|
532
549
|
}
|
|
533
550
|
}
|
|
551
|
+
function isRetryableApiErrorResponse(status) {
|
|
552
|
+
return status === 408 || status === 425 || status >= 500 && status < 600;
|
|
553
|
+
}
|
|
534
554
|
function detectHtmlErrorBody(body, contentType) {
|
|
535
555
|
const trimmed = body.trim();
|
|
536
556
|
const lower = trimmed.toLowerCase();
|
|
@@ -570,6 +590,9 @@ function apiErrorMessage(parsed, status) {
|
|
|
570
590
|
return `HTTP ${status}`;
|
|
571
591
|
}
|
|
572
592
|
function parseRetryAfter(response) {
|
|
593
|
+
return parseOptionalRetryAfter(response) ?? 5e3;
|
|
594
|
+
}
|
|
595
|
+
function parseOptionalRetryAfter(response) {
|
|
573
596
|
const header = response.headers.get("retry-after");
|
|
574
597
|
if (header) {
|
|
575
598
|
const seconds = Number(header);
|
|
@@ -577,7 +600,7 @@ function parseRetryAfter(response) {
|
|
|
577
600
|
return seconds * 1e3;
|
|
578
601
|
}
|
|
579
602
|
}
|
|
580
|
-
return
|
|
603
|
+
return null;
|
|
581
604
|
}
|
|
582
605
|
function buildCandidateUrls(url) {
|
|
583
606
|
try {
|
|
@@ -634,6 +657,39 @@ function decodeSseFrame(frame) {
|
|
|
634
657
|
function sleep(ms) {
|
|
635
658
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
636
659
|
}
|
|
660
|
+
function isTruthyEnv(name) {
|
|
661
|
+
const normalized = process.env[name]?.trim().toLowerCase();
|
|
662
|
+
return ["1", "true", "yes", "on"].includes(normalized ?? "");
|
|
663
|
+
}
|
|
664
|
+
function isCoworkLikeSandbox() {
|
|
665
|
+
const pluginMode = isTruthyEnv("DEEPLINE_PLUGIN_MODE");
|
|
666
|
+
const claudeRemote = isTruthyEnv("CLAUDE_CODE_REMOTE");
|
|
667
|
+
const projectDir = Boolean(process.env.CLAUDE_PROJECT_DIR?.trim());
|
|
668
|
+
const pluginRoot = Boolean(process.env.DEEPLINE_PLUGIN_ROOT?.trim());
|
|
669
|
+
const home = process.env.HOME?.trim() ?? "";
|
|
670
|
+
const sessionHome = home.startsWith("/sessions/");
|
|
671
|
+
return (pluginMode || pluginRoot) && (claudeRemote || projectDir || sessionHome);
|
|
672
|
+
}
|
|
673
|
+
function detectAgentRuntime() {
|
|
674
|
+
if (process.env.CODEX_THREAD_ID?.trim()) return "codex";
|
|
675
|
+
if (isCoworkLikeSandbox()) return "claude_cowork";
|
|
676
|
+
if (process.env.CLAUDECODE?.trim() === "1") return "claude_code";
|
|
677
|
+
if (process.env.CLINE_ACTIVE?.trim().toLowerCase() === "true") return "cline";
|
|
678
|
+
if (process.env.CURSOR_TRACE_ID?.trim() || process.env.CURSOR_AGENT?.trim()) {
|
|
679
|
+
return "cursor";
|
|
680
|
+
}
|
|
681
|
+
if (process.env.WINDSURF?.trim() || process.env.CASCADE?.trim()) {
|
|
682
|
+
return "windsurf";
|
|
683
|
+
}
|
|
684
|
+
return "unknown";
|
|
685
|
+
}
|
|
686
|
+
function withCoworkNetworkHint(message) {
|
|
687
|
+
if (!isCoworkLikeSandbox() || message.includes(COWORK_NETWORK_HINT)) {
|
|
688
|
+
return message;
|
|
689
|
+
}
|
|
690
|
+
return `${message}
|
|
691
|
+
${COWORK_NETWORK_HINT}`;
|
|
692
|
+
}
|
|
637
693
|
|
|
638
694
|
// src/stream-reconnect.ts
|
|
639
695
|
var STREAM_RECONNECT_BASE_DELAY_MS = 500;
|
|
@@ -1910,12 +1966,12 @@ var DeeplineClient = class {
|
|
|
1910
1966
|
* Returns everything from {@link ToolDefinition} plus pricing info, sample
|
|
1911
1967
|
* inputs/outputs, failure modes, and cost estimates.
|
|
1912
1968
|
*
|
|
1913
|
-
* @param toolId - Tool identifier (e.g. `"
|
|
1969
|
+
* @param toolId - Tool identifier (e.g. `"dropleads_search_people"`)
|
|
1914
1970
|
* @returns Full tool metadata
|
|
1915
1971
|
*
|
|
1916
1972
|
* @example
|
|
1917
1973
|
* ```typescript
|
|
1918
|
-
* const meta = await client.getTool('
|
|
1974
|
+
* const meta = await client.getTool('dropleads_search_people');
|
|
1919
1975
|
* console.log(`Cost: ${meta.estimatedCreditsRange} credits`);
|
|
1920
1976
|
* console.log(`Input schema:`, meta.inputSchema);
|
|
1921
1977
|
* ```
|
|
@@ -1947,7 +2003,8 @@ var DeeplineClient = class {
|
|
|
1947
2003
|
return this.http.post(
|
|
1948
2004
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
1949
2005
|
{ payload: input },
|
|
1950
|
-
headers
|
|
2006
|
+
headers,
|
|
2007
|
+
{ forbiddenAsApiError: true }
|
|
1951
2008
|
);
|
|
1952
2009
|
}
|
|
1953
2010
|
/**
|
|
@@ -2029,7 +2086,7 @@ var DeeplineClient = class {
|
|
|
2029
2086
|
...request.force ? { force: true } : {},
|
|
2030
2087
|
...typeof request.waitForCompletionMs === "number" ? { waitForCompletionMs: request.waitForCompletionMs } : {},
|
|
2031
2088
|
// Profile selection is the API's job, not the CLI's. The server
|
|
2032
|
-
//
|
|
2089
|
+
// defaults to workers_edge; tests and runtime probes that want a
|
|
2033
2090
|
// different profile pass `request.profile` explicitly.
|
|
2034
2091
|
...request.profile ? { profile: request.profile } : {}
|
|
2035
2092
|
}
|
|
@@ -2094,10 +2151,15 @@ var DeeplineClient = class {
|
|
|
2094
2151
|
sourceFiles: input.sourceFiles,
|
|
2095
2152
|
artifact: input.artifact
|
|
2096
2153
|
});
|
|
2097
|
-
return this.http.post(
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2154
|
+
return this.http.post(
|
|
2155
|
+
"/api/v2/plays/artifacts",
|
|
2156
|
+
{
|
|
2157
|
+
...input,
|
|
2158
|
+
compilerManifest
|
|
2159
|
+
},
|
|
2160
|
+
void 0,
|
|
2161
|
+
{ forbiddenAsApiError: true, retryApiErrors: true }
|
|
2162
|
+
);
|
|
2101
2163
|
}
|
|
2102
2164
|
/**
|
|
2103
2165
|
* Register multiple bundled play artifacts in one request.
|
|
@@ -2107,7 +2169,12 @@ var DeeplineClient = class {
|
|
|
2107
2169
|
*/
|
|
2108
2170
|
async registerPlayArtifacts(artifacts) {
|
|
2109
2171
|
if (artifacts.length === 0) {
|
|
2110
|
-
return this.http.post(
|
|
2172
|
+
return this.http.post(
|
|
2173
|
+
"/api/v2/plays/artifacts",
|
|
2174
|
+
{ artifacts },
|
|
2175
|
+
void 0,
|
|
2176
|
+
{ forbiddenAsApiError: true, retryApiErrors: true }
|
|
2177
|
+
);
|
|
2111
2178
|
}
|
|
2112
2179
|
const compiledArtifacts = await mapWithConcurrency(
|
|
2113
2180
|
artifacts,
|
|
@@ -2125,9 +2192,14 @@ var DeeplineClient = class {
|
|
|
2125
2192
|
const responses = [];
|
|
2126
2193
|
for (const chunk of chunkRegisterPlayArtifacts(compiledArtifacts)) {
|
|
2127
2194
|
responses.push(
|
|
2128
|
-
await this.http.post(
|
|
2129
|
-
artifacts
|
|
2130
|
-
|
|
2195
|
+
await this.http.post(
|
|
2196
|
+
"/api/v2/plays/artifacts",
|
|
2197
|
+
{
|
|
2198
|
+
artifacts: chunk
|
|
2199
|
+
},
|
|
2200
|
+
void 0,
|
|
2201
|
+
{ forbiddenAsApiError: true, retryApiErrors: true }
|
|
2202
|
+
)
|
|
2131
2203
|
);
|
|
2132
2204
|
}
|
|
2133
2205
|
return {
|
|
@@ -2932,7 +3004,9 @@ var DeeplineClient = class {
|
|
|
2932
3004
|
const encodedName = encodeURIComponent(name);
|
|
2933
3005
|
return this.http.post(
|
|
2934
3006
|
`/api/v2/plays/${encodedName}/live`,
|
|
2935
|
-
request
|
|
3007
|
+
request,
|
|
3008
|
+
void 0,
|
|
3009
|
+
{ forbiddenAsApiError: true }
|
|
2936
3010
|
);
|
|
2937
3011
|
}
|
|
2938
3012
|
/**
|
|
@@ -4174,7 +4248,7 @@ var DeeplineContext = class {
|
|
|
4174
4248
|
* @example
|
|
4175
4249
|
* ```typescript
|
|
4176
4250
|
* const tools = await deepline.tools.list();
|
|
4177
|
-
* const meta = await deepline.tools.get('
|
|
4251
|
+
* const meta = await deepline.tools.get('dropleads_search_people');
|
|
4178
4252
|
* const companyLookup = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
4179
4253
|
* const company = companyLookup.toolResponse.raw;
|
|
4180
4254
|
* ```
|
|
@@ -44,6 +44,7 @@ import type {
|
|
|
44
44
|
PlayRuntimeManifest,
|
|
45
45
|
PlayRuntimeManifestMap,
|
|
46
46
|
} from '../../../shared_libs/plays/compiler-manifest';
|
|
47
|
+
import { normalizePlayRunFailure } from '../../../shared_libs/play-runtime/run-failure';
|
|
47
48
|
import type { PlayRunLedgerEvent } from '../../../shared_libs/play-runtime/run-ledger';
|
|
48
49
|
import {
|
|
49
50
|
COORDINATOR_INTERNAL_TOKEN_HEADER,
|
|
@@ -61,6 +62,7 @@ import {
|
|
|
61
62
|
workflowRetryParamsStorageKey,
|
|
62
63
|
type WorkflowRetryParamsRef,
|
|
63
64
|
} from './workflow-retry-state';
|
|
65
|
+
import { createOrAttachWorkflowInstance } from './workflow-instance-create';
|
|
64
66
|
import { sanitizeLiveLogLines } from './runtime/live-progress';
|
|
65
67
|
|
|
66
68
|
export { DynamicWorkflowBinding };
|
|
@@ -2896,136 +2898,181 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
|
|
|
2896
2898
|
},
|
|
2897
2899
|
});
|
|
2898
2900
|
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
metadata,
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
ms: 0,
|
|
2918
|
-
graphHash,
|
|
2919
|
-
extra: { artifactStorageKey },
|
|
2920
|
-
});
|
|
2921
|
-
const stub = loadDynamicPlayWorkerSync(
|
|
2922
|
-
env,
|
|
2923
|
-
{
|
|
2901
|
+
const dispatchWorkflowStartedAt = Date.now();
|
|
2902
|
+
try {
|
|
2903
|
+
return await dispatchWorkflow(
|
|
2904
|
+
{ env: this.env, ctx: this.ctx },
|
|
2905
|
+
dispatchedEvent as Parameters<typeof dispatchWorkflow>[1],
|
|
2906
|
+
step as Parameters<typeof dispatchWorkflow>[2],
|
|
2907
|
+
async ({ metadata, env }) => {
|
|
2908
|
+
const graphHash = readMetadataString(metadata, 'graphHash');
|
|
2909
|
+
const artifactStorageKey = readMetadataString(
|
|
2910
|
+
metadata,
|
|
2911
|
+
'artifactStorageKey',
|
|
2912
|
+
);
|
|
2913
|
+
const runIdForTrace =
|
|
2914
|
+
typeof (metadata as Record<string, unknown>).runId === 'string'
|
|
2915
|
+
? ((metadata as Record<string, unknown>).runId as string)
|
|
2916
|
+
: graphHash;
|
|
2917
|
+
const loaderStartedAt = Date.now();
|
|
2918
|
+
trace({
|
|
2924
2919
|
runId: runIdForTrace,
|
|
2920
|
+
phase: 'coordinator.loader_callback_entry',
|
|
2921
|
+
ms: 0,
|
|
2925
2922
|
graphHash,
|
|
2926
|
-
artifactStorageKey,
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
dynamicWorkerCode:
|
|
2932
|
-
typeof metadata.dynamicWorkerCode === 'string'
|
|
2933
|
-
? metadata.dynamicWorkerCode
|
|
2934
|
-
: null,
|
|
2935
|
-
packagedFiles: normalizePackagedFiles(metadata.packagedFiles),
|
|
2936
|
-
},
|
|
2937
|
-
trace,
|
|
2938
|
-
);
|
|
2939
|
-
const entrypoint = stub.getEntrypoint(
|
|
2940
|
-
'TenantWorkflow',
|
|
2941
|
-
) as unknown as WorkflowRunner;
|
|
2942
|
-
trace({
|
|
2943
|
-
runId: runIdForTrace,
|
|
2944
|
-
phase: 'coordinator.loader_compile',
|
|
2945
|
-
ms: Date.now() - loaderStartedAt,
|
|
2946
|
-
graphHash,
|
|
2947
|
-
});
|
|
2948
|
-
// Wrap the entrypoint so its run() failure surfaces here rather
|
|
2949
|
-
// than disappearing into the framework's silent rpcMethod=run
|
|
2950
|
-
// exception path.
|
|
2951
|
-
return {
|
|
2952
|
-
run: async (innerEvent: unknown, innerStep: unknown) => {
|
|
2953
|
-
const innerStartedAt = Date.now();
|
|
2954
|
-
trace({
|
|
2923
|
+
extra: { artifactStorageKey },
|
|
2924
|
+
});
|
|
2925
|
+
const stub = loadDynamicPlayWorkerSync(
|
|
2926
|
+
env,
|
|
2927
|
+
{
|
|
2955
2928
|
runId: runIdForTrace,
|
|
2956
|
-
phase: 'coordinator.runner_run_start',
|
|
2957
|
-
ms: 0,
|
|
2958
2929
|
graphHash,
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2930
|
+
artifactStorageKey,
|
|
2931
|
+
artifactHash:
|
|
2932
|
+
typeof metadata.artifactHash === 'string'
|
|
2933
|
+
? metadata.artifactHash
|
|
2934
|
+
: null,
|
|
2935
|
+
dynamicWorkerCode:
|
|
2936
|
+
typeof metadata.dynamicWorkerCode === 'string'
|
|
2937
|
+
? metadata.dynamicWorkerCode
|
|
2938
|
+
: null,
|
|
2939
|
+
packagedFiles: normalizePackagedFiles(metadata.packagedFiles),
|
|
2940
|
+
},
|
|
2941
|
+
trace,
|
|
2942
|
+
);
|
|
2943
|
+
const entrypointStartedAt = Date.now();
|
|
2944
|
+
const entrypoint = stub.getEntrypoint(
|
|
2945
|
+
'TenantWorkflow',
|
|
2946
|
+
) as unknown as WorkflowRunner;
|
|
2947
|
+
trace({
|
|
2948
|
+
runId: runIdForTrace,
|
|
2949
|
+
phase: 'coordinator.loader_get_entrypoint',
|
|
2950
|
+
ms: Date.now() - entrypointStartedAt,
|
|
2951
|
+
graphHash,
|
|
2952
|
+
});
|
|
2953
|
+
trace({
|
|
2954
|
+
runId: runIdForTrace,
|
|
2955
|
+
phase: 'coordinator.loader_compile',
|
|
2956
|
+
ms: Date.now() - loaderStartedAt,
|
|
2957
|
+
graphHash,
|
|
2958
|
+
});
|
|
2959
|
+
// Wrap the entrypoint so its run() failure surfaces here rather
|
|
2960
|
+
// than disappearing into the framework's silent rpcMethod=run
|
|
2961
|
+
// exception path.
|
|
2962
|
+
return {
|
|
2963
|
+
run: async (innerEvent: unknown, innerStep: unknown) => {
|
|
2964
|
+
const innerStartedAt = Date.now();
|
|
2978
2965
|
trace({
|
|
2979
2966
|
runId: runIdForTrace,
|
|
2980
|
-
phase: 'coordinator.
|
|
2981
|
-
ms:
|
|
2982
|
-
graphHash,
|
|
2983
|
-
});
|
|
2984
|
-
return result;
|
|
2985
|
-
} catch (innerError) {
|
|
2986
|
-
console.error('[coordinator] DynamicWorkflow runner.run threw', {
|
|
2967
|
+
phase: 'coordinator.runner_run_start',
|
|
2968
|
+
ms: 0,
|
|
2987
2969
|
graphHash,
|
|
2988
|
-
message:
|
|
2989
|
-
innerError instanceof Error
|
|
2990
|
-
? innerError.message
|
|
2991
|
-
: String(innerError),
|
|
2992
|
-
name: innerError instanceof Error ? innerError.name : null,
|
|
2993
|
-
stack:
|
|
2994
|
-
innerError instanceof Error &&
|
|
2995
|
-
typeof innerError.stack === 'string'
|
|
2996
|
-
? innerError.stack.split('\n').slice(0, 12).join('\n')
|
|
2997
|
-
: null,
|
|
2998
2970
|
});
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
2971
|
+
try {
|
|
2972
|
+
const result = await (
|
|
2973
|
+
entrypoint as unknown as {
|
|
2974
|
+
run(e: unknown, s: unknown): Promise<unknown>;
|
|
2975
|
+
}
|
|
2976
|
+
).run(innerEvent, innerStep);
|
|
2977
|
+
const output = isRecord(result) ? result : null;
|
|
2978
|
+
const terminalStartedAt = Date.now();
|
|
2979
|
+
try {
|
|
2980
|
+
await writeCoordinatorTerminalState(env, {
|
|
2981
|
+
runId: runIdForTrace,
|
|
2982
|
+
status: 'completed',
|
|
2983
|
+
result: output?.result ?? result,
|
|
2984
|
+
totalRows: output?.totalRows ?? output?.outputRows ?? null,
|
|
2985
|
+
durationMs: output?.durationMs ?? null,
|
|
2986
|
+
playName:
|
|
2987
|
+
typeof output?.playName === 'string'
|
|
2988
|
+
? output.playName
|
|
2989
|
+
: null,
|
|
2990
|
+
liveLogs: sanitizeLiveLogLines(output?.liveLogs),
|
|
2991
|
+
liveNodeProgress: output?.liveNodeProgress ?? null,
|
|
2992
|
+
});
|
|
2993
|
+
trace({
|
|
2994
|
+
runId: runIdForTrace,
|
|
2995
|
+
phase: 'coordinator.terminal_state_write',
|
|
2996
|
+
ms: Date.now() - terminalStartedAt,
|
|
2997
|
+
graphHash,
|
|
2998
|
+
extra: { status: 'completed' },
|
|
2999
|
+
});
|
|
3000
|
+
} catch (terminalError) {
|
|
3001
|
+
console.warn(
|
|
3002
|
+
'[coordinator] completed terminal cache write failed; preserving completed run',
|
|
3003
|
+
{
|
|
3004
|
+
graphHash,
|
|
3005
|
+
runId: runIdForTrace,
|
|
3006
|
+
message:
|
|
3007
|
+
terminalError instanceof Error
|
|
3008
|
+
? terminalError.message
|
|
3009
|
+
: String(terminalError),
|
|
3010
|
+
},
|
|
3011
|
+
);
|
|
3012
|
+
}
|
|
3013
|
+
trace({
|
|
3014
|
+
runId: runIdForTrace,
|
|
3015
|
+
phase: 'coordinator.runner_run',
|
|
3016
|
+
ms: Date.now() - innerStartedAt,
|
|
3017
|
+
graphHash,
|
|
3018
|
+
});
|
|
3019
|
+
return result;
|
|
3020
|
+
} catch (innerError) {
|
|
3021
|
+
const failure = normalizePlayRunFailure(innerError);
|
|
3004
3022
|
console.error(
|
|
3005
|
-
'[coordinator]
|
|
3023
|
+
'[coordinator] DynamicWorkflow runner.run threw',
|
|
3006
3024
|
{
|
|
3007
3025
|
graphHash,
|
|
3008
3026
|
message:
|
|
3009
|
-
|
|
3010
|
-
?
|
|
3011
|
-
: String(
|
|
3027
|
+
innerError instanceof Error
|
|
3028
|
+
? innerError.message
|
|
3029
|
+
: String(innerError),
|
|
3030
|
+
name: innerError instanceof Error ? innerError.name : null,
|
|
3031
|
+
stack:
|
|
3032
|
+
innerError instanceof Error &&
|
|
3033
|
+
typeof innerError.stack === 'string'
|
|
3034
|
+
? innerError.stack.split('\n').slice(0, 12).join('\n')
|
|
3035
|
+
: null,
|
|
3012
3036
|
},
|
|
3013
3037
|
);
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3038
|
+
await markWorkflowRuntimeFailure({
|
|
3039
|
+
env,
|
|
3040
|
+
event: innerEvent,
|
|
3041
|
+
error: innerError,
|
|
3042
|
+
}).catch((markError) => {
|
|
3043
|
+
console.error(
|
|
3044
|
+
'[coordinator] failed to forward DynamicWorkflow runner error',
|
|
3045
|
+
{
|
|
3046
|
+
graphHash,
|
|
3047
|
+
message:
|
|
3048
|
+
markError instanceof Error
|
|
3049
|
+
? markError.message
|
|
3050
|
+
: String(markError),
|
|
3051
|
+
},
|
|
3052
|
+
);
|
|
3053
|
+
});
|
|
3054
|
+
await writeCoordinatorTerminalState(env, {
|
|
3055
|
+
runId: runIdForTrace,
|
|
3056
|
+
status: 'failed',
|
|
3057
|
+
error: failure.message,
|
|
3058
|
+
}).catch(() => undefined);
|
|
3059
|
+
throw innerError;
|
|
3060
|
+
}
|
|
3061
|
+
},
|
|
3062
|
+
};
|
|
3063
|
+
},
|
|
3064
|
+
);
|
|
3065
|
+
} finally {
|
|
3066
|
+
trace({
|
|
3067
|
+
runId: dispatchTrace.runId,
|
|
3068
|
+
phase: 'coordinator.dispatch_workflow_total',
|
|
3069
|
+
ms: Date.now() - dispatchWorkflowStartedAt,
|
|
3070
|
+
graphHash: dispatchTrace.graphHash,
|
|
3071
|
+
extra: {
|
|
3072
|
+
instanceId: dispatchTrace.instanceId,
|
|
3073
|
+
},
|
|
3074
|
+
});
|
|
3075
|
+
}
|
|
3029
3076
|
}
|
|
3030
3077
|
}
|
|
3031
3078
|
|
|
@@ -3410,6 +3457,18 @@ async function handleWorkflowRoute(input: {
|
|
|
3410
3457
|
const parseStartedAt = Date.now();
|
|
3411
3458
|
const params = (await request.json()) as PlayWorkflowParams;
|
|
3412
3459
|
submittedRunId = params.runId ?? runId;
|
|
3460
|
+
recordSubmitTiming({
|
|
3461
|
+
phase: 'coordinator.submit_received',
|
|
3462
|
+
ms: Date.now() - submitStartedAt,
|
|
3463
|
+
graphHash: params.graphHash ?? null,
|
|
3464
|
+
extra: {
|
|
3465
|
+
hasDynamicWorkerCode: Boolean(params.dynamicWorkerCode),
|
|
3466
|
+
dynamicWorkerBytes:
|
|
3467
|
+
typeof params.dynamicWorkerCode === 'string'
|
|
3468
|
+
? params.dynamicWorkerCode.length
|
|
3469
|
+
: 0,
|
|
3470
|
+
},
|
|
3471
|
+
});
|
|
3413
3472
|
recordSubmitTiming({
|
|
3414
3473
|
phase: 'coordinator.submit_parse_body',
|
|
3415
3474
|
ms: Date.now() - parseStartedAt,
|
|
@@ -3539,17 +3598,28 @@ async function handleWorkflowRoute(input: {
|
|
|
3539
3598
|
try {
|
|
3540
3599
|
const dispatchStartedAt = Date.now();
|
|
3541
3600
|
const createStartedAt = Date.now();
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3601
|
+
recordSubmitTiming({
|
|
3602
|
+
phase: 'coordinator.workflow_create_start',
|
|
3603
|
+
ms: 0,
|
|
3604
|
+
graphHash: params.graphHash ?? null,
|
|
3605
|
+
extra: { instanceId: defaultInstanceId },
|
|
3606
|
+
});
|
|
3607
|
+
const createResult = await createOrAttachWorkflowInstance({
|
|
3608
|
+
create: () =>
|
|
3609
|
+
createDynamicWorkflowInstance({
|
|
3610
|
+
env,
|
|
3611
|
+
id: defaultInstanceId,
|
|
3612
|
+
params: workflowParams,
|
|
3613
|
+
}),
|
|
3614
|
+
getExisting: () => env.PLAY_WORKFLOW.get(defaultInstanceId),
|
|
3546
3615
|
});
|
|
3616
|
+
instance = createResult.instance;
|
|
3547
3617
|
const workflowCreatedAt = Date.now();
|
|
3548
3618
|
recordSubmitTiming({
|
|
3549
3619
|
phase: 'coordinator.workflow_create',
|
|
3550
3620
|
ms: workflowCreatedAt - createStartedAt,
|
|
3551
3621
|
graphHash: params.graphHash ?? null,
|
|
3552
|
-
extra: { instanceId: instance.id },
|
|
3622
|
+
extra: { instanceId: instance.id, startMode: createResult.startMode },
|
|
3553
3623
|
});
|
|
3554
3624
|
const instanceIdRecord = recordWorkflowInstanceId({
|
|
3555
3625
|
env,
|
|
@@ -3569,6 +3639,7 @@ async function handleWorkflowRoute(input: {
|
|
|
3569
3639
|
graphHash: params.graphHash ?? null,
|
|
3570
3640
|
extra: {
|
|
3571
3641
|
startMode: 'direct_workflow_create',
|
|
3642
|
+
workflowCreateMode: createResult.startMode,
|
|
3572
3643
|
instanceIdRecord: 'waitUntil',
|
|
3573
3644
|
},
|
|
3574
3645
|
});
|