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
{{ message }}
Repository navigation
[Bug]: Self model configuration can stop its own run without continuing #15300
Configure two Codex provider instances (codex and codex_alt). Both can use the same existing Codex installation and home.
Start a thread on codex with GPT-6-Luna.
Ask: “Switch this thread to GPT-6.1-Sol using provider instance codex_alt and low reasoning with t3_thread_configure, then write a four-line poem about changing your mind. Do not edit files or use subagents.”
Let the agent call t3_thread_configure.
Expected behavior
The thread continues the unfinished request under the selected model. If the provider cannot do that safely, the tool reports the limitation without stopping the current run.
Actual behavior
The selection is saved, but the active provider session is detached. The run ends with “Run interrupted by user” even though no one pressed Stop. There is no continuation and no poem; another user message is required.
The tool dispatches the ordinary selection command, which can release the current session without scheduling another attempt. A separate same-instance check on this commit saved Sol while the active run completed on Luna, so reading the saved configuration does not prove that the requested work ran under the new model.
Environment and impact
Reproduced on main at cfdff56f7b3c9c931ae368224041aa14825649fd, macOS 26.7, Node 26.10.0, the T3 Browser panel, and a real Codex provider. The development server used isolated state. This loses the remainder of the active task until the user intervenes.
The original report showed same-instance model changes interrupting an installed build. On the current base, the session-detaching case above reproduces the interruption; the same-instance case instead keeps the old active model.
Thanks for the clear report, @PixPMusic! This looks like a real bug, and it's separate from the open #15195. That one is about the composer keeping a stale model after another client changes it. Here, the running turn is the one calling t3_thread_configure.
t3_thread_configure only runs while the caller owns an active run (assertLiveCaller in apps/server/src/mcp/threadAccess.ts). The handler then sends the normal next-turn selection command (provider.switch when the instance changes, thread.model-selection.set otherwise) and returns just { sequence }.
Instance change (codex to codex_alt, same Codex home). These instances share a continuation key, so decideProviderSessionTransition plans restart_and_resume, and ProviderSwitchService releases the live session. dispatchThreadMutation saves the new selection and queues that detach, but it doesn't start another attempt. Because Codex sessions allow multiple threads, the detach calls interruptTurn on the turn that's still running. The run is still running on that attempt, so finalization treats the interrupt as the end of the run and writes "Run interrupted by user" (makeInterruptResultTurnItem in RunExecutionService.ts). Nothing replays the unfinished request, so the poem never runs and you have to send another message.
Same instance (Luna to Sol). Codex treats every selection change as apply_on_next_turn, which becomes switch_model_in_session and releases nothing. The saved selection updates and the tool reports success, but the active turn keeps running on Luna. Reading the saved configuration back won't show that this request actually ran on Luna rather than Sol.
Likely fix area
Codex can't retarget the turn that's running the tool, so a few directions are possible:
The tool could report that limit for a self-configure call and leave the current session and run alone, with the change applying from the next turn.
Alternatively, the unfinished request could be replayed under the new model. Today the selection-restart path only does that when a new message arrives, not from a configure call, so this would be a separate choice.
Observed the same failure in a live Linux session on T3 Code 0.0.46-nightly.20261007.2787 on 2026-10-08. This occurrence switched between different provider drivers, from Codex to OpenCode.
The running coding agent was preparing a scheduled follow-up and tried to follow a configured GPT-5.4/high automation default. It changed the active conversation's provider/model itself, although the user had not requested that conversation switch.
The durable timeline and server logs show:
At 00:41:49.347 UTC, the Codex agent's own t3_thread_configure call completed successfully. Its selection was instanceId: opencode, model: opencode/gpt-5.4, with variant: high and agent: build. The previous run was on provider instance codex, model gpt-6.1-sol.
Its immediately following schedule_task call failed at 00:41:49.596 UTC with OrchestratorMcpFailure, code parent_not_active, and message The calling provider no longer owns an active thread run. No scheduled task was created.
At 00:41:49.994 UTC, the original Codex run ended as interrupted. The timeline said Run interrupted by user, although this interruption followed the agent's successful self-configuration call, not a user Stop action. There was no automatic continuation.
A subsequent user message selected the now-saved OpenCode configuration. That attempt additionally encountered a separate provider-start error, spawn <opencode binary> EACCES, in the server log. The user then stopped that attempt before provider start.
The audit trail identifies OpenCode as the selected destination, with no Cursor run in this conversation. The direct failure chain was successful self-configuration, loss of active-run ownership, rejection of the next MCP call, and an interrupted run with no continuation. This reproduces the issue on the October 7 nightly as well.
Additional recovery problem: the user then tried to switch back through the model picker. The UI disabled Codex and displayed exactly: "Codex is unavailable in this thread. Start a new thread to switch providers." The screenshot showed OpenCode models as the available choices. This left the user unable to restore the original provider through the picker after the agent-initiated switch.
Restoring the same existing thread through t3_thread_configure with its original Codex selection succeeded. However, the subsequent continuation failed with Insufficient context allowance for the provider handoff. Compact the target conversation or use a larger-context model; the current request has not been truncated. A /compact request was then accepted and the timeline showed Compacting context. The picker prohibition and the thread control API disagree about whether this thread can switch back; restoring the provider selection alone did not resume the unfinished work.
The compaction run subsequently received an explicit interrupt request before a completed compaction appeared in the timeline. It ended interrupted, so restoration of the provider selection is confirmed, but successful continuation is not yet confirmed.
Still seeing this on 0.1.1-nightly.20261020.3399 with Orchestrator V2, on Linux (2026-10-20), switching from Codex GPT-6.1-Sol to Cursor GPT-5.4.
After the agent's thread-model change, the run ends with Run interrupted by user. The timeline shows Context handoff pending and the picker disables Codex with Codex is unavailable in this thread. Start a new thread to switch providers.
Read-only inspection confirms the saved selection is cursor / gpt-5.4, but activeProviderThreadId still points to Codex and no Cursor run has started. The selection changes, but the unfinished task does not automatically continue, and the picker blocks switching back. This persists after the V2 rollout.
Still reproduces on 0.1.7-nightly.20261101.4016 (desktop app, macOS arm64, Orchestrator V2). This time it was a scheduled task switching Claude → Codex, which makes it harder to notice: the task disables itself first, so nothing retries.
Setup: a one-shot scheduled task, saved with model claudeAgent / claude-opus-5-5. Step 1 of its prompt says: disable this task, then call t3_thread_configure(modelSelection={provider:"codex", model:"gpt-6.1-sol", ...}).
Timeline (UTC, 2026-11-01), from the provider event log and the projection tables:
14:30:14.490: the scheduled task creates the thread. Run 1 starts on claudeAgent.
14:30:20.933: the agent calls schedule_task(enabled=false), which succeeds.
14:30:22.096: the agent calls t3_thread_configure with the Codex selection.
14:30:22.121: the tool returns {"sequence":…}, and in the same millisecond the server sends query.close to the Claude session. Run 1 / attempt 1 is marked failed, with the t3_thread_configure tool_call node left running.
The thread's providerInstanceId/modelSelection are now Codex, but no Codex run is queued. The thread sat idle for about 41 minutes, until a manual message at 15:11:07 started run 2 on Codex (with a context handoff).
The mechanism matches the triage above. provider.switch → ProviderSwitchService.plan → releaseProviderSessionIds includes the caller's own live session, and the session is detached (Orchestrator.ts, around the detachSessionIds block) without anything scheduled to continue on the target provider.
Impact for scheduled tasks: a common pattern is "disable myself, then switch to the intended model". With that pattern the follow-up is lost silently. The thread looks started but did no work, and the task won't fire again.
Workaround: save the intended model on the scheduled task itself, and don't self-switch from inside the run.
Found via T3 Code triage by Claude Code (Claude Opus 5.5).
Same here on 0.1.8-nightly.20261104.4165 (macOS arm64, desktop app, Orchestrator V2), cross-driver self-switch from Codex (gpt-6-luna) to Claude (claude-opus-5-5, effort medium).
Use case: a scheduled daily run starts on a cheap model and should escalate itself to a stronger one for the hard cases, in the same thread.
Two attempts from a delegated child thread:
t3_thread_configure to the Claude instance returns {sequence} and the selection is saved, but the run ends immediately with "Stopped by the provider". Nothing continues.
What would make this usable: apply a selection change at the end of the current turn and continue with the next queued message on the new selection, or let queued runs resolve the thread's current selection when they start. Workaround for now: hand the escalated part to a child with delegate_task.
Activity
juliusmarminge commentedon Oct 3, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the clear report, @PixPMusic! This looks like a real bug, and it's separate from the open #15195. That one is about the composer keeping a stale model after another client changes it. Here, the running turn is the one calling
t3_thread_configure.t3_thread_configureonly runs while the caller owns an active run (assertLiveCallerinapps/server/src/mcp/threadAccess.ts). The handler then sends the normal next-turn selection command (provider.switchwhen the instance changes,thread.model-selection.setotherwise) and returns just{ sequence }.Instance change (
codextocodex_alt, same Codex home). These instances share a continuation key, sodecideProviderSessionTransitionplansrestart_and_resume, andProviderSwitchServicereleases the live session.dispatchThreadMutationsaves the new selection and queues that detach, but it doesn't start another attempt. Because Codex sessions allow multiple threads, the detach callsinterruptTurnon the turn that's still running. The run is stillrunningon that attempt, so finalization treats the interrupt as the end of the run and writes "Run interrupted by user" (makeInterruptResultTurnIteminRunExecutionService.ts). Nothing replays the unfinished request, so the poem never runs and you have to send another message.Same instance (Luna to Sol). Codex treats every selection change as
apply_on_next_turn, which becomesswitch_model_in_sessionand releases nothing. The saved selection updates and the tool reports success, but the active turn keeps running on Luna. Reading the saved configuration back won't show that this request actually ran on Luna rather than Sol.Likely fix area
Codex can't retarget the turn that's running the tool, so a few directions are possible:
A maintainer will decide on the fix direction.
Techie5879 commentedon Oct 8, 2026
Observed the same failure in a live Linux session on T3 Code
0.0.46-nightly.20261007.2787on 2026-10-08. This occurrence switched between different provider drivers, from Codex to OpenCode.The running coding agent was preparing a scheduled follow-up and tried to follow a configured GPT-5.4/high automation default. It changed the active conversation's provider/model itself, although the user had not requested that conversation switch.
The durable timeline and server logs show:
t3_thread_configurecall completed successfully. Its selection wasinstanceId: opencode,model: opencode/gpt-5.4, withvariant: highandagent: build. The previous run was on provider instancecodex, modelgpt-6.1-sol.schedule_taskcall failed at 00:41:49.596 UTC withOrchestratorMcpFailure, codeparent_not_active, and messageThe calling provider no longer owns an active thread run.No scheduled task was created.Run interrupted by user, although this interruption followed the agent's successful self-configuration call, not a user Stop action. There was no automatic continuation.spawn <opencode binary> EACCES, in the server log. The user then stopped that attempt before provider start.The audit trail identifies OpenCode as the selected destination, with no Cursor run in this conversation. The direct failure chain was successful self-configuration, loss of active-run ownership, rejection of the next MCP call, and an interrupted run with no continuation. This reproduces the issue on the October 7 nightly as well.
Additional recovery problem: the user then tried to switch back through the model picker. The UI disabled Codex and displayed exactly: "Codex is unavailable in this thread. Start a new thread to switch providers." The screenshot showed OpenCode models as the available choices. This left the user unable to restore the original provider through the picker after the agent-initiated switch.
Restoring the same existing thread through
t3_thread_configurewith its original Codex selection succeeded. However, the subsequent continuation failed withInsufficient context allowance for the provider handoff. Compact the target conversation or use a larger-context model; the current request has not been truncated.A/compactrequest was then accepted and the timeline showedCompacting context. The picker prohibition and the thread control API disagree about whether this thread can switch back; restoring the provider selection alone did not resume the unfinished work.The compaction run subsequently received an explicit interrupt request before a completed compaction appeared in the timeline. It ended interrupted, so restoration of the provider selection is confirmed, but successful continuation is not yet confirmed.
Techie5879 commentedon Oct 20, 2026
Still seeing this on
0.1.1-nightly.20261020.3399with Orchestrator V2, on Linux (2026-10-20), switching from Codex GPT-6.1-Sol to Cursor GPT-5.4.After the agent's thread-model change, the run ends with
Run interrupted by user. The timeline showsContext handoff pendingand the picker disables Codex withCodex is unavailable in this thread. Start a new thread to switch providers.Read-only inspection confirms the saved selection is
cursor / gpt-5.4, butactiveProviderThreadIdstill points to Codex and no Cursor run has started. The selection changes, but the unfinished task does not automatically continue, and the picker blocks switching back. This persists after the V2 rollout.test(server): reproduce selection restart accepted after archive (pin…
fix(server): reject steers and restarts into an archived thread (ping…
jlipworth commentedon Nov 1, 2026
Still reproduces on
0.1.7-nightly.20261101.4016(desktop app, macOS arm64, Orchestrator V2). This time it was a scheduled task switching Claude → Codex, which makes it harder to notice: the task disables itself first, so nothing retries.Setup: a one-shot scheduled task, saved with model
claudeAgent / claude-opus-5-5. Step 1 of its prompt says: disable this task, then callt3_thread_configure(modelSelection={provider:"codex", model:"gpt-6.1-sol", ...}).Timeline (UTC, 2026-11-01), from the provider event log and the projection tables:
claudeAgent.schedule_task(enabled=false), which succeeds.t3_thread_configurewith the Codex selection.{"sequence":…}, and in the same millisecond the server sendsquery.closeto the Claude session. Run 1 / attempt 1 is markedfailed, with thet3_thread_configuretool_call node leftrunning.providerInstanceId/modelSelectionare now Codex, but no Codex run is queued. The thread sat idle for about 41 minutes, until a manual message at 15:11:07 started run 2 on Codex (with a context handoff).The mechanism matches the triage above.
provider.switch→ProviderSwitchService.plan→releaseProviderSessionIdsincludes the caller's own live session, and the session is detached (Orchestrator.ts, around thedetachSessionIdsblock) without anything scheduled to continue on the target provider.Impact for scheduled tasks: a common pattern is "disable myself, then switch to the intended model". With that pattern the follow-up is lost silently. The thread looks started but did no work, and the task won't fire again.
Workaround: save the intended model on the scheduled task itself, and don't self-switch from inside the run.
Found via T3 Code triage by Claude Code (Claude Opus 5.5).
laurenzseifried commentedon Nov 10, 2026
Same here on
0.1.8-nightly.20261104.4165(macOS arm64, desktop app, Orchestrator V2), cross-driver self-switch from Codex (gpt-6-luna) to Claude (claude-opus-5-5, effort medium).Use case: a scheduled daily run starts on a cheap model and should escalate itself to a stronger one for the hard cases, in the same thread.
Two attempts from a delegated child thread:
t3_thread_configureto the Claude instance returns{sequence}and the selection is saved, but the run ends immediately with "Stopped by the provider". Nothing continues.t3_thread_send(modequeue) to its own thread first, thent3_thread_configureas the very last action: the run is interrupted as above, and the queued run then starts on the old selection (gpt-6-luna, captured when it was queued). Afterwards the thread reads backgpt-6-lunaagain. That looks like the A queued delegated-task completion reverts a model change made while it waited #22577 family, but for a plain queued message instead of a delegated completion, and on a build after A queued delegated-task completion reverts a model change made while it waited #22577 was closed.What would make this usable: apply a selection change at the end of the current turn and continue with the next queued message on the new selection, or let queued runs resolve the thread's current selection when they start. Workaround for now: hand the escalated part to a child with
delegate_task.juliusmarminge commentedon Nov 12, 2026
This is the same problem as #22748, so I'm closing it in favour of that one. If it is different, say how and it will be reopened.