[7 of 7] Sync TUI thread settings#22510
Conversation
…e-core # Conflicts: # codex-rs/app-server/src/request_processors/thread_processor_tests.rs
…n-state-tui # Conflicts: # codex-rs/tui/src/chatwidget.rs # codex-rs/tui/src/chatwidget/tests/plan_mode.rs
fcoury-oai
left a comment
There was a problem hiding this comment.
Found a potential issue with the help of Codex: if a user already has a Plan-mode reasoning override, then changes Plan reasoning again from the TUI, the local UI updates but the thread/turnContext/update sent to the app server can still contain the old effort. Other connected TUIs keep showing stale Plan reasoning, which is the sync bug this PR is trying to fix.
Here's how I replicated it with 3 terminals:
- on terminal A run
./target/debug/codex app-server --listen ws://127.0.0.1:48879 - on terminal B run
./target/debug/codex --remote ws://127.0.0.1:48879 -C /tmp/codex-next-turn-smoke --enable collaboration_modes -c 'plan_mode_reasoning_effort="low"' - send something like
Reply exactly: testing planon terminal B - check session id from
/statusor statusline. - on terminal C run
./target/debug/codex resume --remote ws://127.0.0.1:48879 <session-id> --enable collaboration_modes -C /tmp/codex-next-turn-smoke - run
/planfirst then/model, pick the current model and pick High reasoning - choose Apply to Plan mode override
- on terminal B check
statusor statusline, to show plan High - in terminal C run
/status
You'll see C still shows reasoning as low from /status or statuline.
From Codex: "That means the app-server-bound OverrideTurnContext.collaboration_mode.settings.reasoning_effort was low even though the UI action selected high."
etraut-openai
left a comment
There was a problem hiding this comment.
[codex] Fixed in 399695c. The Plan reasoning override path now sends the explicitly selected effort instead of reapplying the stale stored Plan default.
fcoury-oai
left a comment
There was a problem hiding this comment.
I reviewed the code changes, specially the changes after my last review. I also tested the same happy path I tested before with one app server and two terminals, making sure the two clients sync models, reasoning levels, mode (plan/default) and fast on/off.
The problem I found last time was also fixed.
Code looks good and my manual tests all pass.
Approved 👍
|
This PR is superseded by #23507. |
Builds on #23502. ## Why #23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR #22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
**Stack position:** [1 of 7] ## Summary The first three PRs in this stack are a cleanup pass before the actual thread settings API work. Today, core has several overlapping "user input" ops: `UserInput`, `UserInputWithTurnContext`, and `UserTurn`. They differ mostly in how much next-turn state they carry, which makes the later queued thread settings update harder to reason about and review. This PR starts that cleanup by adding the shared `ThreadSettingsOverrides` payload and allowing `Op::UserInput` to carry it. Existing variants remain in place here, so this layer is mostly a behavior-preserving API shape change plus mechanical constructor updates. ## End State After PR3 By the end of PR3, `Op::UserInput` is the only "user input" core op. It can carry optional thread settings overrides for callers that need to update stored defaults with a turn, while callers without updates use empty settings. `Op::UserInputWithTurnContext` and `Op::UserTurn` are deleted. ## End State After PR5 By the end of PR5, core will have only two ops for this area: - `Op::UserInput` for user-input-bearing submissions. - `Op::ThreadSettings` for settings-only updates. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai/codex#23080) (this PR) 2. [2 of 7] [Remove UserInputWithTurnContext](openai/codex#23081) 3. [3 of 7] [Remove UserTurn](openai/codex#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai/codex#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai/codex#22508) 6. [6 of 7] [Add app-server thread settings API](openai/codex#22509) 7. [7 of 7] [Sync TUI thread settings](openai/codex#22510)
**Stack position:** [2 of 7] ## Summary This PR removes the overlapping `Op::UserInputWithTurnContext` variant now that `Op::UserInput` can carry thread settings overrides directly. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai/codex#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai/codex#23081) (this PR) 3. [3 of 7] [Remove UserTurn](openai/codex#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai/codex#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai/codex#22508) 6. [6 of 7] [Add app-server thread settings API](openai/codex#22509) 7. [7 of 7] [Sync TUI thread settings](openai/codex#22510)
**Stack position:** [3 of 7] ## Summary This PR finishes the input-op consolidation by moving the remaining `Op::UserTurn` callers onto `Op::UserInput` and deleting `Op::UserTurn`. This touches a lot of files, but it is a low-risk mechanical migration. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai/codex#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai/codex#23081) 3. [3 of 7] [Remove UserTurn](openai/codex#23075) (this PR) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai/codex#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai/codex#22508) 6. [6 of 7] [Add app-server thread settings API](openai/codex#22509) 7. [7 of 7] [Sync TUI thread settings](openai/codex#22510)
**Stack position:** [5 of 7] ## Summary This PR adds `Op::ThreadSettings`, a queued settings-only update mechanism for changing stored thread settings without starting a new turn. It also removes the legacy `Op::OverrideTurnContext` in the same layer, so reviewers can see the replacement and deletion together. ## Changes - Add `Op::ThreadSettings` for settings-only queued updates. - Emit `ThreadSettingsApplied` with the effective thread settings snapshot after core applies an update. - Route settings-only updates through the same submission queue as user input. - Migrate remaining `OverrideTurnContext` tests and callers to the queued `Op::ThreadSettings` path. - Delete `Op::OverrideTurnContext` from the core protocol and submission loop. This stack addresses #20656 and #22090. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai/codex#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai/codex#23081) 3. [3 of 7] [Remove UserTurn](openai/codex#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai/codex#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai/codex#22508) (this PR) 6. [6 of 7] [Add app-server thread settings API](openai/codex#22509) 7. [7 of 7] [Sync TUI thread settings](openai/codex#22510)
Builds on #23502. ## Why #23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR openai/codex#22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
**Stack position:** [1 of 7] ## Summary The first three PRs in this stack are a cleanup pass before the actual thread settings API work. Today, core has several overlapping "user input" ops: `UserInput`, `UserInputWithTurnContext`, and `UserTurn`. They differ mostly in how much next-turn state they carry, which makes the later queued thread settings update harder to reason about and review. This PR starts that cleanup by adding the shared `ThreadSettingsOverrides` payload and allowing `Op::UserInput` to carry it. Existing variants remain in place here, so this layer is mostly a behavior-preserving API shape change plus mechanical constructor updates. ## End State After PR3 By the end of PR3, `Op::UserInput` is the only "user input" core op. It can carry optional thread settings overrides for callers that need to update stored defaults with a turn, while callers without updates use empty settings. `Op::UserInputWithTurnContext` and `Op::UserTurn` are deleted. ## End State After PR5 By the end of PR5, core will have only two ops for this area: - `Op::UserInput` for user-input-bearing submissions. - `Op::ThreadSettings` for settings-only updates. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) (this PR) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [2 of 7] ## Summary This PR removes the overlapping `Op::UserInputWithTurnContext` variant now that `Op::UserInput` can carry thread settings overrides directly. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) (this PR) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [3 of 7] ## Summary This PR finishes the input-op consolidation by moving the remaining `Op::UserTurn` callers onto `Op::UserInput` and deleting `Op::UserTurn`. This touches a lot of files, but it is a low-risk mechanical migration. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) (this PR) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [5 of 7] ## Summary This PR adds `Op::ThreadSettings`, a queued settings-only update mechanism for changing stored thread settings without starting a new turn. It also removes the legacy `Op::OverrideTurnContext` in the same layer, so reviewers can see the replacement and deletion together. ## Changes - Add `Op::ThreadSettings` for settings-only queued updates. - Emit `ThreadSettingsApplied` with the effective thread settings snapshot after core applies an update. - Route settings-only updates through the same submission queue as user input. - Migrate remaining `OverrideTurnContext` tests and callers to the queued `Op::ThreadSettings` path. - Delete `Op::OverrideTurnContext` from the core protocol and submission loop. This stack addresses openai#20656 and openai#22090. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) (this PR) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
Builds on openai#23502. ## Why openai#23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR openai#22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
**Stack position:** [1 of 7] ## Summary The first three PRs in this stack are a cleanup pass before the actual thread settings API work. Today, core has several overlapping "user input" ops: `UserInput`, `UserInputWithTurnContext`, and `UserTurn`. They differ mostly in how much next-turn state they carry, which makes the later queued thread settings update harder to reason about and review. This PR starts that cleanup by adding the shared `ThreadSettingsOverrides` payload and allowing `Op::UserInput` to carry it. Existing variants remain in place here, so this layer is mostly a behavior-preserving API shape change plus mechanical constructor updates. ## End State After PR3 By the end of PR3, `Op::UserInput` is the only "user input" core op. It can carry optional thread settings overrides for callers that need to update stored defaults with a turn, while callers without updates use empty settings. `Op::UserInputWithTurnContext` and `Op::UserTurn` are deleted. ## End State After PR5 By the end of PR5, core will have only two ops for this area: - `Op::UserInput` for user-input-bearing submissions. - `Op::ThreadSettings` for settings-only updates. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) (this PR) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [2 of 7] ## Summary This PR removes the overlapping `Op::UserInputWithTurnContext` variant now that `Op::UserInput` can carry thread settings overrides directly. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) (this PR) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [3 of 7] ## Summary This PR finishes the input-op consolidation by moving the remaining `Op::UserTurn` callers onto `Op::UserInput` and deleting `Op::UserTurn`. This touches a lot of files, but it is a low-risk mechanical migration. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) (this PR) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [5 of 7] ## Summary This PR adds `Op::ThreadSettings`, a queued settings-only update mechanism for changing stored thread settings without starting a new turn. It also removes the legacy `Op::OverrideTurnContext` in the same layer, so reviewers can see the replacement and deletion together. ## Changes - Add `Op::ThreadSettings` for settings-only queued updates. - Emit `ThreadSettingsApplied` with the effective thread settings snapshot after core applies an update. - Route settings-only updates through the same submission queue as user input. - Migrate remaining `OverrideTurnContext` tests and callers to the queued `Op::ThreadSettings` path. - Delete `Op::OverrideTurnContext` from the core protocol and submission loop. This stack addresses openai#20656 and openai#22090. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) (this PR) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
Builds on openai#23502. ## Why openai#23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR openai#22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
**Stack position:** [1 of 7] ## Summary The first three PRs in this stack are a cleanup pass before the actual thread settings API work. Today, core has several overlapping "user input" ops: `UserInput`, `UserInputWithTurnContext`, and `UserTurn`. They differ mostly in how much next-turn state they carry, which makes the later queued thread settings update harder to reason about and review. This PR starts that cleanup by adding the shared `ThreadSettingsOverrides` payload and allowing `Op::UserInput` to carry it. Existing variants remain in place here, so this layer is mostly a behavior-preserving API shape change plus mechanical constructor updates. ## End State After PR3 By the end of PR3, `Op::UserInput` is the only "user input" core op. It can carry optional thread settings overrides for callers that need to update stored defaults with a turn, while callers without updates use empty settings. `Op::UserInputWithTurnContext` and `Op::UserTurn` are deleted. ## End State After PR5 By the end of PR5, core will have only two ops for this area: - `Op::UserInput` for user-input-bearing submissions. - `Op::ThreadSettings` for settings-only updates. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) (this PR) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [2 of 7] ## Summary This PR removes the overlapping `Op::UserInputWithTurnContext` variant now that `Op::UserInput` can carry thread settings overrides directly. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) (this PR) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [3 of 7] ## Summary This PR finishes the input-op consolidation by moving the remaining `Op::UserTurn` callers onto `Op::UserInput` and deleting `Op::UserTurn`. This touches a lot of files, but it is a low-risk mechanical migration. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) (this PR) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
**Stack position:** [5 of 7] ## Summary This PR adds `Op::ThreadSettings`, a queued settings-only update mechanism for changing stored thread settings without starting a new turn. It also removes the legacy `Op::OverrideTurnContext` in the same layer, so reviewers can see the replacement and deletion together. ## Changes - Add `Op::ThreadSettings` for settings-only queued updates. - Emit `ThreadSettingsApplied` with the effective thread settings snapshot after core applies an update. - Route settings-only updates through the same submission queue as user input. - Migrate remaining `OverrideTurnContext` tests and callers to the queued `Op::ThreadSettings` path. - Delete `Op::OverrideTurnContext` from the core protocol and submission loop. This stack addresses openai#20656 and openai#22090. ## Stack 1. [1 of 7] [Add thread settings to UserInput](openai#23080) 2. [2 of 7] [Remove UserInputWithTurnContext](openai#23081) 3. [3 of 7] [Remove UserTurn](openai#23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](openai#23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](openai#22508) (this PR) 6. [6 of 7] [Add app-server thread settings API](openai#22509) 7. [7 of 7] [Sync TUI thread settings](openai#22510)
Builds on openai#23502. ## Why openai#23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR openai#22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
Stack position: [7 of 7]
Summary
Remote TUI clients can currently show stale thread settings when another TUI changes model, plan mode, fast mode, permissions, or related state. This PR wires the TUI to the app-server API and notification so connected clients stay in sync.
Changes
thread/settings/updatein app-server mode.turn/startsending full state for compatibility.thread/settings/updatedwithout rendering it into the transcript, refreshing active and cached thread state instead.This stack addresses #20656 and #22090.
Stack