deepline 0.3.237 → 0.3.238

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.
@@ -64,15 +64,7 @@ import {
64
64
  type EffectiveProductNotificationGroup,
65
65
  type ProductNotificationGroupDraft,
66
66
  } from '../../shared_libs/product-notifications/configuration.js';
67
- import {
68
- STREAM_HEALTHY_CONNECTION_MS,
69
- isTransientPlayStreamError,
70
- streamReconnectDelayMs,
71
- } from './stream-reconnect.js';
72
- import {
73
- observeRunEvents,
74
- RunObserveTransportUnavailableError,
75
- } from './runs/observe-transport.js';
67
+ import { watchRunEvents as pollRunSnapshotEvents } from './runs/watch-polling.js';
76
68
  import type {
77
69
  DeeplineClientOptions,
78
70
  ResolvedConfig,
@@ -627,28 +619,35 @@ export type RunGetStatus =
627
619
 
628
620
  const RUNS_FAILED_LOG_LIMIT = 20;
629
621
 
630
- /** Streaming options for `client.runs.tail(...)`. */
631
- export type RunsTailOptions = {
622
+ /** Options for `client.runs.watch(...)`. */
623
+ export type RunsWatchOptions = {
632
624
  signal?: AbortSignal;
633
- /** Observe each canonical live event while `tail` waits for terminal state. */
625
+ /** Observe each canonical event while `watch` waits for terminal state. */
634
626
  onEvent?: (event: PlayLiveEvent) => void;
635
627
  /**
636
- * Called before each stream reconnect. Server stream windows are finite, so
637
- * long runs reconnect with backoff until a terminal status is observed.
628
+ * Called once when a transient REST polling outage begins. Polling retries
629
+ * on its normal fixed interval.
638
630
  */
631
+ onRetry?: (info: {
632
+ attempt: number;
633
+ delayMs: number;
634
+ reason: string;
635
+ }) => void;
636
+ /** @deprecated Use `onRetry`. */
639
637
  onReconnect?: (info: {
640
638
  attempt: number;
641
639
  delayMs: number;
642
640
  reason: string;
643
641
  }) => void;
644
642
  /**
645
- * Display-only transport notices: subscription-transport reconnects,
646
- * staleness warnings, and the one-time fallback notice when the server
647
- * cannot serve the Convex subscription transport (ADR-0008).
643
+ * Display-only notices for a transient snapshot polling outage or recovery.
648
644
  */
649
645
  onNotice?: (message: string) => void;
650
646
  };
651
647
 
648
+ /** @deprecated Use `RunsWatchOptions`. */
649
+ export type RunsTailOptions = RunsWatchOptions;
650
+
652
651
  /** Log fetch options for `client.runs.logs(...)`. */
653
652
  export type RunsLogsOptions = {
654
653
  /** Return the LAST `limit` stored log lines (default 200). */
@@ -756,7 +755,7 @@ export type PlaySecretCheck = {
756
755
  };
757
756
 
758
757
  /**
759
- * Use `client.runs` (`/api/v2/runs`) to poll, stream, stop, read logs, and export durable dataset rows.
758
+ * Use `client.runs` (`/api/v2/runs`) to watch, stop, read logs, and export durable dataset rows.
760
759
  *
761
760
  * @sdkReference client 020 client.runs
762
761
  */
@@ -782,7 +781,9 @@ export type RunsNamespace = {
782
781
  list: (options: RunsListOptions) => Promise<PlayRunListItem[]>;
783
782
  /** Read one run page with total, offset, limit and completeness metadata. */
784
783
  listPage: (options: RunsListOptions) => Promise<RunsListPage>;
785
- /** Stream run events and return the latest/terminal run status. */
784
+ /** Poll run snapshots every two seconds until terminal status. */
785
+ watch: (runId: string, options?: RunsWatchOptions) => Promise<PlayStatus>;
786
+ /** @deprecated Use `watch`; retained as a source-compatible alias. */
786
787
  tail: (runId: string, options?: RunsTailOptions) => Promise<PlayStatus>;
787
788
  /** Fetch persisted log lines for a run. */
788
789
  logs: (runId: string, options?: RunsLogsOptions) => Promise<RunsLogsResult>;
@@ -2665,6 +2666,7 @@ export class DeeplineClient {
2665
2666
  status: (runId) => this.getRunLifecycleStatus(runId),
2666
2667
  list: (options) => this.listRuns(options),
2667
2668
  listPage: (options) => this.listRunsPage(options),
2669
+ watch: (runId, options) => this.watchRunToTerminal(runId, options),
2668
2670
  tail: (runId, options) => this.tailRun(runId, options),
2669
2671
  logs: (runId, options) => this.getRunLogs(runId, options),
2670
2672
  input: (runId) => this.getRunInput(runId),
@@ -3391,15 +3393,17 @@ export class DeeplineClient {
3391
3393
  }
3392
3394
 
3393
3395
  /**
3394
- * Start a play run and stream live runtime events from the same request.
3396
+ * Submit a play run through the legacy event response.
3395
3397
  *
3396
- * Use this when a caller wants low-level event handling instead of submitting
3397
- * first and then connecting to `streamPlayRunEvents(runId)`.
3398
+ * This reports admission from the start request; it does not watch an
3399
+ * existing run. Use `startPlayRun()` and `watchRunEvents(runId)` separately.
3400
+ *
3401
+ * @deprecated Use the separate start and watch methods.
3398
3402
  *
3399
3403
  * @param request - Play run configuration.
3400
- * @param options - Optional streaming options.
3401
- * @param options.signal - Optional abort signal for the streaming request.
3402
- * @returns Async stream of play-scoped live events.
3404
+ * @param options - Optional compatibility response options.
3405
+ * @param options.signal - Abort the start response.
3406
+ * @returns Async generator of play-scoped live events.
3403
3407
  */
3404
3408
  async *startPlayRunStream(
3405
3409
  request: StartPlayRunRequest,
@@ -4128,11 +4132,31 @@ export class DeeplineClient {
4128
4132
  return normalizePlayStatus(response);
4129
4133
  }
4130
4134
 
4135
+ /** Poll authenticated run snapshots every two seconds and emit changed events. */
4136
+ async *watchRunEvents(
4137
+ workflowId: string,
4138
+ options?: {
4139
+ signal?: AbortSignal;
4140
+ onNotice?: (message: string) => void;
4141
+ onRetry?: RunsWatchOptions['onRetry'];
4142
+ },
4143
+ ): AsyncGenerator<PlayLiveEvent> {
4144
+ for await (const event of pollRunSnapshotEvents({
4145
+ http: this.http,
4146
+ runId: workflowId,
4147
+ signal: options?.signal,
4148
+ onNotice: options?.onNotice,
4149
+ onRetry: options?.onRetry,
4150
+ })) {
4151
+ yield event as PlayLiveEvent;
4152
+ }
4153
+ }
4154
+
4131
4155
  /**
4132
- * Stream semantic play-run events using the same SSE feed as the dashboard.
4156
+ * Read raw legacy SSE events for callers that explicitly require that
4157
+ * compatibility endpoint. Ordinary run watching uses REST snapshot polling.
4133
4158
  *
4134
- * The server emits a canonical `play.run.snapshot` event first for every
4135
- * connection, then incremental live events until terminal state or reconnect.
4159
+ * @deprecated Use `watchRunEvents` for ordinary run watching.
4136
4160
  */
4137
4161
  async *streamPlayRunEvents(
4138
4162
  workflowId: string,
@@ -4158,6 +4182,82 @@ export class DeeplineClient {
4158
4182
  }
4159
4183
  }
4160
4184
 
4185
+ /**
4186
+ * Compatibility alias for polling canonical run snapshots and emitting
4187
+ * their changed events.
4188
+ *
4189
+ * @deprecated Use `watchRunEvents`; kept as a source-compatible alias.
4190
+ * The `fallback` option is ignored because watching uses REST polling.
4191
+ */
4192
+ async *observeRunEvents(
4193
+ runId: string,
4194
+ options?: {
4195
+ signal?: AbortSignal;
4196
+ onNotice?: (message: string) => void;
4197
+ /** @deprecated Ignored; watching always uses REST snapshot polling. */
4198
+ fallback?: 'sse' | 'none';
4199
+ },
4200
+ ): AsyncGenerator<PlayLiveEvent> {
4201
+ yield* this.watchRunEvents(runId, {
4202
+ signal: options?.signal,
4203
+ onNotice: options?.onNotice,
4204
+ });
4205
+ }
4206
+
4207
+ /** Poll snapshots to terminal status and return the durable package. */
4208
+ private async watchRunToTerminal(
4209
+ runId: string,
4210
+ options?: RunsWatchOptions,
4211
+ ): Promise<PlayStatus> {
4212
+ const state: PlayLiveStatusState = {
4213
+ runId,
4214
+ status: 'running',
4215
+ logs: [],
4216
+ lastLogSeq: 0,
4217
+ latest: null,
4218
+ };
4219
+ let terminalObserved = false;
4220
+ for await (const event of this.watchRunEvents(runId, {
4221
+ signal: options?.signal,
4222
+ onNotice: options?.onNotice,
4223
+ onRetry: options?.onRetry ?? options?.onReconnect,
4224
+ })) {
4225
+ options?.onEvent?.(event);
4226
+ const status = updatePlayLiveStatusState(state, event);
4227
+ if (status && TERMINAL_PLAY_STATUSES.has(status.status)) {
4228
+ terminalObserved = true;
4229
+ }
4230
+ }
4231
+ if (options?.signal?.aborted) {
4232
+ throw new DeeplineError('Run watch aborted.', undefined, 'ABORTED');
4233
+ }
4234
+ if (terminalObserved) {
4235
+ return await this.getRunStatus(runId);
4236
+ }
4237
+ const refreshed = await this.getRunStatus(runId);
4238
+ if (TERMINAL_PLAY_STATUSES.has(refreshed.status)) return refreshed;
4239
+ throw new DeeplineError(
4240
+ `Run watch for ${runId} ended before a terminal status.`,
4241
+ undefined,
4242
+ 'PLAY_WATCH_ENDED',
4243
+ );
4244
+ }
4245
+
4246
+ /**
4247
+ * Wait for a run and return its terminal status.
4248
+ *
4249
+ * This source-compatible alias uses the same authenticated two-second REST
4250
+ * snapshot polling as `client.runs.watch`.
4251
+ *
4252
+ * @deprecated Use `client.runs.watch`; retained for SDK compatibility.
4253
+ * @param runId - Public Deepline play-run id.
4254
+ * @param options - Optional callbacks and cancellation signal.
4255
+ * @returns The final durable run status.
4256
+ */
4257
+ async tailRun(runId: string, options?: RunsTailOptions): Promise<PlayStatus> {
4258
+ return this.watchRunToTerminal(runId, options);
4259
+ }
4260
+
4161
4261
  /**
4162
4262
  * Cancel a running play execution.
4163
4263
  *
@@ -4492,263 +4592,6 @@ export class DeeplineClient {
4492
4592
  return { ...response, runs: response.runs ?? [] };
4493
4593
  }
4494
4594
 
4495
- /**
4496
- * Observe one run's live events. Uses the Convex Run Snapshot subscription
4497
- * transport first (ADR-0008), then falls back to the canonical SSE stream
4498
- * when the subscription transport or its optional client modules are not
4499
- * available. Pass `fallback: 'none'` to receive
4500
- * {@link RunObserveTransportUnavailableError} instead.
4501
- */
4502
- async *observeRunEvents(
4503
- runId: string,
4504
- options?: {
4505
- signal?: AbortSignal;
4506
- onNotice?: (message: string) => void;
4507
- fallback?: 'sse' | 'none';
4508
- },
4509
- ): AsyncGenerator<PlayLiveEvent> {
4510
- let yieldedObserveEvent = false;
4511
- try {
4512
- for await (const event of observeRunEvents({
4513
- http: this.http,
4514
- runId,
4515
- signal: options?.signal,
4516
- onNotice: options?.onNotice,
4517
- }) as AsyncGenerator<PlayLiveEvent>) {
4518
- yieldedObserveEvent = true;
4519
- yield event;
4520
- }
4521
- } catch (error) {
4522
- if (
4523
- !(error instanceof RunObserveTransportUnavailableError) ||
4524
- yieldedObserveEvent ||
4525
- options?.fallback === 'none'
4526
- ) {
4527
- throw error;
4528
- }
4529
- options?.onNotice?.(
4530
- `[observe] live subscription unavailable (${error.reason}); falling back to SSE tail (support window, ADR-0008)`,
4531
- );
4532
- yield* this.streamPlayRunEventsUntilTerminal(runId, options);
4533
- }
4534
- }
4535
-
4536
- private async *streamPlayRunEventsUntilTerminal(
4537
- runId: string,
4538
- options?: { signal?: AbortSignal; onNotice?: (message: string) => void },
4539
- ): AsyncGenerator<PlayLiveEvent> {
4540
- const state: PlayLiveStatusState = {
4541
- runId,
4542
- status: 'running',
4543
- logs: [],
4544
- lastLogSeq: 0,
4545
- latest: null,
4546
- };
4547
- let lastEventId: string | undefined;
4548
- let reconnectAttempt = 0;
4549
-
4550
- for (;;) {
4551
- if (options?.signal?.aborted) {
4552
- return;
4553
- }
4554
- const connectedAt = Date.now();
4555
- let sawEvent = false;
4556
- let endedReason = 'stream window ended before a terminal event';
4557
- try {
4558
- for await (const event of this.streamPlayRunEvents(runId, {
4559
- mode: 'cli',
4560
- signal: options?.signal,
4561
- ...(lastEventId ? { lastEventId } : {}),
4562
- })) {
4563
- sawEvent = true;
4564
- if (event.cursor?.trim()) {
4565
- lastEventId = event.cursor;
4566
- }
4567
- yield event;
4568
- const status = updatePlayLiveStatusState(state, event);
4569
- if (status && TERMINAL_PLAY_STATUSES.has(status.status)) {
4570
- return;
4571
- }
4572
- }
4573
- } catch (error) {
4574
- if (options?.signal?.aborted) {
4575
- return;
4576
- }
4577
- if (!isTransientPlayStreamError(error)) {
4578
- throw error;
4579
- }
4580
- endedReason = error instanceof Error ? error.message : String(error);
4581
- }
4582
-
4583
- let refreshed: PlayStatus | null = null;
4584
- try {
4585
- refreshed = await this.getRunStatus(runId);
4586
- } catch (error) {
4587
- if (!isTransientPlayStreamError(error)) {
4588
- throw error;
4589
- }
4590
- }
4591
- if (refreshed && TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
4592
- yield {
4593
- cursor: String(Date.now()),
4594
- streamId: `sse-fallback:${runId}`,
4595
- scope: 'play',
4596
- type: 'play.run.status',
4597
- at: new Date().toISOString(),
4598
- payload: refreshed as unknown as Record<string, unknown>,
4599
- };
4600
- return;
4601
- }
4602
-
4603
- if (
4604
- sawEvent ||
4605
- Date.now() - connectedAt >= STREAM_HEALTHY_CONNECTION_MS
4606
- ) {
4607
- reconnectAttempt = 0;
4608
- }
4609
- const delayMs = streamReconnectDelayMs(reconnectAttempt);
4610
- reconnectAttempt += 1;
4611
- options?.onNotice?.(
4612
- `[observe] SSE tail window ended before terminal status (${endedReason}); reconnecting to run ${runId}`,
4613
- );
4614
- await sleep(delayMs);
4615
- }
4616
- }
4617
-
4618
- /**
4619
- * Tail one run through the subscription transport until terminal, then
4620
- * return one durable REST status read (the final Run Response Package).
4621
- */
4622
- private async tailRunViaObserveTransport(
4623
- runId: string,
4624
- options?: RunsTailOptions,
4625
- ): Promise<PlayStatus> {
4626
- const state: PlayLiveStatusState = {
4627
- runId,
4628
- status: 'running',
4629
- logs: [],
4630
- lastLogSeq: 0,
4631
- latest: null,
4632
- };
4633
- for await (const event of this.observeRunEvents(runId, {
4634
- signal: options?.signal,
4635
- onNotice: options?.onNotice,
4636
- fallback: 'none',
4637
- })) {
4638
- options?.onEvent?.(event);
4639
- const status = updatePlayLiveStatusState(state, event);
4640
- if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
4641
- continue;
4642
- }
4643
- return await this.getRunStatus(status.runId || runId);
4644
- }
4645
- if (options?.signal?.aborted) {
4646
- throw new DeeplineError('Run observation aborted.', undefined, 'ABORTED');
4647
- }
4648
- // The transport ends only after a terminal snapshot; the differ always
4649
- // emits a terminal `play.run.status` first, so reaching here means the
4650
- // terminal package read raced — re-check durable status once, loudly.
4651
- const refreshed = await this.getRunStatus(runId);
4652
- if (TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
4653
- return refreshed;
4654
- }
4655
- throw new DeeplineError(
4656
- `Run observation for ${runId} ended before a terminal status.`,
4657
- undefined,
4658
- 'PLAY_LIVE_STREAM_ENDED',
4659
- );
4660
- }
4661
-
4662
- /**
4663
- * Read the canonical run stream until a terminal run status is observed.
4664
- *
4665
- * Tries the Convex Run Snapshot subscription transport first (ADR-0008);
4666
- * when the server cannot serve it (grant endpoint missing/unconfigured or
4667
- * Convex unreachable) it falls back — with one `onNotice` message — to the
4668
- * support-window SSE stream below.
4669
- *
4670
- * Server stream windows are finite: they end cleanly at the function
4671
- * ceiling even while the run keeps executing. A window that ends (cleanly
4672
- * or via transient network error) without a terminal event triggers one
4673
- * durable-status re-check followed by a backed-off reconnect, so long runs
4674
- * tail to completion. Abort via `options.signal` to stop waiting.
4675
- */
4676
- async tailRun(runId: string, options?: RunsTailOptions): Promise<PlayStatus> {
4677
- try {
4678
- return await this.tailRunViaObserveTransport(runId, options);
4679
- } catch (error) {
4680
- if (!(error instanceof RunObserveTransportUnavailableError)) {
4681
- throw error;
4682
- }
4683
- options?.onNotice?.(
4684
- `[observe] live subscription unavailable (${error.reason}); falling back to SSE tail (support window, ADR-0008)`,
4685
- );
4686
- }
4687
- const state: PlayLiveStatusState = {
4688
- runId,
4689
- status: 'running',
4690
- logs: [],
4691
- lastLogSeq: 0,
4692
- latest: null,
4693
- };
4694
- let reconnectAttempt = 0;
4695
-
4696
- for (;;) {
4697
- const connectedAt = Date.now();
4698
- let sawEvent = false;
4699
- let terminalRunId: string | null = null;
4700
- let endedReason = 'stream window ended before a terminal event';
4701
- try {
4702
- for await (const event of this.streamPlayRunEvents(runId, {
4703
- mode: 'cli',
4704
- signal: options?.signal,
4705
- })) {
4706
- options?.onEvent?.(event);
4707
- sawEvent = true;
4708
- const status = updatePlayLiveStatusState(state, event);
4709
- if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
4710
- continue;
4711
- }
4712
- terminalRunId = status.runId || runId;
4713
- break;
4714
- }
4715
- } catch (error) {
4716
- if (options?.signal?.aborted || !isTransientPlayStreamError(error)) {
4717
- throw error;
4718
- }
4719
- endedReason = error instanceof Error ? error.message : String(error);
4720
- }
4721
-
4722
- if (terminalRunId) {
4723
- return await this.getRunStatus(terminalRunId);
4724
- }
4725
-
4726
- // Window ended without a terminal event. The run may have finished
4727
- // during the gap — re-check durable status once before reconnecting.
4728
- // `runs.get` owns the durable snapshot; its optional status evidence is
4729
- // additive and must not prevent old servers from ending this stream.
4730
- const refreshed = await this.getRunStatus(runId);
4731
- if (TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
4732
- return refreshed;
4733
- }
4734
-
4735
- if (
4736
- sawEvent ||
4737
- Date.now() - connectedAt >= STREAM_HEALTHY_CONNECTION_MS
4738
- ) {
4739
- reconnectAttempt = 0;
4740
- }
4741
- const delayMs = streamReconnectDelayMs(reconnectAttempt);
4742
- reconnectAttempt += 1;
4743
- options?.onReconnect?.({
4744
- attempt: reconnectAttempt,
4745
- delayMs,
4746
- reason: endedReason,
4747
- });
4748
- await sleep(delayMs);
4749
- }
4750
- }
4751
-
4752
4595
  /** Get the exact original input retained for a run. This is intentionally separate from status. */
4753
4596
  async getRunInput(runId: string): Promise<{
4754
4597
  runId: string;
@@ -5822,10 +5665,10 @@ export class DeeplineClient {
5822
5665
  // ——————————————————————————————————————————————————————————
5823
5666
 
5824
5667
  /**
5825
- * Run a play end-to-end: submit, stream until terminal, return result.
5668
+ * Run a play end-to-end: submit, poll progress until terminal, return result.
5826
5669
  *
5827
5670
  * This is the highest-level play execution method. It submits the play,
5828
- * reads the canonical run stream for status updates, and returns a structured
5671
+ * reads the canonical run snapshot for status updates, and returns a structured
5829
5672
  * result with logs and timing. Supports cancellation via `AbortSignal`.
5830
5673
  *
5831
5674
  * @param code - Source string fallback; pass the bundled artifact in `options.artifact`
@@ -5902,6 +5745,7 @@ export class DeeplineClient {
5902
5745
  lastLogSeq: 0,
5903
5746
  latest: null,
5904
5747
  };
5748
+ let terminalObserved: PlayStatus | null = null;
5905
5749
 
5906
5750
  if (options?.signal?.aborted) {
5907
5751
  await this.cancelPlay(workflowId);
@@ -5914,8 +5758,7 @@ export class DeeplineClient {
5914
5758
  };
5915
5759
  }
5916
5760
 
5917
- for await (const event of this.streamPlayRunEvents(workflowId, {
5918
- mode: 'cli',
5761
+ for await (const event of this.watchRunEvents(workflowId, {
5919
5762
  signal: options?.signal,
5920
5763
  })) {
5921
5764
  if (options?.signal?.aborted) {
@@ -5929,22 +5772,42 @@ export class DeeplineClient {
5929
5772
  };
5930
5773
  }
5931
5774
 
5775
+ const previousStatus = state.latest?.status;
5932
5776
  const status = updatePlayLiveStatusState(state, event);
5933
5777
  if (!status) {
5934
5778
  continue;
5935
5779
  }
5936
- options?.onProgress?.(status);
5780
+ if (
5781
+ event.type !== 'play.run.status' ||
5782
+ status.status !== previousStatus
5783
+ ) {
5784
+ options?.onProgress?.(status);
5785
+ }
5937
5786
 
5938
5787
  if (TERMINAL_PLAY_STATUSES.has(status.status)) {
5939
- const finalStatus = await this.getPlayStatus(
5940
- status.runId || workflowId,
5941
- ).catch(() => status);
5942
- return playRunResultFromStatus(finalStatus, start, workflowId);
5788
+ terminalObserved = status;
5943
5789
  }
5944
5790
  }
5945
5791
 
5792
+ if (options?.signal?.aborted) {
5793
+ await this.cancelPlay(workflowId);
5794
+ return {
5795
+ success: false,
5796
+ runId: workflowId,
5797
+ logs: state.logs,
5798
+ durationMs: Date.now() - start,
5799
+ error: 'Cancelled by user',
5800
+ };
5801
+ }
5802
+ if (terminalObserved) {
5803
+ const finalStatus = await this.getPlayStatus(
5804
+ terminalObserved.runId || workflowId,
5805
+ ).catch(() => terminalObserved!);
5806
+ return playRunResultFromStatus(finalStatus, start, workflowId);
5807
+ }
5808
+
5946
5809
  throw new DeeplineError(
5947
- `Run stream for ${workflowId} ended before the run reached a terminal state.`,
5810
+ `Run watch for ${workflowId} ended before the run reached a terminal state.`,
5948
5811
  undefined,
5949
5812
  'PLAY_RUN_STREAM_ENDED',
5950
5813
  { runId: workflowId, workflowId },
@@ -992,7 +992,7 @@ function isRetryableApiErrorResponse(status: number): boolean {
992
992
  * to CLI users — it lands verbatim in `DeeplineError.message`/`details`. When
993
993
  * detected, we synthesize a structured message (status + extracted <title>) and
994
994
  * preserve the literal token `Worker threw exception` when present, since SDK
995
- * retry classifiers (`isTransientPlayStreamError`) regex-match on it.
995
+ * retry classifiers (`isTransientPlayRunReadError`) regex-match on it.
996
996
  */
997
997
  function detectHtmlErrorBody(
998
998
  body: string,
@@ -137,6 +137,7 @@ export type {
137
137
  RunsLogsOptions,
138
138
  RunsLogsResult,
139
139
  RunsNamespace,
140
+ RunsWatchOptions,
140
141
  RunsTailOptions,
141
142
  StopAllRunsOptions,
142
143
  ToolExecution,
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
202
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
203
- version: '0.3.237',
203
+ version: '0.3.238',
204
204
  updateSummary:
205
205
  'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
206
206
  packageCapabilities: {