openclaw - 💡(How to fix) Fix buildCliSessionHistoryPrompt prefix-slices renderedHistory, dropping the most recent assistant turns from reseed prompt [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

buildCliSessionHistoryPrompt in src/agents/cli-runner/session-history.ts (bundled as dist/session-history-*.js line ~41 in the published package) prefix-slices the rendered history when it exceeds maxHistoryChars, which drops the most recent assistant turns from the reseed prompt instead of the oldest. After PR #80934 made the Claude-CLI reseed path fire by default in v2026.5.12, every Claude-CLI user is exposed to this whenever session_expired triggers a reseed and the rendered transcript is longer than 12288 characters (the hard-coded default).

Root Cause

buildCliSessionHistoryPrompt in src/agents/cli-runner/session-history.ts (bundled as dist/session-history-*.js line ~41 in the published package) prefix-slices the rendered history when it exceeds maxHistoryChars, which drops the most recent assistant turns from the reseed prompt instead of the oldest. After PR #80934 made the Claude-CLI reseed path fire by default in v2026.5.12, every Claude-CLI user is exposed to this whenever session_expired triggers a reseed and the rendered transcript is longer than 12288 characters (the hard-coded default).

Fix Action

Fixed

Code Example

const renderedHistory = renderedHistoryRaw.length > maxHistoryChars
    ? `${renderedHistoryRaw.slice(0, maxHistoryChars).trimEnd()}\n[OpenClaw reseed history truncated]`
    : renderedHistoryRaw;

---

const renderedHistory = renderedHistoryRaw.length > maxHistoryChars
    ? `[OpenClaw reseed history truncated; older turns dropped]\n${renderedHistoryRaw.slice(-maxHistoryChars).trimStart()}`
    : renderedHistoryRaw;
RAW_BUFFERClick to expand / collapse

Summary

buildCliSessionHistoryPrompt in src/agents/cli-runner/session-history.ts (bundled as dist/session-history-*.js line ~41 in the published package) prefix-slices the rendered history when it exceeds maxHistoryChars, which drops the most recent assistant turns from the reseed prompt instead of the oldest. After PR #80934 made the Claude-CLI reseed path fire by default in v2026.5.12, every Claude-CLI user is exposed to this whenever session_expired triggers a reseed and the rendered transcript is longer than 12288 characters (the hard-coded default).

The defect

The current implementation:

const renderedHistory = renderedHistoryRaw.length > maxHistoryChars
    ? `${renderedHistoryRaw.slice(0, maxHistoryChars).trimEnd()}\n[OpenClaw reseed history truncated]`
    : renderedHistoryRaw;

params.messages is in chronological order (oldest → newest), and the flatMap(...).join("\n\n") preserves that order. slice(0, maxHistoryChars) is therefore a prefix slice that keeps the oldest content and drops the most recent — exactly the opposite of what a context-recovery prompt wants. The trailing [OpenClaw reseed history truncated] marker reinforces the wrong mental model: in current behavior, what actually got truncated is at the end, not the beginning.

Reproducer

In a Claude-CLI session whose rendered transcript exceeds ~12k chars (any moderate conversation — keyboard talk, code review, etc.), trigger a session_expired reseed (gateway restart, --safe drain, or any of the orphan-tool-use recovery paths).

The fresh CLI session receives a <conversation_history> block ending with the marker [OpenClaw reseed history truncated] planted mid-word — confirming a blind character slice with no message-boundary respect. The most recent assistant turns are absent. The model correctly diagnoses the truncation and replies with something like "I don't have context for what '...' is — the conversation history got truncated right at the end."

I have a concrete reproducer (Telegram + claude-cli backend, OC v2026.5.12) where the missing turn was visible in OC's session storage at ~/.openclaw/agents/<agent>/sessions/*.jsonl but absent from the reseed preamble at ~/.claude/projects/.../<sessionId>.jsonl records 0-7 of the post-recovery session. Happy to share the redacted JSONL excerpts if useful.

Proposed fix

One-character semantic change at the slice direction, plus moving the truncation marker to the lead so it correctly describes what follows:

const renderedHistory = renderedHistoryRaw.length > maxHistoryChars
    ? `[OpenClaw reseed history truncated; older turns dropped]\n${renderedHistoryRaw.slice(-maxHistoryChars).trimStart()}`
    : renderedHistoryRaw;

This keeps the suffix (newest content) and drops the prefix (oldest content), which matches the intent of every other context-recovery feature I'm aware of in the codebase.

PR with the fix + a regression test will follow.

Why no test caught this

The existing tests in session-history.test.ts and prepare.test.ts (referenced in #79713 and #80905 review threads) assert that the prompt is built when expected and that the boundaries between sections are correct, but none assert that the last message in params.messages appears in the rendered prompt when the input exceeds the cap. A regression test of the form "given N messages totaling > maxHistoryChars, the last message MUST appear in the rendered prompt" would have caught this and would prevent regressions on the slice direction.

Scope

  • Universal: affects every claude-cli user on v2026.5.12+ when a reseed fires and the rendered history exceeds maxHistoryChars.
  • Backend-agnostic: the function is in shared cli-runner code, not in the claude-cli extension. Codex CLI / Gemini CLI hit the same path if they ever opt into the same reseed flag. (Only Claude CLI does today, per #80934.)
  • maxHistoryChars cap (12288 chars / ~3000 tokens) is unrelated — that's an independent config / sizing question. The orientation fix should land regardless of any future cap-tuning.

Related work

  • #80905 (closed by #80934) — addressed "reseed didn't fire at all"; orthogonal to the slice direction.
  • #79713 (closed by #79764) — introduced the reseedFromRawTranscriptWhenUncompacted opt-in.
  • #80934 (merged 2026-05-13, shipped in 2026.5.12) — made the opt-in default for Claude CLI.

This issue describes a separate defect downstream of all three, in the prompt-rendering function rather than the gating/firing logic.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix buildCliSessionHistoryPrompt prefix-slices renderedHistory, dropping the most recent assistant turns from reseed prompt [1 pull requests]