Skip to content

[Feature]: Thread-bound scheduled tasks should optionally use the thread’s current agent/model #15821

Closed

Description

@rohitgirdhar

Problem or use case

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

  1. Create a recurring scheduled task for an existing thread using model A.
  2. Switch the thread to model B and continue working.
  3. Let the scheduled task fire.
  4. 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.

Activity

  1. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    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.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.

    A maintainer will decide on the direction.

  2. CoreInfusion commented on Oct 8, 2026

    @CoreInfusion

    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:

    Deterministic reproduction and focused checks

    1. Create a recurring task bound to a thread using model A.
    2. Explicitly switch that thread to provider/model B and start a B turn.
    3. Use Run now on the existing task while B is still active. One trigger is sufficient; no repeated intervals or provider refusal is needed.
    4. 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.

  3. locked and limited conversation to collaborators on Oct 11, 2026
  4. converted this issue into a discussion #18030 on Oct 11, 2026
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

    enhancementRequested improvement or new capability.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