Context Overflow 3-Tier Recovery Pattern

OpenClaw implements a sophisticated 3-tier recovery strategy for handling context overflow errors during agent execution.

Location

src/agents/pi-embedded-runner/run.ts:684-845

Constants

// Maximum number of auto-compaction attempts before giving up
const MAX_OVERFLOW_COMPACTION_ATTEMPTS = 3;

// Safety margin for token estimation (20% buffer)
const SAFETY_MARGIN = 1.2;

// Minimum reserve tokens for compaction
const DEFAULT_PI_COMPACTION_RESERVE_TOKENS_FLOOR = 20_000;

Recovery Tiers

Tier 1: Detection

const contextOverflowError = (() => {
  if (!promptError) return null;

  const errorText = describeUnknownError(promptError);
  if (isLikelyContextOverflowError(errorText)) {
    return {
      source: "provider",
      text: errorText,
    };
  }
  return null;
})();

Detects overflow errors from:

  • Provider error responses
  • SDK automatic compaction failures
  • Token limit exceeded messages

Tier 2: Auto-Compaction

Maximum 3 attempts to compact the session:

if (overflowCompactionAttempts < MAX_OVERFLOW_COMPACTION_ATTEMPTS) {
  overflowCompactionAttempts++;
  log.warn(
    `context overflow detected (attempt ${overflowCompactionAttempts}/${MAX_OVERFLOW_COMPACTION_ATTEMPTS}); ` +
    `attempting auto-compaction for ${provider}/${modelId}`
  );

  const compactResult = await compactEmbeddedPiSessionDirect({
    sessionId,
    sessionKey,
    sessionFile,
    trigger: "overflow",
    diagId: overflowDiagId,
    attempt: overflowCompactionAttempts,
    maxAttempts: MAX_OVERFLOW_COMPACTION_ATTEMPTS,
    // ... other params
  });

  if (compactResult.compacted) {
    autoCompactionCount += 1;
    log.info(`auto-compaction succeeded; retrying prompt`);
    continue; // Retry the request
  }
}

Compaction Strategy:

  • Calls compactEmbeddedPiSessionDirect() with trigger: "overflow"
  • Increments global attempt counter
  • On success: retries the prompt
  • On failure: proceeds to Tier 3

Tier 3: Tool Result Truncation

For sessions with oversized tool results:

if (!toolResultTruncationAttempted) {
  const contextWindowTokens = ctxInfo.tokens;
  const hasOversized = sessionLikelyHasOversizedToolResults({
    messages: attempt.messagesSnapshot,
    contextWindowTokens,
  });

  if (hasOversized) {
    toolResultTruncationAttempted = true;
    log.warn(
      `[context-overflow-recovery] Attempting tool result truncation for ${provider}/${modelId} ` +
      `(contextWindow=${contextWindowTokens} tokens)`
    );

    const truncResult = await truncateOversizedToolResultsInSession({
      sessionFile,
      contextWindowTokens,
      sessionId,
      sessionKey,
    });

    if (truncResult.truncated) {
      log.info(
        `[context-overflow-recovery] Truncated ${truncResult.truncatedCount} tool result(s); retrying prompt`
      );
      continue; // Retry without resetting overflow counter
    }
  }
}

Truncation Strategy:

  • Identifies tool results exceeding a significant portion of context window
  • Truncates oversized results while preserving metadata
  • Does not reset overflowCompactionAttempts (global cap remains enforced)

Tier 4: Abort with Error

If all recovery attempts fail:

const kind = isCompactionFailure ? "compaction_failure" : "context_overflow";
return {
  payloads: [
    {
      text:
        "Context overflow: prompt too large for the model. " +
        "Try /reset (or /new) to start a fresh session, or use a larger-context model.",
      isError: true,
    },
  ],
  meta: {
    durationMs: Date.now() - started,
    agentMeta: { sessionId, provider, model: model.id },
    systemPromptReport: attempt.systemPromptReport,
    error: { kind, message: errorText },
  },
};

User-Facing Message:

  • Clear explanation of the issue
  • Actionable suggestions: /reset, /new, or larger model
  • Preserves error metadata for debugging

Diagnostic Logging

Each overflow event generates a diagnostic ID:

const overflowDiagId = createCompactionDiagId();
log.warn(
  `[context-overflow-diag] sessionKey=${sessionKey} ` +
  `provider=${provider}/${modelId} source=${contextOverflowError.source} ` +
  `messages=${msgCount} sessionFile=${sessionFile} ` +
  `diagId=${overflowDiagId} compactionAttempts=${overflowCompactionAttempts} ` +
  `error=${errorText.slice(0, 200)}`
);

Cross-References