deepline 0.1.213 → 0.1.214

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.
@@ -1563,8 +1563,8 @@ export class DeeplineClient {
1563
1563
  ? { waitForCompletionMs: request.waitForCompletionMs }
1564
1564
  : {}),
1565
1565
  // Profile selection is the API's job, not the CLI's. The server
1566
- // defaults to workers_edge; tests and runtime probes that want a
1567
- // different profile pass `request.profile` explicitly.
1566
+ // defaults to absurd; callers that need workers_edge pass
1567
+ // `request.profile` explicitly.
1568
1568
  ...(request.profile ? { profile: request.profile } : {}),
1569
1569
  ...(integrationMode ? { integrationMode } : {}),
1570
1570
  ...(testPolicyOverrides ? { testPolicyOverrides } : {}),
@@ -106,10 +106,10 @@ export const SDK_RELEASE = {
106
106
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
107
107
  // fields shipped in 0.1.153.
108
108
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
109
- version: '0.1.213',
109
+ version: '0.1.214',
110
110
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
111
111
  supportPolicy: {
112
- latest: '0.1.213',
112
+ latest: '0.1.214',
113
113
  minimumSupported: '0.1.53',
114
114
  deprecatedBelow: '0.1.53',
115
115
  commandMinimumSupported: [
@@ -1138,9 +1138,9 @@ export interface StartPlayRunRequest {
1138
1138
  /** Optionally let the start request wait briefly and return a terminal result. */
1139
1139
  waitForCompletionMs?: number;
1140
1140
  /**
1141
- * Per-run execution profile override. The server defaults to workers_edge;
1142
- * tests and runtime probes can pass a different profile here. Most callers
1143
- * should leave this unset.
1141
+ * Per-run execution profile override. The server defaults to absurd;
1142
+ * callers that need workers_edge can pass it here. Most callers should leave
1143
+ * this unset.
1144
1144
  */
1145
1145
  profile?: string;
1146
1146
  /** Optional per-run provider execution mode for eval/smoke runs. */
@@ -284,6 +284,11 @@ const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
284
284
  const DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000;
285
285
  const FETCH_TRANSPORT_MAX_ATTEMPTS = 3;
286
286
  const FETCH_TRANSPORT_RETRY_DELAY_MS = 100;
287
+ // cloudflared returns this branded HTML when its connection to the local app
288
+ // resets. It is a transport failure before the app can reach a provider, not a
289
+ // provider 502; require both the branded page and our development tunnel host.
290
+ const DEEPLINE_DEVELOPER_TUNNEL_ORIGIN_502_PATTERN =
291
+ /\bdeeplinedeveloper\.com\s*\|\s*502\s*:\s*bad gateway\b/i;
287
292
  const CHILD_PLAY_LAUNCH_WRITE_CONFLICT_RETRY_DELAYS_MS = [
288
293
  50, 100, 200, 400, 800,
289
294
  ] as const;
@@ -518,6 +523,28 @@ export function resolveToolRuntimeTimeoutMs(
518
523
  : undefined;
519
524
  }
520
525
 
526
+ function isDeeplineDeveloperTunnelOrigin502(input: {
527
+ url: string;
528
+ status: number;
529
+ bodyText: string;
530
+ }): boolean {
531
+ if (
532
+ input.status !== 502 ||
533
+ !DEEPLINE_DEVELOPER_TUNNEL_ORIGIN_502_PATTERN.test(input.bodyText)
534
+ ) {
535
+ return false;
536
+ }
537
+ try {
538
+ const hostname = new URL(input.url).hostname.toLowerCase();
539
+ return (
540
+ hostname === 'deeplinedeveloper.com' ||
541
+ hostname.endsWith('.deeplinedeveloper.com')
542
+ );
543
+ } catch {
544
+ return false;
545
+ }
546
+ }
547
+
521
548
  function loadSafeFetch(): Promise<SafeFetchModule> {
522
549
  safeFetchModule ??= import('@shared_libs/security/safe-fetch');
523
550
  return safeFetchModule;
@@ -8529,6 +8556,32 @@ export class PlayContextImpl {
8529
8556
  const retrySafeTransientHttp =
8530
8557
  retryPolicy?.retrySafeTransientHttp === true;
8531
8558
  let transportAttempt = 0;
8559
+ const retryToolTransportFailure = async (
8560
+ message: string,
8561
+ ): Promise<void> => {
8562
+ transportAttempt += 1;
8563
+ if (transportAttempt < TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS) {
8564
+ await this.governor.chargeBudget('retry');
8565
+ const retryAfterMs =
8566
+ TOOL_RETRY_AFTER_FALLBACK_MS * transportAttempt;
8567
+ span.setAttribute(
8568
+ 'plays.transport_retry_attempt',
8569
+ transportAttempt,
8570
+ );
8571
+ this.log(
8572
+ `Tool ${toolId} transport failed calling ${url} on attempt ${transportAttempt}/${TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS}; retrying after ${retryAfterMs}ms: ${message}`,
8573
+ );
8574
+ await options?.parkProviderCall?.();
8575
+ await this.sleepWithCheckpointHeartbeat(retryAfterMs);
8576
+ return;
8577
+ }
8578
+ throw new ToolHttpError(
8579
+ `Tool ${toolId} transport failed calling ${url} after ${transportAttempt}/${TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS} attempts: ${message}`,
8580
+ null,
8581
+ 0,
8582
+ 'repairable',
8583
+ );
8584
+ };
8532
8585
 
8533
8586
  while (true) {
8534
8587
  let response: Response;
@@ -8696,32 +8749,12 @@ export class PlayContextImpl {
8696
8749
  `Tool ${toolId} runtime API call timed out after ${timeoutMs}ms.`,
8697
8750
  )
8698
8751
  : error;
8699
- transportAttempt += 1;
8700
8752
  const message =
8701
8753
  transportError instanceof Error
8702
8754
  ? transportError.message
8703
8755
  : String(transportError);
8704
- if (transportAttempt < TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS) {
8705
- await this.governor.chargeBudget('retry');
8706
- const retryAfterMs =
8707
- TOOL_RETRY_AFTER_FALLBACK_MS * transportAttempt;
8708
- span.setAttribute(
8709
- 'plays.transport_retry_attempt',
8710
- transportAttempt,
8711
- );
8712
- this.log(
8713
- `Tool ${toolId} transport failed calling ${url} on attempt ${transportAttempt}/${TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS}; retrying after ${retryAfterMs}ms: ${message}`,
8714
- );
8715
- await options?.parkProviderCall?.();
8716
- await this.sleepWithCheckpointHeartbeat(retryAfterMs);
8717
- continue;
8718
- }
8719
- throw new ToolHttpError(
8720
- `Tool ${toolId} transport failed calling ${url} after ${transportAttempt}/${TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS} attempts: ${message}`,
8721
- null,
8722
- 0,
8723
- 'repairable',
8724
- );
8756
+ await retryToolTransportFailure(message);
8757
+ continue;
8725
8758
  } finally {
8726
8759
  if (timeoutHandle) {
8727
8760
  clearTimeout(timeoutHandle);
@@ -8732,6 +8765,18 @@ export class PlayContextImpl {
8732
8765
 
8733
8766
  if (!response.ok) {
8734
8767
  const text = await response.text();
8768
+ if (
8769
+ isDeeplineDeveloperTunnelOrigin502({
8770
+ url,
8771
+ status: response.status,
8772
+ bodyText: text,
8773
+ })
8774
+ ) {
8775
+ await retryToolTransportFailure(
8776
+ 'the Deepline development tunnel returned a branded 502 before reaching the app origin',
8777
+ );
8778
+ continue;
8779
+ }
8735
8780
  const authScopeChanged = parseToolExecuteAuthScopeChangedError({
8736
8781
  status: response.status,
8737
8782
  bodyText: text,
@@ -54,7 +54,7 @@ export const PLAY_RUNTIME_PROVIDERS: Record<
54
54
  };
55
55
 
56
56
  export function defaultPlayRuntimeProvider(): PlayRuntimeProviderDescriptor {
57
- return PLAY_RUNTIME_PROVIDERS.workers_edge;
57
+ return PLAY_RUNTIME_PROVIDERS.absurd;
58
58
  }
59
59
 
60
60
  export function resolvePlayRuntimeProvider(
@@ -4,8 +4,8 @@
4
4
  * One of three pluggable axes (alongside runner-backends and dedup-backends).
5
5
  * Selected per-run via PlayExecutionProfile.
6
6
  *
7
- * Cloudflare Workflows is the default production scheduler through the
8
- * workers_edge profile. Absurd is the durable Daytona-backed scheduler.
7
+ * Absurd is the default production scheduler through the absurd profile.
8
+ * Cloudflare Workflows remains available through the workers_edge profile.
9
9
  *
10
10
  * Customer plays are unaffected — this is purely the orchestration layer.
11
11
  */