diff --git a/packages/kilo-gateway/src/api/models.ts b/packages/kilo-gateway/src/api/models.ts index b5bb9ee2467..5e62fedd644 100644 --- a/packages/kilo-gateway/src/api/models.ts +++ b/packages/kilo-gateway/src/api/models.ts @@ -30,6 +30,7 @@ const openRouterModelSchema = z.object({ top_provider: z.object({ max_completion_tokens: z.number().nullish() }).optional(), supported_parameters: z.array(z.string()).optional(), preferredIndex: z.number().optional(), + isFree: z.boolean().optional(), opencode: z .object({ family: z.string().optional(), @@ -162,6 +163,7 @@ function transformToModelDevFormat(model: OpenRouterModel): any { variants: model.opencode?.variants, prompt: model.opencode?.prompt, tool_call: supportsTools, + isFree: model.isFree, ...(inputPrice !== undefined && outputPrice !== undefined && { cost: { diff --git a/packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts b/packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts index 2c65493465e..c32309e2375 100644 --- a/packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts +++ b/packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts @@ -10,12 +10,8 @@ export function providerSortKey(providerID: string, order = PROVIDER_ORDER): num return idx >= 0 ? idx : order.length } -export function isFree(model: Pick): boolean { - if (model.isFree !== undefined) return model.isFree - // TODO: temporary — this logic will be moved to the backend - if (model.providerID !== KILO_GATEWAY_ID) return false - // TODO: fallback to cost check — delete once backend ships isFree attribute - return model.cost?.input === 0 && model.cost?.output === 0 +export function isFree(model: Pick): boolean { + return model.isFree === true } export function stripSubProviderPrefix(name: string): string { diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index 5d61672458a..2751547c675 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -86,6 +86,7 @@ export namespace ModelsDev { // kilocode_change start recommendedIndex: z.number().optional(), prompt: Prompt.optional().catch(undefined), + isFree: z.boolean().optional(), // kilocode_change end experimental: z.boolean().optional(), diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index eef41c93ce9..e0e4b6142db 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -689,6 +689,7 @@ export namespace Provider { // kilocode_change start recommendedIndex: z.number().optional(), prompt: Prompt.optional().catch(undefined), + isFree: z.boolean().optional(), // kilocode_change end }) .meta({ @@ -775,6 +776,7 @@ export namespace Provider { variants: provider.id === "kilo" ? (model.variants ?? {}) : {}, recommendedIndex: model.recommendedIndex, prompt: model.prompt, + isFree: model.isFree, // kilocode_change end } @@ -923,6 +925,7 @@ export namespace Provider { // kilocode_change start recommendedIndex: model.recommendedIndex ?? existingModel?.recommendedIndex, prompt: model.prompt ?? existingModel?.prompt, + isFree: model.isFree ?? existingModel?.isFree, // kilocode_change end } const merged = mergeDeep(ProviderTransform.variants(parsedModel), model.variants ?? {}) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 8c6a10a5427..bce8bbdea7b 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1214,6 +1214,7 @@ export type ProviderConfig = { } recommendedIndex?: number prompt?: "codex" | "gemini" | "beast" | "anthropic" | "trinity" | "anthropic_without_todo" + isFree?: boolean experimental?: boolean status?: "alpha" | "beta" | "deprecated" options?: { @@ -1646,6 +1647,7 @@ export type Model = { } recommendedIndex?: number prompt?: "codex" | "gemini" | "beast" | "anthropic" | "trinity" | "anthropic_without_todo" + isFree?: boolean } export type Provider = { @@ -4159,6 +4161,7 @@ export type ProviderListResponses = { } recommendedIndex?: number prompt?: "codex" | "gemini" | "beast" | "anthropic" | "trinity" | "anthropic_without_todo" + isFree?: boolean experimental?: boolean status?: "alpha" | "beta" | "deprecated" options: { diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index c65a4ad275e..5181da5b925 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -4838,6 +4838,9 @@ "type": "string", "enum": ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo"] }, + "isFree": { + "type": "boolean" + }, "experimental": { "type": "boolean" }, @@ -11403,6 +11406,9 @@ "type": "string", "enum": ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo"] }, + "isFree": { + "type": "boolean" + }, "experimental": { "type": "boolean" }, @@ -12373,6 +12379,9 @@ "prompt": { "type": "string", "enum": ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo"] + }, + "isFree": { + "type": "boolean" } }, "required": [