Skip to content

Mirror: fix: Improve Kimi model search and add fallback models (#5704)#15

Merged
jeremylongshore merged 3 commits intomainfrom
review/PR-5704
Feb 15, 2026
Merged

Mirror: fix: Improve Kimi model search and add fallback models (#5704)#15
jeremylongshore merged 3 commits intomainfrom
review/PR-5704

Conversation

@jeremylongshore
Copy link
Copy Markdown
Owner

Mirror of Kilo-Org#5704

Field Value
Upstream PR #5704
Author @Patel230
Category fix
Tier 3
Size 74 lines, 4 files

This PR mirrors the upstream change for multi-AI review analysis.

Bot Review Tracker

  • CodeRabbit
  • Gemini Code Assist
  • Greptile
  • CodeQL
  • Qodo PR-Agent

Make model search case-insensitive so users can find models regardless of casing.
For example, searching for "kimi k2.5" will now find models like "Kimi-K2.5-Instruct".

Changes:
- Add custom filtering with toLowerCase() for case-insensitive search
- Disable default Command filtering with shouldFilter={false}
- Use filtered model lists for displaying results

Fixes Kilo-Org#5694
Fixes Kimi model search in OpenAI Compatible provider by:

1. Search normalization - Model search now normalizes dashes, spaces,
   and underscores for fuzzy matching:
   -  matches
   -  matches

2. Kimi fallback models - Kimi models are now included as fallback when
   using OpenAI Compatible with Kimi endpoints:
   - Detects Kimi endpoints (kimi, moonshot, api.moonshot.ai/cn)
   - Always includes all Kimi models even if API fetch fails
   - Uses  as default model for Kimi endpoints
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 14, 2026

Warning

Rate limit exceeded

@jeremylongshore has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch review/PR-5704

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @jeremylongshore, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the user experience for selecting AI models by making the model search functionality more robust and intelligent. It addresses issues with case-sensitive searches and ensures that relevant Kimi/Moonshot models are readily available when their respective API endpoints are configured, streamlining the process of finding and utilizing diverse AI models.

Highlights

  • Improved Model Search: The ModelPicker component now supports case-insensitive search, including normalization for dashes, underscores, and spaces, significantly improving model discoverability for various OpenAI-compatible providers.
  • Kimi Model Fallback Integration: Logic was added to automatically detect Kimi/Moonshot API endpoints and include specific Kimi models as fallbacks, setting an appropriate default model for these providers.
Changelog
  • .changeset/fix-case-insensitive-model-search.md
    • Added a changeset entry for fixing case-insensitive model search in ModelPicker.
    • Documented that users can now search for models regardless of casing, resolving discovery issues with certain providers.
  • .changeset/fix-kimi-model-search.md
    • Added a changeset entry for fixing Kimi model search and incorporating Kimi models as fallbacks for OpenAI Compatible providers.
  • webview-ui/src/components/settings/ModelPicker.tsx
    • Implemented a normalizeForSearch utility function to convert strings to lowercase and remove dashes, underscores, and spaces for search purposes.
    • Modified the ModelPicker to use memoized filtered lists (filteredPreferredIds, filteredRestIds) based on the search input.
    • Disabled the default filtering behavior of the Command component to allow for custom search logic.
    • Updated CommandGroup headings and iterated model lists to reflect the new filtering and search status.
  • webview-ui/src/components/settings/providers/OpenAICompatible.tsx
    • Imported useMemo, moonshotModels, and moonshotDefaultModelId for enhanced model handling.
    • Introduced isKimiEndpoint to detect Kimi/Moonshot URLs based on the openAiBaseUrl.
    • Created a modelsToUse memoized value that conditionally merges moonshotModels with fetched OpenAI models if a Kimi endpoint is detected.
    • Dynamically set the defaultModelId for the ModelPicker to moonshotDefaultModelId when a Kimi endpoint is in use, otherwise defaulting to gpt-4o.
    • Added a key prop to the ModelPicker component to ensure proper re-rendering when the API base URL or Kimi endpoint status changes.
Activity
  • This pull request is a mirror of an upstream change for multi-AI review analysis.
  • Automated bot reviews are pending for CodeRabbit, Gemini Code Assist, Greptile, CodeQL, and Qodo PR-Agent.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Improve model search and add Kimi fallback support

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Implement case-insensitive model search with dash/space normalization
• Add Kimi/Moonshot models as fallback for OpenAI Compatible provider
• Detect Kimi endpoints and use appropriate default model
• Improve model discoverability across different casing conventions
Diagram
flowchart LR
  A["ModelPicker Component"] -->|"normalize search"| B["Case-insensitive Filtering"]
  B -->|"filter results"| C["Filtered Model Lists"]
  D["OpenAI Compatible Provider"] -->|"detect endpoint"| E["Kimi Endpoint Check"]
  E -->|"if Kimi"| F["Include Moonshot Models"]
  E -->|"set default"| G["Use Moonshot Default Model"]
  F -->|"merge with"| H["Final Models List"]
Loading

Grey Divider

File Changes

1. .changeset/fix-case-insensitive-model-search.md 📝 Documentation +10/-0

Changeset for case-insensitive search feature

• Add changeset documentation for case-insensitive model search feature
• Document improvement in model discovery for different casing conventions
• Specify patch version bump for webview-ui package

.changeset/fix-case-insensitive-model-search.md


2. .changeset/fix-kimi-model-search.md 📝 Documentation +5/-0

Changeset for Kimi model search fix

• Add changeset for Kimi model search improvements
• Document fallback model support for OpenAI Compatible provider
• Specify patch version bump for kilo-code package

.changeset/fix-kimi-model-search.md


3. webview-ui/src/components/settings/ModelPicker.tsx ✨ Enhancement +27/-7

Implement case-insensitive model search filtering

• Add normalizeForSearch() function to normalize dashes, spaces, and underscores
• Implement case-insensitive filtering for preferred and rest model lists
• Disable default Command filtering with shouldFilter={false}
• Update section heading to show "Matching Models" when search is active
• Use filtered model lists in CommandGroup rendering

webview-ui/src/components/settings/ModelPicker.tsx


View more (1)
4. webview-ui/src/components/settings/providers/OpenAICompatible.tsx ✨ Enhancement +22/-3

Add Kimi endpoint detection and fallback models

• Import useMemo hook and Moonshot model constants
• Add isKimiEndpoint detection logic checking for kimi, moonshot, and api.moonshot domains
• Create modelsToUse that merges Moonshot fallback models with fetched models for Kimi endpoints
• Set defaultModelId to Moonshot default when Kimi endpoint is detected
• Add key prop to ModelPicker to force re-render on endpoint changes
• Pass dynamic defaultModelId and modelsToUse to ModelPicker component

webview-ui/src/components/settings/providers/OpenAICompatible.tsx


Grey Divider

Qodo Logo

@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces two main improvements: case-insensitive model searching in the ModelPicker and fallback support for Kimi/Moonshot models in the OpenAICompatible provider. The changes are well-implemented. I've provided a couple of suggestions to improve performance and code clarity.

In ModelPicker.tsx, I've suggested an optimization for the search functionality to prevent unnecessary re-renders and to reduce code duplication.

In OpenAICompatible.tsx, I've pointed out a small redundancy in the logic for detecting Kimi endpoints which can be simplified.

Overall, these are good enhancements that will improve the user experience.

Comment on lines +102 to +114
const normalizeForSearch = (str: string) => str.toLowerCase().replace(/[-_\s]/g, "")

const filteredPreferredIds = useMemo(() => {
if (!searchValue.trim()) return preferredModelIds
const searchNormalized = normalizeForSearch(searchValue)
return preferredModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
}, [preferredModelIds, searchValue])

const filteredRestIds = useMemo(() => {
if (!searchValue.trim()) return restModelIds
const searchNormalized = normalizeForSearch(searchValue)
return restModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
}, [restModelIds, searchValue])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The normalizeForSearch function is redefined on every render, which causes the useMemo hooks to re-evaluate unnecessarily. This negates the performance benefits of memoization. Additionally, the filtering logic for preferredModelIds and restModelIds is duplicated.

To improve performance and maintainability, you should:

  1. Wrap normalizeForSearch in useCallback to ensure it's stable across renders.
  2. Combine the two useMemo hooks into a single one to avoid code duplication.
	const normalizeForSearch = useCallback((str: string) => str.toLowerCase().replace(/[-_\s]/g, ""), [])

	const { filteredPreferredIds, filteredRestIds } = useMemo(() => {
		if (!searchValue.trim()) {
			return { filteredPreferredIds: preferredModelIds, filteredRestIds: restModelIds }
		}
		const searchNormalized = normalizeForSearch(searchValue)
		const filterModels = (ids: string[]) =>
			ids.filter((id) => normalizeForSearch(id).includes(searchNormalized))

		return {
			filteredPreferredIds: filterModels(preferredModelIds),
			filteredRestIds: filterModels(restModelIds),
		}
	}, [preferredModelIds, restModelIds, searchValue, normalizeForSearch])

Comment on lines +56 to +57
apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.ai") ||
apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.cn")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These checks for api.moonshot.ai and api.moonshot.cn are redundant, as they are already covered by the includes("moonshot") check on the previous line. You can remove them to simplify the code.

@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. ModelPicker search untested 📘 Rule violation ⛯ Reliability
Description
The PR changes ModelPicker search behavior to be case-insensitive and normalize dashes/spaces, but
there are no updated/additional tests asserting the new matching behavior. This risks regressions
where searches may not return expected models across different casing/formatting.
Code

webview-ui/src/components/settings/ModelPicker.tsx[R101-114]

+	// kilocode_change: Case-insensitive search with dash/space normalization
+	const normalizeForSearch = (str: string) => str.toLowerCase().replace(/[-_\s]/g, "")
+
+	const filteredPreferredIds = useMemo(() => {
+		if (!searchValue.trim()) return preferredModelIds
+		const searchNormalized = normalizeForSearch(searchValue)
+		return preferredModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
+	}, [preferredModelIds, searchValue])
+
+	const filteredRestIds = useMemo(() => {
+		if (!searchValue.trim()) return restModelIds
+		const searchNormalized = normalizeForSearch(searchValue)
+		return restModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
+	}, [restModelIds, searchValue])
Evidence
PR Compliance ID 8 requires tests for non-trivial behavior changes; the PR introduces new search
normalization/filtering logic in ModelPicker, while the existing ModelPicker test suite shown
focuses on selection/custom IDs and does not cover the new search matching behavior.

AGENTS.md
webview-ui/src/components/settings/ModelPicker.tsx[101-114]
webview-ui/src/components/settings/tests/ModelPicker.spec.tsx[74-151]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ModelPicker` search behavior was changed to be case-insensitive and to normalize separators, but there is no corresponding test coverage validating the new search filtering outcomes.

## Issue Context
The PR introduces `normalizeForSearch()` and uses it to filter both preferred and rest model IDs, which is a behavior change that should be covered to prevent regressions.

## Fix Focus Areas
- webview-ui/src/components/settings/ModelPicker.tsx[101-114]
- webview-ui/src/components/settings/__tests__/ModelPicker.spec.tsx[74-151]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Kimi fallback untested 📘 Rule violation ⛯ Reliability
Description
The PR adds Kimi endpoint detection and fallback model/default model selection for
OpenAICompatible, but existing tests do not validate the new defaultModelId/models behavior
passed to ModelPicker. This can break provider configuration silently if endpoint detection or
merging logic changes.
Code

webview-ui/src/components/settings/providers/OpenAICompatible.tsx[R53-68]

+	const isKimiEndpoint =
+		apiConfiguration.openAiBaseUrl?.toLowerCase().includes("kimi") ||
+		apiConfiguration.openAiBaseUrl?.toLowerCase().includes("moonshot") ||
+		apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.ai") ||
+		apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.cn")
+
+	const modelsToUse = useMemo(() => {
+		const fetchedModels = openAiModels ?? {}
+		if (isKimiEndpoint) {
+			return { ...moonshotModels, ...fetchedModels }
+		}
+		return fetchedModels
+	}, [isKimiEndpoint, openAiModels])
+
+	const defaultModelId = isKimiEndpoint ? moonshotDefaultModelId : "gpt-4o"
+
Evidence
PR Compliance ID 8 requires tests for behavior changes; the PR adds new Kimi endpoint detection and
merges in moonshotModels plus changes the default model, while the current OpenAICompatible
tests shown focus on the includeMaxTokens checkbox and do not assert the new
fallback/default-model behavior.

AGENTS.md
webview-ui/src/components/settings/providers/OpenAICompatible.tsx[53-68]
webview-ui/src/components/settings/providers/tests/OpenAICompatible.spec.tsx[88-160]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`OpenAICompatible` now conditionally merges `moonshotModels` and changes `defaultModelId` when the base URL indicates a Kimi/Moonshot endpoint, but tests do not cover this new behavior.

## Issue Context
The component computes `isKimiEndpoint`, builds `modelsToUse`, and sets `defaultModelId` based on that flag. These changes should be validated in Vitest to prevent regressions.

## Fix Focus Areas
- webview-ui/src/components/settings/providers/OpenAICompatible.tsx[53-68]
- webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx[88-160]গুলো

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Missing i18n key 🐞 Bug ✓ Correctness
Description
ModelPicker now references the translation key settings:modelPicker.matchingModels, but it is not
defined in locale files (at least en), so the UI will likely show the raw key string when searching.
Code

webview-ui/src/components/settings/ModelPicker.tsx[R225-231]

+								{filteredPreferredIds.length > 0 && (
+									<CommandGroup
+										heading={
+											searchValue.trim()
+												? t("settings:modelPicker.matchingModels")
+												: t("settings:modelPicker.recommendedModels")
+										}>
Evidence
The UI renders t("settings:modelPicker.matchingModels") when searchValue.trim() is non-empty,
but the English locale modelPicker section contains only recommendedModels and allModels (no
matchingModels), implying the lookup will fail and display the key/fallback.

webview-ui/src/components/settings/ModelPicker.tsx[225-231]
webview-ui/src/i18n/locales/en/settings.json[1107-1116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
ModelPicker renders `t(&quot;settings:modelPicker.matchingModels&quot;)` while searching, but that key is missing from locale JSON files, causing untranslated/raw-key UI text.

### Issue Context
The new label is used when `searchValue.trim()` is truthy.

### Fix Focus Areas
- webview-ui/src/components/settings/ModelPicker.tsx[225-231]
- webview-ui/src/i18n/locales/en/settings.json[1107-1116]
- webview-ui/src/i18n/locales/*/settings.json (add `modelPicker.matchingModels`)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Custom model shown despite matches 🐞 Bug ✓ Correctness
Description
After introducing normalized search (case-insensitive + dash/space removal), the “Use custom model”
option is still gated by exact string equality (modelIds.includes(searchValue)), so it can appear
even when normalized matches exist; selecting it can persist an invalid model id (wrong
casing/spaces).
Code

webview-ui/src/components/settings/ModelPicker.tsx[R101-114]

+	// kilocode_change: Case-insensitive search with dash/space normalization
+	const normalizeForSearch = (str: string) => str.toLowerCase().replace(/[-_\s]/g, "")
+
+	const filteredPreferredIds = useMemo(() => {
+		if (!searchValue.trim()) return preferredModelIds
+		const searchNormalized = normalizeForSearch(searchValue)
+		return preferredModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
+	}, [preferredModelIds, searchValue])
+
+	const filteredRestIds = useMemo(() => {
+		if (!searchValue.trim()) return restModelIds
+		const searchNormalized = normalizeForSearch(searchValue)
+		return restModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
+	}, [restModelIds, searchValue])
Evidence
The PR adds normalized matching that allows inputs like 'kimi k2.5' to match model IDs with
different casing/delimiters, but the custom-model affordance still only checks exact membership. For
OpenAI-compatible settings, the chosen model id is used verbatim from configuration, so selecting a
custom value with spaces/different case can lead to invalid model selection downstream.

webview-ui/src/components/settings/ModelPicker.tsx[101-114]
webview-ui/src/components/settings/ModelPicker.tsx[275-279]
webview-ui/src/components/ui/hooks/useSelectedModel.ts[337-346]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
With normalized searching, users can type strings that match existing models but are not an exact model id. The UI still offers “Use custom: &lt;typed&gt;”, which can cause users to save an invalid model id (spaces/wrong casing) even though a correct model is available.

### Issue Context
The filter now uses `normalizeForSearch(...)` but the custom option uses `!modelIds.includes(searchValue)`.

### Fix Focus Areas
- webview-ui/src/components/settings/ModelPicker.tsx[101-114]
- webview-ui/src/components/settings/ModelPicker.tsx[275-279]

Potential fix approaches:
- Gate the custom option on `(filteredPreferredIds.length + filteredRestIds.length) === 0`.
- Or suppress if any `modelIds` has `normalizeForSearch(id) === normalizeForSearch(searchValue)`.
- Consider trimming `searchValue` before persisting as a custom model id.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +101 to +114
// kilocode_change: Case-insensitive search with dash/space normalization
const normalizeForSearch = (str: string) => str.toLowerCase().replace(/[-_\s]/g, "")

const filteredPreferredIds = useMemo(() => {
if (!searchValue.trim()) return preferredModelIds
const searchNormalized = normalizeForSearch(searchValue)
return preferredModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
}, [preferredModelIds, searchValue])

const filteredRestIds = useMemo(() => {
if (!searchValue.trim()) return restModelIds
const searchNormalized = normalizeForSearch(searchValue)
return restModelIds.filter((id) => normalizeForSearch(id).includes(searchNormalized))
}, [restModelIds, searchValue])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. modelpicker search untested 📘 Rule violation ⛯ Reliability

The PR changes ModelPicker search behavior to be case-insensitive and normalize dashes/spaces, but
there are no updated/additional tests asserting the new matching behavior. This risks regressions
where searches may not return expected models across different casing/formatting.
Agent Prompt
## Issue description
`ModelPicker` search behavior was changed to be case-insensitive and to normalize separators, but there is no corresponding test coverage validating the new search filtering outcomes.

## Issue Context
The PR introduces `normalizeForSearch()` and uses it to filter both preferred and rest model IDs, which is a behavior change that should be covered to prevent regressions.

## Fix Focus Areas
- webview-ui/src/components/settings/ModelPicker.tsx[101-114]
- webview-ui/src/components/settings/__tests__/ModelPicker.spec.tsx[74-151]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +53 to +68
const isKimiEndpoint =
apiConfiguration.openAiBaseUrl?.toLowerCase().includes("kimi") ||
apiConfiguration.openAiBaseUrl?.toLowerCase().includes("moonshot") ||
apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.ai") ||
apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.cn")

const modelsToUse = useMemo(() => {
const fetchedModels = openAiModels ?? {}
if (isKimiEndpoint) {
return { ...moonshotModels, ...fetchedModels }
}
return fetchedModels
}, [isKimiEndpoint, openAiModels])

const defaultModelId = isKimiEndpoint ? moonshotDefaultModelId : "gpt-4o"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Kimi fallback untested 📘 Rule violation ⛯ Reliability

The PR adds Kimi endpoint detection and fallback model/default model selection for
OpenAICompatible, but existing tests do not validate the new defaultModelId/models behavior
passed to ModelPicker. This can break provider configuration silently if endpoint detection or
merging logic changes.
Agent Prompt
## Issue description
`OpenAICompatible` now conditionally merges `moonshotModels` and changes `defaultModelId` when the base URL indicates a Kimi/Moonshot endpoint, but tests do not cover this new behavior.

## Issue Context
The component computes `isKimiEndpoint`, builds `modelsToUse`, and sets `defaultModelId` based on that flag. These changes should be validated in Vitest to prevent regressions.

## Fix Focus Areas
- webview-ui/src/components/settings/providers/OpenAICompatible.tsx[53-68]
- webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx[88-160]গুলো

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +225 to +231
{filteredPreferredIds.length > 0 && (
<CommandGroup
heading={
searchValue.trim()
? t("settings:modelPicker.matchingModels")
: t("settings:modelPicker.recommendedModels")
}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Missing i18n key 🐞 Bug ✓ Correctness

ModelPicker now references the translation key settings:modelPicker.matchingModels, but it is not
defined in locale files (at least en), so the UI will likely show the raw key string when searching.
Agent Prompt
### Issue description
ModelPicker renders `t("settings:modelPicker.matchingModels")` while searching, but that key is missing from locale JSON files, causing untranslated/raw-key UI text.

### Issue Context
The new label is used when `searchValue.trim()` is truthy.

### Fix Focus Areas
- webview-ui/src/components/settings/ModelPicker.tsx[225-231]
- webview-ui/src/i18n/locales/en/settings.json[1107-1116]
- webview-ui/src/i18n/locales/*/settings.json (add `modelPicker.matchingModels`)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@jeremylongshore jeremylongshore merged commit da1e679 into main Feb 15, 2026
16 checks passed
@jeremylongshore jeremylongshore deleted the review/PR-5704 branch February 15, 2026 20:44
@jeremylongshore
Copy link
Copy Markdown
Owner Author

Review Summary

Aspect Assessment
Verdict REQUEST_CHANGES
Confidence 5/5
Blocking Issues 1
Non-blocking Issues 3

Multi-AI analysis: Fork PR reviewed by Gemini, Qodo

Checklist

Check Result Notes
Correctness PARTIAL Missing i18n key will show raw key string in UI
Conventions PASS Follows existing ModelPicker and provider patterns
Changeset PASS Two changesets: webview-ui (patch) and kilo-code (patch)
Tests MISSING No tests for new search normalization or Kimi fallback logic
i18n FAIL settings:modelPicker.matchingModels key not defined in locale files
Types PASS TypeScript compiles clean (22/22 packages)
Security PASS No auth or data handling changes
Scope PASS Two related improvements in 2 UI files + 2 changesets

Findings

1. Missing i18n key matchingModels (blocking)

The PR introduces a new heading when search is active:

searchValue.trim()
  ? t("settings:modelPicker.matchingModels")
  : t("settings:modelPicker.recommendedModels")

The key settings:modelPicker.matchingModels does not exist in webview-ui/src/i18n/locales/en/settings.json. The modelPicker section contains recommendedModels and allModels but not matchingModels. The UI will render the raw key string when a user types in the model search box.

Fix: Add "matchingModels": "Matching models" to the modelPicker section in en/settings.json and all other locale files.

2. normalizeForSearch re-created on every render (non-blocking)

const normalizeForSearch = (str: string) => str.toLowerCase().replace(/[-_\s]/g, "")

This function is defined inside the component body, so it's recreated on every render. Since filteredPreferredIds and filteredRestIds use useMemo with normalizeForSearch in their closures, the function identity doesn't affect memoization correctness here — useMemo deps are [preferredModelIds, searchValue], not the function itself. But moving normalizeForSearch outside the component (as a module-level utility) would be cleaner.

Gemini flagged this as high priority. It's a valid code quality suggestion but not a correctness bug.

3. Redundant endpoint checks (non-blocking)

const isKimiEndpoint =
  apiConfiguration.openAiBaseUrl?.toLowerCase().includes("kimi") ||
  apiConfiguration.openAiBaseUrl?.toLowerCase().includes("moonshot") ||
  apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.ai") ||
  apiConfiguration.openAiBaseUrl?.toLowerCase().includes("api.moonshot.cn")

The api.moonshot.ai and api.moonshot.cn checks are redundant — both are substrings of strings that already match includes("moonshot"). These two lines can be removed.

4. No tests for new behavior (non-blocking)

Both the search normalization logic in ModelPicker.tsx and the Kimi endpoint detection/fallback in OpenAICompatible.tsx lack test coverage. The existing ModelPicker.spec.tsx tests cover selection and custom IDs but not the new search matching behavior. Given the PR's scope (fix, not feature), this is a recommendation, not a blocker.

Local Verification

We merged this PR on our fork and ran the full test suite.

Regression (existing tests)

Test Command Result Details
TypeScript pnpm check-types PASS 22/22 packages
Lint pnpm lint PASS 18/18 packages
Unit Tests pnpm test --continue PASS 7,831 tests, 0 failures

Tested on fork branch review/PR-5704

CI Status

Check Result
Upstream CI PASS (11/11 — all checks green)
Fork CI PR #15
Local verification PASS (7,831 tests, 0 failures)

Code Analysis

Search normalization (ModelPicker.tsx)

The core improvement — normalizeForSearch strips dashes, underscores, and spaces, then lowercases. This means:

  • "kimi k2.5" matches "kimi-k2.5" (space → dash normalization)
  • "KimiK2" matches "kimi-k2-thinking" (case + dash normalization)
  • "gpt 4o" matches "gpt-4o" (general improvement)

The PR disables the built-in Command component's shouldFilter={false} and implements custom filtering via useMemo. This is the correct approach — the built-in filter doesn't support normalization.

Kimi fallback (OpenAICompatible.tsx)

Detects Kimi/Moonshot endpoints by URL substring matching, then:

  1. Merges moonshotModels as fallback (spread before fetchedModels so fetched models take precedence)
  2. Sets moonshotDefaultModelId instead of "gpt-4o" as the default

The key prop on ModelPicker forces a re-render when the base URL changes or endpoint type changes, preventing stale model lists.

Verdict

REQUEST_CHANGES — The search normalization and Kimi fallback logic are both correct and well-implemented. All existing tests pass. However, the missing matchingModels i18n key is a user-visible bug — the model picker heading will show a raw translation key when searching. Once the locale key is added, this is a clean approval.


@jeremylongshore
Copy link
Copy Markdown
Owner Author

Review Journal: kilocode Kilo-Org#5704

PR: #5704 |
Author: @Patel230 | Size: 74 lines, 4 files | Confidence: 5/5

Summary

Two related UX improvements: case-insensitive model search with dash/space normalization in ModelPicker, and Kimi/Moonshot fallback models in OpenAICompatible provider. Both work correctly and all 7,831 tests pass. REQUEST_CHANGES because the PR references an i18n key (matchingModels) that doesn't exist in any locale file — the model picker heading will show a raw key string when a user searches.

What Changed

Four files, 64 additions, 10 deletions. Two distinct improvements:

Search normalization (ModelPicker.tsx): Adds normalizeForSearch() that strips dashes, underscores, spaces and lowercases. Custom filtering via useMemo replaces the built-in Command filter (shouldFilter={false}). Changes heading from "Recommended models" to "Matching models" when search is active — but the i18n key for "Matching models" was never added to locale files.

Kimi fallback (OpenAICompatible.tsx): Detects Kimi/Moonshot endpoints by URL substring. Merges moonshotModels as fallback (fetched models take precedence via spread order). Sets moonshotDefaultModelId instead of "gpt-4o". Adds a key prop to force ModelPicker re-render when endpoint type changes.

Two changesets included — one for webview-ui (search), one for kilo-code (Kimi fallback).

Analysis

The search normalization is the kind of small UX fix that has outsized impact. Model IDs in the AI provider ecosystem use every delimiter convention — gpt-4o, claude_3_opus, kimi k2.5. Normalizing all three (-, _, space) to nothing before comparison means users don't have to guess the exact format. The implementation is correct: useMemo with [preferredModelIds, searchValue] deps ensures filtering only recalculates when inputs change.

The Kimi fallback addresses a real pain point: if the API fetch fails (network issues, auth problems), users see zero models. By merging moonshotModels as a base, Kimi endpoint users always have something to select. The spread order { ...moonshotModels, ...fetchedModels } is correct — fetched models override fallbacks when available.

Gemini flagged normalizeForSearch being defined inside the component as a performance issue. Technically it's recreated on every render, but since it's not in the useMemo dependency arrays, this doesn't affect memoization correctness. It's a code cleanliness point, not a bug.

The i18n bug is the one real issue. The PR adds t("settings:modelPicker.matchingModels") but never defines the key. The en/settings.json modelPicker section has recommendedModels and allModels but not matchingModels. This will show a raw key string like settings:modelPicker.matchingModels in the heading when a user types in the search box.

Verification

Regression (existing tests)

Test Command Result Details
TypeScript pnpm check-types PASS 22/22 packages
Lint pnpm lint PASS 18/18 packages
Unit Tests pnpm test --continue PASS 7,831 tests, 0 failures

Pre-existing failures (not from this PR)

Package Issue
@kilocode/core-schemas No test files (pre-existing)
@kilocode/agent-runtime VSCode.applyEdit.spec.js path issue (pre-existing)

Bot Review Synthesis

Bot Verdict Key Finding Useful?
Gemini COMMENTED normalizeForSearch re-created on every render; redundant moonshot URL checks Valid suggestions, not blockers
Qodo COMMENTED 2 bugs (missing i18n key, missing tests), 2 rule violations Caught the i18n bug — useful
CodeRabbit RATE LIMITED Did not review N/A

Qodo caught the missing i18n key — the most impactful finding. Gemini's endpoint redundancy flag is correct but cosmetic. Both bots flagged missing tests, which is fair for a tier 3 PR but not unusual for UI fixes in this codebase.

Lessons Learned

  • When adding conditional UI text (different heading based on state), the i18n key must exist in locale files. This is easy to miss when the fallback branch already has a key.
  • Qodo's "Bug" category is worth reading even on small PRs — it caught a user-visible issue that manual review might skip.
  • Command component's built-in filtering can be overridden with shouldFilter={false} and custom useMemo filtering — this is the correct pattern for non-standard matching.

Review #22 of 75 | Multi-AI analysis | Methodology

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants