deepline 0.1.79 → 0.1.81
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 +2 -1
- package/dist/cli/index.js +76 -42
- package/dist/cli/index.mjs +76 -42
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +13 -10
- package/dist/index.mjs +13 -10
- package/dist/repo/apps/play-runner-workers/src/child-play-await.ts +192 -0
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +1103 -1617
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +506 -654
- package/dist/repo/apps/play-runner-workers/src/entry.ts +1148 -598
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-http-errors.ts +43 -1
- package/dist/repo/apps/play-runner-workers/src/workflow-retry-state.ts +8 -2
- package/dist/repo/sdk/src/client.ts +15 -8
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/types.ts +5 -0
- package/dist/repo/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +231 -0
- package/dist/repo/shared_libs/play-runtime/governor/governor.ts +376 -0
- package/dist/repo/shared_libs/play-runtime/governor/policy.ts +179 -0
- package/dist/repo/shared_libs/play-runtime/governor/rate-state-backend.ts +87 -0
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +12 -0
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +24 -0
- package/dist/repo/shared_libs/play-runtime/submit-limits.ts +35 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +4 -12
- package/dist/repo/shared_libs/plays/bundling/limits.ts +29 -0
- package/dist/repo/shared_libs/plays/static-pipeline.ts +56 -3
- package/dist/repo/shared_libs/temporal/constants.ts +38 -0
- package/package.json +1 -1
- package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +0 -149
package/dist/index.d.ts
CHANGED
|
@@ -305,6 +305,10 @@ interface ToolDefinition {
|
|
|
305
305
|
operationId?: string;
|
|
306
306
|
/** Alternative names that resolve to this tool. */
|
|
307
307
|
operationAliases?: string[];
|
|
308
|
+
/** Whether detailed input schema is available from `tools describe`. */
|
|
309
|
+
hasInputSchema?: boolean;
|
|
310
|
+
/** Whether detailed output schema is available from `tools describe`. */
|
|
311
|
+
hasOutputSchema?: boolean;
|
|
308
312
|
/** JSON Schema describing the tool's input parameters. */
|
|
309
313
|
inputSchema?: Record<string, unknown>;
|
|
310
314
|
/** JSON Schema describing the tool's output shape. */
|
|
@@ -796,6 +800,7 @@ interface PlayListItem {
|
|
|
796
800
|
currentPublishedVersion?: number | null;
|
|
797
801
|
tableNamespace?: string | null;
|
|
798
802
|
isDraftDirty?: boolean;
|
|
803
|
+
hasInputSchema?: boolean;
|
|
799
804
|
inputSchema?: Record<string, unknown> | null;
|
|
800
805
|
outputSchema?: Record<string, unknown> | null;
|
|
801
806
|
staticPipeline?: unknown;
|
|
@@ -1263,6 +1268,7 @@ declare class DeeplineClient {
|
|
|
1263
1268
|
categories?: string;
|
|
1264
1269
|
grep?: string;
|
|
1265
1270
|
grepMode?: 'all' | 'any' | 'phrase';
|
|
1271
|
+
compact?: boolean;
|
|
1266
1272
|
}): Promise<ToolDefinition[]>;
|
|
1267
1273
|
/**
|
|
1268
1274
|
* Search available tools using Deepline's ranked backend search.
|
|
@@ -1676,7 +1682,9 @@ declare class DeeplineClient {
|
|
|
1676
1682
|
* @param name - Play name
|
|
1677
1683
|
* @returns Version list (newest first)
|
|
1678
1684
|
*/
|
|
1679
|
-
listPlayVersions(name: string
|
|
1685
|
+
listPlayVersions(name: string, options?: {
|
|
1686
|
+
full?: boolean;
|
|
1687
|
+
}): Promise<PlayRevisionSummary[]>;
|
|
1680
1688
|
/**
|
|
1681
1689
|
* Make a play revision live.
|
|
1682
1690
|
*
|
package/dist/index.js
CHANGED
|
@@ -241,10 +241,10 @@ var import_node_path2 = require("path");
|
|
|
241
241
|
|
|
242
242
|
// src/release.ts
|
|
243
243
|
var SDK_RELEASE = {
|
|
244
|
-
version: "0.1.
|
|
244
|
+
version: "0.1.81",
|
|
245
245
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
246
246
|
supportPolicy: {
|
|
247
|
-
latest: "0.1.
|
|
247
|
+
latest: "0.1.81",
|
|
248
248
|
minimumSupported: "0.1.53",
|
|
249
249
|
deprecatedBelow: "0.1.53"
|
|
250
250
|
}
|
|
@@ -881,6 +881,7 @@ var DeeplineClient = class {
|
|
|
881
881
|
params.set("grep", options.grep.trim());
|
|
882
882
|
params.set("grep_mode", options.grepMode ?? "all");
|
|
883
883
|
}
|
|
884
|
+
params.set("compact", options?.compact === true ? "true" : "false");
|
|
884
885
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
885
886
|
const res = await this.http.get(
|
|
886
887
|
`/api/v2/tools${suffix}`
|
|
@@ -1320,7 +1321,7 @@ var DeeplineClient = class {
|
|
|
1320
1321
|
}
|
|
1321
1322
|
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1322
1323
|
const response = await this.http.get(
|
|
1323
|
-
`/api/v2/
|
|
1324
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}${query}`
|
|
1324
1325
|
);
|
|
1325
1326
|
return normalizePlayStatus(response);
|
|
1326
1327
|
}
|
|
@@ -1332,10 +1333,10 @@ var DeeplineClient = class {
|
|
|
1332
1333
|
*/
|
|
1333
1334
|
async *streamPlayRunEvents(workflowId, options) {
|
|
1334
1335
|
const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
|
|
1335
|
-
const params = new URLSearchParams(
|
|
1336
|
+
const params = new URLSearchParams();
|
|
1336
1337
|
params.set("mode", options?.mode ?? "cli");
|
|
1337
1338
|
for await (const event of this.http.streamSse(
|
|
1338
|
-
`/api/v2/
|
|
1339
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}/tail?${params.toString()}`,
|
|
1339
1340
|
{ signal: options?.signal, headers }
|
|
1340
1341
|
)) {
|
|
1341
1342
|
if (event.scope === "play") {
|
|
@@ -1357,7 +1358,7 @@ var DeeplineClient = class {
|
|
|
1357
1358
|
*/
|
|
1358
1359
|
async cancelPlay(workflowId) {
|
|
1359
1360
|
await this.http.request(
|
|
1360
|
-
`/api/v2/
|
|
1361
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
|
|
1361
1362
|
{ method: "POST" }
|
|
1362
1363
|
);
|
|
1363
1364
|
}
|
|
@@ -1369,7 +1370,7 @@ var DeeplineClient = class {
|
|
|
1369
1370
|
*/
|
|
1370
1371
|
async stopPlay(workflowId, options) {
|
|
1371
1372
|
return this.http.post(
|
|
1372
|
-
`/api/v2/
|
|
1373
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
|
|
1373
1374
|
options?.reason ? { reason: options.reason } : {}
|
|
1374
1375
|
);
|
|
1375
1376
|
}
|
|
@@ -1436,6 +1437,7 @@ var DeeplineClient = class {
|
|
|
1436
1437
|
if (status) {
|
|
1437
1438
|
params.set("status", status);
|
|
1438
1439
|
}
|
|
1440
|
+
params.set("compact", "true");
|
|
1439
1441
|
const response = await this.http.get(
|
|
1440
1442
|
`/api/v2/runs?${params.toString()}`
|
|
1441
1443
|
);
|
|
@@ -1488,7 +1490,7 @@ var DeeplineClient = class {
|
|
|
1488
1490
|
* ```
|
|
1489
1491
|
*/
|
|
1490
1492
|
async getRunLogs(runId, options) {
|
|
1491
|
-
const status = await this.getRunStatus(runId);
|
|
1493
|
+
const status = await this.getRunStatus(runId, { full: true });
|
|
1492
1494
|
const logs = status.progress?.logs ?? [];
|
|
1493
1495
|
const limit = typeof options?.limit === "number" && Number.isFinite(options.limit) ? Math.max(0, Math.trunc(options.limit)) : 200;
|
|
1494
1496
|
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
@@ -1600,10 +1602,11 @@ var DeeplineClient = class {
|
|
|
1600
1602
|
* @param name - Play name
|
|
1601
1603
|
* @returns Version list (newest first)
|
|
1602
1604
|
*/
|
|
1603
|
-
async listPlayVersions(name) {
|
|
1605
|
+
async listPlayVersions(name, options) {
|
|
1604
1606
|
const encodedName = encodeURIComponent(name);
|
|
1607
|
+
const suffix = options?.full ? "?full=true" : "";
|
|
1605
1608
|
const response = await this.http.get(
|
|
1606
|
-
`/api/v2/plays/${encodedName}/versions`
|
|
1609
|
+
`/api/v2/plays/${encodedName}/versions${suffix}`
|
|
1607
1610
|
);
|
|
1608
1611
|
return response.versions ?? [];
|
|
1609
1612
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -179,10 +179,10 @@ import { join as join2 } from "path";
|
|
|
179
179
|
|
|
180
180
|
// src/release.ts
|
|
181
181
|
var SDK_RELEASE = {
|
|
182
|
-
version: "0.1.
|
|
182
|
+
version: "0.1.81",
|
|
183
183
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
184
184
|
supportPolicy: {
|
|
185
|
-
latest: "0.1.
|
|
185
|
+
latest: "0.1.81",
|
|
186
186
|
minimumSupported: "0.1.53",
|
|
187
187
|
deprecatedBelow: "0.1.53"
|
|
188
188
|
}
|
|
@@ -819,6 +819,7 @@ var DeeplineClient = class {
|
|
|
819
819
|
params.set("grep", options.grep.trim());
|
|
820
820
|
params.set("grep_mode", options.grepMode ?? "all");
|
|
821
821
|
}
|
|
822
|
+
params.set("compact", options?.compact === true ? "true" : "false");
|
|
822
823
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
823
824
|
const res = await this.http.get(
|
|
824
825
|
`/api/v2/tools${suffix}`
|
|
@@ -1258,7 +1259,7 @@ var DeeplineClient = class {
|
|
|
1258
1259
|
}
|
|
1259
1260
|
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1260
1261
|
const response = await this.http.get(
|
|
1261
|
-
`/api/v2/
|
|
1262
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}${query}`
|
|
1262
1263
|
);
|
|
1263
1264
|
return normalizePlayStatus(response);
|
|
1264
1265
|
}
|
|
@@ -1270,10 +1271,10 @@ var DeeplineClient = class {
|
|
|
1270
1271
|
*/
|
|
1271
1272
|
async *streamPlayRunEvents(workflowId, options) {
|
|
1272
1273
|
const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
|
|
1273
|
-
const params = new URLSearchParams(
|
|
1274
|
+
const params = new URLSearchParams();
|
|
1274
1275
|
params.set("mode", options?.mode ?? "cli");
|
|
1275
1276
|
for await (const event of this.http.streamSse(
|
|
1276
|
-
`/api/v2/
|
|
1277
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}/tail?${params.toString()}`,
|
|
1277
1278
|
{ signal: options?.signal, headers }
|
|
1278
1279
|
)) {
|
|
1279
1280
|
if (event.scope === "play") {
|
|
@@ -1295,7 +1296,7 @@ var DeeplineClient = class {
|
|
|
1295
1296
|
*/
|
|
1296
1297
|
async cancelPlay(workflowId) {
|
|
1297
1298
|
await this.http.request(
|
|
1298
|
-
`/api/v2/
|
|
1299
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
|
|
1299
1300
|
{ method: "POST" }
|
|
1300
1301
|
);
|
|
1301
1302
|
}
|
|
@@ -1307,7 +1308,7 @@ var DeeplineClient = class {
|
|
|
1307
1308
|
*/
|
|
1308
1309
|
async stopPlay(workflowId, options) {
|
|
1309
1310
|
return this.http.post(
|
|
1310
|
-
`/api/v2/
|
|
1311
|
+
`/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
|
|
1311
1312
|
options?.reason ? { reason: options.reason } : {}
|
|
1312
1313
|
);
|
|
1313
1314
|
}
|
|
@@ -1374,6 +1375,7 @@ var DeeplineClient = class {
|
|
|
1374
1375
|
if (status) {
|
|
1375
1376
|
params.set("status", status);
|
|
1376
1377
|
}
|
|
1378
|
+
params.set("compact", "true");
|
|
1377
1379
|
const response = await this.http.get(
|
|
1378
1380
|
`/api/v2/runs?${params.toString()}`
|
|
1379
1381
|
);
|
|
@@ -1426,7 +1428,7 @@ var DeeplineClient = class {
|
|
|
1426
1428
|
* ```
|
|
1427
1429
|
*/
|
|
1428
1430
|
async getRunLogs(runId, options) {
|
|
1429
|
-
const status = await this.getRunStatus(runId);
|
|
1431
|
+
const status = await this.getRunStatus(runId, { full: true });
|
|
1430
1432
|
const logs = status.progress?.logs ?? [];
|
|
1431
1433
|
const limit = typeof options?.limit === "number" && Number.isFinite(options.limit) ? Math.max(0, Math.trunc(options.limit)) : 200;
|
|
1432
1434
|
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
@@ -1538,10 +1540,11 @@ var DeeplineClient = class {
|
|
|
1538
1540
|
* @param name - Play name
|
|
1539
1541
|
* @returns Version list (newest first)
|
|
1540
1542
|
*/
|
|
1541
|
-
async listPlayVersions(name) {
|
|
1543
|
+
async listPlayVersions(name, options) {
|
|
1542
1544
|
const encodedName = encodeURIComponent(name);
|
|
1545
|
+
const suffix = options?.full ? "?full=true" : "";
|
|
1543
1546
|
const response = await this.http.get(
|
|
1544
|
-
`/api/v2/plays/${encodedName}/versions`
|
|
1547
|
+
`/api/v2/plays/${encodedName}/versions${suffix}`
|
|
1545
1548
|
);
|
|
1546
1549
|
return response.versions ?? [];
|
|
1547
1550
|
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Child-play terminal await — the race between a Cloudflare Workflow
|
|
3
|
+
* `waitForEvent('child_play_terminal:...')` and a coordinator terminal-state
|
|
4
|
+
* poll, extracted from entry.ts so the runtime keeps a small, testable surface
|
|
5
|
+
* for "block until this child run reaches a terminal state".
|
|
6
|
+
*
|
|
7
|
+
* Behavior is identical to the inline implementation it replaces: arm the
|
|
8
|
+
* workflow event wait, race it against `pollParentChildTerminalState`, and
|
|
9
|
+
* resolve on whichever reports the child's terminal status first. The poll
|
|
10
|
+
* never resolves on a non-terminal/absent state (it returns a never-settling
|
|
11
|
+
* promise on timeout) so the event wait remains the primary path and the poll
|
|
12
|
+
* is a coordinator-side safety net for missed signals.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type WorkflowStepLike = {
|
|
16
|
+
waitForEvent: (
|
|
17
|
+
name: string,
|
|
18
|
+
options: { type: string; timeout: string },
|
|
19
|
+
) => Promise<{ payload: unknown }>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ChildTerminalCoordinator = {
|
|
23
|
+
readChildTerminalState(
|
|
24
|
+
parentRunId: string,
|
|
25
|
+
eventKey: string,
|
|
26
|
+
timeoutMs?: number,
|
|
27
|
+
): Promise<{ data?: unknown } | null>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type ChildPlayTerminalWaitResult = {
|
|
31
|
+
output: unknown;
|
|
32
|
+
source: 'workflow_event' | 'parent_child_terminal_cache';
|
|
33
|
+
attempts?: number;
|
|
34
|
+
waitMs: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export interface AwaitChildTerminalInput {
|
|
38
|
+
parentRunId: string;
|
|
39
|
+
workflowStep: WorkflowStepLike | undefined;
|
|
40
|
+
workflowId: string;
|
|
41
|
+
playName: string;
|
|
42
|
+
key: string;
|
|
43
|
+
timeoutMs: number;
|
|
44
|
+
/** Coordinator binding for the terminal-state poll. Null disables the poll. */
|
|
45
|
+
coordinator: ChildTerminalCoordinator | null;
|
|
46
|
+
now: () => number;
|
|
47
|
+
/** SHA-256 hex digest helper (same canonical hash entry.ts uses). */
|
|
48
|
+
hashJson: (value: unknown) => Promise<string>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
52
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function workflowEventType(name: string): string {
|
|
56
|
+
const normalized = name
|
|
57
|
+
.trim()
|
|
58
|
+
.replace(/[^A-Za-z0-9_-]+/g, '_')
|
|
59
|
+
.replace(/^_+|_+$/g, '')
|
|
60
|
+
.slice(0, 100);
|
|
61
|
+
return normalized || 'deepline_event';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function integrationEventType(eventKey: string): string {
|
|
65
|
+
return workflowEventType(`integration_event_${eventKey}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function workflowTimeoutFromMs(timeoutMs: number): string {
|
|
69
|
+
const seconds = Math.max(1, Math.ceil(timeoutMs / 1000));
|
|
70
|
+
return `${seconds} second${seconds === 1 ? '' : 's'}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function readChildTerminalPayload(value: unknown): Record<string, unknown> {
|
|
74
|
+
if (!isRecord(value)) return {};
|
|
75
|
+
const data = value.data;
|
|
76
|
+
return isRecord(data) ? data : value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function extractChildPlayOutput(status: Record<string, unknown>): unknown {
|
|
80
|
+
const result = status.result;
|
|
81
|
+
if (isRecord(result) && 'output' in result) {
|
|
82
|
+
return result.output;
|
|
83
|
+
}
|
|
84
|
+
return result ?? null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function childPlayEventKey(input: {
|
|
88
|
+
key: string;
|
|
89
|
+
workflowId: string;
|
|
90
|
+
hashJson: (value: unknown) => Promise<string>;
|
|
91
|
+
}): Promise<string> {
|
|
92
|
+
const readableKey = workflowEventType(input.key).slice(0, 40);
|
|
93
|
+
const digest = (
|
|
94
|
+
await input.hashJson({ key: input.key, workflowId: input.workflowId })
|
|
95
|
+
).slice(0, 32);
|
|
96
|
+
return `child_play_${digest}_${readableKey}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function pollParentChildTerminalState(input: {
|
|
100
|
+
coordinator: ChildTerminalCoordinator | null;
|
|
101
|
+
parentRunId: string;
|
|
102
|
+
eventKey: string;
|
|
103
|
+
timeoutMs: number;
|
|
104
|
+
now: () => number;
|
|
105
|
+
}): Promise<{
|
|
106
|
+
source: 'parent_child_terminal_cache';
|
|
107
|
+
payload: Record<string, unknown>;
|
|
108
|
+
attempts: number;
|
|
109
|
+
}> {
|
|
110
|
+
const { coordinator, parentRunId } = input;
|
|
111
|
+
if (!coordinator?.readChildTerminalState || !parentRunId) {
|
|
112
|
+
return await new Promise(() => undefined);
|
|
113
|
+
}
|
|
114
|
+
const startedAt = input.now();
|
|
115
|
+
let attempts = 0;
|
|
116
|
+
while (input.now() - startedAt < input.timeoutMs) {
|
|
117
|
+
attempts += 1;
|
|
118
|
+
const remainingMs = Math.max(
|
|
119
|
+
0,
|
|
120
|
+
input.timeoutMs - (input.now() - startedAt),
|
|
121
|
+
);
|
|
122
|
+
const waitMs = Math.min(remainingMs, 30_000);
|
|
123
|
+
const state = await coordinator
|
|
124
|
+
.readChildTerminalState(parentRunId, input.eventKey, waitMs)
|
|
125
|
+
.catch(() => null);
|
|
126
|
+
if (isRecord(state?.data)) {
|
|
127
|
+
return {
|
|
128
|
+
source: 'parent_child_terminal_cache',
|
|
129
|
+
payload: state.data,
|
|
130
|
+
attempts,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return await new Promise(() => undefined);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Block until the child run reaches a terminal state, via the workflow event
|
|
139
|
+
* wait raced against the coordinator terminal-state poll. Throws on a non-
|
|
140
|
+
* completed terminal status.
|
|
141
|
+
*/
|
|
142
|
+
export async function awaitChildTerminal(
|
|
143
|
+
input: AwaitChildTerminalInput,
|
|
144
|
+
): Promise<ChildPlayTerminalWaitResult> {
|
|
145
|
+
if (!input.workflowStep) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
'ctx.runPlay child waits require the cf-workflows runtime event scheduler.',
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const waitStartedAt = input.now();
|
|
151
|
+
const eventKey = await childPlayEventKey({
|
|
152
|
+
key: input.key,
|
|
153
|
+
workflowId: input.workflowId,
|
|
154
|
+
hashJson: input.hashJson,
|
|
155
|
+
});
|
|
156
|
+
const eventPromise = input.workflowStep
|
|
157
|
+
.waitForEvent(`child_play_terminal:${eventKey}`, {
|
|
158
|
+
type: integrationEventType(eventKey),
|
|
159
|
+
timeout: workflowTimeoutFromMs(input.timeoutMs),
|
|
160
|
+
})
|
|
161
|
+
.then((event) => ({
|
|
162
|
+
source: 'workflow_event' as const,
|
|
163
|
+
payload: readChildTerminalPayload(event.payload),
|
|
164
|
+
attempts: undefined as number | undefined,
|
|
165
|
+
}));
|
|
166
|
+
const terminal = await Promise.race([
|
|
167
|
+
eventPromise,
|
|
168
|
+
pollParentChildTerminalState({
|
|
169
|
+
coordinator: input.coordinator,
|
|
170
|
+
parentRunId: input.parentRunId,
|
|
171
|
+
eventKey,
|
|
172
|
+
timeoutMs: Math.min(input.timeoutMs, 30_000),
|
|
173
|
+
now: input.now,
|
|
174
|
+
}),
|
|
175
|
+
]);
|
|
176
|
+
const payload = terminal.payload;
|
|
177
|
+
const status = String(payload.status ?? '').toLowerCase();
|
|
178
|
+
if (status === 'completed') {
|
|
179
|
+
return {
|
|
180
|
+
output: extractChildPlayOutput(payload),
|
|
181
|
+
source: terminal.source,
|
|
182
|
+
attempts: terminal.attempts,
|
|
183
|
+
waitMs: input.now() - waitStartedAt,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const error = isRecord(payload.error) ? payload.error : null;
|
|
187
|
+
const message =
|
|
188
|
+
(typeof error?.message === 'string' && error.message.trim()) ||
|
|
189
|
+
(typeof payload.error === 'string' && payload.error.trim()) ||
|
|
190
|
+
`Child play ${input.playName} (${input.workflowId}) finished with status ${status || 'unknown'}.`;
|
|
191
|
+
throw new Error(message);
|
|
192
|
+
}
|