Skip to content

Mirror: Dynamic OpenAI compatible model fetching on front page (#5562)#12

Closed
jeremylongshore wants to merge 5 commits intomainfrom
review/PR-5562
Closed

Mirror: Dynamic OpenAI compatible model fetching on front page (#5562)#12
jeremylongshore wants to merge 5 commits intomainfrom
review/PR-5562

Conversation

@jeremylongshore
Copy link
Copy Markdown
Owner

@jeremylongshore jeremylongshore commented Feb 14, 2026

Mirror of Kilo-Org#5562

Field Value
Upstream PR #5562
Author @crazyrabbit0
Category feature
Tier 3
Size 59 lines, 4 files

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

Changes

Adds dynamic model fetching for OpenAI-compatible providers. When base URL and API key are configured, the extension fetches available models from the provider's /v1/models endpoint and displays them in the model dropdown.

Bot Review Tracker

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

Links

Summary by CodeRabbit

  • New Features

    • Added support for dynamic OpenAI model fetching for OpenAI-compatible providers, automatically retrieving available models at runtime.
  • Tests

    • Added comprehensive unit tests for OpenAI model fetching functionality.
  • Chores

    • Updated internal configuration to support OpenAI models state management.

zachariouv-mpass and others added 4 commits January 30, 2026 22:44
Add support for dynamically fetching and displaying models from OpenAI-compatible providers.

- Add openAiModels field to ExtensionState and context
- Implement debounced model fetching request in ExtensionStateContext
- Update useProviderModels hook to prioritize fetched models for OpenAI providers
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 14, 2026

📝 Walkthrough

Walkthrough

This pull request implements dynamic OpenAI model fetching for the extension. It extends the extension state type with an openAiModels property, adds hooks to retrieve and manage dynamically fetched models, integrates model fetching into the state context with debounced requests, and includes comprehensive unit tests.

Changes

Cohort / File(s) Summary
Type Definitions
packages/types/src/vscode-extension-host.ts, .changeset/dynamic-openai-model-fetching.md
Added openAiModels?: string[] property to ExtensionState type; includes changeset metadata documenting the feature.
Hook Implementation & Tests
webview-ui/src/components/kilocode/hooks/useProviderModels.ts, webview-ui/src/components/kilocode/hooks/__tests__/dynamic-openai-models.spec.ts
Extended getModelsByProvider signature to accept optional openAiModels array and map them to sane defaults; added comprehensive unit tests covering provided models, empty states, and default configurations.
State Management
webview-ui/src/context/ExtensionStateContext.tsx
Added openAiModels state property with message handling; implemented debounced fetching of models on startup/config changes when OpenAI provider is active; integrated useDebounce hook and request-response pattern.

Sequence Diagram

sequenceDiagram
    participant Extension as Extension Host
    participant Context as ExtensionStateContext
    participant Hook as useProviderModels
    participant Backend as API/Backend

    Extension->>Context: Initialize with config (apiProvider, baseUrl)
    Context->>Context: Hydrate state
    activate Context
    Context->>Context: Debounced effect triggered<br/>(apiProvider is "openai"?)
    alt When OpenAI provider detected
        Context->>Backend: requestOpenAiModels(baseUrl, apiKey, headers)
        Backend-->>Context: Returns model list (openAiModels)
        Context->>Context: Update state with openAiModels
        Context-->>Hook: Broadcast updated ExtensionState
    else When non-OpenAI provider
        Context->>Context: Skip fetch
    end
    deactivate Context
    
    Hook->>Hook: Read openAiModels from context
    Hook->>Hook: getModelsByProvider(provider, routerModels, ..., openAiModels)
    alt When openAiModels provided
        Hook->>Hook: Map models to sane defaults
        Hook->>Hook: Set first model as defaultModel
    else When openAiModels empty/missing
        Hook->>Hook: Return empty models map
    end
    Hook-->>Extension: Return mapped models
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A dash of dynamism hops our way,
OpenAI models now fetch and play,
Debounced and dapper with state so bright,
Hook and context dance through the night,
More options bloom where choices take flight! 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (422 files):

⚔️ .devcontainer/devcontainer.json (content)
⚔️ .github/copilot-instructions.md (content)
⚔️ .github/dependabot.yml (content)
⚔️ .gitignore (content)
⚔️ .kilocode/skills/translation/SKILL.md (content)
⚔️ .kilocode/workflows/add-missing-translations.md (content)
⚔️ AGENTS.md (content)
⚔️ CHANGELOG.md (content)
⚔️ CONTRIBUTING.md (content)
⚔️ README.md (content)
⚔️ apps/kilocode-docs/AGENTS.md (content)
⚔️ apps/kilocode-docs/README.md (content)
⚔️ apps/kilocode-docs/components/CodeBlock.tsx (content)
⚔️ apps/kilocode-docs/components/Image.tsx (content)
⚔️ apps/kilocode-docs/components/SideNav.tsx (content)
⚔️ apps/kilocode-docs/components/TopNav.tsx (content)
⚔️ apps/kilocode-docs/lib/nav/automate.ts (content)
⚔️ apps/kilocode-docs/lib/nav/code-with-ai.ts (content)
⚔️ apps/kilocode-docs/lib/nav/collaborate.ts (content)
⚔️ apps/kilocode-docs/lib/nav/contributing.ts (content)
⚔️ apps/kilocode-docs/lib/nav/customize.ts (content)
⚔️ apps/kilocode-docs/lib/nav/getting-started.ts (content)
⚔️ apps/kilocode-docs/lib/nav/index.ts (content)
⚔️ apps/kilocode-docs/lib/types.ts (content)
⚔️ apps/kilocode-docs/mappingplan.md (content)
⚔️ apps/kilocode-docs/pages/_app.tsx (content)
⚔️ apps/kilocode-docs/pages/ai-providers/kilocode.md (content)
⚔️ apps/kilocode-docs/pages/ai-providers/ollama.md (content)
⚔️ apps/kilocode-docs/pages/ai-providers/v0.md (content)
⚔️ apps/kilocode-docs/pages/ai-providers/virtual-quota-fallback.md (content)
⚔️ apps/kilocode-docs/pages/automate/code-reviews.md (content)
⚔️ apps/kilocode-docs/pages/automate/extending/shell-integration.md (content)
⚔️ apps/kilocode-docs/pages/automate/how-tools-work.md (content)
⚔️ apps/kilocode-docs/pages/automate/mcp/using-in-kilo-code.md (content)
⚔️ apps/kilocode-docs/pages/automate/tools/codebase-search.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/agents/chat-interface.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/agents/free-and-budget-models.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/agents/model-selection.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/agents/using-modes.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/features/autocomplete/index.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/features/autocomplete/mistral-setup.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/features/browser-use.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/features/checkpoints.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/features/task-todo-list.md (content)
⚔️ apps/kilocode-docs/pages/code-with-ai/platforms/cli.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/adoption-dashboard/overview.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/adoption-dashboard/understanding-your-score.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/enterprise/audit-logs.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/enterprise/model-access-controls.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/enterprise/sso.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/teams/about-plans.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/teams/dashboard.md (content)
⚔️ apps/kilocode-docs/pages/collaborate/teams/getting-started.md (content)
⚔️ apps/kilocode-docs/pages/contributing/architecture/index.md (content)
⚔️ apps/kilocode-docs/pages/contributing/development-environment.md (content)
⚔️ apps/kilocode-docs/pages/contributing/index.md (content)
⚔️ apps/kilocode-docs/pages/customize/agents-md.md (content)
⚔️ apps/kilocode-docs/pages/customize/context/codebase-indexing.md (content)
⚔️ apps/kilocode-docs/pages/customize/custom-modes.md (content)
⚔️ apps/kilocode-docs/pages/customize/custom-rules.md (content)
⚔️ apps/kilocode-docs/pages/customize/index.md (content)
⚔️ apps/kilocode-docs/pages/deploy-secure/deploy.md (content)
⚔️ apps/kilocode-docs/pages/getting-started/faq.md (content)
⚔️ apps/kilocode-docs/pages/getting-started/installing.md (content)
⚔️ apps/kilocode-docs/pages/getting-started/quickstart.md (content)
⚔️ apps/kilocode-docs/pages/index.tsx (content)
⚔️ apps/kilocode-docs/previous-docs-redirects.js (content)
⚔️ apps/kilocode-docs/public/globals.css (content)
⚔️ apps/kilocode-docs/public/img/checkpoints/checkpoints.png (content)
⚔️ apps/kilocode-docs/public/img/context-mentions/context-mentions-6.png (content)
⚔️ apps/kilocode-docs/public/img/custom-instructions/custom-instructions.png (content)
⚔️ apps/kilocode-docs/public/img/fast-edits/fast-edits-5.png (content)
⚔️ apps/web-roo-code/src/app/pricing/page.tsx (content)
⚔️ cli/src/commands/checkpoint.ts (content)
⚔️ cli/src/config/mapper.ts (content)
⚔️ cli/src/constants/providers/labels.ts (content)
⚔️ cli/src/constants/providers/models.ts (content)
⚔️ cli/src/constants/providers/settings.ts (content)
⚔️ cli/src/constants/providers/validation.ts (content)
⚔️ cli/src/services/__tests__/autocomplete.detectInputState.test.ts (content)
⚔️ cli/src/state/hooks/__tests__/useSessionCost.test.ts (content)
⚔️ jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/commands/SetContextCommands.kt (content)
⚔️ jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/core/ContextManager.kt (content)
⚔️ jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/inline/InlineCompletionConstants.kt (content)
⚔️ jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/inline/InlineCompletionService.kt (content)
⚔️ jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/inline/KiloCodeInlineCompletionProvider.kt (content)
⚔️ jetbrains/plugin/src/test/kotlin/ai/kilocode/jetbrains/util/ReflectUtilsStatusBarTest.kt (content)
⚔️ jetbrains/plugin/turbo.json (content)
⚔️ package.json (content)
⚔️ packages/core-schemas/src/agent-manager/types.ts (content)
⚔️ packages/core-schemas/src/config/provider.ts (content)
⚔️ packages/core/src/message-utils/consolidateTokenUsage.ts (content)
⚔️ packages/types/package.json (content)
⚔️ packages/types/src/__tests__/kilocode.test.ts (content)
⚔️ packages/types/src/codebase-index.ts (content)
⚔️ packages/types/src/embedding.ts (content)
⚔️ packages/types/src/global-settings.ts (content)
⚔️ packages/types/src/kilocode/kiloLanguages.ts (content)
⚔️ packages/types/src/kilocode/kilocode.ts (content)
⚔️ packages/types/src/model.ts (content)
⚔️ packages/types/src/provider-settings.ts (content)
⚔️ packages/types/src/providers/anthropic.ts (content)
⚔️ packages/types/src/providers/fireworks.ts (content)
⚔️ packages/types/src/providers/index.ts (content)
⚔️ packages/types/src/providers/mistral.ts (content)
⚔️ packages/types/src/providers/moonshot.ts (content)
⚔️ packages/types/src/providers/openai-codex.ts (content)
⚔️ packages/types/src/providers/vertex.ts (content)
⚔️ packages/types/src/providers/zai.ts (content)
⚔️ packages/types/src/vscode-extension-host.ts (content)
⚔️ packages/types/src/vscode.ts (content)
⚔️ pnpm-lock.yaml (content)
⚔️ src/__tests__/extension.spec.ts (content)
⚔️ src/api/index.ts (content)
⚔️ src/api/providers/__tests__/bedrock-custom-arn.spec.ts (content)
⚔️ src/api/providers/__tests__/chutes.spec.ts (content)
⚔️ src/api/providers/__tests__/fireworks.spec.ts (content)
⚔️ src/api/providers/__tests__/kilocode-openrouter.spec.ts (content)
⚔️ src/api/providers/__tests__/mistral-fim.spec.ts (content)
⚔️ src/api/providers/__tests__/moonshot.spec.ts (content)
⚔️ src/api/providers/__tests__/openai-codex.spec.ts (content)
⚔️ src/api/providers/__tests__/zai.spec.ts (content)
⚔️ src/api/providers/anthropic-vertex.ts (content)
⚔️ src/api/providers/anthropic.ts (content)
⚔️ src/api/providers/chutes.ts (content)
⚔️ src/api/providers/fetchers/__tests__/ollama.test.ts (content)
⚔️ src/api/providers/fetchers/modelCache.ts (content)
⚔️ src/api/providers/fetchers/ollama.ts (content)
⚔️ src/api/providers/index.ts (content)
⚔️ src/api/providers/kilocode-openrouter.ts (content)
⚔️ src/api/providers/mistral.ts (content)
⚔️ src/api/providers/moonshot.ts (content)
⚔️ src/api/providers/nano-gpt.ts (content)
⚔️ src/api/providers/openrouter.ts (content)
⚔️ src/api/providers/zai.ts (content)
⚔️ src/api/transform/__tests__/model-params.spec.ts (content)
⚔️ src/api/transform/__tests__/reasoning.spec.ts (content)
⚔️ src/api/transform/model-params.ts (content)
⚔️ src/api/transform/openai-format.ts (content)
⚔️ src/api/transform/reasoning.ts (content)
⚔️ src/assets/icons/kilo-dark.svg (content)
⚔️ src/assets/icons/kilo-light.svg (content)
⚔️ src/core/assistant-message/NativeToolCallParser.ts (content)
⚔️ src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts (content)
⚔️ src/core/assistant-message/presentAssistantMessage.ts (content)
⚔️ src/core/auto-approval/commands.ts (content)
⚔️ src/core/condense/__tests__/index.spec.ts (content)
⚔️ src/core/condense/index.ts (content)
⚔️ src/core/kilocode/agent-manager/AgentManagerProvider.ts (content)
⚔️ src/core/kilocode/agent-manager/AgentRegistry.ts (content)
⚔️ src/core/kilocode/agent-manager/RuntimeProcessHandler.ts (content)
⚔️ src/core/prompts/commands.ts (content)
⚔️ src/core/prompts/responses.ts (content)
⚔️ src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts (content)
⚔️ src/core/prompts/sections/tool-use-guidelines.ts (content)
⚔️ src/core/task-persistence/taskMetadata.ts (content)
⚔️ src/core/task/Task.ts (content)
⚔️ src/core/task/__tests__/Task.spec.ts (content)
⚔️ src/core/tools/ExecuteCommandTool.ts (content)
⚔️ src/core/tools/__tests__/editFileTool.spec.ts (content)
⚔️ src/core/webview/ClineProvider.ts (content)
⚔️ src/core/webview/__tests__/ClineProvider.apiHandlerRebuild.spec.ts (content)
⚔️ src/core/webview/__tests__/ClineProvider.spec.ts (content)
⚔️ src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts (content)
⚔️ src/core/webview/__tests__/ClineProvider.sticky-profile.spec.ts (content)
⚔️ src/core/webview/__tests__/webviewMessageHandler.spec.ts (content)
⚔️ src/core/webview/sttHandlers.ts (content)
⚔️ src/core/webview/webviewMessageHandler.ts (content)
⚔️ src/esbuild.mjs (content)
⚔️ src/eslint.config.mjs (content)
⚔️ src/extension.ts (content)
⚔️ src/i18n/locales/ar/embeddings.json (content)
⚔️ src/i18n/locales/ar/kilocode.json (content)
⚔️ src/i18n/locales/ca/embeddings.json (content)
⚔️ src/i18n/locales/ca/kilocode.json (content)
⚔️ src/i18n/locales/cs/embeddings.json (content)
⚔️ src/i18n/locales/cs/kilocode.json (content)
⚔️ src/i18n/locales/de/embeddings.json (content)
⚔️ src/i18n/locales/de/kilocode.json (content)
⚔️ src/i18n/locales/en/embeddings.json (content)
⚔️ src/i18n/locales/en/kilocode.json (content)
⚔️ src/i18n/locales/es/embeddings.json (content)
⚔️ src/i18n/locales/es/kilocode.json (content)
⚔️ src/i18n/locales/fr/embeddings.json (content)
⚔️ src/i18n/locales/fr/kilocode.json (content)
⚔️ src/i18n/locales/hi/embeddings.json (content)
⚔️ src/i18n/locales/hi/kilocode.json (content)
⚔️ src/i18n/locales/id/embeddings.json (content)
⚔️ src/i18n/locales/id/kilocode.json (content)
⚔️ src/i18n/locales/it/embeddings.json (content)
⚔️ src/i18n/locales/it/kilocode.json (content)
⚔️ src/i18n/locales/ja/embeddings.json (content)
⚔️ src/i18n/locales/ja/kilocode.json (content)
⚔️ src/i18n/locales/ko/embeddings.json (content)
⚔️ src/i18n/locales/ko/kilocode.json (content)
⚔️ src/i18n/locales/nl/embeddings.json (content)
⚔️ src/i18n/locales/nl/kilocode.json (content)
⚔️ src/i18n/locales/pl/embeddings.json (content)
⚔️ src/i18n/locales/pl/kilocode.json (content)
⚔️ src/i18n/locales/pt-BR/embeddings.json (content)
⚔️ src/i18n/locales/pt-BR/kilocode.json (content)
⚔️ src/i18n/locales/ru/embeddings.json (content)
⚔️ src/i18n/locales/ru/kilocode.json (content)
⚔️ src/i18n/locales/th/embeddings.json (content)
⚔️ src/i18n/locales/th/kilocode.json (content)
⚔️ src/i18n/locales/tr/embeddings.json (content)
⚔️ src/i18n/locales/tr/kilocode.json (content)
⚔️ src/i18n/locales/uk/embeddings.json (content)
⚔️ src/i18n/locales/uk/kilocode.json (content)
⚔️ src/i18n/locales/vi/embeddings.json (content)
⚔️ src/i18n/locales/vi/kilocode.json (content)
⚔️ src/i18n/locales/zh-CN/embeddings.json (content)
⚔️ src/i18n/locales/zh-CN/kilocode.json (content)
⚔️ src/i18n/locales/zh-TW/embeddings.json (content)
⚔️ src/i18n/locales/zh-TW/kilocode.json (content)
⚔️ src/integrations/terminal/ShellIntegrationManager.ts (content)
⚔️ src/integrations/terminal/TerminalProcess.ts (content)
⚔️ src/integrations/terminal/__tests__/TerminalProcess.spec.ts (content)
⚔️ src/integrations/theme/getTheme.ts (content)
⚔️ src/package.json (content)
⚔️ src/package.nls.ar.json (content)
⚔️ src/package.nls.ca.json (content)
⚔️ src/package.nls.cs.json (content)
⚔️ src/package.nls.de.json (content)
⚔️ src/package.nls.es.json (content)
⚔️ src/package.nls.fr.json (content)
⚔️ src/package.nls.hi.json (content)
⚔️ src/package.nls.id.json (content)
⚔️ src/package.nls.it.json (content)
⚔️ src/package.nls.ja.json (content)
⚔️ src/package.nls.json (content)
⚔️ src/package.nls.ko.json (content)
⚔️ src/package.nls.nl.json (content)
⚔️ src/package.nls.pl.json (content)
⚔️ src/package.nls.pt-BR.json (content)
⚔️ src/package.nls.ru.json (content)
⚔️ src/package.nls.th.json (content)
⚔️ src/package.nls.tr.json (content)
⚔️ src/package.nls.uk.json (content)
⚔️ src/package.nls.vi.json (content)
⚔️ src/package.nls.zh-CN.json (content)
⚔️ src/package.nls.zh-TW.json (content)
⚔️ src/services/code-index/__tests__/service-factory.spec.ts (content)
⚔️ src/services/code-index/config-manager.ts (content)
⚔️ src/services/code-index/embedders/ollama.ts (content)
⚔️ src/services/code-index/interfaces/config.ts (content)
⚔️ src/services/code-index/interfaces/embedder.ts (content)
⚔️ src/services/code-index/interfaces/manager.ts (content)
⚔️ src/services/code-index/service-factory.ts (content)
⚔️ src/services/command/__tests__/built-in-commands.spec.ts (content)
⚔️ src/services/command/built-in-commands.ts (content)
⚔️ src/services/roo-config/__tests__/index.spec.ts (content)
⚔️ src/services/roo-config/index.ts (content)
⚔️ src/services/skills/SkillsManager.ts (content)
⚔️ src/services/stt/context/__tests__/codeGlossaryExtractor.spec.ts (content)
⚔️ src/services/stt/context/codeGlossaryExtractor.ts (content)
⚔️ src/shared/api.ts (content)
⚔️ src/shared/embeddingModels.ts (content)
⚔️ src/shared/kilocode/errorUtils.ts (content)
⚔️ src/shared/kilocode/getTaskHistory.ts (content)
⚔️ src/shared/kilocode/headers.ts (content)
⚔️ src/shared/kilocode/kiloLanguages.ts (content)
⚔️ src/shared/support-prompt.ts (content)
⚔️ src/test-llm-autocompletion/README.md (content)
⚔️ src/test-llm-autocompletion/approvals.spec.ts (content)
⚔️ src/test-llm-autocompletion/llm-client.ts (content)
⚔️ src/test-llm-autocompletion/mock-context-provider.ts (content)
⚔️ src/test-llm-autocompletion/package.json (content)
⚔️ src/test-llm-autocompletion/runner.ts (content)
⚔️ src/test-llm-autocompletion/utils.ts (content)
⚔️ src/vitest.config.ts (content)
⚔️ webview-ui/package.json (content)
⚔️ webview-ui/src/App.tsx (content)
⚔️ webview-ui/src/__tests__/App.spec.tsx (content)
⚔️ webview-ui/src/components/chat/AutoApproveDropdown.tsx (content)
⚔️ webview-ui/src/components/chat/ChatRow.tsx (content)
⚔️ webview-ui/src/components/chat/ChatTextArea.tsx (content)
⚔️ webview-ui/src/components/chat/ChatView.tsx (content)
⚔️ webview-ui/src/components/chat/CodeIndexPopover.tsx (content)
⚔️ webview-ui/src/components/chat/ReasoningBlock.tsx (content)
⚔️ webview-ui/src/components/chat/ReviewScopeSelector.tsx (content)
⚔️ webview-ui/src/components/chat/TaskHeader.tsx (content)
⚔️ webview-ui/src/components/chat/__tests__/ReviewScopeSelector.spec.tsx (content)
⚔️ webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx (content)
⚔️ webview-ui/src/components/chat/checkpoints/CheckpointSaved.tsx (content)
⚔️ webview-ui/src/components/chat/context-management/CondensationResultRow.tsx (content)
⚔️ webview-ui/src/components/history/BatchDeleteTaskDialog.tsx (content)
⚔️ webview-ui/src/components/history/HistoryView.tsx (content)
⚔️ webview-ui/src/components/history/TaskItemFooter.tsx (content)
⚔️ webview-ui/src/components/history/__tests__/BatchDeleteTaskDialog.spec.tsx (content)
⚔️ webview-ui/src/components/history/__tests__/TaskItem.spec.tsx (content)
⚔️ webview-ui/src/components/history/__tests__/TaskItemFooter.spec.tsx (content)
⚔️ webview-ui/src/components/kilocode/KiloTaskHeader.tsx (content)
⚔️ webview-ui/src/components/kilocode/chat/IdeaSuggestionsBox.tsx (content)
⚔️ webview-ui/src/components/kilocode/chat/KiloProfileSelector.tsx (content)
⚔️ webview-ui/src/components/kilocode/chat/ModelSelector.tsx (content)
⚔️ webview-ui/src/components/kilocode/hooks/__tests__/getModelsByProvider.spec.ts (content)
⚔️ webview-ui/src/components/kilocode/hooks/useProviderModels.ts (content)
⚔️ webview-ui/src/components/kilocode/hooks/useSelectedModel.ts (content)
⚔️ webview-ui/src/components/kilocode/rules/RuleRow.tsx (content)
⚔️ webview-ui/src/components/marketplace/MarketplaceView.tsx (content)
⚔️ webview-ui/src/components/mcp/McpView.tsx (content)
⚔️ webview-ui/src/components/settings/ApiOptions.tsx (content)
⚔️ webview-ui/src/components/settings/AutoApproveSettings.tsx (content)
⚔️ webview-ui/src/components/settings/ModelPicker.tsx (content)
⚔️ webview-ui/src/components/settings/SettingsSearch.tsx (content)
⚔️ webview-ui/src/components/settings/SettingsSearchInput.tsx (content)
⚔️ webview-ui/src/components/settings/SettingsView.tsx (content)
⚔️ webview-ui/src/components/settings/ThinkingBudget.tsx (content)
⚔️ webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx (content)
⚔️ webview-ui/src/components/settings/__tests__/ThinkingBudget.spec.tsx (content)
⚔️ webview-ui/src/components/settings/constants.ts (content)
⚔️ webview-ui/src/components/settings/providers/Moonshot.tsx (content)
⚔️ webview-ui/src/components/settings/providers/index.ts (content)
⚔️ webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts (content)
⚔️ webview-ui/src/components/ui/hooks/useRouterModels.ts (content)
⚔️ webview-ui/src/components/ui/hooks/useSelectedModel.ts (content)
⚔️ webview-ui/src/context/ExtensionStateContext.tsx (content)
⚔️ webview-ui/src/hooks/useKeybindings.spec.ts (content)
⚔️ webview-ui/src/hooks/useKeybindings.ts (content)
⚔️ webview-ui/src/i18n/locales/ar/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/ar/history.json (content)
⚔️ webview-ui/src/i18n/locales/ar/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/ar/settings.json (content)
⚔️ webview-ui/src/i18n/locales/ca/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/ca/history.json (content)
⚔️ webview-ui/src/i18n/locales/ca/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/ca/settings.json (content)
⚔️ webview-ui/src/i18n/locales/cs/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/cs/history.json (content)
⚔️ webview-ui/src/i18n/locales/cs/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/cs/settings.json (content)
⚔️ webview-ui/src/i18n/locales/de/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/de/history.json (content)
⚔️ webview-ui/src/i18n/locales/de/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/de/settings.json (content)
⚔️ webview-ui/src/i18n/locales/en/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/en/chat.json (content)
⚔️ webview-ui/src/i18n/locales/en/history.json (content)
⚔️ webview-ui/src/i18n/locales/en/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/en/settings.json (content)
⚔️ webview-ui/src/i18n/locales/es/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/es/history.json (content)
⚔️ webview-ui/src/i18n/locales/es/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/es/settings.json (content)
⚔️ webview-ui/src/i18n/locales/fr/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/fr/history.json (content)
⚔️ webview-ui/src/i18n/locales/fr/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/fr/settings.json (content)
⚔️ webview-ui/src/i18n/locales/hi/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/hi/history.json (content)
⚔️ webview-ui/src/i18n/locales/hi/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/hi/settings.json (content)
⚔️ webview-ui/src/i18n/locales/id/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/id/history.json (content)
⚔️ webview-ui/src/i18n/locales/id/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/id/settings.json (content)
⚔️ webview-ui/src/i18n/locales/it/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/it/history.json (content)
⚔️ webview-ui/src/i18n/locales/it/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/it/settings.json (content)
⚔️ webview-ui/src/i18n/locales/ja/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/ja/history.json (content)
⚔️ webview-ui/src/i18n/locales/ja/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/ja/settings.json (content)
⚔️ webview-ui/src/i18n/locales/ko/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/ko/history.json (content)
⚔️ webview-ui/src/i18n/locales/ko/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/ko/settings.json (content)
⚔️ webview-ui/src/i18n/locales/nl/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/nl/history.json (content)
⚔️ webview-ui/src/i18n/locales/nl/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/nl/settings.json (content)
⚔️ webview-ui/src/i18n/locales/pl/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/pl/history.json (content)
⚔️ webview-ui/src/i18n/locales/pl/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/pl/settings.json (content)
⚔️ webview-ui/src/i18n/locales/pt-BR/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/pt-BR/history.json (content)
⚔️ webview-ui/src/i18n/locales/pt-BR/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/pt-BR/settings.json (content)
⚔️ webview-ui/src/i18n/locales/ru/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/ru/history.json (content)
⚔️ webview-ui/src/i18n/locales/ru/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/ru/settings.json (content)
⚔️ webview-ui/src/i18n/locales/th/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/th/history.json (content)
⚔️ webview-ui/src/i18n/locales/th/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/th/settings.json (content)
⚔️ webview-ui/src/i18n/locales/tr/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/tr/history.json (content)
⚔️ webview-ui/src/i18n/locales/tr/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/tr/settings.json (content)
⚔️ webview-ui/src/i18n/locales/uk/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/uk/history.json (content)
⚔️ webview-ui/src/i18n/locales/uk/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/uk/settings.json (content)
⚔️ webview-ui/src/i18n/locales/vi/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/vi/history.json (content)
⚔️ webview-ui/src/i18n/locales/vi/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/vi/settings.json (content)
⚔️ webview-ui/src/i18n/locales/zh-CN/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/zh-CN/history.json (content)
⚔️ webview-ui/src/i18n/locales/zh-CN/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/zh-CN/settings.json (content)
⚔️ webview-ui/src/i18n/locales/zh-TW/agentManager.json (content)
⚔️ webview-ui/src/i18n/locales/zh-TW/history.json (content)
⚔️ webview-ui/src/i18n/locales/zh-TW/kilocode.json (content)
⚔️ webview-ui/src/i18n/locales/zh-TW/settings.json (content)
⚔️ webview-ui/src/kilocode/agent-manager/components/AgentManagerApp.css (content)
⚔️ webview-ui/src/kilocode/agent-manager/components/KiloLogo.tsx (content)
⚔️ webview-ui/src/kilocode/agent-manager/components/MessageList.tsx (content)
⚔️ webview-ui/src/kilocode/agent-manager/components/SessionDetail.tsx (content)
⚔️ webview-ui/src/kilocode/agent-manager/components/SessionSidebar.tsx (content)
⚔️ webview-ui/src/kilocode/agent-manager/components/__tests__/MessageList.spec.tsx (content)
⚔️ webview-ui/src/kilocode/agent-manager/state/atoms/sessions.ts (content)
⚔️ webview-ui/src/utils/__tests__/slash-commands.spec.ts (content)
⚔️ webview-ui/src/utils/__tests__/validate.spec.ts (content)
⚔️ webview-ui/src/utils/costFormatting.ts (content)
⚔️ webview-ui/src/utils/slash-commands.ts (content)
⚔️ webview-ui/src/utils/validate.ts (content)
⚔️ webview-ui/vite.config.ts (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
Description check ❓ Inconclusive The description provides context, implementation details, and links to the upstream PR, but lacks testing instructions, screenshots, and Discord contact information required by the template. Add 'How to Test' section with step-by-step instructions for verifying dynamic model fetching, include before/after screenshots if applicable, and provide a Discord handle for contact.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main feature being implemented—dynamic OpenAI compatible model fetching—and references the upstream PR number.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch review/PR-5562
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch review/PR-5562
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

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 significantly enhances the application's flexibility by introducing dynamic model fetching for OpenAI-compatible providers. Instead of relying on static model lists, the system now retrieves available models directly from the configured API endpoint. This ensures that the user interface always presents the most current model options, improving adaptability to new models and configuration changes without requiring manual updates.

Highlights

  • Dynamic OpenAI Model Fetching: Implemented functionality to dynamically fetch available models from OpenAI-compatible providers' /v1/models endpoint when a base URL and API key are configured.
  • Configuration-Driven Model Display: The model dropdown now displays models retrieved directly from the configured provider, ensuring an up-to-date list of options.
  • Extension State Integration: Integrated openAiModels into the extension's state management, allowing for consistent access and updates across the user interface.
Changelog
  • .changeset/dynamic-openai-model-fetching.md
    • Added a new changeset entry documenting the implementation of dynamic model fetching for OpenAI-compatible providers.
  • packages/types/src/vscode-extension-host.ts
    • Extended the ExtensionState type to include an optional openAiModels array for storing dynamically fetched OpenAI model IDs.
  • webview-ui/src/components/kilocode/hooks/useProviderModels.ts
    • Imported openAiModelInfoSaneDefaults for consistent model information.
    • Modified the getModelsByProvider function to accept and utilize a list of openAiModels when the provider is 'openai'.
    • Updated the useProviderModels hook to retrieve openAiModels from the extension state and pass them to getModelsByProvider.
  • webview-ui/src/context/ExtensionStateContext.tsx
    • Imported the useDebounce hook from react-use to optimize API calls.
    • Added openAiModels to the ExtensionStateContextType interface.
    • Initialized openAiModels as an empty array within the ExtensionStateContextProvider's state.
    • Implemented a new message handler case (openAiModels) to update the state with fetched OpenAI models.
    • Introduced a useDebounce effect that triggers a requestOpenAiModels message to the VS Code API when relevant API configuration settings change, facilitating dynamic model fetching.
Activity
  • This pull request is a mirror of an upstream change from Kilo-Org/kilocode#5562.
  • The PR is currently awaiting review from several automated bots, including 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.

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 dynamic model fetching for OpenAI-compatible providers, which is a great feature. The implementation is solid, but I've identified a couple of areas for improvement. My suggestions focus on making the logic more robust by clearing stale model data when the configuration changes and improving the clarity of the code that handles the fetched models. These changes will enhance the user experience and maintainability.

Comment on lines +187 to +192
if (openAiModels) {
return {
models: Object.fromEntries(openAiModels.map((model) => [model, openAiModelInfoSaneDefaults])),
defaultModel: openAiModels[0] || "",
}
}
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

The if (openAiModels) check is truthy for an empty array. This makes the logic inside the if block redundant for that case, as it produces the same result as the return statement on line 193. It's better to explicitly check if the array has elements for clarity and to avoid the || "" fallback.

            if (openAiModels && openAiModels.length > 0) {
				return {
					models: Object.fromEntries(openAiModels.map((model) => [model, openAiModelInfoSaneDefaults])),
					defaultModel: openAiModels[0],
				}
			}

Comment on lines +565 to +594
useDebounce(
() => {
if (!didHydrateState) {
return
}

const { apiProvider, openAiBaseUrl, openAiApiKey, openAiHeaders } = state.apiConfiguration || {}

if (apiProvider === "openai" || apiProvider === "openai-responses") {
if (openAiBaseUrl) {
vscode.postMessage({
type: "requestOpenAiModels",
values: {
baseUrl: openAiBaseUrl,
apiKey: openAiApiKey,
openAiHeaders,
},
})
}
}
},
500,
[
didHydrateState,
state.apiConfiguration?.apiProvider,
state.apiConfiguration?.openAiBaseUrl,
state.apiConfiguration?.openAiApiKey,
state.apiConfiguration?.openAiHeaders,
],
)
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

The current implementation of the useDebounce hook for fetching OpenAI models doesn't clear the openAiModels state when the user switches to a different provider or removes the openAiBaseUrl. This can lead to stale data being displayed in the UI, which can be confusing. To improve the user experience, the model list should be cleared in these scenarios.

	useDebounce(
		() => {
			if (!didHydrateState) {
				return
			}

			const { apiProvider, openAiBaseUrl, openAiApiKey, openAiHeaders } = state.apiConfiguration || {}

			if (apiProvider === "openai" || apiProvider === "openai-responses") {
				if (openAiBaseUrl) {
					vscode.postMessage({
						type: "requestOpenAiModels",
						values: {
							baseUrl: openAiBaseUrl,
							apiKey: openAiApiKey,
							openAiHeaders,
						},
					})
				} else if (state.openAiModels?.length) {
					// Clear models if base URL is removed for the relevant provider
					setState((prevState) => ({ ...prevState, openAiModels: [] }))
				}
			} else if (state.openAiModels?.length) {
				// Clear models if provider is not OpenAI-compatible
				setState((prevState) => ({ ...prevState, openAiModels: [] }))
			}
		},
		500,
		[
			didHydrateState,
			state.apiConfiguration?.apiProvider,
			state.apiConfiguration?.openAiBaseUrl,
			state.apiConfiguration?.openAiApiKey,
			state.apiConfiguration?.openAiHeaders,
		],
	)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@webview-ui/src/components/kilocode/hooks/__tests__/dynamic-openai-models.spec.ts`:
- Around line 45-57: getModelsByProvider is missing handling for the
"openai-responses" provider so dynamically fetched models passed via
openAiModels get discarded; add a case "openai-responses" in getModelsByProvider
that mirrors the existing "openai" branch (using the openAiModels argument to
populate result.models and result.defaultModel with the same defaults like
contextWindow and supportsImages) or alternatively remove "openai-responses"
from the fetch trigger in ExtensionStateContext so both locations stay
consistent; update getModelsByProvider (and ensure any tests referencing
getModelsByProvider still pass) to reference the openAiModels parameter when
apiProvider === "openai-responses".
🧹 Nitpick comments (2)
webview-ui/src/context/ExtensionStateContext.tsx (1)

564-594: Consider clearing openAiModels when switching away from OpenAI provider.

When the user switches from an OpenAI provider to another provider, the previously fetched openAiModels remain in state. While this is harmless for the current implementation (since getModelsByProvider only uses openAiModels for the "openai" case), it could lead to stale data if the user switches back before a new fetch completes.

♻️ Optional: Clear models when provider changes away from OpenAI
 	useDebounce(
 		() => {
 			if (!didHydrateState) {
 				return
 			}
 
 			const { apiProvider, openAiBaseUrl, openAiApiKey, openAiHeaders } = state.apiConfiguration || {}
 
 			if (apiProvider === "openai" || apiProvider === "openai-responses") {
 				if (openAiBaseUrl) {
 					vscode.postMessage({
 						type: "requestOpenAiModels",
 						values: {
 							baseUrl: openAiBaseUrl,
 							apiKey: openAiApiKey,
 							openAiHeaders,
 						},
 					})
 				}
+			} else {
+				setState((prev) => ({ ...prev, openAiModels: [] }))
 			}
 		},
 		500,
webview-ui/src/components/kilocode/hooks/useProviderModels.ts (1)

186-197: Truthy check on openAiModels treats empty arrays as "provided".

if (openAiModels) is truthy for [], so an empty array returns { models: {}, defaultModel: "" } — which happens to match the fallback. This works but is semantically ambiguous: an empty fetch result and "not yet fetched" produce the same output. If you ever need to distinguish these states (e.g., to show a loading indicator), consider using openAiModels?.length or undefined vs [].

For now this is fine since the tests confirm the expected behavior.

Comment on lines +45 to +57
it("returns dynamically fetched models when openAiModels is provided", () => {
const result = getModelsByProvider({
...baseArgs,
provider: "openai",
openAiModels: ["gpt-4o", "gpt-4o-mini", "o1-preview"],
})

expect(Object.keys(result.models)).toEqual(["gpt-4o", "gpt-4o-mini", "o1-preview"])
expect(result.defaultModel).toBe("gpt-4o")
// Each model should have sane defaults (128K context, supports images)
expect(result.models["gpt-4o"].contextWindow).toBe(128_000)
expect(result.models["gpt-4o"].supportsImages).toBe(true)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if openai-responses is handled in getModelsByProvider
rg -n 'openai-responses' webview-ui/src/components/kilocode/hooks/useProviderModels.ts

Repository: jeremylongshore/kilocode

Length of output: 50


🏁 Script executed:

# Also search for openai-responses more broadly to understand its usage
rg -n 'openai-responses' webview-ui/src/components/kilocode/hooks/ -A 2 -B 2

Repository: jeremylongshore/kilocode

Length of output: 678


🏁 Script executed:

# Check the switch statement in getModelsByProvider to see all cases
fd 'useProviderModels.ts' webview-ui/src/components/kilocode/hooks/ --exec cat -n {} \;

Repository: jeremylongshore/kilocode

Length of output: 11631


🏁 Script executed:

# Check the ExtensionStateContext to see where model fetching is triggered
rg -n 'ExtensionStateContext' webview-ui/src/components/kilocode/ -l

Repository: jeremylongshore/kilocode

Length of output: 1031


🏁 Script executed:

# Search for ExtensionStateContext to find where model fetching is triggered
rg -n 'openai-responses' webview-ui/src/context/ -A 3 -B 3

Repository: jeremylongshore/kilocode

Length of output: 699


🏁 Script executed:

# Also check the ExtensionStateContext file itself for model fetching logic
fd 'ExtensionStateContext' webview-ui/src/ --exec cat -n {} \; | head -600

Repository: jeremylongshore/kilocode

Length of output: 29014


🏁 Script executed:

# Search more broadly for where openAiModels is fetched or populated
rg -n 'openAiModels' webview-ui/src/context/ -A 2 -B 2

Repository: jeremylongshore/kilocode

Length of output: 1261


🏁 Script executed:

# Check if openai-responses is used as a provider anywhere in the codebase
rg -n '"openai-responses"' webview-ui/src --type ts --type tsx -B 2 -A 2

Repository: jeremylongshore/kilocode

Length of output: 95


🏁 Script executed:

# Also check if there's any mention of openai-responses in provider type definitions
rg -n 'openai-responses' --type ts --type tsx -l

Repository: jeremylongshore/kilocode

Length of output: 95


🏁 Script executed:

# Check if openai-responses is used as a provider anywhere in the codebase
rg -n '"openai-responses"' webview-ui/src -B 2 -A 2

Repository: jeremylongshore/kilocode

Length of output: 3569


🏁 Script executed:

# Check if openai-responses is defined in type definitions
fd 'types' webview-ui/src -type d | head -5

Repository: jeremylongshore/kilocode

Length of output: 238


🏁 Script executed:

# Search for ProviderName type definition to see all valid providers
rg -n 'type ProviderName' webview-ui/src -A 30

Repository: jeremylongshore/kilocode

Length of output: 14398


🏁 Script executed:

# Check the complete case for openai-responses in useSelectedModel.ts
sed -n '349,365p' webview-ui/src/components/ui/hooks/useSelectedModel.ts

Repository: jeremylongshore/kilocode

Length of output: 817


🏁 Script executed:

# Check if openAiModels state is used anywhere in useSelectedModel or elsewhere
rg -n 'openAiModels' webview-ui/src/components -B 2 -A 2

Repository: jeremylongshore/kilocode

Length of output: 6925


Add missing case for openai-responses in getModelsByProvider.

The ExtensionStateContext (line 573) triggers model fetching for both "openai" and "openai-responses" providers, but getModelsByProvider only has a case "openai" branch (lines 186-197). When apiProvider is "openai-responses", the function falls through to the default case and returns empty models and defaultModel, silently discarding the dynamically fetched models. Either add a matching case for "openai-responses" that handles the openAiModels parameter, or remove "openai-responses" from the fetch trigger in ExtensionStateContext.

🤖 Prompt for AI Agents
In
`@webview-ui/src/components/kilocode/hooks/__tests__/dynamic-openai-models.spec.ts`
around lines 45 - 57, getModelsByProvider is missing handling for the
"openai-responses" provider so dynamically fetched models passed via
openAiModels get discarded; add a case "openai-responses" in getModelsByProvider
that mirrors the existing "openai" branch (using the openAiModels argument to
populate result.models and result.defaultModel with the same defaults like
contextWindow and supportsImages) or alternatively remove "openai-responses"
from the fetch trigger in ExtensionStateContext so both locations stay
consistent; update getModelsByProvider (and ensure any tests referencing
getModelsByProvider still pass) to reference the openAiModels parameter when
apiProvider === "openai-responses".

@jeremylongshore
Copy link
Copy Markdown
Owner Author

Content pushed directly to main — merge conflict resolved.

@jeremylongshore
Copy link
Copy Markdown
Owner Author

Review Summary

Aspect Assessment
Verdict APPROVE
Confidence 4/5
Blocking Issues 0
Non-blocking Issues 3

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

Checklist

Check Result Notes
Correctness PASS Dynamic model fetching works correctly for openai provider
Conventions PASS Follows existing patterns — same requestOpenAiModels message type used by settings page
Changeset PASS Changeset included for kilo-code and @kilocode/types (patch)
Tests MISSING No tests included by author for the new openAiModels parameter in getModelsByProvider
i18n N/A No user-facing strings added
Types PASS TypeScript compiles clean (22/22 packages)
Security PASS API key handled via existing message channel, no new credential exposure
Scope PASS Well-scoped — frontend wiring to existing backend API

Findings

1. openai-responses provider: fetch without display (non-blocking)

The debounce in ExtensionStateContext.tsx:567 triggers model fetching for both "openai" and "openai-responses":

if (apiProvider === "openai" || apiProvider === "openai-responses") {

But getModelsByProvider only handles case "openai" — there is no case "openai-responses" in the switch statement. Models are fetched from the API but never displayed for this provider. The openai-responses provider falls through to the default case which returns { models: {}, defaultModel: "" }.

Suggestion: Either add case "openai-responses": before case "openai": (fall-through), or remove "openai-responses" from the debounce trigger to avoid the unnecessary API call.

2. API key required by backend but not by all providers (non-blocking)

The backend handler in webviewMessageHandler.ts requires both baseUrl and apiKey:

if (message?.values?.baseUrl && message?.values?.apiKey) {

But the PR description mentions local providers like LM Studio that don't require API keys. The frontend sends the message regardless of apiKey presence (only checks openAiBaseUrl), but the backend silently drops it.

Note: This is a pre-existing backend limitation, not introduced by this PR. The settings page (ApiOptions.tsx) has the same pattern. A follow-up could make the apiKey check optional.

3. Merge conflict (non-blocking)

GitHub reports this PR as CONFLICTING. Needs rebase against current main before merge.

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,803 passed, 85 skipped (pre-existing failures: core-schemas, agent-runtime)

Behavioral (new targeted tests)

Test Case Expected Result
openAiModels: ["gpt-4o", "gpt-4o-mini", "o1-preview"] Models returned with sane defaults (128K context, supports images) PASS
No openAiModels provided Empty models, empty default PASS
openAiModels: [] (empty array) Empty models, empty default PASS

Test file: dynamic-openai-models.spec.ts

Tested on fork branch review/PR-5562

Code Analysis

Architecture

This PR connects the front page model selector to an existing backend API (requestOpenAiModels) that was already used by the settings page. Clean layering:

  1. ExtensionStateContext.tsx — debounced message sender (triggers on config change)
  2. webviewMessageHandler.ts (pre-existing) — fetches from /v1/models endpoint
  3. useProviderModels.ts — consumes openAiModels from state, converts to ModelRecord
  4. vscode-extension-host.ts — adds openAiModels?: string[] to ExtensionState type

Key Design Decisions

  • useDebounce(500ms): Prevents API spam during rapid config changes. Appropriate for text input fields.
  • openAiModelInfoSaneDefaults: Uses 128K context, supports images, $0 pricing. Reasonable for unknown models.
  • State via message channel: Models are fetched on demand and stored in React state, not persisted to disk. Re-fetches on startup via the didHydrateState trigger.

CI Status

Check Result
Upstream CI PASS (11/11 checks)
Merge status CONFLICTING (needs rebase)
Fork CI PR #12
Local verification PASS (all tests)

Verdict

APPROVE — Well-scoped feature that connects the front page to an existing backend API for dynamic model fetching. The openai-responses mismatch is non-blocking and the merge conflict needs resolution by the author. Code follows established patterns and passes all tests.


@jeremylongshore
Copy link
Copy Markdown
Owner Author

Review Journal: kilocode Kilo-Org#5562

PR: #5562 |
Author: @crazyrabbit0 | Size: 59 lines, 4 files | Confidence: 4/5

Summary

Adds dynamic model fetching for the OpenAI provider on the front page. When users configure an OpenAI-compatible base URL, the extension now automatically queries the /v1/models endpoint and populates the model dropdown. We merged this on our fork, ran 7,803 tests, all passed. APPROVE with notes about openai-responses mismatch and merge conflict.

What Changed

The PR connects the front page model selector to an existing backend API that was already used by the settings page. The architecture is clean — four files touched, each with a clear role:

  1. Type extension (vscode-extension-host.ts): Adds openAiModels?: string[] to ExtensionState
  2. State management (ExtensionStateContext.tsx): Debounced effect (500ms) sends requestOpenAiModels when OpenAI config changes
  3. Model consumption (useProviderModels.ts): getModelsByProvider uses openAiModels to build ModelRecord with sane defaults
  4. Changeset: Patch bump for kilo-code and @kilocode/types

The backend handler (webviewMessageHandler.ts) already existed — it fetches from /v1/models, returns model IDs. The settings page already used it. This PR just wires it to the front page too.

Verification

Regression (did we break anything?)

Test Command Result
TypeScript pnpm check-types PASS (22/22 packages)
Lint pnpm lint PASS (18/18 packages)
Unit Tests pnpm test --continue PASS (7,803 tests, 0 failures)
Upstream CI gh pr checks PASS (11/11 checks)

Behavioral (does the feature actually work?)

We wrote 3 targeted tests to verify the getModelsByProvider function:

Test Assertion Result
Models provided Returns all models with 128K context defaults PASS
No models provided Returns empty models and default PASS
Empty array Handles gracefully, returns empty PASS

Test file: dynamic-openai-models.spec.ts

Tested on fork branch review/PR-5562.

Lessons Learned

  • The backend API (requestOpenAiModels) already existed for the settings page. This PR just wires the front page to it. Always check what infrastructure already exists before assuming a PR is incomplete.
  • RouterModels type requires ALL provider keys — can't use a partial mock in tests. The existing test file getModelsByProvider.spec.ts shows the correct pattern.
  • Pre-push hooks (Husky) run check-types and lint — caught our type error before push (second time this happened). The hooks are a safety net worth appreciating.
  • openai-responses has no case in the getModelsByProvider switch at all — not just missing the dynamic models, it has zero model handling. This is a pre-existing gap.

Review #19 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.

3 participants