Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions apps/web/src/lib/ai-gateway/auto-model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import {
type Verbosity,
} from '@kilocode/db/schema-types';
import { KIMI_CURRENT_MODEL_ID } from '@/lib/ai-gateway/providers/moonshotai';
import {
gemma_4_26b_a4b_it_free_model,
GEMMA_4_26B_A4B_IT_ID,
} from '@/lib/ai-gateway/providers/google';

export type AutoModelPricing = {
prompt: string;
Expand Down Expand Up @@ -159,6 +163,11 @@ export const KILO_AUTO_SMALL_MODEL: AutoModel = {
opencode_settings: undefined,
};

export const AUTO_SMALL_TARGET_MODELS = {
paid: GEMMA_4_26B_A4B_IT_ID,
free: gemma_4_26b_a4b_it_free_model.public_id,
} as const;

export const KILO_AUTO_EFFICIENT_MODEL: AutoModel = {
...KILO_AUTO_BALANCED_MODEL,
id: 'kilo-auto/efficient',
Expand Down
9 changes: 3 additions & 6 deletions apps/web/src/lib/ai-gateway/auto-model/resolution.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import type { FeatureValue } from '@/lib/feature-detection';
import {
gemma_4_26b_a4b_it_free_model,
GEMMA_4_26B_A4B_IT_ID,
} from '@/lib/ai-gateway/providers/google';
import type {
GatewayRequest,
OpenRouterChatCompletionRequest,
Expand All @@ -15,6 +11,7 @@ import type {
} from '@/lib/organizations/organization-types';
import { isVirtualAutoModelId, type AutoRoutingDecision } from '@kilocode/auto-routing-contracts';
import {
AUTO_SMALL_TARGET_MODELS,
KILO_AUTO_FREE_MODEL,
KILO_AUTO_SMALL_MODEL,
KILO_AUTO_BALANCED_MODEL,
Expand Down Expand Up @@ -314,8 +311,8 @@ export async function resolveAutoModel(
resolved: {
model:
(await balancePromise) > 0
? GEMMA_4_26B_A4B_IT_ID
: gemma_4_26b_a4b_it_free_model.public_id,
? AUTO_SMALL_TARGET_MODELS.paid
: AUTO_SMALL_TARGET_MODELS.free,
},
};
}
Expand Down
36 changes: 36 additions & 0 deletions apps/web/src/lib/ai-gateway/auto-routing-models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,42 @@ describe('addAutoRoutingModels', () => {
]);
});

test('annotates the frontier auto model with its visible targets', async () => {
const frontierModel = makeModel('kilo-auto/frontier');
const opusModel = makeModel('anthropic/claude-opus-5');
const sonnetModel = makeModel('anthropic/claude-sonnet-5');

const result = await addAutoRoutingModels([frontierModel, sonnetModel, opusModel]);

expect(result).toEqual([
{
...frontierModel,
autoRouting: { models: ['anthropic/claude-opus-5', 'anthropic/claude-sonnet-5'] },
},
sonnetModel,
opusModel,
]);
});

test('annotates the small auto model with its visible targets', async () => {
const smallModel = makeModel('kilo-auto/small');
const paidModel = makeModel('google/gemma-4-26b-a4b-it');
const freeModel = makeModel('google/gemma-4-26b-a4b-it:free');

const result = await addAutoRoutingModels([smallModel, paidModel, freeModel]);

expect(result).toEqual([
{
...smallModel,
autoRouting: {
models: ['google/gemma-4-26b-a4b-it', 'google/gemma-4-26b-a4b-it:free'],
},
},
paidModel,
freeModel,
]);
});

test('excludes virtual auto ids and dedupes and sorts candidates', async () => {
const efficientModel = makeModel('kilo-auto/efficient');
const balancedModel = makeModel('kilo-auto/balanced');
Expand Down
18 changes: 17 additions & 1 deletion apps/web/src/lib/ai-gateway/auto-routing-models.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type { OpenRouterModelsResponse } from '@/lib/organizations/organization-types';
import {
AUTO_SMALL_TARGET_MODELS,
FRONTIER_MODE_TO_MODEL,
KILO_AUTO_BALANCED_MODEL,
KILO_AUTO_EFFICIENT_MODEL,
KILO_AUTO_FREE_MODEL,
KILO_AUTO_FRONTIER_MODEL,
KILO_AUTO_SMALL_MODEL,
} from '@/lib/ai-gateway/auto-model';
import { getAutoFreeCandidates } from '@/lib/ai-gateway/auto-model/resolution';
import { isVirtualAutoModelId } from '@kilocode/auto-routing-contracts';
Expand All @@ -19,9 +23,11 @@ export async function addAutoRoutingModels(
): Promise<OpenRouterModelsResponse['data']> {
const availableModelIds = new Set(models.map(model => model.id));
if (
!availableModelIds.has(KILO_AUTO_FRONTIER_MODEL.id) &&
!availableModelIds.has(KILO_AUTO_BALANCED_MODEL.id) &&
!availableModelIds.has(KILO_AUTO_EFFICIENT_MODEL.id) &&
!availableModelIds.has(KILO_AUTO_FREE_MODEL.id)
!availableModelIds.has(KILO_AUTO_FREE_MODEL.id) &&
!availableModelIds.has(KILO_AUTO_SMALL_MODEL.id)
) {
return models;
}
Expand All @@ -37,12 +43,22 @@ export async function addAutoRoutingModels(
.map(candidate => candidate.model),
availableModelIds
);
const frontierModelIds = visibleConcreteModelIds(
Object.values(FRONTIER_MODE_TO_MODEL).map(({ model }) => model),
availableModelIds
);
const freeModelIds = visibleConcreteModelIds(autoFreeCandidates ?? [], availableModelIds);
const smallModelIds = visibleConcreteModelIds(
Object.values(AUTO_SMALL_TARGET_MODELS),
availableModelIds
);
const hideAutoFreeModel = autoFreeCandidates !== null && freeModelIds.length === 0;
const autoRoutingChoices = new Map([
[KILO_AUTO_FRONTIER_MODEL.id, frontierModelIds],
[KILO_AUTO_BALANCED_MODEL.id, efficientModelIds],
[KILO_AUTO_EFFICIENT_MODEL.id, efficientModelIds],
[KILO_AUTO_FREE_MODEL.id, freeModelIds],
[KILO_AUTO_SMALL_MODEL.id, smallModelIds],
]);

return models.flatMap(model => {
Expand Down