Conversation
pi restores a session's model and thinking level from session history only when the session already has at least one message. A freshly created schedule session has none, so the implicit entries written by CreateSessionFileWithSettings are ignored and pi falls back to its global default model. A schedule configured for one model therefore silently ran on another (and failed, for example, when the default model's auth had expired). Apply the schedule's explicit model and thinking level to the worker after it is ensured, before the instructions are sent. When the schedule leaves them unset, keep pi's defaults.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A schedule's configured model is ignored. Every run falls back to pi's global default model instead.
Reproduction with a schedule set to
opencode-go/deepseek-v4.1-flash(+ thinkinghigh), while pi's default isopenai-codex/gpt-5.6-sol:{"type":"model_change","provider":"opencode-go","modelId":"deepseek-v4.1-flash","implicit":true} {"type":"thinking_level_change","thinkingLevel":"high","implicit":true} {"type":"model_change","provider":"openai-codex","modelId":"gpt-5.6-sol"} {"type":"thinking_level_change","thinkingLevel":"low"}The run then dies on the default model's provider (in this case an expired
openai-codexlogin), and the session showsSwitched to model: openai-codex/gpt-5.6-solinstead of the configured model.Root cause
fireScheduleContextwrites the schedule's model/thinking into the new session file as implicitmodel_change/thinking_level_changeentries and relies on pi picking them up from history. But pi only restores the session model when the session already has messages:A freshly created schedule session has zero messages, so the implicit settings are skipped and the global default model wins.
Verified directly, independent of pi-web:
Fix
After the worker is ensured and before the instructions are sent, apply the schedule's explicit model and thinking level to the worker. When the schedule leaves them unset, pi's defaults are kept (no RPC calls).
internal/server/scheduler.go:This makes the schedule independent of whether pi can restore settings from an empty session. The trade-off is a visible
Switched to model: …entry on scheduled runs, which seems preferable to runs silently using the wrong model.Tests
Two new table-driven-style tests in
internal/server/scheduler_test.gousing the existingfakeSender:TestFireScheduleAppliesConfiguredModel— assertsSetModel/SetThinkingLevelare called with the schedule's values and the created session id.TestFireScheduleKeepsDefaultsWhenUnset— asserts neither RPC is called when the schedule has no model/thinking set.go test ./internal/server/andgo vet ./internal/server/pass.Notes
handleNewSession+initializeNewSessionWorkerrely on the same implicit-entry mechanism, so a session created from another session also starts on the global default rather than the source session's model. I left that out of this PR to keep it focused; happy to follow up if you want it addressed.