deepline 0.1.20 → 0.1.22
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 +845 -337
- package/dist/cli/index.mjs +902 -389
- package/dist/index.d.mts +23 -58
- package/dist/index.d.ts +23 -58
- package/dist/index.js +195 -92
- package/dist/index.mjs +195 -92
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +888 -227
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +540 -36
- package/dist/repo/apps/play-runner-workers/src/entry.ts +477 -374
- package/dist/repo/sdk/src/client.ts +245 -118
- package/dist/repo/sdk/src/http.ts +19 -1
- package/dist/repo/sdk/src/plays/harness-stub.ts +12 -0
- 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/profiles.ts +4 -14
- package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +3 -6
- 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,
|
|
@@ -88,11 +89,7 @@ export type RunsListOptions = {
|
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
export type RunsTailOptions = {
|
|
91
|
-
|
|
92
|
-
afterLogIndex?: number;
|
|
93
|
-
waitMs?: number;
|
|
94
|
-
terminalOnly?: boolean;
|
|
95
|
-
compact?: boolean;
|
|
92
|
+
signal?: AbortSignal;
|
|
96
93
|
};
|
|
97
94
|
|
|
98
95
|
export type RunsLogsOptions = {
|
|
@@ -127,11 +124,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
127
124
|
|
|
128
125
|
function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
|
|
129
126
|
const status =
|
|
130
|
-
typeof raw.status === 'string'
|
|
131
|
-
? raw.status
|
|
132
|
-
: typeof raw.temporalStatus === 'string'
|
|
133
|
-
? mapLegacyTemporalStatus(raw.temporalStatus)
|
|
134
|
-
: 'running';
|
|
127
|
+
typeof raw.status === 'string' ? raw.status : 'running';
|
|
135
128
|
const runId =
|
|
136
129
|
typeof raw.runId === 'string'
|
|
137
130
|
? raw.runId
|
|
@@ -145,22 +138,138 @@ function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
|
|
|
145
138
|
};
|
|
146
139
|
}
|
|
147
140
|
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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';
|
|
141
|
+
function decodeBase64Bytes(value: string): Uint8Array {
|
|
142
|
+
const binary = atob(value);
|
|
143
|
+
const bytes = new Uint8Array(binary.length);
|
|
144
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
145
|
+
bytes[index] = binary.charCodeAt(index);
|
|
163
146
|
}
|
|
147
|
+
return bytes;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function readStringArray(value: unknown): string[] {
|
|
151
|
+
return Array.isArray(value)
|
|
152
|
+
? value.filter((line): line is string => typeof line === 'string')
|
|
153
|
+
: [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type PlayLiveStatusState = {
|
|
157
|
+
runId: string;
|
|
158
|
+
status: PlayStatus['status'];
|
|
159
|
+
logs: string[];
|
|
160
|
+
result?: unknown;
|
|
161
|
+
error?: string;
|
|
162
|
+
latest: PlayStatus | null;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
function getPlayLiveEventPayload(event: PlayLiveEvent): Record<string, unknown> {
|
|
166
|
+
return event.payload && typeof event.payload === 'object'
|
|
167
|
+
? (event.payload as Record<string, unknown>)
|
|
168
|
+
: {};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function normalizeLiveStatus(value: unknown): PlayStatus['status'] | null {
|
|
172
|
+
if (
|
|
173
|
+
value === 'queued' ||
|
|
174
|
+
value === 'running' ||
|
|
175
|
+
value === 'waiting' ||
|
|
176
|
+
value === 'completed' ||
|
|
177
|
+
value === 'failed' ||
|
|
178
|
+
value === 'cancelled'
|
|
179
|
+
) {
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function updatePlayLiveStatusState(
|
|
186
|
+
state: PlayLiveStatusState,
|
|
187
|
+
event: PlayLiveEvent,
|
|
188
|
+
): PlayStatus | null {
|
|
189
|
+
const payload = getPlayLiveEventPayload(event);
|
|
190
|
+
if (event.type === 'play.run.log') {
|
|
191
|
+
state.logs.push(...readStringArray(payload.lines));
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
if (
|
|
195
|
+
event.type !== 'play.run.snapshot' &&
|
|
196
|
+
event.type !== 'play.run.status' &&
|
|
197
|
+
event.type !== 'play.run.final_status'
|
|
198
|
+
) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const runId =
|
|
203
|
+
typeof payload.runId === 'string' && payload.runId
|
|
204
|
+
? payload.runId
|
|
205
|
+
: state.runId;
|
|
206
|
+
const status = normalizeLiveStatus(payload.status) ?? state.status;
|
|
207
|
+
const logs = readStringArray(payload.logs);
|
|
208
|
+
if (logs.length > 0 || event.type === 'play.run.snapshot') {
|
|
209
|
+
state.logs = logs;
|
|
210
|
+
}
|
|
211
|
+
if ('result' in payload) {
|
|
212
|
+
state.result = payload.result;
|
|
213
|
+
}
|
|
214
|
+
if (typeof payload.error === 'string' && payload.error.trim()) {
|
|
215
|
+
state.error = payload.error;
|
|
216
|
+
}
|
|
217
|
+
state.runId = runId;
|
|
218
|
+
state.status = status;
|
|
219
|
+
|
|
220
|
+
const progressRecord =
|
|
221
|
+
payload.progress &&
|
|
222
|
+
typeof payload.progress === 'object' &&
|
|
223
|
+
!Array.isArray(payload.progress)
|
|
224
|
+
? (payload.progress as Record<string, unknown>)
|
|
225
|
+
: {};
|
|
226
|
+
const next: PlayStatus = {
|
|
227
|
+
...(payload as unknown as Omit<PlayStatus, 'runId' | 'status' | 'progress'>),
|
|
228
|
+
runId,
|
|
229
|
+
status,
|
|
230
|
+
progress: {
|
|
231
|
+
...progressRecord,
|
|
232
|
+
status:
|
|
233
|
+
typeof progressRecord.status === 'string'
|
|
234
|
+
? progressRecord.status
|
|
235
|
+
: status,
|
|
236
|
+
logs: state.logs,
|
|
237
|
+
...(state.error ? { error: state.error } : {}),
|
|
238
|
+
},
|
|
239
|
+
...('result' in state ? { result: state.result } : {}),
|
|
240
|
+
};
|
|
241
|
+
state.latest = next;
|
|
242
|
+
return next;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function playRunResultFromStatus(
|
|
246
|
+
status: PlayStatus,
|
|
247
|
+
startedAt: number,
|
|
248
|
+
fallbackRunId: string,
|
|
249
|
+
): PlayRunResult {
|
|
250
|
+
return {
|
|
251
|
+
success: status.status === 'completed',
|
|
252
|
+
runId: status.runId || fallbackRunId,
|
|
253
|
+
result: status.result,
|
|
254
|
+
logs: status.progress?.logs ?? [],
|
|
255
|
+
durationMs: Date.now() - startedAt,
|
|
256
|
+
error:
|
|
257
|
+
status.progress?.error ??
|
|
258
|
+
(status.status !== 'completed' ? status.status : undefined),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function playRunStatusFromState(state: PlayLiveStatusState): PlayStatus {
|
|
263
|
+
return {
|
|
264
|
+
runId: state.runId,
|
|
265
|
+
status: state.status,
|
|
266
|
+
progress: {
|
|
267
|
+
status: state.status,
|
|
268
|
+
logs: state.logs,
|
|
269
|
+
...(state.error ? { error: state.error } : {}),
|
|
270
|
+
},
|
|
271
|
+
...('result' in state ? { result: state.result } : {}),
|
|
272
|
+
};
|
|
164
273
|
}
|
|
165
274
|
|
|
166
275
|
/**
|
|
@@ -330,7 +439,7 @@ export class DeeplineClient {
|
|
|
330
439
|
/**
|
|
331
440
|
* Search available tools using Deepline's ranked backend search.
|
|
332
441
|
*
|
|
333
|
-
* This is the same discovery surface used by the
|
|
442
|
+
* This is the same discovery surface used by the CLI: it ranks across
|
|
334
443
|
* tool metadata, categories, agent guidance, and input schema fields.
|
|
335
444
|
*/
|
|
336
445
|
async searchTools(
|
|
@@ -444,7 +553,7 @@ export class DeeplineClient {
|
|
|
444
553
|
* `progress.logs`; they are not part of the user output object.
|
|
445
554
|
*
|
|
446
555
|
* @param request - Play run configuration (name, code, input, etc.)
|
|
447
|
-
* @returns
|
|
556
|
+
* @returns Run metadata including the public `workflowId`
|
|
448
557
|
*
|
|
449
558
|
* @example
|
|
450
559
|
* ```typescript
|
|
@@ -849,9 +958,34 @@ export class DeeplineClient {
|
|
|
849
958
|
bytes: number;
|
|
850
959
|
}>,
|
|
851
960
|
): Promise<PlayStagedFileRef[]> {
|
|
852
|
-
const
|
|
961
|
+
const formData = new FormData();
|
|
962
|
+
formData.set(
|
|
963
|
+
'metadata',
|
|
964
|
+
JSON.stringify({
|
|
965
|
+
files: files.map((file, index) => ({
|
|
966
|
+
index,
|
|
967
|
+
logicalPath: file.logicalPath,
|
|
968
|
+
contentHash: file.contentHash,
|
|
969
|
+
contentType: file.contentType,
|
|
970
|
+
bytes: file.bytes,
|
|
971
|
+
})),
|
|
972
|
+
}),
|
|
973
|
+
);
|
|
974
|
+
for (const [index, file] of files.entries()) {
|
|
975
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
976
|
+
const body = bytes.buffer.slice(
|
|
977
|
+
bytes.byteOffset,
|
|
978
|
+
bytes.byteOffset + bytes.byteLength,
|
|
979
|
+
) as ArrayBuffer;
|
|
980
|
+
formData.set(
|
|
981
|
+
`file:${index}`,
|
|
982
|
+
new Blob([body], { type: file.contentType }),
|
|
983
|
+
file.logicalPath,
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
const response = await this.http.postFormData<{ files: PlayStagedFileRef[] }>(
|
|
853
987
|
'/api/v2/plays/files/stage',
|
|
854
|
-
|
|
988
|
+
formData,
|
|
855
989
|
);
|
|
856
990
|
return response.files;
|
|
857
991
|
}
|
|
@@ -883,9 +1017,6 @@ export class DeeplineClient {
|
|
|
883
1017
|
* Internal/advanced primitive. Public callers should usually prefer
|
|
884
1018
|
* {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
|
|
885
1019
|
*
|
|
886
|
-
* Poll this method until `status` reaches a terminal state:
|
|
887
|
-
* `'completed'`, `'failed'`, or `'cancelled'`.
|
|
888
|
-
*
|
|
889
1020
|
* @param workflowId - Play-run id from {@link startPlayRun}
|
|
890
1021
|
* @returns Current status with progress logs and partial results
|
|
891
1022
|
*
|
|
@@ -896,41 +1027,17 @@ export class DeeplineClient {
|
|
|
896
1027
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
897
1028
|
* ```
|
|
898
1029
|
*/
|
|
899
|
-
async getPlayStatus(
|
|
900
|
-
const response = await this.http.get<Record<string, unknown>>(
|
|
901
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}`,
|
|
902
|
-
);
|
|
903
|
-
return normalizePlayStatus(response);
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
/**
|
|
907
|
-
* Get the lightweight tail-polling status for a play execution.
|
|
908
|
-
*
|
|
909
|
-
* This is intentionally smaller than {@link getPlayStatus}: it returns the
|
|
910
|
-
* fields needed for CLI log tailing while the run is in flight, without
|
|
911
|
-
* forcing the API to rebuild final result views on every poll. Call
|
|
912
|
-
* {@link getPlayStatus} once after a terminal state for the full result.
|
|
913
|
-
*/
|
|
914
|
-
async getPlayTailStatus(
|
|
1030
|
+
async getPlayStatus(
|
|
915
1031
|
workflowId: string,
|
|
916
|
-
options?: {
|
|
917
|
-
afterLogIndex?: number;
|
|
918
|
-
waitMs?: number;
|
|
919
|
-
terminalOnly?: boolean;
|
|
920
|
-
},
|
|
1032
|
+
options?: { billing?: boolean },
|
|
921
1033
|
): Promise<PlayStatus> {
|
|
922
|
-
const params = new URLSearchParams(
|
|
923
|
-
if (
|
|
924
|
-
params.set('
|
|
925
|
-
}
|
|
926
|
-
if (typeof options?.waitMs === 'number') {
|
|
927
|
-
params.set('waitMs', String(options.waitMs));
|
|
928
|
-
}
|
|
929
|
-
if (options?.terminalOnly) {
|
|
930
|
-
params.set('terminalOnly', 'true');
|
|
1034
|
+
const params = new URLSearchParams();
|
|
1035
|
+
if (options?.billing === false) {
|
|
1036
|
+
params.set('billing', 'false');
|
|
931
1037
|
}
|
|
1038
|
+
const query = params.size > 0 ? `?${params.toString()}` : '';
|
|
932
1039
|
const response = await this.http.get<Record<string, unknown>>(
|
|
933
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}
|
|
1040
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}${query}`,
|
|
934
1041
|
);
|
|
935
1042
|
return normalizePlayStatus(response);
|
|
936
1043
|
}
|
|
@@ -938,8 +1045,8 @@ export class DeeplineClient {
|
|
|
938
1045
|
/**
|
|
939
1046
|
* Stream semantic play-run events using the same SSE feed as the dashboard.
|
|
940
1047
|
*
|
|
941
|
-
*
|
|
942
|
-
*
|
|
1048
|
+
* The server emits a canonical `play.run.snapshot` event first for every
|
|
1049
|
+
* connection, then incremental live events until terminal state or reconnect.
|
|
943
1050
|
*/
|
|
944
1051
|
async *streamPlayRunEvents(
|
|
945
1052
|
workflowId: string,
|
|
@@ -970,7 +1077,7 @@ export class DeeplineClient {
|
|
|
970
1077
|
*
|
|
971
1078
|
* Sends a stop request for the run.
|
|
972
1079
|
*
|
|
973
|
-
* @param workflowId -
|
|
1080
|
+
* @param workflowId - Public Deepline play-run id to cancel
|
|
974
1081
|
*
|
|
975
1082
|
* @example
|
|
976
1083
|
* ```typescript
|
|
@@ -987,7 +1094,7 @@ export class DeeplineClient {
|
|
|
987
1094
|
/**
|
|
988
1095
|
* Stop a running play execution, including open HITL waits.
|
|
989
1096
|
*
|
|
990
|
-
* @param workflowId -
|
|
1097
|
+
* @param workflowId - Public Deepline play-run id to stop
|
|
991
1098
|
* @param options.reason - Optional audit/debug reason
|
|
992
1099
|
*/
|
|
993
1100
|
async stopPlay(
|
|
@@ -1066,39 +1173,42 @@ export class DeeplineClient {
|
|
|
1066
1173
|
return response.runs ?? [];
|
|
1067
1174
|
}
|
|
1068
1175
|
|
|
1069
|
-
/**
|
|
1070
|
-
* Fetch the lightweight tail status for a run using the public runs resource model.
|
|
1071
|
-
*
|
|
1072
|
-
* This is the SDK equivalent of:
|
|
1073
|
-
*
|
|
1074
|
-
* ```bash
|
|
1075
|
-
* deepline runs tail <run-id> --json
|
|
1076
|
-
* ```
|
|
1077
|
-
*/
|
|
1176
|
+
/** Read the canonical run stream and return the latest run snapshot. */
|
|
1078
1177
|
async tailRun(runId: string, options?: RunsTailOptions): Promise<PlayStatus> {
|
|
1079
|
-
const
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1178
|
+
const state: PlayLiveStatusState = {
|
|
1179
|
+
runId,
|
|
1180
|
+
status: 'running',
|
|
1181
|
+
logs: [],
|
|
1182
|
+
latest: null,
|
|
1183
|
+
};
|
|
1184
|
+
let terminal = false;
|
|
1185
|
+
for await (const event of this.streamPlayRunEvents(runId, {
|
|
1186
|
+
mode: 'cli',
|
|
1187
|
+
signal: options?.signal,
|
|
1188
|
+
})) {
|
|
1189
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1190
|
+
if (!status) {
|
|
1191
|
+
continue;
|
|
1192
|
+
}
|
|
1193
|
+
terminal = TERMINAL_PLAY_STATUSES.has(status.status);
|
|
1194
|
+
if (terminal) {
|
|
1195
|
+
break;
|
|
1196
|
+
}
|
|
1090
1197
|
}
|
|
1091
|
-
if (
|
|
1092
|
-
|
|
1198
|
+
if (terminal && state.latest) {
|
|
1199
|
+
return await this.getRunStatus(state.latest.runId || runId).catch(
|
|
1200
|
+
() => state.latest ?? playRunStatusFromState(state),
|
|
1201
|
+
);
|
|
1093
1202
|
}
|
|
1094
|
-
if (
|
|
1095
|
-
|
|
1203
|
+
if (state.latest) {
|
|
1204
|
+
return state.latest;
|
|
1096
1205
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1206
|
+
throw new DeeplineError(
|
|
1207
|
+
`Run stream for ${runId} ended before the initial snapshot.`,
|
|
1208
|
+
undefined,
|
|
1209
|
+
'PLAY_RUN_STREAM_EMPTY',
|
|
1210
|
+
{ runId },
|
|
1100
1211
|
);
|
|
1101
|
-
return normalizePlayStatus(response);
|
|
1102
1212
|
}
|
|
1103
1213
|
|
|
1104
1214
|
/**
|
|
@@ -1295,11 +1405,11 @@ export class DeeplineClient {
|
|
|
1295
1405
|
// ——————————————————————————————————————————————————————————
|
|
1296
1406
|
|
|
1297
1407
|
/**
|
|
1298
|
-
* Run a play end-to-end: submit,
|
|
1408
|
+
* Run a play end-to-end: submit, stream until terminal, return result.
|
|
1299
1409
|
*
|
|
1300
1410
|
* This is the highest-level play execution method. It submits the play,
|
|
1301
|
-
*
|
|
1302
|
-
* and timing. Supports cancellation via `AbortSignal`.
|
|
1411
|
+
* reads the canonical run stream for status updates, and returns a structured
|
|
1412
|
+
* result with logs and timing. Supports cancellation via `AbortSignal`.
|
|
1303
1413
|
*
|
|
1304
1414
|
* @param code - Source string fallback; pass the bundled artifact in `options.artifact`
|
|
1305
1415
|
* @param csvPath - Input CSV path, or `null`
|
|
@@ -1315,7 +1425,6 @@ export class DeeplineClient {
|
|
|
1315
1425
|
* const logs = status.progress?.logs ?? [];
|
|
1316
1426
|
* console.log(`[${status.status}] ${logs.length} log lines`);
|
|
1317
1427
|
* },
|
|
1318
|
-
* pollIntervalMs: 1000,
|
|
1319
1428
|
* });
|
|
1320
1429
|
*
|
|
1321
1430
|
* if (result.success) {
|
|
@@ -1341,10 +1450,8 @@ export class DeeplineClient {
|
|
|
1341
1450
|
csvPath: string | null,
|
|
1342
1451
|
name?: string,
|
|
1343
1452
|
options?: {
|
|
1344
|
-
/** Called
|
|
1453
|
+
/** Called for each status snapshot emitted by the run stream. */
|
|
1345
1454
|
onProgress?: (status: PlayStatus) => void;
|
|
1346
|
-
/** Milliseconds between status polls. Default: `500`. */
|
|
1347
|
-
pollIntervalMs?: number;
|
|
1348
1455
|
/** Abort signal — triggers cancellation and immediate return. */
|
|
1349
1456
|
signal?: AbortSignal;
|
|
1350
1457
|
/** Runtime input for the play function. */
|
|
@@ -1367,39 +1474,59 @@ export class DeeplineClient {
|
|
|
1367
1474
|
packagedFiles: options?.packagedFiles,
|
|
1368
1475
|
force: options?.force,
|
|
1369
1476
|
});
|
|
1370
|
-
const pollInterval = options?.pollIntervalMs ?? 500;
|
|
1371
1477
|
const start = Date.now();
|
|
1478
|
+
const state: PlayLiveStatusState = {
|
|
1479
|
+
runId: workflowId,
|
|
1480
|
+
status: 'running',
|
|
1481
|
+
logs: [],
|
|
1482
|
+
latest: null,
|
|
1483
|
+
};
|
|
1372
1484
|
|
|
1373
|
-
|
|
1485
|
+
if (options?.signal?.aborted) {
|
|
1486
|
+
await this.cancelPlay(workflowId);
|
|
1487
|
+
return {
|
|
1488
|
+
success: false,
|
|
1489
|
+
runId: workflowId,
|
|
1490
|
+
logs: [],
|
|
1491
|
+
durationMs: Date.now() - start,
|
|
1492
|
+
error: 'Cancelled by user',
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
for await (const event of this.streamPlayRunEvents(workflowId, {
|
|
1497
|
+
mode: 'cli',
|
|
1498
|
+
signal: options?.signal,
|
|
1499
|
+
})) {
|
|
1374
1500
|
if (options?.signal?.aborted) {
|
|
1375
1501
|
await this.cancelPlay(workflowId);
|
|
1376
1502
|
return {
|
|
1377
1503
|
success: false,
|
|
1378
1504
|
runId: workflowId,
|
|
1379
|
-
logs:
|
|
1505
|
+
logs: state.logs,
|
|
1380
1506
|
durationMs: Date.now() - start,
|
|
1381
1507
|
error: 'Cancelled by user',
|
|
1382
1508
|
};
|
|
1383
1509
|
}
|
|
1384
1510
|
|
|
1385
|
-
const status =
|
|
1511
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1512
|
+
if (!status) {
|
|
1513
|
+
continue;
|
|
1514
|
+
}
|
|
1386
1515
|
options?.onProgress?.(status);
|
|
1387
1516
|
|
|
1388
1517
|
if (TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
result: status.result,
|
|
1393
|
-
logs: status.progress?.logs ?? [],
|
|
1394
|
-
durationMs: Date.now() - start,
|
|
1395
|
-
error:
|
|
1396
|
-
status.progress?.error ??
|
|
1397
|
-
(status.status !== 'completed' ? status.status : undefined),
|
|
1398
|
-
};
|
|
1518
|
+
const finalStatus = await this.getPlayStatus(status.runId || workflowId)
|
|
1519
|
+
.catch(() => status);
|
|
1520
|
+
return playRunResultFromStatus(finalStatus, start, workflowId);
|
|
1399
1521
|
}
|
|
1400
|
-
|
|
1401
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1402
1522
|
}
|
|
1523
|
+
|
|
1524
|
+
throw new DeeplineError(
|
|
1525
|
+
`Run stream for ${workflowId} ended before the run reached a terminal state.`,
|
|
1526
|
+
undefined,
|
|
1527
|
+
'PLAY_RUN_STREAM_ENDED',
|
|
1528
|
+
{ runId: workflowId, workflowId },
|
|
1529
|
+
);
|
|
1403
1530
|
}
|
|
1404
1531
|
|
|
1405
1532
|
// ——————————————————————————————————————————————————————————
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
interface RequestOptions {
|
|
32
32
|
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
33
33
|
body?: unknown;
|
|
34
|
+
formData?: FormData;
|
|
34
35
|
headers?: Record<string, string>;
|
|
35
36
|
/** Per-request timeout override in milliseconds. */
|
|
36
37
|
timeout?: number;
|
|
@@ -150,7 +151,12 @@ export class HttpClient {
|
|
|
150
151
|
const response = await fetch(candidateUrl, {
|
|
151
152
|
method,
|
|
152
153
|
headers,
|
|
153
|
-
body:
|
|
154
|
+
body:
|
|
155
|
+
options?.formData !== undefined
|
|
156
|
+
? options.formData
|
|
157
|
+
: options?.body !== undefined
|
|
158
|
+
? JSON.stringify(options.body)
|
|
159
|
+
: undefined,
|
|
154
160
|
signal: controller.signal,
|
|
155
161
|
});
|
|
156
162
|
|
|
@@ -317,6 +323,18 @@ export class HttpClient {
|
|
|
317
323
|
});
|
|
318
324
|
}
|
|
319
325
|
|
|
326
|
+
async postFormData<T = unknown>(
|
|
327
|
+
path: string,
|
|
328
|
+
formData: FormData,
|
|
329
|
+
headers?: Record<string, string>,
|
|
330
|
+
): Promise<T> {
|
|
331
|
+
return this.request<T>(path, {
|
|
332
|
+
method: 'POST',
|
|
333
|
+
formData,
|
|
334
|
+
headers,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
320
338
|
/**
|
|
321
339
|
* Send a DELETE request.
|
|
322
340
|
*
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
import type {
|
|
35
35
|
PlayHarnessRpc,
|
|
36
|
+
PreloadedRuntimeDbSessionInput,
|
|
36
37
|
RuntimeApiCallInput,
|
|
37
38
|
RuntimeApiCallResult,
|
|
38
39
|
RuntimePayloadSchemaId,
|
|
@@ -121,6 +122,17 @@ export async function harnessRuntimeApiCall(
|
|
|
121
122
|
return requireBinding().runtimeApiCall(input);
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Warm Postgres sessions in the long-lived harness Worker. This preserves the
|
|
127
|
+
* map fast path without bundling the Neon client into every dynamic play.
|
|
128
|
+
*/
|
|
129
|
+
export async function harnessPrewarmPostgresSessions(input: {
|
|
130
|
+
executorToken: string;
|
|
131
|
+
sessions: PreloadedRuntimeDbSessionInput[];
|
|
132
|
+
}): Promise<{ ok: true; sessions: number }> {
|
|
133
|
+
return requireBinding().prewarmPostgresSessions(input);
|
|
134
|
+
}
|
|
135
|
+
|
|
124
136
|
/**
|
|
125
137
|
* Start or continue a map dataset write inside the harness, so this call
|
|
126
138
|
* skips per-play callback overhead for heavy Postgres writes.
|
|
@@ -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.22";
|
|
2
2
|
export const SDK_API_CONTRACT = "2026-05-runs-v2";
|