Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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