Skip to content

feat(scheduler): pin model preset per task - #1879

Open
wgnrai wants to merge 1 commit into
agent0ai:mainfrom
wgnrai:feat/scheduler-pinned-preset
Open

wgnrai wants to merge 1 commit into
agent0ai:mainfrom
wgnrai:feat/scheduler-pinned-preset

Conversation

@wgnrai

@wgnrai wgnrai commented Sep 7, 2026

Copy link
Copy Markdown

Problem

Scheduled tasks currently inherit the ambient model configuration: when a task fires, its context is (re)built from whatever the global settings happen to be at that moment. If the ambient preset's provider quota is exhausted at fire time, the unattended task dies with a RateLimitError and lands in error state — even though other presets in the instance are healthy. Unattended jobs should not inherit ambient config drift between dispatch and fire (the scheduler has no way to express "this task was created to run on model X").

Related prior discussion: #1058. A previous attempt (#1462) was closed by the stale bot without review; this PR is an independent, minimal implementation against current main.

Solution

Opt-in pinned_preset on scheduler tasks:

  • BaseTask.pinned_preset: str | None = None (pydantic; existing tasks.json round-trips unchanged, default None).
  • create_scheduled_task / create_adhoc_task / create_planned_task accept an optional pinned_preset; invalid names are rejected up front with the list of available presets.
  • update_task accepts pinned_preset too (empty string unpins), so existing tasks can be pinned without recreation.
  • At fire time, TaskScheduler._get_chat_context() resolves the pin via the framework's own _model_config preset lookup and applies chat_model_override on the context — the same mechanism the /model command uses — to both freshly created and already-existing dedicated contexts, so pinning via update_task takes effect without a restart.
  • If the pinned preset no longer exists at fire time, the task fails loudly (error naming task + uuid + preset, task set to error state). It never silently falls back to ambient settings.
  • Tasks without a pin behave exactly as before (zero behavior change for unpinned tasks).

Testing

Verified on a live instance (framework runtime) plus a clean worktree of main:

  • Live tasks.json with 5 pre-existing tasks loads and re-validates unchanged (all pinned_preset=None).
  • Scratch pinned task: _get_chat_context returns a real AgentContext whose chat_model_override equals the pinned preset, and the resolved chat model matches that preset.
  • Missing-preset break-test (pinned_preset='does-not-exist'): loud ValueError naming task/uuid/preset, refusing ambient fallback; no context created.
  • Unpinned control task: no override applied (ambient behavior unchanged).
  • tests/test_task_scheduler_timezone.py: 4/4 pass.
  • Real-context E2E through _get_chat_context (context creation + override consumption path) passes; import helpers.task_scheduler, tools.scheduler clean under the framework runtime.

Compatibility notes

  • Purely additive to the task schema and tool surface; pinned_preset defaults to None and is omitted from serialization when unset, so old tasks.json files load unchanged and old tool callers see no difference.
  • The pin resolves through the existing bundled _model_config plugin (same get_preset_by_name + chat_model_override path used by /model), so pinned tasks automatically respect any future changes to preset resolution or override handling.
  • Tool prompt (prompts/agent.system.tool.scheduler.md) documents the new parameter for the scheduler tool.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant