Download src/agents/sessions/agent-session-execution.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 3.98 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/sessions/agent-session-execution.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/agents/sessions/agent-session-execution.ts
-
curl -L -o agent-session-execution.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/sessions/agent-session-execution.ts
3.98 kB
| import { isResponsesOutputLimitToolCallError } from "@openclaw/ai/diagnostics"; | |
| import { isContextOverflow } from "@openclaw/ai/internal/runtime"; | |
| import type { AssistantMessage } from "../../llm/types.js"; | |
| import { isRetryableAssistantError } from "../../llm/utils/retry.js"; | |
| import { sleep } from "../../utils/sleep.js"; | |
| import { classifyRateLimitWindow } from "../failover/retry-evidence.js"; | |
| import { AgentSessionExtensions } from "./agent-session-extensions.js"; | |
| export abstract class AgentSessionExecution extends AgentSessionExtensions { | |
| // ========================================================================= | |
| // Auto-Retry | |
| // ========================================================================= | |
| /** | |
| * Check if an error is retryable (overloaded, rate limit, server errors). | |
| * Context overflow errors are NOT retryable (handled by compaction instead). | |
| */ | |
| protected isRetryableError(message: AssistantMessage): boolean { | |
| if (message.stopReason !== "error" || !message.errorMessage) { | |
| return false; | |
| } | |
| // Context overflow is handled by compaction, not retry | |
| const contextWindow = this.model?.contextWindow ?? 0; | |
| if (isContextOverflow(message, contextWindow)) { | |
| return false; | |
| } | |
| return isResponsesOutputLimitToolCallError(message) || isRetryableAssistantError(message); | |
| } | |
| /** | |
| * Prepare a retryable error for continuation with exponential backoff. | |
| * @returns true if the caller should continue the agent, false otherwise | |
| */ | |
| protected async prepareRetry(message: AssistantMessage): Promise<boolean> { | |
| const settings = this.settingsManager.getRetrySettings(); | |
| if (!settings.enabled) { | |
| return false; | |
| } | |
| this.retryCount++; | |
| if (this.retryCount > settings.maxRetries) { | |
| // Preserve the completed attempt count so post-run handling can emit the final failure. | |
| this.retryCount--; | |
| return false; | |
| } | |
| const backoffDelayMs = settings.baseDelayMs * 2 ** (this.retryCount - 1); | |
| const rateLimitWindow = classifyRateLimitWindow(message.errorMessage); | |
| const retryAfterDelayMs = | |
| rateLimitWindow.kind === "short" && rateLimitWindow.retryAfterSeconds !== undefined | |
| ? Math.ceil(rateLimitWindow.retryAfterSeconds * 1000) | |
| : 0; | |
| const delayMs = Math.max(backoffDelayMs, retryAfterDelayMs); | |
| this.emit({ | |
| type: "auto_retry_start", | |
| attempt: this.retryCount, | |
| maxAttempts: settings.maxRetries, | |
| delayMs, | |
| errorMessage: message.errorMessage || "Unknown error", | |
| }); | |
| // Async tool results can settle after the error. Keep them and the durable transcript. | |
| const messages = this.agent.state.messages; | |
| const failedIndex = messages.findLastIndex((candidate) => candidate === message); | |
| if (failedIndex >= 0) { | |
| this.agent.state.messages = messages.toSpliced(failedIndex, 1); | |
| } | |
| // Wait with exponential backoff (abortable) | |
| this.retryAbortController = new AbortController(); | |
| try { | |
| await sleep(delayMs, this.retryAbortController.signal); | |
| } catch { | |
| // Aborted during sleep - emit end event so UI can clean up | |
| const attempt = this.retryCount; | |
| this.retryCount = 0; | |
| this.emit({ | |
| type: "auto_retry_end", | |
| success: false, | |
| attempt, | |
| finalError: "Retry cancelled", | |
| }); | |
| return false; | |
| } finally { | |
| this.retryAbortController = undefined; | |
| } | |
| return true; | |
| } | |
| /** | |
| * Cancel in-progress retry. | |
| */ | |
| abortRetry(): void { | |
| this.retryAbortController?.abort(); | |
| } | |
| /** Whether auto-retry is currently in progress */ | |
| get isRetrying(): boolean { | |
| return this.retryAbortController !== undefined; | |
| } | |
| /** Whether auto-retry is enabled */ | |
| get autoRetryEnabled(): boolean { | |
| return this.settingsManager.getRetryEnabled(); | |
| } | |
| /** | |
| * Toggle auto-retry setting. | |
| */ | |
| setAutoRetryEnabled(enabled: boolean): void { | |
| this.settingsManager.setRetryEnabled(enabled); | |
| } | |
| } | |