feat(kenari): add Kenari as a first-class provider#793
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThis PR adds Kenari as a first-class provider across shared types, backend model fetching and chat handling, webview router-model aggregation, settings UI wiring, validation, and localized settings strings. ChangesKenari Provider Integration
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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.
🧹 Nitpick comments (2)
src/api/providers/fetchers/kenari.ts (1)
7-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winBase URL string duplicated with the API handler.
KENARI_BASE_URLhere and the hardcoded"https://kenari.id/v1"literal insrc/api/providers/kenari.ts(constructorbaseURL) are two independent sources of truth. If Kenari's endpoint changes, only one may get updated.♻️ Proposed fix: export and reuse the constant
-const KENARI_BASE_URL = "https://kenari.id/v1" +export const KENARI_BASE_URL = "https://kenari.id/v1"Then in
src/api/providers/kenari.ts:- baseURL: "https://kenari.id/v1", + baseURL: KENARI_BASE_URL,🤖 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/fetchers/kenari.ts` at line 7, The Kenari base URL is defined in two places, creating duplicate sources of truth between KENARI_BASE_URL in the fetcher module and the hardcoded baseURL in the Kenari provider constructor. Export and reuse the shared KENARI_BASE_URL constant from the fetcher module inside the Kenari provider so both paths always use the same endpoint, and keep the provider constructor aligned with that shared symbol.src/core/webview/webviewMessageHandler.ts (1)
1156-1172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated "public provider candidate" wiring (same as opencode-go block above).
Lines 1156-1172 mirror lines 1139-1154 almost verbatim (comment text included). Consider extracting a small helper (e.g.
pushPublicProviderCandidate(candidates, key, resolvedKey, flushCondition)) since this pattern will likely repeat for future public dynamic providers.♻️ Sketch of a shared helper
+const pushPublicKeyedCandidate = async ( + candidates: { key: RouterName; options: GetModelsOptions }[], + routerKey: RouterName, + apiKey: string | undefined, + explicitKeyProvided: boolean, +) => { + if (explicitKeyProvided) { + await flushModels({ provider: routerKey, apiKey } as GetModelsOptions, true) + } + candidates.push({ key: routerKey, options: { provider: routerKey, apiKey } as GetModelsOptions }) +}🤖 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/core/webview/webviewMessageHandler.ts` around lines 1156 - 1172, The Kenari candidate setup is duplicating the same “public provider candidate” wiring already used in the opencode-go block, so extract the shared logic into a small helper (for example around the candidate push/flush flow in `webviewMessageHandler.ts`). Move the repeated key resolution, optional `flushModels` call, and `candidates.push` behavior into that helper, then reuse it for both the `kenari` and `opencode-go` paths so future public dynamic providers can follow the same pattern without copy-paste.
🤖 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.
Nitpick comments:
In `@src/api/providers/fetchers/kenari.ts`:
- Line 7: The Kenari base URL is defined in two places, creating duplicate
sources of truth between KENARI_BASE_URL in the fetcher module and the hardcoded
baseURL in the Kenari provider constructor. Export and reuse the shared
KENARI_BASE_URL constant from the fetcher module inside the Kenari provider so
both paths always use the same endpoint, and keep the provider constructor
aligned with that shared symbol.
In `@src/core/webview/webviewMessageHandler.ts`:
- Around line 1156-1172: The Kenari candidate setup is duplicating the same
“public provider candidate” wiring already used in the opencode-go block, so
extract the shared logic into a small helper (for example around the candidate
push/flush flow in `webviewMessageHandler.ts`). Move the repeated key
resolution, optional `flushModels` call, and `candidates.push` behavior into
that helper, then reuse it for both the `kenari` and `opencode-go` paths so
future public dynamic providers can follow the same pattern without copy-paste.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 3570c048-727a-4a48-a722-5c0b66d0506e
📒 Files selected for processing (43)
packages/types/src/global-settings.tspackages/types/src/provider-settings.tspackages/types/src/providers/index.tspackages/types/src/providers/kenari.tssrc/api/index.tssrc/api/providers/__tests__/kenari.spec.tssrc/api/providers/fetchers/__tests__/kenari.spec.tssrc/api/providers/fetchers/kenari.tssrc/api/providers/fetchers/modelCache.tssrc/api/providers/index.tssrc/api/providers/kenari.tssrc/core/webview/__tests__/ClineProvider.spec.tssrc/core/webview/__tests__/webviewMessageHandler.spec.tssrc/core/webview/webviewMessageHandler.tssrc/shared/api.tswebview-ui/src/components/settings/ApiOptions.tsxwebview-ui/src/components/settings/ModelPicker.tsxwebview-ui/src/components/settings/constants.tswebview-ui/src/components/settings/providers/Kenari.tsxwebview-ui/src/components/settings/providers/__tests__/Kenari.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/ca/settings.jsonwebview-ui/src/i18n/locales/de/settings.jsonwebview-ui/src/i18n/locales/en/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.jsonwebview-ui/src/utils/__tests__/validate.spec.tswebview-ui/src/utils/validate.ts
eb9af0e to
90a25b9
Compare
|
The platform-unit-test failure was in SettingsView.change-detection.spec.tsx ("resets cached provider state when a new import timestamp arrives", expected baseten / got deepseek), a file this PR does not touch; it passes locally on this branch (4/4) and the same test failed once on main's own CI when it landed in #726. Pushed a same-content commit to retrigger CI since I lack rerun permissions. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Closes #792
What
Adds Kenari as a first-class dynamic provider. Kenari is an Indonesian OpenAI-compatible AI gateway billed in Rupiah (IDR): one
kn-API key covers Claude, GPT, DeepSeek, GLM, Kimi and more. It already works through the generic OpenAI Compatible provider; this gives it a named entry with the live model list auto-populated.How
Mirrors the Opencode Go provider (#319) file-by-file, adapted to current main:
src/api/providers/kenari.ts: handler onRouterProvider(streaming text,reasoning_content, tool-call partials, usage with cache-read tokens).src/api/providers/fetchers/kenari.ts: dynamic model list from the publichttps://kenari.id/v1/models(no key needed; the key is forwarded when present). Mapscontext_lengthandmodalities.input(image support). Pricing is intentionally not mapped: Kenari returns IDR (micro_idr_per_1m_tokens), and the ModelInfo price fields are USD, so a converted or raw value would be wrong; cost stays undefined instead.packages/types:kenari.ts(defaultglm-5-2, 1,048,576 context fallback matching the live default model), settings schema, discriminated union,modelIdKeys,MODELS_BY_PROVIDER,SECRET_STATE_KEYS.buildApiHandler,modelCache,webviewMessageHandler(fetched unconditionally like the other public-endpoint routers),dynamicProviderExtras.Kenari.tsxsettings component (key field + get-key CTA + ModelPicker),ApiOptions,PROVIDERSconstant,providerModelConfig,useSelectedModel,validate.ts, and thekenariApiKey/getKenariApiKeystrings across all 18 locales.Deliberately skipped from #319: the Anthropic-wire split machinery. Kenari serves every model over OpenAI
/chat/completions, so the default "openai" protocol is correct with no extra code.Testing
packages/typessuite,srcshared+providers sweep (1603 passed / 1 skipped), webview settings+hooks+utils sweep (592 passed), kenari-focused suites 216/216.check-typesclean in all three packages; eslint--max-warnings=0and prettier clean on every touched file.https://kenari.id/v1/modelspublic (24 models withcontext_lengthand modalities); chat completions verified with a realkn-key againsthttps://kenari.id/v1. Docs: https://kenari.id/docs, OpenAPI: https://kenari.id/openapi.json.Disclosure: I run kenari.id. Happy to provide a test key for verification.
Summary by CodeRabbit
kenariApiKey).