Skip to content

Conversation

@TheSmuks
Copy link

@TheSmuks TheSmuks commented Jan 19, 2026

Summary

  • Add model rotation feature for automatic failover when rate limits, quota exceeded, or overloaded errors occur
  • Configurable per-agent with model pools, usage tracking (calls/tokens), and cooldown periods
  • Includes rotation-status command to view current rotation state

Changes

  • New src/features/model-rotation/ module:
    • error-parser.ts - Detects rate limit, quota, and overload errors from API responses
    • state-manager.ts - Persists rotation state across sessions
    • rotation-engine.ts - Handles model selection and rotation logic
    • hooks.ts - Event-based rotation triggers
    • constants.ts - Error patterns and default configuration
  • New src/hooks/model-rotation/ - Hook registration
  • Schema updates in src/config/schema.ts:
    • AgentOverrideConfig.model now accepts string | string[]
    • Added RotationConfigSchema with enabled, limitType, limitValue, cooldownMs
    • Added model-rotation to HookNameSchema
    • Added rotation-status to BuiltinCommandNameSchema
  • Updated src/agents/utils.ts - normalizeModel() helper for model array handling with rotation awareness
  • Updated src/agents/sisyphus-junior.ts - Model normalization for rotation support
  • Updated src/agents/types.ts - Re-export types from schema
  • Added rotation-status command in src/features/builtin-commands/

Screenshots

N/A - Backend feature, no UI changes

Testing

bun run typecheck
bun test
  • All tests pass

Related Issues

N/A


Summary by cubic

Adds automatic model rotation to fail over when rate limits, quota, or overload errors occur. Also overhauls model resolution and removes hardcoded defaults so agents use your OpenCode default model unless you set them explicitly.

  • New Features

    • Per‑agent model pools using model: string[]
    • Rotation policy: limitType (calls|tokens), limitValue, cooldownMs
    • Error detection for Anthropic/OpenAI/Google triggers rotation
    • Usage tracking + cooldown with state persisted in your OpenCode config directory
    • Unified resolver: userModel → inheritedModel → systemDefault
    • New hook: model-rotation; new command: rotation-status
    • Schema: AgentOverrideConfig.model now string | string[]; added RotationConfig; added rotation-status to commands
    • Fair round‑robin selection that skips depleted/cooldown models and never re‑selects the current one
  • Migration

    • Default model is now optional; most agents run without it. orchestrator-sisyphus is skipped if no default is set unless you provide an override model
    • Update any direct agent usage to call factory functions with a model (e.g., createOracleAgent("provider/model")); singleton agent exports were removed
    • If you relied on category defaults, set models in categories or rely on the OpenCode default
    • To enable rotation, set per-agent overrides with model: ["modelA","modelB"] and rotation: { enabled: true, ... }

Written for commit 9ba54cc. Summary will update on new commits.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 19, 2026

All contributors have signed the CLA. Thank you! ✅
Posted by the CLA Assistant Lite bot.

@TheSmuks
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Jan 19, 2026
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues found across 51 files

Confidence score: 3/5

  • There is concrete user-impact risk: src/agents/utils.ts now throws if systemDefaultModel is omitted despite the optional TypeScript signature, which can crash existing callers.
  • Model rotation has functional gaps: src/features/model-rotation/rotation-engine.ts never records/checks token limits, so limitType="tokens" won’t rotate as expected.
  • Several parsing/template issues can misreport providers/status (e.g., src/features/model-rotation/error-parser.ts misclassifies OpenAI rate-limit errors; src/features/builtin-commands/templates/rotation-status.ts can read wrong config paths), keeping this at moderate risk.
  • Pay close attention to src/agents/utils.ts, src/features/model-rotation/rotation-engine.ts, src/features/model-rotation/error-parser.ts, src/features/builtin-commands/templates/rotation-status.ts - runtime crashes, rotation not triggering, and incorrect provider/status parsing.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/agents/utils.ts">

<violation number="1" location="src/agents/utils.ts:146">
P2: Empty model override array clears existing model (merged.model set to undefined)</violation>

<violation number="2" location="src/agents/utils.ts:167">
P2: Optional parameter now required at runtime — TypeScript signature says `systemDefaultModel` is optional but code throws when it’s missing, causing runtime crashes for callers that omit it.</violation>
</file>

<file name="src/features/builtin-commands/templates/rotation-status.ts">

<violation number="1" location="src/features/builtin-commands/templates/rotation-status.ts:22">
P2: Rotation status template hard-codes config/state paths, ignoring XDG/OPENCODE_CONFIG_DIR and Windows resolution, so it can read wrong files and misreport status.</violation>
</file>

<file name="src/features/model-rotation/rotation-engine.ts">

<violation number="1" location="src/features/model-rotation/rotation-engine.ts:33">
P2: Token-based rotation is nonfunctional: token limits are never recorded or checked, so limitType="tokens" will not trigger rotation.</violation>
</file>

<file name="src/features/model-rotation/error-parser.test.ts">

<violation number="1" location="src/features/model-rotation/error-parser.test.ts:28">
P2: Anthropic 529 error fixture is incorrect (`quota_exceeded` instead of documented `overloaded_error`), causing real Anthropic overload/quota errors to parse as unknown provider.</violation>
</file>

<file name="src/features/model-rotation/error-parser.ts">

<violation number="1" location="src/features/model-rotation/error-parser.ts:86">
P2: OpenAI rate-limit errors with `type: "rate_limit_error"` are misclassified as Anthropic because provider detection checks `errorType` before OpenAI `errorCode`.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

TheSmuks and others added 4 commits January 19, 2026 20:28
Model rotation feature allows agents to automatically switch between
multiple configured models when rate limits or quota errors are detected.

Features:
- Configurable rotation per agent with model pools
- Error detection for rate limits, quota exceeded, overloaded errors
- Usage tracking (calls or tokens) with configurable limits
- Cooldown periods before model reuse
- State persistence across sessions
- rotation-status command to view current rotation state

Schema changes:
- AgentOverrideConfig.model now accepts string | string[]
- Added RotationConfig schema for rotation settings
- Added 'rotation-status' to BuiltinCommandNameSchema
- Added 'model-rotation' to HookNameSchema
@TheSmuks TheSmuks changed the base branch from master to dev January 19, 2026 19:40
@TheSmuks
Copy link
Author

@cubic-dev-ai re-run a review

@cubic-dev-ai
Copy link

cubic-dev-ai bot commented Jan 19, 2026

@cubic-dev-ai re-run a review

@TheSmuks I have started the AI code review. It will take a few minutes to complete.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 20 files

Confidence score: 3/5

  • Model rotation has two concrete failover risks in src/features/model-rotation/rotation-engine.ts: cooldown never reactivates depleted models and rotation can return the current model, which could leave systems stuck on an unhealthy model.
  • Error handling in src/features/model-rotation/error-parser.ts misclassifies 429 quota errors as rate limits, which could cause incorrect backoff/retry behavior for quota-exhausted users.
  • These are medium–high severity behavioral issues (6–7/10), so there’s some user-impacting risk despite being localized to model-rotation logic.
  • Pay close attention to src/features/model-rotation/rotation-engine.ts, src/features/model-rotation/error-parser.ts - failover rotation and quota error classification behavior.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/features/model-rotation/rotation-engine.ts">

<violation number="1" location="src/features/model-rotation/rotation-engine.ts:68">
P1: Rotation can return the current model, preventing failover and marking it depleted while still selected.</violation>

<violation number="2" location="src/features/model-rotation/rotation-engine.ts:107">
P1: Cooldown reset never triggers because depleted flag blocks reactivation, leaving models permanently unavailable.</violation>
</file>

<file name="src/features/model-rotation/error-parser.ts">

<violation number="1" location="src/features/model-rotation/error-parser.ts:32">
P2: 429 quota errors (e.g., OpenAI `insufficient_quota`) are misclassified as `rate_limit` because the 429 shortcut ignores nested quota codes/messages.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 21 files

Confidence score: 3/5

  • There is some risk due to concrete behavior gaps in src/agents/utils.ts and model rotation logic, so a cautious merge is warranted.
  • Most severe: in src/agents/utils.ts, orchestrator-sisyphus is skipped when systemDefaultModel is unset even if an override provides a model, which can change runtime selection behavior.
  • Model-rotation handling in src/features/model-rotation/error-parser.ts and src/features/model-rotation/hooks.ts may miss overload-triggered rotations and inflate usage metrics during streaming, potentially affecting resilience and reporting.
  • Pay close attention to src/agents/utils.ts, src/features/model-rotation/error-parser.ts, src/features/model-rotation/hooks.ts - model selection/rotation logic and usage accounting may be impacted.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/features/model-rotation/error-parser.ts">

<violation number="1" location="src/features/model-rotation/error-parser.ts:96">
P2: Anthropic overload errors (`overloaded_error`) are detected for provider inference but not treated as rotation-triggering unless the message happens to include rotation keywords, so overload failures can be missed.</violation>
</file>

<file name="src/agents/utils.ts">

<violation number="1" location="src/agents/utils.ts:226">
P1: orchestrator-sisyphus is skipped when systemDefaultModel is unset, even if an override provides a model</violation>
</file>

<file name="src/features/model-rotation/hooks.ts">

<violation number="1" location="src/features/model-rotation/hooks.ts:123">
P2: Usage is recorded on every streaming `message.updated`, inflating call/token counts for a single assistant message.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 22 files

Confidence score: 3/5

  • Round-robin rotation in src/features/model-rotation/rotation-engine.ts always restarts from the first model, which can bias selection and skip the next-after-current behavior users expect.
  • This is a user-visible behavior bug with moderate severity, so there’s some risk if merged without a fix.
  • Pay close attention to src/features/model-rotation/rotation-engine.ts - rotation logic restarts from the first model instead of advancing from the current one.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/features/model-rotation/rotation-engine.ts">

<violation number="1" location="src/features/model-rotation/rotation-engine.ts:83">
P2: Round-robin rotation is incorrect: selection always restarts from the first model, biasing earlier entries and not choosing the next after the current model.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Previously, findNextAvailableModel always iterated from the beginning
of the availableModels array, biasing earlier entries. Now it starts
from the model after the current one and wraps around, ensuring fair
round-robin distribution (a → b → c → a → ...).
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 22 files

Confidence score: 3/5

  • Cooldown expiry handling in src/features/model-rotation/state-manager.ts doesn’t reset usage counters, which can leave models stuck over limit and immediately re-depleted after cooldown, affecting rotation behavior.
  • This is a concrete user-facing logic issue, so there’s some risk despite the rest of the changes being unspecified.
  • Pay close attention to src/features/model-rotation/state-manager.ts - ensure cooldown expiry properly resets usage counters.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/features/model-rotation/state-manager.ts">

<violation number="1" location="src/features/model-rotation/state-manager.ts:82">
P2: Cooldown expiry does not reset usage counters, so models remain over limit and are immediately re-depleted after a cooldown ends.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

When a model's cooldown period expired, only the cooldown flags were
being cleared but usage counters (callCount, tokenCount) remained at
their previous values. This caused models to immediately re-deplete
after cooldown since they were still over their limits.

Now markAvailable() also resets callCount to 0 and tokenCount to
undefined, allowing the model to start fresh after cooldown.
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 22 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

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