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
[Feature]: Thread-bound scheduled tasks should optionally use the thread’s current agent/model #15821
I use recurring scheduled tasks attached to existing threads. A schedule
has its own saved agent/model selection, which can differ from the
thread's current selection.
When the schedule fires, it uses its saved selection. If I have switched
the thread to another agent/model, scheduled and manual turns keep
switching between them. I want the schedule to continue work with
whichever agent is currently selected for that thread.
Steps to reproduce
Create a recurring scheduled task for an existing thread using model A.
Switch the thread to model B and continue working.
Let the scheduled task fire.
It uses model A instead of following the thread's current selection.
Proposed behavior
Add a "Use thread's current agent/model" option for schedules targeting
an existing thread, ideally as the default for new thread-bound schedules.
Resolve the provider instance, model, and associated model settings when
each scheduled run starts, rather than copying them when the schedule
is created. The scheduled run should not override the thread's selection.
Keep an explicit fixed-agent/model option for users who want it.
Schedules that create new threads can continue requiring their own selection.
Expected result
After switching a thread from A to B, subsequent scheduled runs use B
without requiring me to edit every schedule attached to that thread.
Environment
Orchestrator v2, branch t3code/codex-turn-mapping.
Observed on revision 402205e, updated on 2026-09-27.
Local macOS desktop app connected to a Linux VM server.
Thanks @rohitgirdhar for the clear write-up and repro steps. It made the behavior easy to trace.
What I found
ScheduledTask.modelSelection is required, and scheduled_tasks.model_selection_json is NOT NULL. ScheduledTaskService.runTask always sends that saved selection along with the prompt. For an existing thread this goes through sendToThread.
If the saved selection differs from the thread's, dispatch records thread.model-selection-updated or thread.provider-switched. After that, the thread keeps the schedule's model. The same thing happens when a run steers an in-progress turn (mode: "auto"). Model options travel with the selection, so effort and similar settings switch too. That explains the back-and-forth you're seeing.
schedule_task copies the thread's model, options, runtime mode, and interaction mode when the schedule is created, and update_scheduled_task keeps that copy. So "inherits from the thread" means a snapshot taken at creation, not a read when the schedule fires. Runtime and interaction mode only apply when a task launches a new thread.
Both the web and mobile settings require you to pick a model before saving. There's currently no option to follow the thread.
Likely fix area
Options a maintainer could weigh:
A follow-thread mode for schedules attached to an existing thread. It would read the thread's instance, model, and options when the run starts, and dispatch without a selection so the run doesn't overwrite the thread's choice.
Keeping fixed selections: the current pinned selection stays available for tasks that want a fixed model. Because the column is required today, this would be a separate mode, and already-saved tasks would keep their pinned model.
Default behavior: whether follow-thread becomes the default for new thread-bound schedules, including ones agents create, is a separate decision from adding the option.
Additional empirical evidence for this existing report. The same behavior caused two unexpected Codex-to-Claude reversions on 0.0.46-nightly.20261006.2735.
The thread was switched explicitly from Claude Opus to codex / gpt-6.1-sol. Both switch commands were accepted, and subsequent manual turns completed on Sol. A recurring task attached to that thread still had a saved claudeAgent / claude-opus-5-5 selection. Its queued occurrences then changed the thread's selection back to Claude as soon as Sol finished.
Recorded sequence
All times below are 2026-10-08 in Asia/Jerusalem, UTC+03:00. Exported fields are limited to times, event sequence, run ordinal/status and model selection. Private prompts, identifiers, home paths and credentials are omitted.
10:32:50 explicit provider.switch accepted -> codex / gpt-6.1-sol
10:50:05 run 135 created queued -> claudeAgent / claude-opus-5-5
10:52:12 run 134 completed -> codex / gpt-6.1-sol [event 365449]
10:52:12 thread.provider-switched -> claudeAgent [event 365451]
10:52:12 scheduled run 135 starting on saved Claude [event 365458]
10:52:18 scheduled run 135 failed
10:55:38 explicit provider.switch accepted -> codex / gpt-6.1-sol
11:00:06 run 140 created queued -> claudeAgent / claude-opus-5-5
11:01:03 run 139 completed -> codex / gpt-6.1-sol [event 366527]
11:01:03 thread.provider-switched -> claudeAgent [event 366529]
11:01:03 scheduled run 140 starting on saved Claude [event 366536]
11:01:10 scheduled run 140 failed
The two explicit switch command IDs matched the Telegram bridge's deterministic provider.switch command IDs. The scheduled messages carry scheduledTaskId; their run creation events carry the same saved Claude selection. The automatic switch events have no external command ID. This distinguishes an accepted manual switch followed by queue promotion from a bridge resending an old model or a model-picker update failing.
Source check
Reviewed upstream main at a4c9494b0e3606775cc5fc929fc138399288bd43:
startNextQueuedRun emits thread.provider-switched / thread.model-selection-updated and saves the queued run's selection on the thread.
Deterministic reproduction and focused checks
Create a recurring task bound to a thread using model A.
Explicitly switch that thread to provider/model B and start a B turn.
Use Run now on the existing task while B is still active. One trigger is sufficient; no repeated intervals or provider refusal is needed.
Confirm the scheduled run is queued with A. Complete B, then inspect the promoted run and the thread's stored selection: both become A.
For a backend regression test, use a fake provider and a deferred completion to keep B active, enqueue the existing task, release B, then drain the orchestration effect worker. Check both the promoted run's selection and the persisted thread selection, not just the scheduler's dispatch arguments. No sleeps are needed. Once the intended follow-thread behavior is agreed, also cover a task queued before a subsequent manual model change, same-provider model/options changes, and the explicit fixed-model mode described in this proposal.
Validation performed: read-only DB/event inspection of both occurrences, verification of both bridge command IDs, and a deterministic offline assertion over the redacted event sequences. The offline assertion passed for both occurrences. Source was inspected at the pinned current-main revision; a new isolated runtime reproduction or upstream test run on that revision was not performed.
This supports the existing proposal; it does not establish approval for changing default behavior. I am adding evidence here rather than opening a duplicate issue or proposing an unapproved behavior-changing PR.
Related #16833 matters for recovery: the MCP update_scheduled_task input has no model/target field, and its handler preserves existing.modelSelection. Updating the saved task selection requires the app's scheduled-task editor or its supported full-task update API; merely updating via that MCP tool cannot accomplish it. Updating a task also does not rewrite a previously queued run's selection, so existing queued occurrences need separate attention.
Prepared with gpt-6.1-sol through the Codex harness in T3 Code.
Activity
juliusmarminge commentedon Oct 5, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks @rohitgirdhar for the clear write-up and repro steps. It made the behavior easy to trace.
What I found
ScheduledTask.modelSelectionis required, andscheduled_tasks.model_selection_jsonisNOT NULL.ScheduledTaskService.runTaskalways sends that saved selection along with the prompt. For an existing thread this goes throughsendToThread.thread.model-selection-updatedorthread.provider-switched. After that, the thread keeps the schedule's model. The same thing happens when a run steers an in-progress turn (mode: "auto"). Model options travel with the selection, so effort and similar settings switch too. That explains the back-and-forth you're seeing.schedule_taskcopies the thread's model, options, runtime mode, and interaction mode when the schedule is created, andupdate_scheduled_taskkeeps that copy. So "inherits from the thread" means a snapshot taken at creation, not a read when the schedule fires. Runtime and interaction mode only apply when a task launches a new thread.Likely fix area
Options a maintainer could weigh:
A maintainer will decide on the direction.
CoreInfusion commentedon Oct 8, 2026
Additional empirical evidence for this existing report. The same behavior caused two unexpected Codex-to-Claude reversions on
0.0.46-nightly.20261006.2735.The thread was switched explicitly from Claude Opus to
codex / gpt-6.1-sol. Both switch commands were accepted, and subsequent manual turns completed on Sol. A recurring task attached to that thread still had a savedclaudeAgent / claude-opus-5-5selection. Its queued occurrences then changed the thread's selection back to Claude as soon as Sol finished.Recorded sequence
All times below are 2026-10-08 in Asia/Jerusalem, UTC+03:00. Exported fields are limited to times, event sequence, run ordinal/status and model selection. Private prompts, identifiers, home paths and credentials are omitted.
The two explicit switch command IDs matched the Telegram bridge's deterministic
provider.switchcommand IDs. The scheduled messages carryscheduledTaskId; their run creation events carry the same saved Claude selection. The automatic switch events have no external command ID. This distinguishes an accepted manual switch followed by queue promotion from a bridge resending an old model or a model-picker update failing.Source check
Reviewed upstream
mainata4c9494b0e3606775cc5fc929fc138399288bd43:ScheduledTaskService.runTaskpassesactive.modelSelectionandmode: "queue"into a bound thread.ThreadManagementService.sendToThreadpasses that selection tomessage.dispatch.startNextQueuedRunemitsthread.provider-switched/thread.model-selection-updatedand saves the queued run's selection on the thread.Deterministic reproduction and focused checks
For a backend regression test, use a fake provider and a deferred completion to keep B active, enqueue the existing task, release B, then drain the orchestration effect worker. Check both the promoted run's selection and the persisted thread selection, not just the scheduler's dispatch arguments. No sleeps are needed. Once the intended follow-thread behavior is agreed, also cover a task queued before a subsequent manual model change, same-provider model/options changes, and the explicit fixed-model mode described in this proposal.
Validation performed: read-only DB/event inspection of both occurrences, verification of both bridge command IDs, and a deterministic offline assertion over the redacted event sequences. The offline assertion passed for both occurrences. Source was inspected at the pinned current-main revision; a new isolated runtime reproduction or upstream test run on that revision was not performed.
This supports the existing proposal; it does not establish approval for changing default behavior. I am adding evidence here rather than opening a duplicate issue or proposing an unapproved behavior-changing PR.
Related #16833 matters for recovery: the MCP
update_scheduled_taskinput has no model/target field, and its handler preservesexisting.modelSelection. Updating the saved task selection requires the app's scheduled-task editor or its supported full-task update API; merely updating via that MCP tool cannot accomplish it. Updating a task also does not rewrite a previously queued run's selection, so existing queued occurrences need separate attention.Prepared with gpt-6.1-sol through the Codex harness in T3 Code.