openclaw - 💡(How to fix) Fix [Bug]: Codex app-server stores per-turn OpenClaw runtime context in native user history, causing runaway response.create input growth

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…

Codex app-server turns currently prepend an OpenClaw runtime-context block to the user prompt for every turn:

OpenClaw runtime context for this turn:
...
Current user request:
...

That decorated text is sent to Codex app-server as turn/start.input[0].text. Codex native history then persists it as a normal user item, so later response.create calls replay all prior copies. After enough turns, most of the model input is repeated OpenClaw runtime context rather than the current user request.

This is distinct from the PI runner openclaw.runtime-context / queueRuntimeContextForNextTurn() path. In the analyzed logs, the repeated marker was OpenClaw runtime context for this turn:, not openclaw.runtime-context or OpenClaw runtime context for the immediately preceding user message.

Root Cause

Codex app-server turns currently prepend an OpenClaw runtime-context block to the user prompt for every turn:

OpenClaw runtime context for this turn:
...
Current user request:
...

That decorated text is sent to Codex app-server as turn/start.input[0].text. Codex native history then persists it as a normal user item, so later response.create calls replay all prior copies. After enough turns, most of the model input is repeated OpenClaw runtime context rather than the current user request.

This is distinct from the PI runner openclaw.runtime-context / queueRuntimeContextForNextTurn() path. In the analyzed logs, the repeated marker was OpenClaw runtime context for this turn:, not openclaw.runtime-context or OpenClaw runtime context for the immediately preceding user message.

Code Example

OpenClaw runtime context for this turn:
...
Current user request:
...

---

extensions/codex/src/app-server/run-attempt.ts
  buildCodexOpenClawPromptContext()
  -> prependCodexOpenClawPromptContext()
  -> codexTurnPromptText
  -> startCodexTurn()
  -> buildTurnStartParams(... promptText: codexTurnPromptText)

extensions/codex/src/app-server/thread-lifecycle.ts
  buildTurnStartParams()
  -> buildUserInput(params, promptText)
  -> [{ type: text, text: promptText, text_elements: [] }]

---

response.create example A:
  input items: 146
  runtime-context user messages: 86
  runtime-context text: ~1,219,607 chars
  total input text: ~1,257,588 chars
  runtime-context share: ~96.98%

response.create example B:
  input items: 16
  runtime-context user messages: 13
  runtime-context text: ~260,910 chars
  total input text: ~291,863 chars
  runtime-context share: ~89.39%

---

openclaw.runtime-context
OpenClaw runtime context for the immediately preceding user message.

---

turn 1: 1 copy
turn 2: 2 copies
turn 3: 3 copies
...

---

OpenClaw runtime context for this turn:
RAW_BUFFERClick to expand / collapse

Summary

Codex app-server turns currently prepend an OpenClaw runtime-context block to the user prompt for every turn:

OpenClaw runtime context for this turn:
...
Current user request:
...

That decorated text is sent to Codex app-server as turn/start.input[0].text. Codex native history then persists it as a normal user item, so later response.create calls replay all prior copies. After enough turns, most of the model input is repeated OpenClaw runtime context rather than the current user request.

This is distinct from the PI runner openclaw.runtime-context / queueRuntimeContextForNextTurn() path. In the analyzed logs, the repeated marker was OpenClaw runtime context for this turn:, not openclaw.runtime-context or OpenClaw runtime context for the immediately preceding user message.

Code path

The relevant path is in the Codex app-server harness:

extensions/codex/src/app-server/run-attempt.ts
  buildCodexOpenClawPromptContext()
  -> prependCodexOpenClawPromptContext()
  -> codexTurnPromptText
  -> startCodexTurn()
  -> buildTurnStartParams(... promptText: codexTurnPromptText)

extensions/codex/src/app-server/thread-lifecycle.ts
  buildTurnStartParams()
  -> buildUserInput(params, promptText)
  -> [{ type: text, text: promptText, text_elements: [] }]

Key source locations from current tree:

  • extensions/codex/src/app-server/run-attempt.ts: buildCodexOpenClawPromptContext() builds the block starting with OpenClaw runtime context for this turn:.
  • extensions/codex/src/app-server/run-attempt.ts: prependCodexOpenClawPromptContext() prepends that block above Current user request:.
  • extensions/codex/src/app-server/run-attempt.ts: startCodexTurn() passes promptText: codexTurnPromptText to turn/start.
  • extensions/codex/src/app-server/thread-lifecycle.ts: buildUserInput() turns that prompt text into a normal text user input item.

Observed evidence

Local forensic logs and rollout JSONL files show the decorated prompt being persisted as user history and replayed into model requests:

  • Rollout session file: many response_item entries with role=user containing OpenClaw runtime context for this turn:.
  • The same marker also appears in event/display records, but the important part is the response_item role=user form.
  • In response.create payloads, prior user items containing the marker are replayed as model-visible input.

Representative measured examples from local logs:

response.create example A:
  input items: 146
  runtime-context user messages: 86
  runtime-context text: ~1,219,607 chars
  total input text: ~1,257,588 chars
  runtime-context share: ~96.98%

response.create example B:
  input items: 16
  runtime-context user messages: 13
  runtime-context text: ~260,910 chars
  total input text: ~291,863 chars
  runtime-context share: ~89.39%

Compaction was also affected: compact requests contained many copies of the same runtime-context block, so compaction was spending most of its input budget summarizing repeated per-turn scaffolding instead of conversation content.

Why existing cleanup does not catch this

This does not appear to go through the PI runner LLM-boundary cleanup path. The relevant marker is not the PI custom-message marker:

openclaw.runtime-context
OpenClaw runtime context for the immediately preceding user message.

Instead, the repeated text is injected by the Codex app-server harness as a normal user prompt before turn/start. Cleanup such as normalizeMessagesForLlmBoundary() does not intercept the native Codex app-server response.create history built from that native thread.

Role of Telegram / channel context

Telegram is not the direct source of this repeated marker. The Telegram adapter can contribute large dynamic group context, which makes each turn heavier, but the repeated marker in the analyzed payloads comes from the Codex app-server harness runtime-context block.

Expected behavior

Per-turn OpenClaw runtime context should be available to the current model call without being persisted as ordinary native Codex user history and replayed in every later turn.

After three turns on the same native Codex thread, the number of historical copies of OpenClaw runtime context for this turn: in the next response.create input should remain bounded, ideally zero historical copies.

Actual behavior

Each turn stores the decorated prompt as a normal user history item. On the next turn, prior decorated prompts are replayed along with the new decorated prompt, causing roughly linear accumulation:

turn 1: 1 copy
turn 2: 2 copies
turn 3: 3 copies
...

In longer sessions this becomes the dominant input payload and can trigger very slow responses, cache churn, and failed or expensive compaction.

Proposed fix direction

Preferred fix:

  • Do not persist OpenClaw runtime context for this turn: as normal Codex native user history.
  • Add a Codex app-server current-turn/transient-context path if available, or split the prompt so only the real user request is saved as the user turn.

Safe interim fix:

  • Strip historical user items beginning with OpenClaw runtime context for this turn: before replay/compaction, preserving only the text after Current user request:.
  • Keep current-turn context available for the active model call, but prevent historical copies from entering future response.create inputs.

Security/rank caution:

  • Do not blindly move all of this block to developer instructions. Some of the content, such as user-editable workspace or memory context, is intentionally reference data and should not be promoted to developer/system authority.
  • Stable instructions such as OpenClaw skills may be safe to move to developer/bootstrap instructions, but user-editable workspace context should remain quoted/reference scoped.

Test plan

Add a Codex app-server harness test that simulates multiple turns on the same native thread:

  1. Run turn 1 with workspace prompt context enabled.
  2. Run turn 2 and turn 3 on the same bound Codex native thread.
  3. Capture the turn/start payload and/or mocked native response.create input.
  4. Count occurrences of:
OpenClaw runtime context for this turn:

Before the fix, the count grows with each turn. After the fix, historical copies should not accumulate.

Also add a compaction/replay test proving that compacted.replacement_history or equivalent replay input does not preserve repeated historical runtime-context blocks.

Related issues

Related but broader / less specific:

  • #78947: Codex native runtime high latency for trivial turns.
  • #68209: Native Codex route can trigger runaway context growth and off-task workspace contamination.
  • #84110: Codex app-server prompt rewriting/cache busting on tool continuation turns.

This issue is specifically about per-turn OpenClaw runtime context being injected into normal Codex user history and replayed into later response.create requests.

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…

FAQ

Expected behavior

Per-turn OpenClaw runtime context should be available to the current model call without being persisted as ordinary native Codex user history and replayed in every later turn.

After three turns on the same native Codex thread, the number of historical copies of OpenClaw runtime context for this turn: in the next response.create input should remain bounded, ideally zero historical copies.

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 [Bug]: Codex app-server stores per-turn OpenClaw runtime context in native user history, causing runaway response.create input growth