You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(acp): Prevent race condition during agent switching
When switching agents, events from the OLD agent could leak into the NEW
widget before SessionConfigured was received, causing the UI to show
responses from the wrong agent.
Fix:
- Add expected_model field to ChatWidgetInit to specify expected model
- Add session_configured_received flag to ChatWidget
- Filter events in handle_codex_event() until SessionConfigured arrives
with matching model name
Also:
- Add E2E tests for agent switch message flow
- Remove unused ClearPendingAgent event and has_pending_agent method
- Fix clippy warnings for dead code
🤖 Generated with [Nori](https://nori.ai)
Co-Authored-By: Nori <contact@tilework.tech>
Copy file name to clipboardExpand all lines: codex-rs/tui-pty-e2e/docs.md
+9-2Lines changed: 9 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,7 +145,7 @@ This delay allows the PTY subprocess time to process input and update the displa
145
145
|`@/codex-rs/tui-pty-e2e/tests/input_handling.rs`| Text editing, backspace, Ctrl-C clearing, arrow key navigation with snapshot testing |
146
146
|`@/codex-rs/tui-pty-e2e/tests/streaming.rs`| Prompt submission with timing delays, agent response streaming |
147
147
|`@/codex-rs/tui-pty-e2e/tests/acp_mode.rs`| ACP mode startup, response flow, and approval bridging - validates TUI works with ACP wire API and mock agent; includes test for permission request display |
148
-
|`@/codex-rs/tui-pty-e2e/tests/agent_switching.rs`| ACP agent subprocess lifecycle - verifies subprocess spawning, cleanup on session switch, and different agents use different processes (Linux only) |
148
+
|`@/codex-rs/tui-pty-e2e/tests/agent_switching.rs`| ACP agent subprocess lifecycle and event isolation - verifies subprocess spawning, cleanup on session switch, different agents use different processes, and event filtering prevents cross-agent contamination (Linux only) |
149
149
|`@/codex-rs/tui-pty-e2e/tests/live_acp.rs`| Live authenticated ACP tests for Gemini and Claude with real API connections (opt-in, marked `#[ignore]`) |
150
150
151
151
**Snapshot Files:**
@@ -237,7 +237,9 @@ See `@/codex-rs/mock-acp-agent/docs.md` for full list of env vars.
-`test_agent_switch_message_flow_mock_to_mock_alt` verifies that after switching agents, the NEW agent receives and responds to prompts (catches race conditions where OLD agent events could leak)
256
+
-`test_agent_switch_logs_correct_sequence` verifies the expected log sequence during agent switch: agent receives prompt, logs receipt, sends response
257
+
251
258
**Binary Discovery:**
252
259
253
260
`codex_binary_path()` locates the compiled binary:
Copy file name to clipboardExpand all lines: codex-rs/tui/docs.md
+13Lines changed: 13 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -122,6 +122,19 @@ Most event types (exec begin/end, MCP calls, elicitation) are queued during acti
122
122
- The `InterruptManager` still contains `ExecApproval` and `ApplyPatchApproval` variants for completeness, but these methods are marked `#[allow(dead_code)]`
123
123
-`on_task_complete()` calls `flush_interrupt_queue()` for any remaining queued items
124
124
125
+
**Agent Switch Event Filtering:**
126
+
127
+
When switching between ACP agents (e.g., via `/agent` command), `ChatWidget` uses an event filtering mechanism to prevent race conditions:
128
+
129
+
-`expected_model: Option<String>` in `ChatWidgetInit` specifies which model the widget expects
130
+
-`session_configured_received: bool` tracks whether `SessionConfigured` has arrived from the expected model
131
+
- When `expected_model` is set, `handle_codex_event()` filters events:
132
+
- All events are ignored until `SessionConfigured` arrives
133
+
-`SessionConfigured` is only accepted if `event.model` matches `expected_model` (case-insensitive)
134
+
- Once matching `SessionConfigured` arrives, `session_configured_received` is set to `true` and normal event processing resumes
135
+
- This prevents the OLD agent's final events (completion, shutdown) from being processed by the NEW agent's widget
136
+
- Fresh sessions, resumed sessions, and `/new` command use `expected_model: None` (no filtering)
137
+
125
138
**Color System:**
126
139
127
140
The `color.rs` and `terminal_palette.rs` modules handle terminal color detection and theming. The app queries terminal colors at startup for theme adaptation.
0 commit comments