openclaw - 💡(How to fix) Fix [Bug]: Codex before_prompt_build receives empty messages after #88262 [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…

After PR #88262, the Codex app-server passes messages: [] into before_prompt_build, even when the session transcript was loaded successfully.

That breaks the public hook contract and silently degrades existing history-sensitive plugins. The PR intended to prevent mirrored history from being injected into Codex model input, but it also removed the hook's read-only view of the session history.

These are different surfaces and should not share the same empty array.

Root Cause

flowchart LR
    A["hookObservationMessages"] --> B["before_prompt_build"]
    C["codexModelInputHistoryMessages"] --> D["Codex turn/model input"]
    C --> E["May be [] for native resume"]
    A --> F["Should not be forced to [] just because C is []"]

Fix Action

Fixed

Code Example

flowchart TD
    A["Session JSONL / mirrored transcript"] --> B["readMirroredSessionHistoryMessages(...)"]
    B --> C["historyMessages populated"]
    C --> D["before_prompt_build hook"]
    C --> E["Codex model input"]

    D --> F["Plugin observes recent turns, latest user text, safety state"]
    E --> G["Native Codex thread receives current prompt only on resume"]

    H["Current merged code"] --> I["codexModelInputHistoryMessages = []"]
    I --> D
    I --> E
    I --> J["Hook loses observation history even though model-history dedupe was the real concern"]

---

flowchart LR
    A["hookObservationMessages"] --> B["before_prompt_build"]
    C["codexModelInputHistoryMessages"] --> D["Codex turn/model input"]
    C --> E["May be [] for native resume"]
    A --> F["Should not be forced to [] just because C is []"]
RAW_BUFFERClick to expand / collapse

Bug type

Regression / plugin contract break in the Codex app-server hook surface.

Summary

After PR #88262, the Codex app-server passes messages: [] into before_prompt_build, even when the session transcript was loaded successfully.

That breaks the public hook contract and silently degrades existing history-sensitive plugins. The PR intended to prevent mirrored history from being injected into Codex model input, but it also removed the hook's read-only view of the session history.

These are different surfaces and should not share the same empty array.

Why this is high confidence

Diagram

flowchart TD
    A["Session JSONL / mirrored transcript"] --> B["readMirroredSessionHistoryMessages(...)"]
    B --> C["historyMessages populated"]
    C --> D["before_prompt_build hook"]
    C --> E["Codex model input"]

    D --> F["Plugin observes recent turns, latest user text, safety state"]
    E --> G["Native Codex thread receives current prompt only on resume"]

    H["Current merged code"] --> I["codexModelInputHistoryMessages = []"]
    I --> D
    I --> E
    I --> J["Hook loses observation history even though model-history dedupe was the real concern"]

Expected behavior

before_prompt_build should continue to receive the session messages that were prepared for the run, or a clearly documented filtered/redacted subset of them.

Separately, the Codex native model input can still use an empty parallel history array when the native Codex thread already owns conversation continuity.

In other words:

flowchart LR
    A["hookObservationMessages"] --> B["before_prompt_build"]
    C["codexModelInputHistoryMessages"] --> D["Codex turn/model input"]
    C --> E["May be [] for native resume"]
    A --> F["Should not be forced to [] just because C is []"]

Actual behavior

before_prompt_build receives [].

That means a plugin cannot tell whether:

  • this is the first turn of a session,
  • there are previous user constraints,
  • the latest user message in the session differs from the current prompt,
  • recent turns include context needed for memory recall,
  • safety or routing state depends on recent messages.

The plugin sees the same messages: [] for a brand-new session and for a long-running session.

Minimal reproduction shape

  1. Add a prior assistant or user message to the OpenClaw session file.
  2. Register a before_prompt_build hook that records event.messages.
  3. Run a Codex app-server attempt.
  4. Inspect the hook input.

With the merged code, event.messages is [].

The current test suite already demonstrates this behavior in run-attempt.test.ts; the test expectation should be reversed or split so that hook-observation history and Codex model-input history are verified independently.

Impact

This is a plugin API compatibility break, not just an internal implementation detail.

Known in-tree impact:

  • active-memory will produce weaker or incorrect recall context because recentTurns becomes empty.
  • memory-lancedb can fall back to event.prompt even when the session has a more precise latest user message in event.messages.
  • Any third-party plugin that uses before_prompt_build.messages for policy, prompt shaping, memory recall, audit, or safety checks now loses the transcript without an API version change.

This can also confuse lossless-context integrations indirectly. Even if the active context-engine path still receives historyMessages during assembly, plugins that run in the same pre-prompt phase no longer see the loaded messages described by the hook contract.

Suggested fix direction

Keep the PR's intended model-input behavior, but split the variables:

  • hookObservationMessages: the loaded, filtered session messages passed to before_prompt_build.
  • codexModelInputHistoryMessages: the actual history sent as parallel Codex model input, which may remain [].
  • diagnosticModelInputMessages: whatever the model diagnostics need to reflect the actual Codex input.

If Codex app-server intentionally wants a different hook contract than other harnesses, the type and docs should be changed explicitly, and the hook should receive a reason field such as messagesUnavailableReason: "codex-native-thread-owns-history". Right now it looks like a silent contract regression.

Evidence checked

  • Merged PR: openclaw/openclaw#88262
  • Merge commit: 530351e394a19b1dd2943cb08259657a13f90572
  • PR head audited locally: 04a4427d0c0b8f2e7bb666bbbcda5c557d033972

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

before_prompt_build should continue to receive the session messages that were prepared for the run, or a clearly documented filtered/redacted subset of them.

Separately, the Codex native model input can still use an empty parallel history array when the native Codex thread already owns conversation continuity.

In other words:

flowchart LR
    A["hookObservationMessages"] --> B["before_prompt_build"]
    C["codexModelInputHistoryMessages"] --> D["Codex turn/model input"]
    C --> E["May be [] for native resume"]
    A --> F["Should not be forced to [] just because C is []"]

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 before_prompt_build receives empty messages after #88262 [1 pull requests]