Skip to content

Commit 1d03a13

Browse files
committed
fix(rotation): strictly respect preference order in model switching
1 parent 4b7ed95 commit 1d03a13

4 files changed

Lines changed: 29 additions & 30 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.2.8] - 2026-01-24
9+
10+
### Fixed
11+
- **Model Selector Order** - Corrected `ModelSelector` to strictly respect the user's preference order defined in `quota.json`. Previously, it was incorrectly picking the model with the highest remaining quota percentage instead of following the priority list.
12+
- **Provider ID Support** - Improved `providerID` detection for more models (including GPT/OpenAI) and added support for explicit `provider/model` format in model IDs.
13+
814
## [2.2.7] - 2026-01-24
915

1016
### Fixed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opencode-antigravity-autopilot",
3-
"version": "2.2.7",
3+
"version": "2.2.8",
44
"description": "Intelligent quota monitoring and model auto-switching for OpenCode with Antigravity. Plugin-based, zero source modifications required.",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",

src/plugin.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,14 @@ export const plugin: Plugin = async (ctx) => {
9696

9797
output.message.model.modelID = result.nextModel;
9898

99-
if (result.nextModel.includes('claude')) {
99+
if (result.nextModel.toLowerCase().includes('claude')) {
100100
output.message.model.providerID = 'anthropic';
101-
} else if (result.nextModel.includes('gemini')) {
101+
} else if (result.nextModel.toLowerCase().includes('gemini')) {
102102
output.message.model.providerID = 'google';
103+
} else if (result.nextModel.toLowerCase().includes('gpt')) {
104+
output.message.model.providerID = 'openai';
105+
} else if (result.nextModel.includes('/')) {
106+
output.message.model.providerID = result.nextModel.split('/')[0];
103107
}
104108

105109
await ctx.client.tui.showToast({

src/rotation/QuotaTracker.ts

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -62,42 +62,31 @@ export class QuotaTracker {
6262
}
6363

6464
getBestAvailableModel(candidates: string[]): string | null {
65-
this.logger.debug('QuotaTracker', 'Finding best available model', {
65+
this.logger.debug('QuotaTracker', 'Finding best available model (respecting preference order)', {
6666
candidatesCount: candidates.length,
6767
candidates,
6868
});
6969

70-
let bestModel: string | null = null;
71-
let bestQuota = -1;
72-
7370
for (const model of candidates) {
74-
if (!this.isModelAvailable(model)) {
75-
this.logger.debug('QuotaTracker', 'Model unavailable (below threshold)', { model });
76-
continue;
77-
}
78-
79-
const state = this.quotaState.get(model);
80-
const quota = state?.quotaFraction ?? 1.0;
81-
82-
if (quota > bestQuota) {
83-
bestQuota = quota;
84-
bestModel = model;
71+
if (this.isModelAvailable(model)) {
72+
const state = this.quotaState.get(model);
73+
const quotaPercentage = state ? `${(state.quotaFraction * 100).toFixed(1)}%` : 'unknown (assumed healthy)';
74+
75+
this.logger.info('QuotaTracker', 'Selected model based on preference order', {
76+
model,
77+
quotaPercentage,
78+
});
79+
return model;
8580
}
81+
82+
this.logger.debug('QuotaTracker', 'Model unavailable (below threshold), skipping', { model });
8683
}
8784

88-
if (bestModel) {
89-
this.logger.info('QuotaTracker', 'Best model found', {
90-
model: bestModel,
91-
quotaFraction: bestQuota,
92-
quotaPercentage: `${(bestQuota * 100).toFixed(1)}%`,
93-
});
94-
} else {
95-
this.logger.warn('QuotaTracker', 'No available model found among candidates', {
96-
candidatesCount: candidates.length,
97-
});
98-
}
85+
this.logger.warn('QuotaTracker', 'No available model found among candidates', {
86+
candidatesCount: candidates.length,
87+
});
9988

100-
return bestModel;
89+
return null;
10190
}
10291

10392
getAllQuotaStates(): ModelQuotaState[] {

0 commit comments

Comments
 (0)