Skip to content

[Bug]: Codex memory output still leaks into the chat when the memory thread is never announced #14706

Description

@SunkenInTime

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server (Codex adapter, CodexSessionRuntime)

Steps to reproduce

Same as #4683:

  1. Open a Codex conversation with automatic memories enabled.
  2. Exchange a few ordinary messages.
  3. Let post-turn memory consolidation run.

Expected behavior

Memory consolidation output stays out of the user's chat.

Actual behavior

The memory worker's messages and tool activity are saved into the open conversation. #5468 fixed this for memory threads that announce themselves with thread/started and a memory_consolidation source. It still happens when Codex streams the worker's items (item/agentMessage/delta, item/completed, warning) without sending thread/started first. The filter never learns that thread id, so the output falls through to the parent path. @gfdelarue hit this on 0.0.38 with Codex CLI 0.153.3 (comment on #8989). The persisted rows had data.threadId set to the worker threads.

Impact

Minor bug or occasional failure

Version or commit

Reproduced in tests against main at a3abb52. Reported live on 0.0.38.

Environment

Codex CLI 0.153.3 (reporter), NixOS; tests on Windows 11.

Logs or stack traces

No response

Workaround

Turn off automatic memories in Codex.

Why this isn't a one-line fix

I tried twice in #8989, and both attempts were closed. Notes for whoever picks this up:

  • Dropping output from any unknown foreign thread fixes the leak but also loses real subagent output. Codex can stream a v2 child's items before the subAgentActivity or thread/started that registers it, and on arrival that child looks the same as unannounced memory work.

  • Holding unknown-thread output until the thread is identified, then replaying it, works in principle. It passes the leak test and the early-child test. Review turned up seven ordering bugs in four rounds, though:

    • replay re-ran receiver-turn bookkeeping and restored an older turn;
    • a replayed old error cleared a child's newer live turn, so Stop skipped it;
    • every root delta scanned all held threads;
    • a child that failed before registering stayed interruptible;
    • the new root's output was stranded after a resume fallback;
    • an early memory turn/completed marks the session ready before the open response, so the real root's output gets held;
    • a replayed old error marks a newer running child as failed.

    The first five are fixed on the prototype. The last two are not.

  • A clean fix probably needs a signal that says "this thread is memory work" on every notification, or a decision on what to do with output from threads that are never identified.

The prototype and its tests are on SunkenInTime:wip/codex-unannounced-memory (CodexSessionRuntime.ts and CodexCollabRuntime.integration.test.ts). The integration tests that replay unannounced memory output and early child items fail on main and could be reused for any fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions