@runtypelabs/sdk 1.10.0 → 1.10.2

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.d.cts CHANGED
@@ -3172,6 +3172,8 @@ interface RunTaskToolTraceSlice {
3172
3172
  verificationPassed: boolean;
3173
3173
  verificationBlocked: boolean;
3174
3174
  localToolLoopGuardTriggered: boolean;
3175
+ /** Per-file write counts for detecting excessive same-file rewrites */
3176
+ writeCountByPath: Record<string, number>;
3175
3177
  forcedTurnEndReason?: string;
3176
3178
  bestCandidatePath?: string;
3177
3179
  bestCandidateReason?: string;
@@ -4257,7 +4259,7 @@ interface ExecuteWithLocalToolsOptions {
4257
4259
  /**
4258
4260
  * Status of a long-task agent run
4259
4261
  */
4260
- type RunTaskStatus = 'running' | 'complete' | 'paused' | 'error' | 'budget_exceeded' | 'max_sessions';
4262
+ type RunTaskStatus = 'running' | 'complete' | 'paused' | 'error' | 'budget_exceeded' | 'max_sessions' | 'stalled';
4261
4263
  /**
4262
4264
  * A continuation point within a long-task run (for marathon resume).
4263
4265
  */
@@ -4389,6 +4391,10 @@ interface RunTaskState {
4389
4391
  workflowVariant?: string;
4390
4392
  /** Number of consecutive sessions where verification was blocked */
4391
4393
  consecutiveBlockedVerificationSessions?: number;
4394
+ /** Reason the last TASK_COMPLETE claim was rejected (set when detected but not accepted) */
4395
+ lastCompletionRejectionReason?: string;
4396
+ /** Number of consecutive sessions with no tool actions (for stall detection) */
4397
+ consecutiveEmptySessions?: number;
4392
4398
  /** Arbitrary bag for workflow-specific data */
4393
4399
  workflowState?: Record<string, unknown>;
4394
4400
  }
@@ -4426,7 +4432,7 @@ interface RunTaskContextCompactionEvent {
4426
4432
  }
4427
4433
  type RunTaskOnContextCompaction = (event: RunTaskContextCompactionEvent) => void | Promise<void>;
4428
4434
  interface RunTaskContextNoticeEvent {
4429
- kind: 'provider_native_compaction' | 'tool_definitions_warning';
4435
+ kind: 'provider_native_compaction' | 'tool_definitions_warning' | 'server_network_retry';
4430
4436
  sessionIndex: number;
4431
4437
  model?: string;
4432
4438
  message: string;
@@ -4690,6 +4696,7 @@ declare class AgentsEndpoint {
4690
4696
  private hasSufficientResearchEvidence;
4691
4697
  private buildEffectiveSessionOutput;
4692
4698
  private canAcceptTaskCompletion;
4699
+ private computeCompletionRejectionReason;
4693
4700
  private summarizeUnknownForTrace;
4694
4701
  private summarizeTextBlockForTrace;
4695
4702
  private parseVerificationResult;
@@ -4747,6 +4754,12 @@ declare class AgentsEndpoint {
4747
4754
  * ```
4748
4755
  */
4749
4756
  runTask(id: string, options: RunTaskOptions): Promise<RunTaskResult>;
4757
+ /** Error message patterns from server-side sessions that indicate a transient network failure
4758
+ * (e.g. AI provider connection dropped). These are retried automatically. */
4759
+ private static readonly RETRYABLE_SESSION_ERROR_PATTERNS;
4760
+ /** Returns true if a server-side session error message indicates a transient
4761
+ * network failure that is safe to retry. */
4762
+ static isRetryableSessionError(errorMessage?: string): boolean;
4750
4763
  /** Stop phrases that indicate the agent considers its task complete. */
4751
4764
  private static readonly STOP_PHRASES;
4752
4765
  /**
package/dist/index.d.ts CHANGED
@@ -3172,6 +3172,8 @@ interface RunTaskToolTraceSlice {
3172
3172
  verificationPassed: boolean;
3173
3173
  verificationBlocked: boolean;
3174
3174
  localToolLoopGuardTriggered: boolean;
3175
+ /** Per-file write counts for detecting excessive same-file rewrites */
3176
+ writeCountByPath: Record<string, number>;
3175
3177
  forcedTurnEndReason?: string;
3176
3178
  bestCandidatePath?: string;
3177
3179
  bestCandidateReason?: string;
@@ -4257,7 +4259,7 @@ interface ExecuteWithLocalToolsOptions {
4257
4259
  /**
4258
4260
  * Status of a long-task agent run
4259
4261
  */
4260
- type RunTaskStatus = 'running' | 'complete' | 'paused' | 'error' | 'budget_exceeded' | 'max_sessions';
4262
+ type RunTaskStatus = 'running' | 'complete' | 'paused' | 'error' | 'budget_exceeded' | 'max_sessions' | 'stalled';
4261
4263
  /**
4262
4264
  * A continuation point within a long-task run (for marathon resume).
4263
4265
  */
@@ -4389,6 +4391,10 @@ interface RunTaskState {
4389
4391
  workflowVariant?: string;
4390
4392
  /** Number of consecutive sessions where verification was blocked */
4391
4393
  consecutiveBlockedVerificationSessions?: number;
4394
+ /** Reason the last TASK_COMPLETE claim was rejected (set when detected but not accepted) */
4395
+ lastCompletionRejectionReason?: string;
4396
+ /** Number of consecutive sessions with no tool actions (for stall detection) */
4397
+ consecutiveEmptySessions?: number;
4392
4398
  /** Arbitrary bag for workflow-specific data */
4393
4399
  workflowState?: Record<string, unknown>;
4394
4400
  }
@@ -4426,7 +4432,7 @@ interface RunTaskContextCompactionEvent {
4426
4432
  }
4427
4433
  type RunTaskOnContextCompaction = (event: RunTaskContextCompactionEvent) => void | Promise<void>;
4428
4434
  interface RunTaskContextNoticeEvent {
4429
- kind: 'provider_native_compaction' | 'tool_definitions_warning';
4435
+ kind: 'provider_native_compaction' | 'tool_definitions_warning' | 'server_network_retry';
4430
4436
  sessionIndex: number;
4431
4437
  model?: string;
4432
4438
  message: string;
@@ -4690,6 +4696,7 @@ declare class AgentsEndpoint {
4690
4696
  private hasSufficientResearchEvidence;
4691
4697
  private buildEffectiveSessionOutput;
4692
4698
  private canAcceptTaskCompletion;
4699
+ private computeCompletionRejectionReason;
4693
4700
  private summarizeUnknownForTrace;
4694
4701
  private summarizeTextBlockForTrace;
4695
4702
  private parseVerificationResult;
@@ -4747,6 +4754,12 @@ declare class AgentsEndpoint {
4747
4754
  * ```
4748
4755
  */
4749
4756
  runTask(id: string, options: RunTaskOptions): Promise<RunTaskResult>;
4757
+ /** Error message patterns from server-side sessions that indicate a transient network failure
4758
+ * (e.g. AI provider connection dropped). These are retried automatically. */
4759
+ private static readonly RETRYABLE_SESSION_ERROR_PATTERNS;
4760
+ /** Returns true if a server-side session error message indicates a transient
4761
+ * network failure that is safe to retry. */
4762
+ static isRetryableSessionError(errorMessage?: string): boolean;
4750
4763
  /** Stop phrases that indicate the agent considers its task complete. */
4751
4764
  private static readonly STOP_PHRASES;
4752
4765
  /**
@@ -2240,7 +2240,10 @@ function hasSufficientResearchEvidence(state) {
2240
2240
  return false;
2241
2241
  }
2242
2242
  if (state.isCreationTask) {
2243
- return (state.recentReadPaths?.length || 0) >= 1;
2243
+ const hasReadFiles = (state.recentReadPaths?.length || 0) >= 1;
2244
+ const isDiscoveryKey = (key) => key.startsWith("tree_directory:") || key.startsWith("list_directory:") || key === "server:tree_directory" || key === "server:list_directory";
2245
+ const hasPerformedDiscovery = state.sessions.some((session) => session.actionKeys?.some(isDiscoveryKey)) || (state.recentActionKeys?.some(isDiscoveryKey) ?? false);
2246
+ return hasReadFiles || hasPerformedDiscovery;
2244
2247
  }
2245
2248
  if (!state.bestCandidatePath) return false;
2246
2249
  const normalizedBestCandidatePath = normalizeCandidatePath(state.bestCandidatePath);
@@ -2455,6 +2458,21 @@ var researchPhase = {
2455
2458
  ].join("\n");
2456
2459
  },
2457
2460
  interceptToolCall(toolName, _args, ctx) {
2461
+ if (ctx.state.isCreationTask && !isExternalTask(ctx.state)) {
2462
+ const isWriteLikeTool = toolName === "write_file" || toolName === "edit_file" || toolName === "restore_file_checkpoint";
2463
+ if (isWriteLikeTool) {
2464
+ const normalizedPathArg2 = typeof _args.path === "string" && _args.path.trim() ? ctx.normalizePath(String(_args.path)) : void 0;
2465
+ const normalizedPlanPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
2466
+ if (normalizedPathArg2 && normalizedPlanPath && normalizedPathArg2 !== normalizedPlanPath) {
2467
+ return [
2468
+ `Blocked by marathon research guard: ${toolName} cannot create product files during the research phase.`,
2469
+ "Complete research first, then the system will advance you to planning.",
2470
+ `You may write the plan to "${normalizedPlanPath}" once research is complete.`
2471
+ ].join(" ");
2472
+ }
2473
+ }
2474
+ return void 0;
2475
+ }
2458
2476
  if (!isExternalTask(ctx.state)) {
2459
2477
  return void 0;
2460
2478
  }
@@ -2557,7 +2575,7 @@ var researchPhase = {
2557
2575
  },
2558
2576
  canAcceptCompletion(state, trace) {
2559
2577
  if (!isExternalTask(state)) {
2560
- return true;
2578
+ return false;
2561
2579
  }
2562
2580
  return Boolean(state.planWritten || trace.planWritten);
2563
2581
  }
@@ -2611,7 +2629,7 @@ var planningPhase = {
2611
2629
  interceptToolCall(toolName, args, ctx) {
2612
2630
  const normalizedPathArg = typeof args.path === "string" && args.path.trim() ? ctx.normalizePath(String(args.path)) : void 0;
2613
2631
  const normalizedPlanPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
2614
- const isWriteLikeTool = toolName === "write_file" || toolName === "restore_file_checkpoint";
2632
+ const isWriteLikeTool = toolName === "write_file" || toolName === "edit_file" || toolName === "restore_file_checkpoint";
2615
2633
  if (isWriteLikeTool && normalizedPathArg && normalizedPlanPath && normalizedPathArg !== normalizedPlanPath) {
2616
2634
  return [
2617
2635
  `Blocked by marathon planning guard: ${toolName} must target the exact plan path during planning.`,
@@ -2685,9 +2703,11 @@ var executionPhase = {
2685
2703
  "Do not write the plan file first in execution. Make a real repo-file edit before you update the plan with progress.",
2686
2704
  "Do not create scratch or test files to probe the repo or tool behavior.",
2687
2705
  "write_file automatically checkpoints original repo files before overwriting them. If an edit regresses behavior, use restore_file_checkpoint on that file.",
2688
- "Read the target file and edit it with write_file. Update the plan file with progress after completing real edits.",
2706
+ "Use edit_file for targeted changes instead of rewriting the entire file with write_file. edit_file takes old_string and new_string to surgically replace specific code.",
2707
+ "Read the target file and edit it with edit_file (preferred) or write_file. Update the plan file with progress after completing real edits.",
2689
2708
  "Before large edits, read any already discovered supporting source/style files that power the target so you preserve existing behavior.",
2690
- "Prefer minimal diffs over rewrites. If you cannot verify related behavior, stop and record what is still unverified instead of rewriting blindly.",
2709
+ "Prefer edit_file for small changes. Only use write_file when creating new files or when the changes are so extensive that a full rewrite is simpler.",
2710
+ "After writing a file 2+ times, you MUST read it back to verify correctness before writing again.",
2691
2711
  'Use run_check for real verification before TASK_COMPLETE. Good examples: "pnpm lint", "pnpm exec tsc --noEmit", "pnpm test", or a focused vitest/pytest command.',
2692
2712
  "Broad discovery is only allowed if a read of the current target file fails."
2693
2713
  ];
@@ -2699,7 +2719,7 @@ var executionPhase = {
2699
2719
  const normalizedPathArg = typeof args.path === "string" && args.path.trim() ? ctx.normalizePath(String(args.path)) : void 0;
2700
2720
  const normalizedPlanPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
2701
2721
  const normalizedBestCandidatePath = ctx.state.bestCandidatePath ? ctx.normalizePath(ctx.state.bestCandidatePath) : void 0;
2702
- const isWriteLikeTool = toolName === "write_file" || toolName === "restore_file_checkpoint";
2722
+ const isWriteLikeTool = toolName === "write_file" || toolName === "edit_file" || toolName === "restore_file_checkpoint";
2703
2723
  if (normalizedBestCandidatePath && ctx.isDiscoveryTool(toolName) && !ctx.trace.bestCandidateReadFailed) {
2704
2724
  return [
2705
2725
  `Blocked by marathon execution guard: ${toolName} is disabled during execution.`,
@@ -2761,6 +2781,21 @@ var executionPhase = {
2761
2781
  },
2762
2782
  buildRecoveryMessage(state) {
2763
2783
  const recent = state.sessions.slice(-2);
2784
+ if (recent.length >= 2 && recent.every(
2785
+ (session) => session.hadTextOutput === true && session.wroteFiles !== true
2786
+ )) {
2787
+ const noToolActions = recent.every(
2788
+ (session) => !session.wroteFiles && !session.verificationAttempted
2789
+ );
2790
+ if (noToolActions) {
2791
+ return [
2792
+ "Recovery instruction: You have been rejected from completing multiple times.",
2793
+ "The likely reason is that verification has not passed.",
2794
+ "Your next action must be run_check with a concrete command (e.g., syntax check, lint, or test).",
2795
+ "Do NOT output TASK_COMPLETE again until verification passes."
2796
+ ].join("\n");
2797
+ }
2798
+ }
2764
2799
  if (recent.length >= 2 && recent.every(
2765
2800
  (session) => session.verificationAttempted === true && session.wroteFiles !== true
2766
2801
  )) {
@@ -2809,6 +2844,18 @@ var executionPhase = {
2809
2844
  if (!ctx.trace.executionFileWritten && snapshot.consecutiveDiscoveryPauseCount >= 18) {
2810
2845
  return "execution is looping on discovery instead of editing repo files and ending the turn";
2811
2846
  }
2847
+ const writeKeys = snapshot.recentActionKeys.filter((k) => k.startsWith("write_file:"));
2848
+ if (writeKeys.length >= 4) {
2849
+ const uniqueWriteTargets = new Set(writeKeys.map((k) => k.split(":").slice(1).join(":")));
2850
+ if (uniqueWriteTargets.size === 1) {
2851
+ return `write_file called ${writeKeys.length} times on the same file \u2014 read the file and verify before continuing`;
2852
+ }
2853
+ }
2854
+ for (const [filePath, count] of Object.entries(ctx.trace.writeCountByPath)) {
2855
+ if (count >= 4) {
2856
+ return `same file rewritten ${count} times without verification (${filePath}) \u2014 read the file and verify before continuing`;
2857
+ }
2858
+ }
2812
2859
  return void 0;
2813
2860
  }
2814
2861
  };
@@ -4745,7 +4792,8 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4745
4792
  verificationAttempted: false,
4746
4793
  verificationPassed: false,
4747
4794
  verificationBlocked: false,
4748
- localToolLoopGuardTriggered: false
4795
+ localToolLoopGuardTriggered: false,
4796
+ writeCountByPath: {}
4749
4797
  };
4750
4798
  }
4751
4799
  isDiscoveryLocalTool(toolName) {
@@ -4948,8 +4996,26 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4948
4996
  sessionTrace
4949
4997
  );
4950
4998
  }
4999
+ const phaseIndex = workflow.phases.findIndex((p) => p.name === state.workflowPhase);
5000
+ const executionPhaseIndex = workflow.phases.findIndex((p) => p.name === "execution");
5001
+ if (executionPhaseIndex >= 0 && phaseIndex < executionPhaseIndex) {
5002
+ return false;
5003
+ }
4951
5004
  return true;
4952
5005
  }
5006
+ computeCompletionRejectionReason(state, trace) {
5007
+ const reasons = [];
5008
+ if (!state.planWritten) {
5009
+ reasons.push("Plan file has not been written");
5010
+ }
5011
+ if (state.bestCandidatePath && !state.bestCandidateVerified && !trace.bestCandidateVerified) {
5012
+ reasons.push("Best candidate file has not been verified (read back after writing)");
5013
+ }
5014
+ if (state.verificationRequired && !state.lastVerificationPassed && !trace.verificationPassed) {
5015
+ reasons.push("Verification has not passed \u2014 run a verification command (run_check) before completing");
5016
+ }
5017
+ return reasons.length > 0 ? reasons.join("; ") : "Completion gates not satisfied for the current workflow phase";
5018
+ }
4953
5019
  summarizeUnknownForTrace(value, maxLength = 180) {
4954
5020
  const text = typeof value === "string" ? value : value === void 0 ? "" : JSON.stringify(value);
4955
5021
  return text.replace(/\s+/g, " ").trim().slice(0, maxLength);
@@ -5263,7 +5329,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5263
5329
  const pathArg = typeof args.path === "string" && args.path.trim() ? ` path=${String(args.path)}` : "";
5264
5330
  const queryArg = typeof args.query === "string" && args.query.trim() ? ` query="${String(args.query)}"` : "";
5265
5331
  const patternArg = typeof args.pattern === "string" && args.pattern.trim() ? ` pattern="${String(args.pattern)}"` : "";
5266
- const isWriteLikeTool = toolName === "write_file" || toolName === "restore_file_checkpoint";
5332
+ const isWriteLikeTool = toolName === "write_file" || toolName === "edit_file" || toolName === "restore_file_checkpoint";
5267
5333
  const isVerificationTool = toolName === "run_check";
5268
5334
  const currentPhase = workflow.phases.find((p) => p.name === state.workflowPhase);
5269
5335
  if (currentPhase?.interceptToolCall) {
@@ -5318,8 +5384,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5318
5384
  );
5319
5385
  throw error;
5320
5386
  }
5321
- if (isWriteLikeTool && normalizedPathArg) {
5387
+ const writeResultIndicatesError = isWriteLikeTool && typeof result === "string" && result.startsWith("Error:");
5388
+ if (isWriteLikeTool && normalizedPathArg && !writeResultIndicatesError) {
5322
5389
  trace.wroteFiles = true;
5390
+ trace.writeCountByPath[normalizedPathArg] = (trace.writeCountByPath[normalizedPathArg] || 0) + 1;
5323
5391
  if (normalizedPlanPath && normalizedPathArg === normalizedPlanPath) {
5324
5392
  trace.planWritten = true;
5325
5393
  } else if (state.workflowPhase === "execution") {
@@ -5627,6 +5695,8 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5627
5695
  const maxCost = options.maxCost;
5628
5696
  const useStream = options.stream ?? true;
5629
5697
  const workflow = options.workflow ?? defaultWorkflow;
5698
+ const maxServerNetworkRetries = 3;
5699
+ let consecutiveServerNetworkErrors = 0;
5630
5700
  const agent = await this.get(id);
5631
5701
  const taskName = typeof options.trackProgress === "string" ? options.trackProgress : options.trackProgress ? `${agent.name} task` : "";
5632
5702
  const resolvedTaskName = taskName || `${agent.name} task`;
@@ -5933,16 +6003,60 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5933
6003
  if (state.sessions.length > 50) {
5934
6004
  state.sessions = state.sessions.slice(-50);
5935
6005
  }
6006
+ if (sessionResult.stopReason !== "error") {
6007
+ consecutiveServerNetworkErrors = 0;
6008
+ }
5936
6009
  const detectedTaskCompletion = this.detectTaskCompletion(sessionResult.result);
5937
6010
  const acceptedTaskCompletion = detectedTaskCompletion && this.canAcceptTaskCompletion(sessionResult.result, state, sessionTrace, workflow);
6011
+ if (detectedTaskCompletion && !acceptedTaskCompletion) {
6012
+ state.lastCompletionRejectionReason = this.computeCompletionRejectionReason(state, sessionTrace);
6013
+ if (state.verificationRequired && !state.lastVerificationPassed && !sessionTrace.verificationPassed && !sessionTrace.verificationAttempted) {
6014
+ state.consecutiveBlockedVerificationSessions = (state.consecutiveBlockedVerificationSessions || 0) + 1;
6015
+ if ((state.consecutiveBlockedVerificationSessions || 0) >= 2) {
6016
+ state.verificationRequired = false;
6017
+ state.lastVerificationPassed = true;
6018
+ if (!state.planWritten) {
6019
+ state.planWritten = true;
6020
+ }
6021
+ if (!state.bestCandidateVerified) {
6022
+ state.bestCandidateVerified = true;
6023
+ }
6024
+ }
6025
+ }
6026
+ } else {
6027
+ state.lastCompletionRejectionReason = void 0;
6028
+ }
6029
+ const sessionHadActions = sessionTrace.wroteFiles || sessionTrace.readFiles || sessionTrace.discoveryPerformed || sessionTrace.verificationAttempted;
6030
+ if (sessionHadActions) {
6031
+ state.consecutiveEmptySessions = 0;
6032
+ } else {
6033
+ state.consecutiveEmptySessions = (state.consecutiveEmptySessions || 0) + 1;
6034
+ }
5938
6035
  if (sessionResult.stopReason === "complete" && !detectedTaskCompletion) {
5939
6036
  state.status = "complete";
5940
6037
  } else if (sessionResult.stopReason === "error") {
5941
- state.status = "error";
6038
+ if (_AgentsEndpoint.isRetryableSessionError(sessionResult.error) && consecutiveServerNetworkErrors < maxServerNetworkRetries) {
6039
+ consecutiveServerNetworkErrors++;
6040
+ const delayMs = Math.min(
6041
+ 5e3 * Math.pow(2, consecutiveServerNetworkErrors - 1),
6042
+ 3e4
6043
+ );
6044
+ const delaySec = Math.round(delayMs / 1e3);
6045
+ await this.emitContextNotice(options.onContextNotice, {
6046
+ kind: "server_network_retry",
6047
+ sessionIndex: session,
6048
+ message: `Server network error: ${sessionResult.error}. Retrying in ${delaySec}s (attempt ${consecutiveServerNetworkErrors}/${maxServerNetworkRetries})...`
6049
+ });
6050
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
6051
+ } else {
6052
+ state.status = "error";
6053
+ }
5942
6054
  } else if (sessionResult.stopReason === "max_cost") {
5943
6055
  state.status = "budget_exceeded";
5944
6056
  } else if (acceptedTaskCompletion) {
5945
6057
  state.status = "complete";
6058
+ } else if ((state.consecutiveEmptySessions || 0) >= 3) {
6059
+ state.status = "stalled";
5946
6060
  } else if (maxCost && state.totalCost >= maxCost) {
5947
6061
  state.status = "budget_exceeded";
5948
6062
  } else if (session + 1 >= maxSessions) {
@@ -5971,6 +6085,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5971
6085
  recordId
5972
6086
  };
5973
6087
  }
6088
+ /** Returns true if a server-side session error message indicates a transient
6089
+ * network failure that is safe to retry. */
6090
+ static isRetryableSessionError(errorMessage) {
6091
+ if (!errorMessage) return false;
6092
+ const lower = errorMessage.toLowerCase();
6093
+ return _AgentsEndpoint.RETRYABLE_SESSION_ERROR_PATTERNS.some(
6094
+ (pattern) => lower.includes(pattern)
6095
+ );
6096
+ }
5974
6097
  /**
5975
6098
  * Client-side fallback for detecting task completion in agent output.
5976
6099
  * Mirrors the API's detectAutoComplete() for non-loop agents that return 'end_turn'.
@@ -6575,6 +6698,7 @@ Do NOT redo any of the above work.`
6575
6698
  ).join("\n");
6576
6699
  if (state.messages && state.messages.length > 0) {
6577
6700
  const recoveryMessage2 = this.buildStuckTurnRecoveryMessage(state, wf);
6701
+ const rejectionNotice = state.lastCompletionRejectionReason ? `TASK_COMPLETE was rejected because: ${state.lastCompletionRejectionReason}. Address this before signaling completion again.` : void 0;
6578
6702
  const continuationContent = [
6579
6703
  "Continue the task.",
6580
6704
  phaseBlock,
@@ -6586,6 +6710,7 @@ Do NOT redo any of the above work.`
6586
6710
  `Previous sessions:`,
6587
6711
  progressSummary,
6588
6712
  "",
6713
+ ...rejectionNotice ? [rejectionNotice, ""] : [],
6589
6714
  ...recoveryMessage2 ? [recoveryMessage2, ""] : [],
6590
6715
  "Do not redo previous work. If the task is already complete, respond with TASK_COMPLETE."
6591
6716
  ].join("\n");
@@ -6646,6 +6771,7 @@ Do NOT redo any of the above work.`
6646
6771
  };
6647
6772
  }
6648
6773
  const recoveryMessage = this.buildStuckTurnRecoveryMessage(state, wf);
6774
+ const fallbackRejectionNotice = state.lastCompletionRejectionReason ? `TASK_COMPLETE was rejected because: ${state.lastCompletionRejectionReason}. Address this before signaling completion again.` : void 0;
6649
6775
  const content = [
6650
6776
  originalMessage,
6651
6777
  phaseBlock,
@@ -6657,6 +6783,7 @@ Do NOT redo any of the above work.`
6657
6783
  `Previous sessions:`,
6658
6784
  progressSummary,
6659
6785
  "",
6786
+ ...fallbackRejectionNotice ? [fallbackRejectionNotice, ""] : [],
6660
6787
  ...recoveryMessage ? [recoveryMessage, ""] : [],
6661
6788
  `Last output (do NOT repeat this \u2014 build on it):`,
6662
6789
  state.lastOutput.slice(0, 1e3),
@@ -6718,6 +6845,24 @@ Do NOT redo any of the above work.`
6718
6845
  };
6719
6846
  _AgentsEndpoint.AUTO_COMPACT_SUMMARY_PREFIX = "You are continuing a long-running task. Here is a compact summary of prior work:";
6720
6847
  _AgentsEndpoint.FORCED_COMPACT_SUMMARY_PREFIX = "You are continuing a previously completed task. Here is a summary of prior work:";
6848
+ /** Error message patterns from server-side sessions that indicate a transient network failure
6849
+ * (e.g. AI provider connection dropped). These are retried automatically. */
6850
+ _AgentsEndpoint.RETRYABLE_SESSION_ERROR_PATTERNS = [
6851
+ "network connection lost",
6852
+ "network error",
6853
+ "fetch failed",
6854
+ "connection reset",
6855
+ "connection refused",
6856
+ "connection closed",
6857
+ "socket hang up",
6858
+ "econnreset",
6859
+ "econnrefused",
6860
+ "econnaborted",
6861
+ "etimedout",
6862
+ "enetunreach",
6863
+ "enotfound",
6864
+ "request timeout"
6865
+ ];
6721
6866
  /** Stop phrases that indicate the agent considers its task complete. */
6722
6867
  _AgentsEndpoint.STOP_PHRASES = [
6723
6868
  "DONE:",
@@ -8075,4 +8220,4 @@ export {
8075
8220
  sanitizeTaskSlug,
8076
8221
  streamEvents
8077
8222
  };
8078
- //# sourceMappingURL=index.js.map
8223
+ //# sourceMappingURL=index.mjs.map