[Feat] Add Kimi Code provider with OAuth device flow#945
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Kimi Code as a provider with API-key and OAuth authentication, model discovery, token refresh, extension messaging, configuration validation, and a dedicated settings UI. ChangesKimi Code provider
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant SettingsUI
participant WebviewMessageHandler
participant KimiCodeOAuthManager
participant KimiCodeOAuthAPI
SettingsUI->>WebviewMessageHandler: Request Kimi Code sign-in
WebviewMessageHandler->>KimiCodeOAuthManager: Start device authorization
KimiCodeOAuthManager->>KimiCodeOAuthAPI: Request and poll OAuth token
KimiCodeOAuthManager-->>WebviewMessageHandler: Return OAuth state
WebviewMessageHandler-->>SettingsUI: Update authentication state
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/api/providers/__tests__/kimi-code.spec.ts`:
- Around line 15-30: Extend the package-local KimiCodeHandler tests to cover
forced-refresh retry behavior for both createMessage() and completePrompt():
verify OAuth HTTP 401 failures refresh credentials and retry exactly once, while
non-401 OAuth failures and all API-key failures do not refresh. Reuse the
existing handler/authentication symbols and assert both refresh invocation
counts and the resulting request behavior.
In `@src/api/providers/kimi-code.ts`:
- Around line 59-69: Update KimiCodeProvider.prepareRequest and its
model-discovery state so a failed or empty getModels result is marked as
completed for the current provider lifecycle, preventing discovery from running
before every completion. Preserve the configured model ID and fallback metadata,
and only retry discovery through an explicit refresh or backoff mechanism if one
already exists.
In `@src/core/webview/ClineProvider.ts`:
- Around line 2537-2540: Wrap the async `kimiCodeOAuthState` aggregation block
in `getStateToPostToWebview()` with try/catch handling, covering both the
dynamic import and `kimiCodeOAuthManager.getState()` call. Match the
fallback/error-handling behavior used by the adjacent `kimiCodeIsAuthenticated`
block so a failure returns safe UI state without rejecting the overall
aggregation.
In `@src/integrations/kimi-code/oauth.ts`:
- Around line 233-258: Guard all shared-state mutations in startAuthorization
and its related finally cleanup (including the code around the pollingPromise
handling) with an ownership check that this.pollingController === controller. A
superseded authorization must not set state to "error" or clear the newer
operation’s pollingPromise; only the currently owned controller may update or
clean up shared authorization state.
- Around line 193-198: Update clearCredentials and the refresh flow around
refreshPromise/saveCredentials so sign-out invalidates any in-flight refresh
result before deleting stored credentials. Use a credential-generation counter
or abort mechanism, increment or cancel it in clearCredentials, and ensure stale
refresh completions cannot call saveCredentials or restore this.credentials;
preserve normal refresh behavior for the current generation.
- Around line 127-142: The Kimi Code authentication network calls need bounded
cancellation deadlines. In src/integrations/kimi-code/oauth.ts lines 127-142,
update refreshKimiCodeAccessToken and its postForm call to pass a bounded abort
signal so refreshPromise always settles; in
src/api/providers/fetchers/kimi-code.ts lines 27-29, add the same bounded abort
signal to the model-discovery request so chat requests can fall back promptly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4829e21f-2153-4085-9ea2-45a5b5e0eaff
📒 Files selected for processing (31)
packages/types/src/__tests__/kimi-code.test.tspackages/types/src/global-settings.tspackages/types/src/model.tspackages/types/src/provider-settings.tspackages/types/src/providers/index.tspackages/types/src/providers/kimi-code.tspackages/types/src/vscode-extension-host.tssrc/api/index.tssrc/api/providers/__tests__/kimi-code.spec.tssrc/api/providers/fetchers/__tests__/kimi-code.spec.tssrc/api/providers/fetchers/kimi-code.tssrc/api/providers/fetchers/modelCache.tssrc/api/providers/index.tssrc/api/providers/kimi-code.tssrc/core/webview/ClineProvider.tssrc/core/webview/webviewMessageHandler.tssrc/extension.tssrc/integrations/kimi-code/__tests__/oauth.spec.tssrc/integrations/kimi-code/oauth.tssrc/shared/api.tssrc/shared/checkExistApiConfig.tswebview-ui/src/components/settings/ApiOptions.tsxwebview-ui/src/components/settings/constants.tswebview-ui/src/components/settings/providers/KimiCode.tsxwebview-ui/src/components/settings/providers/__tests__/KimiCode.spec.tsxwebview-ui/src/components/settings/providers/index.tswebview-ui/src/components/settings/utils/providerModelConfig.tswebview-ui/src/components/ui/hooks/useSelectedModel.tswebview-ui/src/i18n/locales/en/settings.jsonwebview-ui/src/utils/__tests__/validate.spec.tswebview-ui/src/utils/validate.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
webview-ui/src/i18n/locales/zh-CN/settings.json (1)
462-472: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winLocalize the Kimi Code UI strings to Simplified Chinese.
Consider translating these English fallback strings to improve the experience for Chinese users, especially since Moonshot/Kimi is primarily aimed at this audience.
🌐 Proposed translation
- "kimiCode": { - "authMethod": "Authentication method", - "oauth": "Kimi Code subscription (OAuth)", - "apiKey": "Kimi Code API key", - "apiKeyLabel": "Kimi Code API Key", - "signIn": "Sign in to Kimi Code", - "signOut": "Sign out", - "authenticated": "Signed in to Kimi Code", - "deviceCodeHelp": "Enter this device code in the Kimi authorization page:", - "docs": "Kimi Code documentation" - }, + "kimiCode": { + "authMethod": "身份验证方法", + "oauth": "Kimi Code 订阅 (OAuth)", + "apiKey": "Kimi Code API 密钥", + "apiKeyLabel": "Kimi Code API 密钥", + "signIn": "登录 Kimi Code", + "signOut": "登出", + "authenticated": "已登录 Kimi Code", + "deviceCodeHelp": "请在 Kimi 授权页面输入此设备代码:", + "docs": "Kimi Code 文档" + },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webview-ui/src/i18n/locales/zh-CN/settings.json` around lines 462 - 472, Translate all English values in the kimiCode localization object to natural Simplified Chinese, including authentication method, OAuth, API key, sign-in/out, authenticated status, device-code help, and documentation labels. Preserve the existing keys and JSON structure.webview-ui/src/i18n/locales/zh-TW/settings.json (1)
489-499: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winLocalize the Kimi Code UI strings to Traditional Chinese.
Consider translating these English fallback strings to improve the experience for Traditional Chinese users.
🌐 Proposed translation
- "kimiCode": { - "authMethod": "Authentication method", - "oauth": "Kimi Code subscription (OAuth)", - "apiKey": "Kimi Code API key", - "apiKeyLabel": "Kimi Code API Key", - "signIn": "Sign in to Kimi Code", - "signOut": "Sign out", - "authenticated": "Signed in to Kimi Code", - "deviceCodeHelp": "Enter this device code in the Kimi authorization page:", - "docs": "Kimi Code documentation" - }, + "kimiCode": { + "authMethod": "驗證方式", + "oauth": "Kimi Code 訂閱 (OAuth)", + "apiKey": "Kimi Code API 金鑰", + "apiKeyLabel": "Kimi Code API 金鑰", + "signIn": "登入 Kimi Code", + "signOut": "登出", + "authenticated": "已登入 Kimi Code", + "deviceCodeHelp": "請在 Kimi 授權頁面輸入此裝置代碼:", + "docs": "Kimi Code 說明文件" + },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webview-ui/src/i18n/locales/zh-TW/settings.json` around lines 489 - 499, Translate every English value in the kimiCode localization object to natural Traditional Chinese, including authentication method, OAuth/API key labels, sign-in/out states, device-code help, and documentation text; preserve all keys and JSON structure unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@webview-ui/src/i18n/locales/de/settings.json`:
- Around line 462-472: Localize every English value in the kimiCode settings
block, including authMethod, oauth, apiKey, apiKeyLabel, signIn, signOut,
authenticated, deviceCodeHelp, and docs. Apply appropriate translations in
webview-ui/src/i18n/locales/de/settings.json#L462-L472,
es/settings.json#L462-L472, fr/settings.json#L462-L472,
hi/settings.json#L462-L472, id/settings.json#L462-L472,
it/settings.json#L462-L472, ja/settings.json#L462-L472,
ko/settings.json#L462-L472, and nl/settings.json#L462-L472, while preserving the
existing kimiCode keys and JSON structure.
---
Nitpick comments:
In `@webview-ui/src/i18n/locales/zh-CN/settings.json`:
- Around line 462-472: Translate all English values in the kimiCode localization
object to natural Simplified Chinese, including authentication method, OAuth,
API key, sign-in/out, authenticated status, device-code help, and documentation
labels. Preserve the existing keys and JSON structure.
In `@webview-ui/src/i18n/locales/zh-TW/settings.json`:
- Around line 489-499: Translate every English value in the kimiCode
localization object to natural Traditional Chinese, including authentication
method, OAuth/API key labels, sign-in/out states, device-code help, and
documentation text; preserve all keys and JSON structure unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f3268b3c-808b-465a-99fc-fb7658596249
📒 Files selected for processing (20)
src/api/providers/kimi-code.tssrc/core/webview/__tests__/ClineProvider.spec.tssrc/core/webview/__tests__/webviewMessageHandler.spec.tswebview-ui/src/i18n/locales/ca/settings.jsonwebview-ui/src/i18n/locales/de/settings.jsonwebview-ui/src/i18n/locales/es/settings.jsonwebview-ui/src/i18n/locales/fr/settings.jsonwebview-ui/src/i18n/locales/hi/settings.jsonwebview-ui/src/i18n/locales/id/settings.jsonwebview-ui/src/i18n/locales/it/settings.jsonwebview-ui/src/i18n/locales/ja/settings.jsonwebview-ui/src/i18n/locales/ko/settings.jsonwebview-ui/src/i18n/locales/nl/settings.jsonwebview-ui/src/i18n/locales/pl/settings.jsonwebview-ui/src/i18n/locales/pt-BR/settings.jsonwebview-ui/src/i18n/locales/ru/settings.jsonwebview-ui/src/i18n/locales/tr/settings.jsonwebview-ui/src/i18n/locales/vi/settings.jsonwebview-ui/src/i18n/locales/zh-CN/settings.jsonwebview-ui/src/i18n/locales/zh-TW/settings.json
🚧 Files skipped from review as they are similar to previous changes (1)
- src/api/providers/kimi-code.ts
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/api/providers/__tests__/kimi-code.spec.ts`:
- Around line 105-140: Extend the tests in the KimiCodeHandler suite to cover
completePrompt() retrying after a 401 under OAuth, including a successful second
response and verification that mockForceRefreshAccessToken is called. Also add
an OAuth createMessage() case for a non-401 failure such as 500, asserting the
request rejects and mockForceRefreshAccessToken is not called.
In `@src/core/webview/__tests__/webviewMessageHandler.spec.ts`:
- Around line 1474-1477: Add vi.resetModules() to the beforeEach blocks for both
kimiCodeSignIn and kimiCodeSignOut in
src/core/webview/__tests__/webviewMessageHandler.spec.ts at lines 1474-1477 and
1583-1586, alongside vi.clearAllMocks(), so each test dynamically imports its
newly configured OAuth mock.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ff97bda0-13eb-4852-985c-7223a525ac01
📒 Files selected for processing (6)
src/api/providers/__tests__/kimi-code.spec.tssrc/api/providers/fetchers/__tests__/kimi-code.spec.tssrc/core/webview/__tests__/webviewMessageHandler.spec.tssrc/integrations/kimi-code/__tests__/oauth.spec.tssrc/shared/__tests__/checkExistApiConfig.spec.tswebview-ui/src/utils/__tests__/validate.spec.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/api/providers/openai.ts (1)
299-337: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRemove the redundant outer
try-catchto prevent double-wrapping errors.The outer
try-catchblock is redundant and causes API errors to be wrapped twice. The innertry-catchblock properly intercepts API failures and throwshandleOpenAIError. That handler already prefixes the message withcompletion errorand reliably preservesstatus,errorDetails, andcodefields.Because the outer block catches this newly formatted error and wraps it again, the UI will display duplicated prefixes (e.g.,
OpenAI completion error: OpenAI completion error: ...). Removing the outertry-catchaltogether allows the correctly formatted error fromhandleOpenAIErrorto propagate cleanly.♻️ Proposed fix to remove the outer try-catch
async completePrompt(prompt: string, options?: CompletePromptOptions): Promise<string> { - try { - const isAzureAiInference = this._isAzureAiInference(this.options.openAiBaseUrl) - const model = this.getModel() - const modelInfo = model.info - - const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = { - model: model.id, - messages: [{ role: "user", content: prompt }], - } - - // Add max_tokens if needed - this.addMaxTokensIfNeeded(requestOptions, modelInfo) - - let response - try { - response = await this.client.chat.completions.create( - requestOptions, - isAzureAiInference ? { path: OPENAI_AZURE_AI_INFERENCE_PATH } : {}, - ) - } catch (error) { - throw handleOpenAIError(error, this.providerName) - } - - return response.choices?.[0]?.message.content || "" - } catch (error) { - if (error instanceof Error) { - const wrapped = new Error(`${this.providerName} completion error: ${error.message}`, { cause: error }) - const source = error as Error & { status?: number; errorDetails?: unknown; code?: unknown } - const target = wrapped as Error & { status?: number; errorDetails?: unknown; code?: unknown } - if (source.status !== undefined) target.status = source.status - if (source.errorDetails !== undefined) target.errorDetails = source.errorDetails - if (source.code !== undefined) target.code = source.code - throw wrapped - } - - throw error - } + const isAzureAiInference = this._isAzureAiInference(this.options.openAiBaseUrl) + const model = this.getModel() + const modelInfo = model.info + + const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = { + model: model.id, + messages: [{ role: "user", content: prompt }], + } + + // Add max_tokens if needed + this.addMaxTokensIfNeeded(requestOptions, modelInfo) + + let response + try { + response = await this.client.chat.completions.create( + requestOptions, + isAzureAiInference ? { path: OPENAI_AZURE_AI_INFERENCE_PATH } : {}, + ) + } catch (error) { + throw handleOpenAIError(error, this.providerName) + } + + return response.choices?.[0]?.message.content || "" }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/providers/openai.ts` around lines 299 - 337, Remove the outer try-catch and its wrapping logic from completePrompt, while retaining the inner catch that passes API failures to handleOpenAIError. Let the formatted error propagate directly, preserving the existing request construction, response handling, and Azure inference behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/api/providers/openai.ts`:
- Around line 299-337: Remove the outer try-catch and its wrapping logic from
completePrompt, while retaining the inner catch that passes API failures to
handleOpenAIError. Let the formatted error propagate directly, preserving the
existing request construction, response handling, and Azure inference behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 45463726-2032-4822-91ac-6d1dd82d0835
📒 Files selected for processing (8)
src/api/providers/__tests__/kimi-code.spec.tssrc/api/providers/__tests__/openai.spec.tssrc/api/providers/fetchers/__tests__/kimi-code.spec.tssrc/api/providers/fetchers/kimi-code.tssrc/api/providers/kimi-code.tssrc/api/providers/openai.tssrc/integrations/kimi-code/__tests__/oauth.spec.tssrc/integrations/kimi-code/oauth.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- src/api/providers/fetchers/kimi-code.ts
- src/api/providers/fetchers/tests/kimi-code.spec.ts
- src/api/providers/tests/kimi-code.spec.ts
- src/api/providers/kimi-code.ts
- src/integrations/kimi-code/oauth.ts
|
Done — merge conflicts resolved and all 5 outstanding review threads addressed in Merge conflicts with
Review threads (all resolved):
Validation: full monorepo |
- Wrap kimiCodeOAuthState aggregation in try/catch in ClineProvider - Add non-401 OAuth no-retry test for createMessage - Add vi.resetModules() to kimiCode sign-in/out spec setup - Localize kimiCode settings strings in 9 locales - Merge origin/main: adopt canonical providerIdentifiers registry, keep both kimi-code and zoo-gateway setup-gate checks
Related GitHub Issue
No linked issue — this PR was opened on behalf of a user request to add Moonshot's Kimi Code platform as a first-class provider.
Description
Adds Kimi Code (provider ID
kimi-code) as a standalone provider, entirely separate from the existing Moonshot Open Platform provider (no reuse or migration ofmoonshotApiKey).Key implementation details:
auth.kimi.comwith the official public client ID17e5f671-d194-4dfb-9706-5516cb48c098. OAuth credentials live only in VS Code SecretStorage (global keykimi-code-oauth-credentials), never in profile JSON or cloud sync. Refresh is concurrency-safe (deduplicated via a shared refresh promise and invalidated on sign-out with a credential-generation counter), and API requests resolve the token at request time with exactly one forced-refresh retry after an OAuth HTTP 401 in both streaming (createMessage) and non-streaming (completePrompt) paths.kimiCodeApiKeypath following ordinary provider-secret persistence (SECRET_STATE_KEYS) for users who prefer API-key auth.https://api.kimi.com/coding/v1with authenticated dynamic model discovery, official metadata mapping, preservation of unknown configured model IDs, and thekimi-for-codingfallback only when no model is selected. Discovery failures are bounded (10s timeout) and attempted at most once per handler lifecycle so a down models endpoint does not stall chat requests; OAuth token calls are bounded by a 30s request timeout.low/high/max, defaultmax) matching the Kimi K3reasoning_effortAPI, rendered through the shared Model Reasoning Effort dropdown; unsupported persisted efforts (e.g.mediumfrom another provider) fall back to the model default.getStateToPostToWebview()is fault-tolerant: a failure in the dynamic import or state read returns safe defaults instead of breaking UI state synchronization.Reviewer notes: the branch was recently merged with
mainand adopted the canonicalproviderIdentifiersregistry (provider-identifiers.ts), withkimiCoderegistered there;checkExistApiConfigkeeps both the Kimi Code OAuth special case and the Zoo Gateway session-auth check.Test Procedure
pnpm test(full monorepo) passes: 423 test files, 6,912 tests.src/integrations/kimi-code/__tests__/oauth.spec.ts— official client ID, form-encoded device requests, concurrent refresh deduplication, credential storage.src/api/providers/__tests__/kimi-code.spec.ts— separate dispatch from Moonshot, unknown model preservation, fallback-only default, OAuth 401 forced-refresh retry exactly once forcreateMessageandcompletePrompt, no retry on non-401 OAuth failures or API-key auth, single model-discovery attempt after failure/empty response, reasoning-effort defaults and fallback.src/api/providers/fetchers/__tests__/kimi-code.spec.ts— model discovery, schema validation, metadata mapping, request timeout.src/api/transform/__tests__/reasoning.spec.ts— reasoning effort transform.src/core/webview/__tests__/webviewMessageHandler.spec.ts— Kimi Code sign-in/sign-out handlers (module cache reset per test).src/shared/__tests__/checkExistApiConfig.spec.ts— setup-gate behavior for OAuth vs API-key auth.webview-ui/src/components/settings/providers/__tests__/KimiCode.spec.tsx— buffered API key binding and device-code polling display.packages/types/src/__tests__/kimi-code.test.ts— secret-key registration and schema validation.Pre-Submission Checklist
Screenshots / Videos
Not captured in this environment: Zoo-Code is a VS Code extension whose settings UI runs inside the editor's webview (F5 debug host) with no browser-reachable surface in CI/sandbox. Behavior is covered by the webview component tests listed above.
Documentation Updates
Related PRs
Additional Notes
CodeRabbit review feedback has been addressed across prior commits and the latest push: forced-refresh retry contract tests (streaming and non-streaming, 401 and non-401), bounded timeouts on OAuth token and model-discovery requests, sign-out invalidation of in-flight refreshes, ownership guards for superseded authorization attempts, single-attempt model discovery, fault-tolerant OAuth state aggregation, spec module-cache isolation, and full localization of the Kimi Code settings strings.
Get in Touch
Reachable via the Discord thread linked in the provenance block above.