Skip to content
Open
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
1 change: 1 addition & 0 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export const SECRET_STATE_KEYS = [
"fireworksApiKey",
"vercelAiGatewayApiKey",
"opencodeGoApiKey",
"kenariApiKey",
"basetenApiKey",
] as const

Expand Down
11 changes: 11 additions & 0 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const dynamicProviders = [
"poe",
"deepseek",
"opencode-go",
"kenari",
] as const

export type DynamicProvider = (typeof dynamicProviders)[number]
Expand Down Expand Up @@ -407,6 +408,11 @@ const opencodeGoSchema = baseProviderSettingsSchema.extend({
opencodeGoModelId: z.string().optional(),
})

const kenariSchema = baseProviderSettingsSchema.extend({
kenariApiKey: z.string().optional(),
kenariModelId: z.string().optional(),
})

const zooGatewaySchema = baseProviderSettingsSchema.extend({
zooSessionToken: z.string().optional(),
zooGatewayModelId: z.string().optional(),
Expand Down Expand Up @@ -452,6 +458,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
qwenCodeSchema.merge(z.object({ apiProvider: z.literal("qwen-code") })),
vercelAiGatewaySchema.merge(z.object({ apiProvider: z.literal("vercel-ai-gateway") })),
opencodeGoSchema.merge(z.object({ apiProvider: z.literal("opencode-go") })),
kenariSchema.merge(z.object({ apiProvider: z.literal("kenari") })),
zooGatewaySchema.merge(z.object({ apiProvider: z.literal("zoo-gateway") })),
defaultSchema,
])
Expand Down Expand Up @@ -488,6 +495,7 @@ export const providerSettingsSchema = z.object({
...qwenCodeSchema.shape,
...vercelAiGatewaySchema.shape,
...opencodeGoSchema.shape,
...kenariSchema.shape,
...zooGatewaySchema.shape,
...codebaseIndexProviderSchema.shape,
})
Expand Down Expand Up @@ -520,6 +528,7 @@ export const modelIdKeys = [
"litellmModelId",
"vercelAiGatewayModelId",
"opencodeGoModelId",
"kenariModelId",
"zooGatewayModelId",
] as const satisfies readonly (keyof ProviderSettings)[]

Expand Down Expand Up @@ -567,6 +576,7 @@ export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
fireworks: "apiModelId",
"vercel-ai-gateway": "vercelAiGatewayModelId",
"opencode-go": "opencodeGoModelId",
kenari: "kenariModelId",
"zoo-gateway": "zooGatewayModelId",
}

Expand Down Expand Up @@ -701,6 +711,7 @@ export const MODELS_BY_PROVIDER: Record<
unbound: { id: "unbound", label: "Unbound", models: [] },
"vercel-ai-gateway": { id: "vercel-ai-gateway", label: "Vercel AI Gateway", models: [] },
"opencode-go": { id: "opencode-go", label: "Opencode Go", models: [] },
kenari: { id: "kenari", label: "Kenari", models: [] },
"zoo-gateway": { id: "zoo-gateway", label: "Zoo Gateway", models: [] },

// Local providers; models discovered from localhost endpoints.
Expand Down
4 changes: 4 additions & 0 deletions packages/types/src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export * from "./vscode-llm.js"
export * from "./xai.js"
export * from "./vercel-ai-gateway.js"
export * from "./opencode-go.js"
export * from "./kenari.js"
export * from "./zai.js"
export * from "./minimax.js"
export * from "./mimo.js"
Expand All @@ -49,6 +50,7 @@ import { vscodeLlmDefaultModelId } from "./vscode-llm.js"
import { xaiDefaultModelId } from "./xai.js"
import { vercelAiGatewayDefaultModelId } from "./vercel-ai-gateway.js"
import { opencodeGoDefaultModelId } from "./opencode-go.js"
import { kenariDefaultModelId } from "./kenari.js"
import { internationalZAiDefaultModelId, mainlandZAiDefaultModelId } from "./zai.js"
import { minimaxDefaultModelId } from "./minimax.js"
import { mimoDefaultModelId } from "./mimo.js"
Expand Down Expand Up @@ -121,6 +123,8 @@ export function getProviderDefaultModelId(
return vercelAiGatewayDefaultModelId
case "opencode-go":
return opencodeGoDefaultModelId
case "kenari":
return kenariDefaultModelId
case "zoo-gateway":
return zooGatewayDefaultModelId
case "anthropic":
Expand Down
21 changes: 21 additions & 0 deletions packages/types/src/providers/kenari.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { ModelInfo } from "../model.js"

// Kenari: Indonesian OpenAI-compatible AI gateway billed in Rupiah (IDR).
// https://kenari.id/docs · base URL: https://kenari.id/v1
//
// The full model list (and metadata) is fetched dynamically from
// `https://kenari.id/v1/models`, so models can be switched on the fly.
// The values below are only a fallback used before the live list resolves.
export const kenariDefaultModelId = "glm-5-2"

export const kenariDefaultModelInfo: ModelInfo = {
maxTokens: 32_768,
contextWindow: 1_048_576,
supportsImages: false,
supportsPromptCache: false,
// Pricing is intentionally omitted: Kenari bills in IDR (micro-rupiah per 1M tokens),
// which cannot be rendered in the USD price fields without a misleading conversion.
description: "Kenari model. Available models and metadata are resolved dynamically from /v1/models.",
}

export const KENARI_DEFAULT_TEMPERATURE = 0
29 changes: 29 additions & 0 deletions src/api/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// npx vitest run src/api/__tests__/index.spec.ts

// Mock vscode first to avoid import errors
vitest.mock("vscode", () => ({
workspace: {
getConfiguration: () => ({
get: (_key: string, defaultValue?: unknown) => defaultValue,
}),
},
}))

import type { ProviderSettings } from "@roo-code/types"

import { buildApiHandler } from "../index"
import { KenariHandler } from "../providers/kenari"

describe("buildApiHandler", () => {
it("returns a KenariHandler for the kenari provider", () => {
const configuration: ProviderSettings = {
apiProvider: "kenari",
kenariApiKey: "test-key",
kenariModelId: "glm-5-2",
}

const handler = buildApiHandler(configuration)

expect(handler).toBeInstanceOf(KenariHandler)
})
})
3 changes: 3 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
FireworksHandler,
VercelAiGatewayHandler,
OpencodeGoHandler,
KenariHandler,
ZooGatewayHandler,
MiniMaxHandler,
MimoHandler,
Expand Down Expand Up @@ -193,6 +194,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
return new VercelAiGatewayHandler(options)
case "opencode-go":
return new OpencodeGoHandler(options)
case "kenari":
return new KenariHandler(options)
case "zoo-gateway":
return new ZooGatewayHandler(options)
case "minimax":
Expand Down
Loading
Loading