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/index.js CHANGED
@@ -241,7 +241,7 @@ function resolveConfig(options) {
241
241
  }
242
242
 
243
243
  // src/version.ts
244
- var SDK_VERSION = "0.1.21";
244
+ var SDK_VERSION = "0.1.23";
245
245
  var SDK_API_CONTRACT = "2026-05-runs-v2";
246
246
 
247
247
  // ../shared_libs/play-runtime/coordinator-headers.ts
@@ -529,11 +529,24 @@ function sleep(ms) {
529
529
  // src/client.ts
530
530
  var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
531
531
  var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
532
+ var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
533
+ function sleep2(ms) {
534
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
535
+ }
536
+ function isTransientCompileManifestError(error) {
537
+ if (error instanceof DeeplineError && typeof error.statusCode === "number") {
538
+ return error.statusCode === 408 || error.statusCode === 425 || error.statusCode === 499 || error.statusCode >= 500 && error.statusCode < 600;
539
+ }
540
+ const message = error instanceof Error ? error.message : String(error);
541
+ return /fetch failed|connection (?:closed|reset|terminated)|socket hang up|econnreset|etimedout|eai_again|abort/i.test(
542
+ message
543
+ );
544
+ }
532
545
  function isRecord(value) {
533
546
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
534
547
  }
535
548
  function normalizePlayStatus(raw) {
536
- const status = typeof raw.status === "string" ? raw.status : typeof raw.temporalStatus === "string" ? mapLegacyTemporalStatus(raw.temporalStatus) : "running";
549
+ const status = typeof raw.status === "string" ? raw.status : "running";
537
550
  const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : "";
538
551
  return {
539
552
  ...raw,
@@ -541,23 +554,6 @@ function normalizePlayStatus(raw) {
541
554
  status
542
555
  };
543
556
  }
544
- function mapLegacyTemporalStatus(status) {
545
- switch (status.trim().toUpperCase()) {
546
- case "PENDING":
547
- return "queued";
548
- case "COMPLETED":
549
- return "completed";
550
- case "FAILED":
551
- return "failed";
552
- case "CANCELLED":
553
- case "TERMINATED":
554
- case "TIMED_OUT":
555
- return "cancelled";
556
- case "RUNNING":
557
- default:
558
- return "running";
559
- }
560
- }
561
557
  function decodeBase64Bytes(value) {
562
558
  const binary = atob(value);
563
559
  const bytes = new Uint8Array(binary.length);
@@ -566,6 +562,79 @@ function decodeBase64Bytes(value) {
566
562
  }
567
563
  return bytes;
568
564
  }
565
+ function readStringArray(value) {
566
+ return Array.isArray(value) ? value.filter((line) => typeof line === "string") : [];
567
+ }
568
+ function getPlayLiveEventPayload(event) {
569
+ return event.payload && typeof event.payload === "object" ? event.payload : {};
570
+ }
571
+ function normalizeLiveStatus(value) {
572
+ if (value === "queued" || value === "running" || value === "waiting" || value === "completed" || value === "failed" || value === "cancelled") {
573
+ return value;
574
+ }
575
+ return null;
576
+ }
577
+ function updatePlayLiveStatusState(state, event) {
578
+ const payload = getPlayLiveEventPayload(event);
579
+ if (event.type === "play.run.log") {
580
+ state.logs.push(...readStringArray(payload.lines));
581
+ return null;
582
+ }
583
+ if (event.type !== "play.run.snapshot" && event.type !== "play.run.status" && event.type !== "play.run.final_status") {
584
+ return null;
585
+ }
586
+ const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : state.runId;
587
+ const status = normalizeLiveStatus(payload.status) ?? state.status;
588
+ const logs = readStringArray(payload.logs);
589
+ if (logs.length > 0 || event.type === "play.run.snapshot") {
590
+ state.logs = logs;
591
+ }
592
+ if ("result" in payload) {
593
+ state.result = payload.result;
594
+ }
595
+ if (typeof payload.error === "string" && payload.error.trim()) {
596
+ state.error = payload.error;
597
+ }
598
+ state.runId = runId;
599
+ state.status = status;
600
+ const progressRecord = payload.progress && typeof payload.progress === "object" && !Array.isArray(payload.progress) ? payload.progress : {};
601
+ const next = {
602
+ ...payload,
603
+ runId,
604
+ status,
605
+ progress: {
606
+ ...progressRecord,
607
+ status: typeof progressRecord.status === "string" ? progressRecord.status : status,
608
+ logs: state.logs,
609
+ ...state.error ? { error: state.error } : {}
610
+ },
611
+ ..."result" in state ? { result: state.result } : {}
612
+ };
613
+ state.latest = next;
614
+ return next;
615
+ }
616
+ function playRunResultFromStatus(status, startedAt, fallbackRunId) {
617
+ return {
618
+ success: status.status === "completed",
619
+ runId: status.runId || fallbackRunId,
620
+ result: status.result,
621
+ logs: status.progress?.logs ?? [],
622
+ durationMs: Date.now() - startedAt,
623
+ error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
624
+ };
625
+ }
626
+ function playRunStatusFromState(state) {
627
+ return {
628
+ runId: state.runId,
629
+ status: state.status,
630
+ progress: {
631
+ status: state.status,
632
+ logs: state.logs,
633
+ ...state.error ? { error: state.error } : {}
634
+ },
635
+ ..."result" in state ? { result: state.result } : {}
636
+ };
637
+ }
569
638
  var DeeplineClient = class {
570
639
  http;
571
640
  config;
@@ -675,7 +744,7 @@ var DeeplineClient = class {
675
744
  /**
676
745
  * Search available tools using Deepline's ranked backend search.
677
746
  *
678
- * This is the same discovery surface used by the legacy CLI: it ranks across
747
+ * This is the same discovery surface used by the CLI: it ranks across
679
748
  * tool metadata, categories, agent guidance, and input schema fields.
680
749
  */
681
750
  async searchTools(options = {}) {
@@ -768,7 +837,7 @@ var DeeplineClient = class {
768
837
  * `progress.logs`; they are not part of the user output object.
769
838
  *
770
839
  * @param request - Play run configuration (name, code, input, etc.)
771
- * @returns Workflow metadata including the `workflowId` for status polling
840
+ * @returns Run metadata including the public `workflowId`
772
841
  *
773
842
  * @example
774
843
  * ```typescript
@@ -878,8 +947,22 @@ var DeeplineClient = class {
878
947
  });
879
948
  }
880
949
  async compilePlayManifest(input) {
881
- const response = await this.http.post("/api/v2/plays/compile-manifest", input);
882
- return response.compilerManifest;
950
+ const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
951
+ 0,
952
+ Math.max(0, this.config.maxRetries)
953
+ );
954
+ for (let attempt = 0; ; attempt += 1) {
955
+ try {
956
+ const response = await this.http.post("/api/v2/plays/compile-manifest", input);
957
+ return response.compilerManifest;
958
+ } catch (error) {
959
+ const delayMs = retryDelays[attempt];
960
+ if (delayMs === void 0 || !isTransientCompileManifestError(error)) {
961
+ throw error;
962
+ }
963
+ await sleep2(delayMs);
964
+ }
965
+ }
883
966
  }
884
967
  /**
885
968
  * Check a bundled play artifact against the server's current play compiler.
@@ -1060,9 +1143,6 @@ var DeeplineClient = class {
1060
1143
  * Internal/advanced primitive. Public callers should usually prefer
1061
1144
  * {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
1062
1145
  *
1063
- * Poll this method until `status` reaches a terminal state:
1064
- * `'completed'`, `'failed'`, or `'cancelled'`.
1065
- *
1066
1146
  * @param workflowId - Play-run id from {@link startPlayRun}
1067
1147
  * @returns Current status with progress logs and partial results
1068
1148
  *
@@ -1084,35 +1164,11 @@ var DeeplineClient = class {
1084
1164
  );
1085
1165
  return normalizePlayStatus(response);
1086
1166
  }
1087
- /**
1088
- * Get the lightweight tail-polling status for a play execution.
1089
- *
1090
- * This is intentionally smaller than {@link getPlayStatus}: it returns the
1091
- * fields needed for CLI log tailing while the run is in flight, without
1092
- * forcing the API to rebuild final result views on every poll. Call
1093
- * {@link getPlayStatus} once after a terminal state for the full result.
1094
- */
1095
- async getPlayTailStatus(workflowId, options) {
1096
- const params = new URLSearchParams({ mode: "tail" });
1097
- if (typeof options?.afterLogIndex === "number") {
1098
- params.set("afterLogIndex", String(options.afterLogIndex));
1099
- }
1100
- if (typeof options?.waitMs === "number") {
1101
- params.set("waitMs", String(options.waitMs));
1102
- }
1103
- if (options?.terminalOnly) {
1104
- params.set("terminalOnly", "true");
1105
- }
1106
- const response = await this.http.get(
1107
- `/api/v2/plays/run/${encodeURIComponent(workflowId)}?${params.toString()}`
1108
- );
1109
- return normalizePlayStatus(response);
1110
- }
1111
1167
  /**
1112
1168
  * Stream semantic play-run events using the same SSE feed as the dashboard.
1113
1169
  *
1114
- * Consumers should still keep a polling fallback: SSE is the fast live-update
1115
- * transport, while the status endpoints remain the authoritative recovery path.
1170
+ * The server emits a canonical `play.run.snapshot` event first for every
1171
+ * connection, then incremental live events until terminal state or reconnect.
1116
1172
  */
1117
1173
  async *streamPlayRunEvents(workflowId, options) {
1118
1174
  const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
@@ -1132,7 +1188,7 @@ var DeeplineClient = class {
1132
1188
  *
1133
1189
  * Sends a stop request for the run.
1134
1190
  *
1135
- * @param workflowId - Temporal workflow ID to cancel
1191
+ * @param workflowId - Public Deepline play-run id to cancel
1136
1192
  *
1137
1193
  * @example
1138
1194
  * ```typescript
@@ -1148,7 +1204,7 @@ var DeeplineClient = class {
1148
1204
  /**
1149
1205
  * Stop a running play execution, including open HITL waits.
1150
1206
  *
1151
- * @param workflowId - Temporal workflow ID to stop
1207
+ * @param workflowId - Public Deepline play-run id to stop
1152
1208
  * @param options.reason - Optional audit/debug reason
1153
1209
  */
1154
1210
  async stopPlay(workflowId, options) {
@@ -1220,32 +1276,42 @@ var DeeplineClient = class {
1220
1276
  );
1221
1277
  return response.runs ?? [];
1222
1278
  }
1223
- /**
1224
- * Fetch the lightweight tail status for a run using the public runs resource model.
1225
- *
1226
- * This is the SDK equivalent of:
1227
- *
1228
- * ```bash
1229
- * deepline runs tail <run-id> --json
1230
- * ```
1231
- */
1279
+ /** Read the canonical run stream and return the latest run snapshot. */
1232
1280
  async tailRun(runId, options) {
1233
- const afterLogIndex = typeof options?.afterLogIndex === "number" ? options.afterLogIndex : typeof options?.cursor === "number" ? options.cursor : typeof options?.cursor === "string" && options.cursor.trim() ? Number(options.cursor) : void 0;
1234
- const params = new URLSearchParams();
1235
- if (Number.isFinite(afterLogIndex)) {
1236
- params.set("afterLogIndex", String(Number(afterLogIndex)));
1281
+ const state = {
1282
+ runId,
1283
+ status: "running",
1284
+ logs: [],
1285
+ latest: null
1286
+ };
1287
+ let terminal = false;
1288
+ for await (const event of this.streamPlayRunEvents(runId, {
1289
+ mode: "cli",
1290
+ signal: options?.signal
1291
+ })) {
1292
+ const status = updatePlayLiveStatusState(state, event);
1293
+ if (!status) {
1294
+ continue;
1295
+ }
1296
+ terminal = TERMINAL_PLAY_STATUSES.has(status.status);
1297
+ if (terminal) {
1298
+ break;
1299
+ }
1237
1300
  }
1238
- if (typeof options?.waitMs === "number") {
1239
- params.set("waitMs", String(options.waitMs));
1301
+ if (terminal && state.latest) {
1302
+ return await this.getRunStatus(state.latest.runId || runId).catch(
1303
+ () => state.latest ?? playRunStatusFromState(state)
1304
+ );
1240
1305
  }
1241
- if (options?.terminalOnly) {
1242
- params.set("terminalOnly", "true");
1306
+ if (state.latest) {
1307
+ return state.latest;
1243
1308
  }
1244
- const suffix = params.toString() ? `?${params.toString()}` : "";
1245
- const response = await this.http.get(
1246
- `/api/v2/runs/${encodeURIComponent(runId)}/tail${suffix}`
1309
+ throw new DeeplineError(
1310
+ `Run stream for ${runId} ended before the initial snapshot.`,
1311
+ void 0,
1312
+ "PLAY_RUN_STREAM_EMPTY",
1313
+ { runId }
1247
1314
  );
1248
- return normalizePlayStatus(response);
1249
1315
  }
1250
1316
  /**
1251
1317
  * Fetch persisted logs for a run using the public runs resource model.
@@ -1402,11 +1468,11 @@ var DeeplineClient = class {
1402
1468
  // Plays — high-level orchestration
1403
1469
  // ——————————————————————————————————————————————————————————
1404
1470
  /**
1405
- * Run a play end-to-end: submit, poll until terminal, return result.
1471
+ * Run a play end-to-end: submit, stream until terminal, return result.
1406
1472
  *
1407
1473
  * This is the highest-level play execution method. It submits the play,
1408
- * polls for status updates, and returns a structured result with logs
1409
- * and timing. Supports cancellation via `AbortSignal`.
1474
+ * reads the canonical run stream for status updates, and returns a structured
1475
+ * result with logs and timing. Supports cancellation via `AbortSignal`.
1410
1476
  *
1411
1477
  * @param code - Source string fallback; pass the bundled artifact in `options.artifact`
1412
1478
  * @param csvPath - Input CSV path, or `null`
@@ -1422,7 +1488,6 @@ var DeeplineClient = class {
1422
1488
  * const logs = status.progress?.logs ?? [];
1423
1489
  * console.log(`[${status.status}] ${logs.length} log lines`);
1424
1490
  * },
1425
- * pollIntervalMs: 1000,
1426
1491
  * });
1427
1492
  *
1428
1493
  * if (result.success) {
@@ -1453,33 +1518,53 @@ var DeeplineClient = class {
1453
1518
  packagedFiles: options?.packagedFiles,
1454
1519
  force: options?.force
1455
1520
  });
1456
- const pollInterval = options?.pollIntervalMs ?? 500;
1457
1521
  const start = Date.now();
1458
- while (true) {
1522
+ const state = {
1523
+ runId: workflowId,
1524
+ status: "running",
1525
+ logs: [],
1526
+ latest: null
1527
+ };
1528
+ if (options?.signal?.aborted) {
1529
+ await this.cancelPlay(workflowId);
1530
+ return {
1531
+ success: false,
1532
+ runId: workflowId,
1533
+ logs: [],
1534
+ durationMs: Date.now() - start,
1535
+ error: "Cancelled by user"
1536
+ };
1537
+ }
1538
+ for await (const event of this.streamPlayRunEvents(workflowId, {
1539
+ mode: "cli",
1540
+ signal: options?.signal
1541
+ })) {
1459
1542
  if (options?.signal?.aborted) {
1460
1543
  await this.cancelPlay(workflowId);
1461
1544
  return {
1462
1545
  success: false,
1463
1546
  runId: workflowId,
1464
- logs: [],
1547
+ logs: state.logs,
1465
1548
  durationMs: Date.now() - start,
1466
1549
  error: "Cancelled by user"
1467
1550
  };
1468
1551
  }
1469
- const status = await this.getPlayStatus(workflowId);
1552
+ const status = updatePlayLiveStatusState(state, event);
1553
+ if (!status) {
1554
+ continue;
1555
+ }
1470
1556
  options?.onProgress?.(status);
1471
1557
  if (TERMINAL_PLAY_STATUSES.has(status.status)) {
1472
- return {
1473
- success: status.status === "completed",
1474
- runId: status.runId || workflowId,
1475
- result: status.result,
1476
- logs: status.progress?.logs ?? [],
1477
- durationMs: Date.now() - start,
1478
- error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
1479
- };
1558
+ const finalStatus = await this.getPlayStatus(status.runId || workflowId).catch(() => status);
1559
+ return playRunResultFromStatus(finalStatus, start, workflowId);
1480
1560
  }
1481
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
1482
1561
  }
1562
+ throw new DeeplineError(
1563
+ `Run stream for ${workflowId} ended before the run reached a terminal state.`,
1564
+ void 0,
1565
+ "PLAY_RUN_STREAM_ENDED",
1566
+ { runId: workflowId, workflowId }
1567
+ );
1483
1568
  }
1484
1569
  // ——————————————————————————————————————————————————————————
1485
1570
  // Health