deepline 0.1.21 → 0.1.23
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 +552 -237
- package/dist/cli/index.mjs +609 -289
- package/dist/index.d.mts +21 -58
- package/dist/index.d.ts +21 -58
- package/dist/index.js +177 -92
- package/dist/index.mjs +177 -92
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3 -1
- package/dist/repo/apps/play-runner-workers/src/entry.ts +153 -0
- package/dist/repo/sdk/src/client.ts +243 -124
- package/dist/repo/sdk/src/types.ts +8 -14
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/execution-plan.ts +27 -2
- package/dist/repo/shared_libs/play-runtime/profiles.ts +4 -14
- package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +1 -1
- package/package.json +1 -1
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
* @module
|
|
35
35
|
*/
|
|
36
36
|
import { resolveConfig } from './config.js';
|
|
37
|
+
import { DeeplineError } from './errors.js';
|
|
37
38
|
import { HttpClient } from './http.js';
|
|
38
39
|
import type {
|
|
39
40
|
DeeplineClientOptions,
|
|
@@ -66,6 +67,26 @@ import type { PlayCompilerManifest } from '../../shared_libs/plays/compiler-mani
|
|
|
66
67
|
|
|
67
68
|
const TERMINAL_PLAY_STATUSES = new Set(['completed', 'failed', 'cancelled']);
|
|
68
69
|
const INCLUDE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
|
|
70
|
+
const COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1_000];
|
|
71
|
+
|
|
72
|
+
function sleep(ms: number): Promise<void> {
|
|
73
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isTransientCompileManifestError(error: unknown): boolean {
|
|
77
|
+
if (error instanceof DeeplineError && typeof error.statusCode === 'number') {
|
|
78
|
+
return (
|
|
79
|
+
error.statusCode === 408 ||
|
|
80
|
+
error.statusCode === 425 ||
|
|
81
|
+
error.statusCode === 499 ||
|
|
82
|
+
(error.statusCode >= 500 && error.statusCode < 600)
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
+
return /fetch failed|connection (?:closed|reset|terminated)|socket hang up|econnreset|etimedout|eai_again|abort/i.test(
|
|
87
|
+
message,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
69
90
|
|
|
70
91
|
type ExecuteToolRawOptions = {
|
|
71
92
|
includeToolMetadata?: boolean;
|
|
@@ -88,11 +109,7 @@ export type RunsListOptions = {
|
|
|
88
109
|
};
|
|
89
110
|
|
|
90
111
|
export type RunsTailOptions = {
|
|
91
|
-
|
|
92
|
-
afterLogIndex?: number;
|
|
93
|
-
waitMs?: number;
|
|
94
|
-
terminalOnly?: boolean;
|
|
95
|
-
compact?: boolean;
|
|
112
|
+
signal?: AbortSignal;
|
|
96
113
|
};
|
|
97
114
|
|
|
98
115
|
export type RunsLogsOptions = {
|
|
@@ -127,11 +144,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
127
144
|
|
|
128
145
|
function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
|
|
129
146
|
const status =
|
|
130
|
-
typeof raw.status === 'string'
|
|
131
|
-
? raw.status
|
|
132
|
-
: typeof raw.temporalStatus === 'string'
|
|
133
|
-
? mapLegacyTemporalStatus(raw.temporalStatus)
|
|
134
|
-
: 'running';
|
|
147
|
+
typeof raw.status === 'string' ? raw.status : 'running';
|
|
135
148
|
const runId =
|
|
136
149
|
typeof raw.runId === 'string'
|
|
137
150
|
? raw.runId
|
|
@@ -145,24 +158,6 @@ function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
|
|
|
145
158
|
};
|
|
146
159
|
}
|
|
147
160
|
|
|
148
|
-
function mapLegacyTemporalStatus(status: string): PlayStatus['status'] {
|
|
149
|
-
switch (status.trim().toUpperCase()) {
|
|
150
|
-
case 'PENDING':
|
|
151
|
-
return 'queued';
|
|
152
|
-
case 'COMPLETED':
|
|
153
|
-
return 'completed';
|
|
154
|
-
case 'FAILED':
|
|
155
|
-
return 'failed';
|
|
156
|
-
case 'CANCELLED':
|
|
157
|
-
case 'TERMINATED':
|
|
158
|
-
case 'TIMED_OUT':
|
|
159
|
-
return 'cancelled';
|
|
160
|
-
case 'RUNNING':
|
|
161
|
-
default:
|
|
162
|
-
return 'running';
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
161
|
function decodeBase64Bytes(value: string): Uint8Array {
|
|
167
162
|
const binary = atob(value);
|
|
168
163
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -172,6 +167,131 @@ function decodeBase64Bytes(value: string): Uint8Array {
|
|
|
172
167
|
return bytes;
|
|
173
168
|
}
|
|
174
169
|
|
|
170
|
+
function readStringArray(value: unknown): string[] {
|
|
171
|
+
return Array.isArray(value)
|
|
172
|
+
? value.filter((line): line is string => typeof line === 'string')
|
|
173
|
+
: [];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
type PlayLiveStatusState = {
|
|
177
|
+
runId: string;
|
|
178
|
+
status: PlayStatus['status'];
|
|
179
|
+
logs: string[];
|
|
180
|
+
result?: unknown;
|
|
181
|
+
error?: string;
|
|
182
|
+
latest: PlayStatus | null;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
function getPlayLiveEventPayload(event: PlayLiveEvent): Record<string, unknown> {
|
|
186
|
+
return event.payload && typeof event.payload === 'object'
|
|
187
|
+
? (event.payload as Record<string, unknown>)
|
|
188
|
+
: {};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function normalizeLiveStatus(value: unknown): PlayStatus['status'] | null {
|
|
192
|
+
if (
|
|
193
|
+
value === 'queued' ||
|
|
194
|
+
value === 'running' ||
|
|
195
|
+
value === 'waiting' ||
|
|
196
|
+
value === 'completed' ||
|
|
197
|
+
value === 'failed' ||
|
|
198
|
+
value === 'cancelled'
|
|
199
|
+
) {
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function updatePlayLiveStatusState(
|
|
206
|
+
state: PlayLiveStatusState,
|
|
207
|
+
event: PlayLiveEvent,
|
|
208
|
+
): PlayStatus | null {
|
|
209
|
+
const payload = getPlayLiveEventPayload(event);
|
|
210
|
+
if (event.type === 'play.run.log') {
|
|
211
|
+
state.logs.push(...readStringArray(payload.lines));
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
if (
|
|
215
|
+
event.type !== 'play.run.snapshot' &&
|
|
216
|
+
event.type !== 'play.run.status' &&
|
|
217
|
+
event.type !== 'play.run.final_status'
|
|
218
|
+
) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const runId =
|
|
223
|
+
typeof payload.runId === 'string' && payload.runId
|
|
224
|
+
? payload.runId
|
|
225
|
+
: state.runId;
|
|
226
|
+
const status = normalizeLiveStatus(payload.status) ?? state.status;
|
|
227
|
+
const logs = readStringArray(payload.logs);
|
|
228
|
+
if (logs.length > 0 || event.type === 'play.run.snapshot') {
|
|
229
|
+
state.logs = logs;
|
|
230
|
+
}
|
|
231
|
+
if ('result' in payload) {
|
|
232
|
+
state.result = payload.result;
|
|
233
|
+
}
|
|
234
|
+
if (typeof payload.error === 'string' && payload.error.trim()) {
|
|
235
|
+
state.error = payload.error;
|
|
236
|
+
}
|
|
237
|
+
state.runId = runId;
|
|
238
|
+
state.status = status;
|
|
239
|
+
|
|
240
|
+
const progressRecord =
|
|
241
|
+
payload.progress &&
|
|
242
|
+
typeof payload.progress === 'object' &&
|
|
243
|
+
!Array.isArray(payload.progress)
|
|
244
|
+
? (payload.progress as Record<string, unknown>)
|
|
245
|
+
: {};
|
|
246
|
+
const next: PlayStatus = {
|
|
247
|
+
...(payload as unknown as Omit<PlayStatus, 'runId' | 'status' | 'progress'>),
|
|
248
|
+
runId,
|
|
249
|
+
status,
|
|
250
|
+
progress: {
|
|
251
|
+
...progressRecord,
|
|
252
|
+
status:
|
|
253
|
+
typeof progressRecord.status === 'string'
|
|
254
|
+
? progressRecord.status
|
|
255
|
+
: status,
|
|
256
|
+
logs: state.logs,
|
|
257
|
+
...(state.error ? { error: state.error } : {}),
|
|
258
|
+
},
|
|
259
|
+
...('result' in state ? { result: state.result } : {}),
|
|
260
|
+
};
|
|
261
|
+
state.latest = next;
|
|
262
|
+
return next;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function playRunResultFromStatus(
|
|
266
|
+
status: PlayStatus,
|
|
267
|
+
startedAt: number,
|
|
268
|
+
fallbackRunId: string,
|
|
269
|
+
): PlayRunResult {
|
|
270
|
+
return {
|
|
271
|
+
success: status.status === 'completed',
|
|
272
|
+
runId: status.runId || fallbackRunId,
|
|
273
|
+
result: status.result,
|
|
274
|
+
logs: status.progress?.logs ?? [],
|
|
275
|
+
durationMs: Date.now() - startedAt,
|
|
276
|
+
error:
|
|
277
|
+
status.progress?.error ??
|
|
278
|
+
(status.status !== 'completed' ? status.status : undefined),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function playRunStatusFromState(state: PlayLiveStatusState): PlayStatus {
|
|
283
|
+
return {
|
|
284
|
+
runId: state.runId,
|
|
285
|
+
status: state.status,
|
|
286
|
+
progress: {
|
|
287
|
+
status: state.status,
|
|
288
|
+
logs: state.logs,
|
|
289
|
+
...(state.error ? { error: state.error } : {}),
|
|
290
|
+
},
|
|
291
|
+
...('result' in state ? { result: state.result } : {}),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
175
295
|
/**
|
|
176
296
|
* Low-level client for the Deepline REST API.
|
|
177
297
|
*
|
|
@@ -339,7 +459,7 @@ export class DeeplineClient {
|
|
|
339
459
|
/**
|
|
340
460
|
* Search available tools using Deepline's ranked backend search.
|
|
341
461
|
*
|
|
342
|
-
* This is the same discovery surface used by the
|
|
462
|
+
* This is the same discovery surface used by the CLI: it ranks across
|
|
343
463
|
* tool metadata, categories, agent guidance, and input schema fields.
|
|
344
464
|
*/
|
|
345
465
|
async searchTools(
|
|
@@ -453,7 +573,7 @@ export class DeeplineClient {
|
|
|
453
573
|
* `progress.logs`; they are not part of the user output object.
|
|
454
574
|
*
|
|
455
575
|
* @param request - Play run configuration (name, code, input, etc.)
|
|
456
|
-
* @returns
|
|
576
|
+
* @returns Run metadata including the public `workflowId`
|
|
457
577
|
*
|
|
458
578
|
* @example
|
|
459
579
|
* ```typescript
|
|
@@ -659,10 +779,24 @@ export class DeeplineClient {
|
|
|
659
779
|
artifact: Record<string, unknown>;
|
|
660
780
|
importedPlayDependencies?: PlayCompilerManifest[];
|
|
661
781
|
}): Promise<PlayCompilerManifest> {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
782
|
+
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
783
|
+
0,
|
|
784
|
+
Math.max(0, this.config.maxRetries),
|
|
785
|
+
);
|
|
786
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
787
|
+
try {
|
|
788
|
+
const response = await this.http.post<{
|
|
789
|
+
compilerManifest: PlayCompilerManifest;
|
|
790
|
+
}>('/api/v2/plays/compile-manifest', input);
|
|
791
|
+
return response.compilerManifest;
|
|
792
|
+
} catch (error) {
|
|
793
|
+
const delayMs = retryDelays[attempt];
|
|
794
|
+
if (delayMs === undefined || !isTransientCompileManifestError(error)) {
|
|
795
|
+
throw error;
|
|
796
|
+
}
|
|
797
|
+
await sleep(delayMs);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
666
800
|
}
|
|
667
801
|
|
|
668
802
|
/**
|
|
@@ -917,9 +1051,6 @@ export class DeeplineClient {
|
|
|
917
1051
|
* Internal/advanced primitive. Public callers should usually prefer
|
|
918
1052
|
* {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
|
|
919
1053
|
*
|
|
920
|
-
* Poll this method until `status` reaches a terminal state:
|
|
921
|
-
* `'completed'`, `'failed'`, or `'cancelled'`.
|
|
922
|
-
*
|
|
923
1054
|
* @param workflowId - Play-run id from {@link startPlayRun}
|
|
924
1055
|
* @returns Current status with progress logs and partial results
|
|
925
1056
|
*
|
|
@@ -945,43 +1076,11 @@ export class DeeplineClient {
|
|
|
945
1076
|
return normalizePlayStatus(response);
|
|
946
1077
|
}
|
|
947
1078
|
|
|
948
|
-
/**
|
|
949
|
-
* Get the lightweight tail-polling status for a play execution.
|
|
950
|
-
*
|
|
951
|
-
* This is intentionally smaller than {@link getPlayStatus}: it returns the
|
|
952
|
-
* fields needed for CLI log tailing while the run is in flight, without
|
|
953
|
-
* forcing the API to rebuild final result views on every poll. Call
|
|
954
|
-
* {@link getPlayStatus} once after a terminal state for the full result.
|
|
955
|
-
*/
|
|
956
|
-
async getPlayTailStatus(
|
|
957
|
-
workflowId: string,
|
|
958
|
-
options?: {
|
|
959
|
-
afterLogIndex?: number;
|
|
960
|
-
waitMs?: number;
|
|
961
|
-
terminalOnly?: boolean;
|
|
962
|
-
},
|
|
963
|
-
): Promise<PlayStatus> {
|
|
964
|
-
const params = new URLSearchParams({ mode: 'tail' });
|
|
965
|
-
if (typeof options?.afterLogIndex === 'number') {
|
|
966
|
-
params.set('afterLogIndex', String(options.afterLogIndex));
|
|
967
|
-
}
|
|
968
|
-
if (typeof options?.waitMs === 'number') {
|
|
969
|
-
params.set('waitMs', String(options.waitMs));
|
|
970
|
-
}
|
|
971
|
-
if (options?.terminalOnly) {
|
|
972
|
-
params.set('terminalOnly', 'true');
|
|
973
|
-
}
|
|
974
|
-
const response = await this.http.get<Record<string, unknown>>(
|
|
975
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}?${params.toString()}`,
|
|
976
|
-
);
|
|
977
|
-
return normalizePlayStatus(response);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
1079
|
/**
|
|
981
1080
|
* Stream semantic play-run events using the same SSE feed as the dashboard.
|
|
982
1081
|
*
|
|
983
|
-
*
|
|
984
|
-
*
|
|
1082
|
+
* The server emits a canonical `play.run.snapshot` event first for every
|
|
1083
|
+
* connection, then incremental live events until terminal state or reconnect.
|
|
985
1084
|
*/
|
|
986
1085
|
async *streamPlayRunEvents(
|
|
987
1086
|
workflowId: string,
|
|
@@ -1012,7 +1111,7 @@ export class DeeplineClient {
|
|
|
1012
1111
|
*
|
|
1013
1112
|
* Sends a stop request for the run.
|
|
1014
1113
|
*
|
|
1015
|
-
* @param workflowId -
|
|
1114
|
+
* @param workflowId - Public Deepline play-run id to cancel
|
|
1016
1115
|
*
|
|
1017
1116
|
* @example
|
|
1018
1117
|
* ```typescript
|
|
@@ -1029,7 +1128,7 @@ export class DeeplineClient {
|
|
|
1029
1128
|
/**
|
|
1030
1129
|
* Stop a running play execution, including open HITL waits.
|
|
1031
1130
|
*
|
|
1032
|
-
* @param workflowId -
|
|
1131
|
+
* @param workflowId - Public Deepline play-run id to stop
|
|
1033
1132
|
* @param options.reason - Optional audit/debug reason
|
|
1034
1133
|
*/
|
|
1035
1134
|
async stopPlay(
|
|
@@ -1108,39 +1207,42 @@ export class DeeplineClient {
|
|
|
1108
1207
|
return response.runs ?? [];
|
|
1109
1208
|
}
|
|
1110
1209
|
|
|
1111
|
-
/**
|
|
1112
|
-
* Fetch the lightweight tail status for a run using the public runs resource model.
|
|
1113
|
-
*
|
|
1114
|
-
* This is the SDK equivalent of:
|
|
1115
|
-
*
|
|
1116
|
-
* ```bash
|
|
1117
|
-
* deepline runs tail <run-id> --json
|
|
1118
|
-
* ```
|
|
1119
|
-
*/
|
|
1210
|
+
/** Read the canonical run stream and return the latest run snapshot. */
|
|
1120
1211
|
async tailRun(runId: string, options?: RunsTailOptions): Promise<PlayStatus> {
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1212
|
+
const state: PlayLiveStatusState = {
|
|
1213
|
+
runId,
|
|
1214
|
+
status: 'running',
|
|
1215
|
+
logs: [],
|
|
1216
|
+
latest: null,
|
|
1217
|
+
};
|
|
1218
|
+
let terminal = false;
|
|
1219
|
+
for await (const event of this.streamPlayRunEvents(runId, {
|
|
1220
|
+
mode: 'cli',
|
|
1221
|
+
signal: options?.signal,
|
|
1222
|
+
})) {
|
|
1223
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1224
|
+
if (!status) {
|
|
1225
|
+
continue;
|
|
1226
|
+
}
|
|
1227
|
+
terminal = TERMINAL_PLAY_STATUSES.has(status.status);
|
|
1228
|
+
if (terminal) {
|
|
1229
|
+
break;
|
|
1230
|
+
}
|
|
1132
1231
|
}
|
|
1133
|
-
if (
|
|
1134
|
-
|
|
1232
|
+
if (terminal && state.latest) {
|
|
1233
|
+
return await this.getRunStatus(state.latest.runId || runId).catch(
|
|
1234
|
+
() => state.latest ?? playRunStatusFromState(state),
|
|
1235
|
+
);
|
|
1135
1236
|
}
|
|
1136
|
-
if (
|
|
1137
|
-
|
|
1237
|
+
if (state.latest) {
|
|
1238
|
+
return state.latest;
|
|
1138
1239
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1240
|
+
throw new DeeplineError(
|
|
1241
|
+
`Run stream for ${runId} ended before the initial snapshot.`,
|
|
1242
|
+
undefined,
|
|
1243
|
+
'PLAY_RUN_STREAM_EMPTY',
|
|
1244
|
+
{ runId },
|
|
1142
1245
|
);
|
|
1143
|
-
return normalizePlayStatus(response);
|
|
1144
1246
|
}
|
|
1145
1247
|
|
|
1146
1248
|
/**
|
|
@@ -1337,11 +1439,11 @@ export class DeeplineClient {
|
|
|
1337
1439
|
// ——————————————————————————————————————————————————————————
|
|
1338
1440
|
|
|
1339
1441
|
/**
|
|
1340
|
-
* Run a play end-to-end: submit,
|
|
1442
|
+
* Run a play end-to-end: submit, stream until terminal, return result.
|
|
1341
1443
|
*
|
|
1342
1444
|
* This is the highest-level play execution method. It submits the play,
|
|
1343
|
-
*
|
|
1344
|
-
* and timing. Supports cancellation via `AbortSignal`.
|
|
1445
|
+
* reads the canonical run stream for status updates, and returns a structured
|
|
1446
|
+
* result with logs and timing. Supports cancellation via `AbortSignal`.
|
|
1345
1447
|
*
|
|
1346
1448
|
* @param code - Source string fallback; pass the bundled artifact in `options.artifact`
|
|
1347
1449
|
* @param csvPath - Input CSV path, or `null`
|
|
@@ -1357,7 +1459,6 @@ export class DeeplineClient {
|
|
|
1357
1459
|
* const logs = status.progress?.logs ?? [];
|
|
1358
1460
|
* console.log(`[${status.status}] ${logs.length} log lines`);
|
|
1359
1461
|
* },
|
|
1360
|
-
* pollIntervalMs: 1000,
|
|
1361
1462
|
* });
|
|
1362
1463
|
*
|
|
1363
1464
|
* if (result.success) {
|
|
@@ -1383,10 +1484,8 @@ export class DeeplineClient {
|
|
|
1383
1484
|
csvPath: string | null,
|
|
1384
1485
|
name?: string,
|
|
1385
1486
|
options?: {
|
|
1386
|
-
/** Called
|
|
1487
|
+
/** Called for each status snapshot emitted by the run stream. */
|
|
1387
1488
|
onProgress?: (status: PlayStatus) => void;
|
|
1388
|
-
/** Milliseconds between status polls. Default: `500`. */
|
|
1389
|
-
pollIntervalMs?: number;
|
|
1390
1489
|
/** Abort signal — triggers cancellation and immediate return. */
|
|
1391
1490
|
signal?: AbortSignal;
|
|
1392
1491
|
/** Runtime input for the play function. */
|
|
@@ -1409,39 +1508,59 @@ export class DeeplineClient {
|
|
|
1409
1508
|
packagedFiles: options?.packagedFiles,
|
|
1410
1509
|
force: options?.force,
|
|
1411
1510
|
});
|
|
1412
|
-
const pollInterval = options?.pollIntervalMs ?? 500;
|
|
1413
1511
|
const start = Date.now();
|
|
1512
|
+
const state: PlayLiveStatusState = {
|
|
1513
|
+
runId: workflowId,
|
|
1514
|
+
status: 'running',
|
|
1515
|
+
logs: [],
|
|
1516
|
+
latest: null,
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
if (options?.signal?.aborted) {
|
|
1520
|
+
await this.cancelPlay(workflowId);
|
|
1521
|
+
return {
|
|
1522
|
+
success: false,
|
|
1523
|
+
runId: workflowId,
|
|
1524
|
+
logs: [],
|
|
1525
|
+
durationMs: Date.now() - start,
|
|
1526
|
+
error: 'Cancelled by user',
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1414
1529
|
|
|
1415
|
-
|
|
1530
|
+
for await (const event of this.streamPlayRunEvents(workflowId, {
|
|
1531
|
+
mode: 'cli',
|
|
1532
|
+
signal: options?.signal,
|
|
1533
|
+
})) {
|
|
1416
1534
|
if (options?.signal?.aborted) {
|
|
1417
1535
|
await this.cancelPlay(workflowId);
|
|
1418
1536
|
return {
|
|
1419
1537
|
success: false,
|
|
1420
1538
|
runId: workflowId,
|
|
1421
|
-
logs:
|
|
1539
|
+
logs: state.logs,
|
|
1422
1540
|
durationMs: Date.now() - start,
|
|
1423
1541
|
error: 'Cancelled by user',
|
|
1424
1542
|
};
|
|
1425
1543
|
}
|
|
1426
1544
|
|
|
1427
|
-
const status =
|
|
1545
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1546
|
+
if (!status) {
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1428
1549
|
options?.onProgress?.(status);
|
|
1429
1550
|
|
|
1430
1551
|
if (TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
result: status.result,
|
|
1435
|
-
logs: status.progress?.logs ?? [],
|
|
1436
|
-
durationMs: Date.now() - start,
|
|
1437
|
-
error:
|
|
1438
|
-
status.progress?.error ??
|
|
1439
|
-
(status.status !== 'completed' ? status.status : undefined),
|
|
1440
|
-
};
|
|
1552
|
+
const finalStatus = await this.getPlayStatus(status.runId || workflowId)
|
|
1553
|
+
.catch(() => status);
|
|
1554
|
+
return playRunResultFromStatus(finalStatus, start, workflowId);
|
|
1441
1555
|
}
|
|
1442
|
-
|
|
1443
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1444
1556
|
}
|
|
1557
|
+
|
|
1558
|
+
throw new DeeplineError(
|
|
1559
|
+
`Run stream for ${workflowId} ended before the run reached a terminal state.`,
|
|
1560
|
+
undefined,
|
|
1561
|
+
'PLAY_RUN_STREAM_ENDED',
|
|
1562
|
+
{ runId: workflowId, workflowId },
|
|
1563
|
+
);
|
|
1445
1564
|
}
|
|
1446
1565
|
|
|
1447
1566
|
// ——————————————————————————————————————————————————————————
|
|
@@ -200,7 +200,7 @@ export interface ToolMetadata extends ToolDefinition {
|
|
|
200
200
|
export interface PlayRunResult {
|
|
201
201
|
/** `true` if the play completed successfully (`status === 'completed'`). */
|
|
202
202
|
success: boolean;
|
|
203
|
-
/** Public play-run identifier
|
|
203
|
+
/** Public play-run identifier. */
|
|
204
204
|
runId: string;
|
|
205
205
|
/** The play's return value. Only present on success. */
|
|
206
206
|
result?: unknown;
|
|
@@ -222,8 +222,6 @@ export interface PlayProgressStatus {
|
|
|
222
222
|
totalRows?: number;
|
|
223
223
|
/** Accumulated log lines from `ctx.log()`. Grows monotonically. */
|
|
224
224
|
logs: string[];
|
|
225
|
-
/** Zero-based offset of the first returned log line when a tail cursor is used. */
|
|
226
|
-
logOffset?: number;
|
|
227
225
|
/** Error message if the play has failed. */
|
|
228
226
|
error?: string;
|
|
229
227
|
}
|
|
@@ -265,7 +263,7 @@ export interface PlayStatus {
|
|
|
265
263
|
progress?: PlayProgressStatus;
|
|
266
264
|
/** Partial or final result. Available once the play returns. */
|
|
267
265
|
result?: unknown;
|
|
268
|
-
/**
|
|
266
|
+
/** Scheduler-backed run metadata when returned by the status endpoint. */
|
|
269
267
|
run?: {
|
|
270
268
|
startTime?: string | null;
|
|
271
269
|
closeTime?: string | null;
|
|
@@ -315,9 +313,9 @@ export interface StopPlayRunResult {
|
|
|
315
313
|
* Summary of a single play run, returned by {@link DeeplineClient.listPlayRuns}.
|
|
316
314
|
*/
|
|
317
315
|
export interface PlayRunListItem {
|
|
318
|
-
/**
|
|
316
|
+
/** Public Deepline play-run id. */
|
|
319
317
|
workflowId: string;
|
|
320
|
-
/**
|
|
318
|
+
/** Backend run attempt id, when exposed. */
|
|
321
319
|
runId: string;
|
|
322
320
|
/** Workflow type (typically `'Workflow'`). */
|
|
323
321
|
type: string;
|
|
@@ -440,7 +438,7 @@ export interface PlayDefinitionDetail {
|
|
|
440
438
|
runCount: number;
|
|
441
439
|
/** Primary key column for CSV-based plays. */
|
|
442
440
|
tableNamespace?: string | null;
|
|
443
|
-
/**
|
|
441
|
+
/** Public Deepline id of the latest run. */
|
|
444
442
|
latestRunId?: string | null;
|
|
445
443
|
/** Unix timestamp (ms). */
|
|
446
444
|
createdAt: number;
|
|
@@ -559,12 +557,11 @@ export interface ClearPlayHistoryResult {
|
|
|
559
557
|
* ```typescript
|
|
560
558
|
* const started = await client.startPlayRun({ name: 'my-play', input: { domain: 'stripe.com' } });
|
|
561
559
|
* console.log(`Started: ${started.workflowId}`);
|
|
562
|
-
* console.log(`Status URL: ${started.statusUrl}`);
|
|
563
560
|
* console.log(`Dashboard: ${started.dashboardUrl}`);
|
|
564
561
|
* ```
|
|
565
562
|
*/
|
|
566
563
|
export interface PlayRunStart {
|
|
567
|
-
/**
|
|
564
|
+
/** Public Deepline play-run id for tracking this execution. */
|
|
568
565
|
workflowId: string;
|
|
569
566
|
/** Public Deepline play-run API version. */
|
|
570
567
|
apiVersion?: number;
|
|
@@ -576,8 +573,6 @@ export interface PlayRunStart {
|
|
|
576
573
|
runtimeBackend?: string;
|
|
577
574
|
/** Canonical run contract compatibility metadata. */
|
|
578
575
|
contract?: Record<string, unknown> | null;
|
|
579
|
-
/** URL to poll for status updates. */
|
|
580
|
-
statusUrl?: string;
|
|
581
576
|
/** Dashboard URL for the named play. */
|
|
582
577
|
dashboardUrl?: string;
|
|
583
578
|
/** Terminal status returned when the start request used a short completion wait. */
|
|
@@ -589,7 +584,7 @@ export interface PlayRunStart {
|
|
|
589
584
|
*
|
|
590
585
|
* This is the check-only version of play artifact registration: the server runs
|
|
591
586
|
* the same preflight compiler and static-analysis pass without storing,
|
|
592
|
-
* publishing, or starting a
|
|
587
|
+
* publishing, or starting a play run.
|
|
593
588
|
*/
|
|
594
589
|
export interface PlayCheckResult {
|
|
595
590
|
valid: boolean;
|
|
@@ -657,8 +652,7 @@ export interface StartPlayRunRequest {
|
|
|
657
652
|
waitForCompletionMs?: number;
|
|
658
653
|
/**
|
|
659
654
|
* Per-run execution profile override. The server defaults to `workers_edge`;
|
|
660
|
-
* tests
|
|
661
|
-
* this unset.
|
|
655
|
+
* tests can pass `local` here. Most callers should leave this unset.
|
|
662
656
|
*/
|
|
663
657
|
profile?: string;
|
|
664
658
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.
|
|
1
|
+
export const SDK_VERSION = "0.1.23";
|
|
2
2
|
export const SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
export const EXECUTION_PLAN_DEFAULTS = {
|
|
8
8
|
inlineRowsLimit: 1_000,
|
|
9
9
|
largeMapChunkSize: 5_000,
|
|
10
|
+
complexMapChunkSize: 1_000,
|
|
10
11
|
workflowSoftStepBudget: 20_000,
|
|
11
12
|
workflowHardStepBudget: 25_000,
|
|
12
13
|
ingestStepCount: 1,
|
|
@@ -183,6 +184,10 @@ function extractPlanMaps(
|
|
|
183
184
|
(substep): substep is Extract<PlayStaticSubstep, { type: 'waterfall' }> =>
|
|
184
185
|
substep.type === 'waterfall',
|
|
185
186
|
);
|
|
187
|
+
const fallbackStepSuites = substeps.filter(
|
|
188
|
+
(substep): substep is Extract<PlayStaticSubstep, { type: 'step_suite' }> =>
|
|
189
|
+
substep.type === 'step_suite',
|
|
190
|
+
);
|
|
186
191
|
return substeps
|
|
187
192
|
.filter(
|
|
188
193
|
(substep): substep is Extract<PlayStaticSubstep, { type: 'map' }> =>
|
|
@@ -200,13 +205,33 @@ function extractPlanMaps(
|
|
|
200
205
|
waterfallId: waterfall.id ?? waterfall.field,
|
|
201
206
|
stageIds: waterfall.steps?.map((step) => step.id) ?? [],
|
|
202
207
|
}));
|
|
208
|
+
const stepSuites = fallbackStepSuites.filter((stepSuite) => {
|
|
209
|
+
if (!mapSubstep.waterfallIds?.length) return true;
|
|
210
|
+
return mapSubstep.waterfallIds.includes(stepSuite.field);
|
|
211
|
+
});
|
|
212
|
+
const stepSuiteStepsPerChunk = stepSuites.reduce(
|
|
213
|
+
(max, stepSuite) => Math.max(max, stepSuite.steps.length),
|
|
214
|
+
0,
|
|
215
|
+
);
|
|
216
|
+
const waterfallStepsPerChunk = waterfallStages.reduce(
|
|
217
|
+
(max, waterfall) => Math.max(max, waterfall.stageIds.length),
|
|
218
|
+
0,
|
|
219
|
+
);
|
|
220
|
+
const stepsPerChunk = Math.max(
|
|
221
|
+
1,
|
|
222
|
+
waterfallStepsPerChunk,
|
|
223
|
+
stepSuiteStepsPerChunk,
|
|
224
|
+
);
|
|
203
225
|
return {
|
|
204
226
|
mapName: mapSubstep.name ?? mapSubstep.field,
|
|
205
227
|
tableNamespace: mapSubstep.tableNamespace ?? mapSubstep.field,
|
|
206
228
|
outputFields: mapSubstep.outputFields ?? [],
|
|
207
229
|
waterfallStages,
|
|
208
|
-
defaultChunkSize:
|
|
209
|
-
|
|
230
|
+
defaultChunkSize:
|
|
231
|
+
stepsPerChunk > 1
|
|
232
|
+
? EXECUTION_PLAN_DEFAULTS.complexMapChunkSize
|
|
233
|
+
: EXECUTION_PLAN_DEFAULTS.largeMapChunkSize,
|
|
234
|
+
stepsPerChunk,
|
|
210
235
|
};
|
|
211
236
|
});
|
|
212
237
|
}
|