Skip to content
Merged
29 changes: 29 additions & 0 deletions packages/types/src/__tests__/kimi-code.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
SECRET_STATE_KEYS,
dynamicProviders,
kimiCodeDefaultModelId,
providerSettingsSchema,
providerSettingsSchemaDiscriminated,
} from "../index.js"

describe("Kimi Code provider types", () => {
it("registers Kimi Code as a dynamic provider with a distinct secret", () => {
expect(dynamicProviders).toContain("kimi-code")
expect(SECRET_STATE_KEYS).toContain("kimiCodeApiKey")
expect(SECRET_STATE_KEYS).toContain("moonshotApiKey")
})

it("parses OAuth and API-key settings independently from Moonshot", () => {
expect(
providerSettingsSchemaDiscriminated.parse({
apiProvider: "kimi-code",
kimiCodeAuthMethod: "api-key",
kimiCodeApiKey: "kimi-key",
apiModelId: kimiCodeDefaultModelId,
}),
).toMatchObject({ kimiCodeApiKey: "kimi-key" })
expect(providerSettingsSchema.parse({ apiProvider: "kimi-code", kimiCodeAuthMethod: "oauth" })).toMatchObject({
kimiCodeAuthMethod: "oauth",
})
})
})
2 changes: 2 additions & 0 deletions packages/types/src/__tests__/provider-identifiers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const expectedProviderIdentifiers = [
"gemini-cli",
"mistral",
"moonshot",
"kimi-code",
"minimax",
"mimo",
"openai-codex",
Expand Down Expand Up @@ -104,6 +105,7 @@ describe("provider identifiers", () => {
providerIdentifiers.moonshot,
providerIdentifiers.opencodeGo,
providerIdentifiers.kenari,
providerIdentifiers.kimiCode,
])
expect(localProviders).toEqual([providerIdentifiers.ollama, providerIdentifiers.lmstudio])
expect(internalProviders).toEqual([providerIdentifiers.vscodeLm])
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ export const SECRET_STATE_KEYS = [
"openAiNativeApiKey",
"deepSeekApiKey",
"moonshotApiKey",
"kimiCodeApiKey",
"mistralApiKey",
"minimaxApiKey",
"requestyApiKey",
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export const modelInfoSchema = z.object({
})
.optional(),
description: z.string().optional(),
displayName: z.string().optional(),
// Default effort value for models that support reasoning effort
reasoningEffort: reasoningEffortExtendedSchema.optional(),
minTokensPerCachePoint: z.number().optional(),
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/provider-identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const providerIdentifiers = {
geminiCli: "gemini-cli",
mistral: "mistral",
moonshot: "moonshot",
kimiCode: "kimi-code",
minimax: "minimax",
mimo: "mimo",
openaiCodex: "openai-codex",
Expand Down
17 changes: 17 additions & 0 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const dynamicProviders = [
providerIdentifiers.moonshot,
providerIdentifiers.opencodeGo,
providerIdentifiers.kenari,
providerIdentifiers.kimiCode,
] as const

export type DynamicProvider = (typeof dynamicProviders)[number]
Expand Down Expand Up @@ -309,6 +310,14 @@ const moonshotSchema = apiModelIdProviderModelSchema.extend({
moonshotApiKey: z.string().optional(),
})

export const kimiCodeAuthMethodSchema = z.enum(["oauth", "api-key"])
export type KimiCodeAuthMethod = z.infer<typeof kimiCodeAuthMethodSchema>

const kimiCodeSchema = apiModelIdProviderModelSchema.extend({
kimiCodeAuthMethod: kimiCodeAuthMethodSchema.optional(),
kimiCodeApiKey: z.string().optional(),
})

const minimaxSchema = apiModelIdProviderModelSchema.extend({
minimaxBaseUrl: z
.union([z.literal("https://api.minimax.io/v1"), z.literal("https://api.minimaxi.com/v1")])
Expand Down Expand Up @@ -425,6 +434,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
deepSeekSchema.merge(z.object({ apiProvider: z.literal("deepseek") })),
poeSchema.merge(z.object({ apiProvider: z.literal("poe") })),
moonshotSchema.merge(z.object({ apiProvider: z.literal("moonshot") })),
kimiCodeSchema.merge(z.object({ apiProvider: z.literal("kimi-code") })),
minimaxSchema.merge(z.object({ apiProvider: z.literal("minimax") })),
mimoSchema.merge(z.object({ apiProvider: z.literal("mimo") })),
requestySchema.merge(z.object({ apiProvider: z.literal("requesty") })),
Expand Down Expand Up @@ -463,6 +473,7 @@ export const providerSettingsSchema = z.object({
...deepSeekSchema.shape,
...poeSchema.shape,
...moonshotSchema.shape,
...kimiCodeSchema.shape,
...minimaxSchema.shape,
...mimoSchema.shape,
...requestySchema.shape,
Expand Down Expand Up @@ -544,6 +555,7 @@ export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
"gemini-cli": "apiModelId",
mistral: "apiModelId",
moonshot: "apiModelId",
"kimi-code": "apiModelId",
minimax: "apiModelId",
mimo: "apiModelId",
deepseek: "apiModelId",
Expand Down Expand Up @@ -652,6 +664,11 @@ export const MODELS_BY_PROVIDER: Record<
label: "Moonshot",
models: Object.keys(moonshotModels),
},
"kimi-code": {
id: "kimi-code",
label: "Kimi Code",
models: [],
},
minimax: {
id: "minimax",
label: "MiniMax",
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 @@ -25,6 +25,7 @@ export * from "./xai.js"
export * from "./vercel-ai-gateway.js"
export * from "./opencode-go.js"
export * from "./kenari.js"
export * from "./kimi-code.js"
export * from "./zai.js"
export * from "./minimax.js"
export * from "./mimo.js"
Expand Down Expand Up @@ -53,6 +54,7 @@ import { xaiDefaultModelId } from "./xai.js"
import { vercelAiGatewayDefaultModelId } from "./vercel-ai-gateway.js"
import { opencodeGoDefaultModelId } from "./opencode-go.js"
import { kenariDefaultModelId } from "./kenari.js"
import { kimiCodeDefaultModelId } from "./kimi-code.js"
import { internationalZAiDefaultModelId, mainlandZAiDefaultModelId } from "./zai.js"
import { minimaxDefaultModelId } from "./minimax.js"
import { mimoDefaultModelId } from "./mimo.js"
Expand Down Expand Up @@ -129,6 +131,8 @@ export function getProviderDefaultModelId(
return opencodeGoDefaultModelId
case "kenari":
return kenariDefaultModelId
case "kimi-code":
return kimiCodeDefaultModelId
case "zoo-gateway":
return zooGatewayDefaultModelId
case "anthropic":
Expand Down
23 changes: 23 additions & 0 deletions packages/types/src/providers/kimi-code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { ModelInfo } from "../model.js"

export const KIMI_CODE_BASE_URL = "https://api.kimi.com/coding/v1"
export const kimiCodeDefaultModelId = "kimi-for-coding"

export const kimiCodeReasoningEfforts = ["low", "high", "max"] as const

export const kimiCodeDefaultModelInfo: ModelInfo = {
contextWindow: 262_144,
maxTokens: 32_768,
supportsImages: false,
supportsPromptCache: false,
supportsReasoningEffort: [...kimiCodeReasoningEfforts],
requiredReasoningEffort: true,
reasoningEffort: "max",
description: "Kimi Code's coding model for subscription and API-key access.",
}

export const kimiCodeModels = {
[kimiCodeDefaultModelId]: kimiCodeDefaultModelInfo,
} as const satisfies Record<string, ModelInfo>

export type KimiCodeModelId = keyof typeof kimiCodeModels
10 changes: 10 additions & 0 deletions packages/types/src/vscode-extension-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,14 @@ export type ExtensionState = Pick<
mdmCompliant?: boolean
taskSyncEnabled: boolean
openAiCodexIsAuthenticated?: boolean
kimiCodeIsAuthenticated?: boolean
kimiCodeOAuthState?: {
status: "idle" | "authorizing" | "polling" | "authenticated" | "error"
userCode?: string
verificationUri?: string
expiresAt?: number
error?: string
}
zooCodeIsAuthenticated?: boolean
zooCodeUserName?: string
zooCodeUserEmail?: string
Expand Down Expand Up @@ -538,6 +546,8 @@ export interface WebviewMessage {
| "rooCloudManualUrl"
| "openAiCodexSignIn"
| "openAiCodexSignOut"
| "kimiCodeSignIn"
| "kimiCodeSignOut"
| "zooCodeSignOut"
| "switchOrganization"
| "condenseTaskContextRequest"
Expand Down
3 changes: 3 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
OpenAiNativeHandler,
DeepSeekHandler,
MoonshotHandler,
KimiCodeHandler,
MistralHandler,
VsCodeLmHandler,
RequestyHandler,
Expand Down Expand Up @@ -178,6 +179,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
return new QwenCodeHandler(options)
case "moonshot":
return new MoonshotHandler(options)
case "kimi-code":
return new KimiCodeHandler(options)
case "vscode-lm":
return new VsCodeLmHandler(options)
case "mistral":
Expand Down
Loading
Loading