Skip to content

feat(v2): fall back to the next model instead of only waiting - #41

Merged
azumag merged 2 commits into
mainfrom
feat/v2-model-fallback
Oct 17, 2026
Merged

azumag merged 2 commits into
mainfrom
feat/v2-model-fallback

Conversation

@azumag

@azumag azumag commented Oct 17, 2026

Copy link
Copy Markdown
Owner

What

Implements the v1-style fallback chain for the OpenCode v2 entry point (v2.ts) instead of only supporting fallbackMode: "wait".

  • fallbackModels is an ordered chain: on a rate limit / transient upstream error the session switches to the next model and retries after ~1s.
  • Once the chain is exhausted, cycle / retry-last / stop behave like their v1 counterparts.
  • wait mode keeps its existing single-model, exponential-backoff behavior.
  • Resume after OpenCode's own retry ceiling is driven by session.execution.failed, so an interrupted turn is not resumed.

Backward compatibility

  • The v1 entry point (index.ts, 1.x line) is untouched.
  • Default config has no fallbackModels, so a non-wait config registers nothing, exactly like 2.0.x.
  • Sessions whose model is not in the chain are left to OpenCode by default (otherModels: "ignore"). otherModels: "wait" opts into waiting on the same model, matching 2.0.x wait behavior.
  • package.json goes 2.0.3 -> 2.1.0; publishing stays under the opencode-v2 npm tag, so latest remains the 1.x line.

Tests

  • npm run typecheck passes.
  • v2/config suites pass (37 tests).
  • The full local run only fails the pre-existing __tests__/config/watcher.test.ts fs.watch timing tests, which fail identically on main on macOS; they are untouched by this branch and CI runs on Ubuntu.

azumag and others added 2 commits October 17, 2026 06:21
In v2, fallbackModels is now an ordered chain. When a request fails with
a rate limit or a transient upstream error, a session whose model is in
the chain is switched (session.switchModel) to the next model after it
and retried about one second later. Once the chain is exhausted,
fallbackMode decides: cycle back to the session's own model after a
cooldown, retry-last, stop, or wait (never switch). A session whose
model is not in the chain keeps the wait behaviour. The next real user
prompt puts the session back on its own model.

OpenCode 2.0.31 keeps retrying past attempt 5 (its ceiling is about 10),
so the timer that resumed at attempt 5 pushed an empty user message into
a turn that was still running. A turn is now resumed only after
session.execution.failed with a retryable error; interrupted turns stay
stopped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Leave sessions whose model is not in fallbackModels to OpenCode by
  default, as 2.0.x did; "otherModels": "wait" opts into retrying the
  same model after a cooldown.
- Register nothing for a non-wait config without fallback models, so a
  default config still does nothing.
- Validate otherModels in config and cover the compatibility cases in
  tests.
@azumag
azumag merged commit d343af5 into main Oct 17, 2026
1 check passed
@azumag
azumag deleted the feat/v2-model-fallback branch October 17, 2026 17:51
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