Skip to content

feat: Load dynamic model list from LM Studio#9558

Open
ricardofiorani wants to merge 7 commits intoKilo-Org:mainfrom
ricardofiorani:get-updated-list-from-lm-studio
Open

feat: Load dynamic model list from LM Studio#9558
ricardofiorani wants to merge 7 commits intoKilo-Org:mainfrom
ricardofiorani:get-updated-list-from-lm-studio

Conversation

@ricardofiorani
Copy link
Copy Markdown
Contributor

Context

LM Studio appeared as a provider in the models list but only showed static placeholder models from a snapshot instead of the user's actual local models. Users expected the model picker to reflect what was loaded in their local LM Studio instance.

Implementation

Added dynamic model discovery for LM Studio by:

  1. New fetchOpenAICompatibleModels() helper in model-cache.ts that queries any OpenAI-compatible /models endpoint. Uses Bun.fetch (global fetch was unreliable in the bundled binary context). Returns a Record<string, Model> with sensible defaults.

  2. Refactored fetchApertisModels() to reuse the new helper, reducing code duplication.

  3. Added lmstudio case to the fetchModels() dispatcher and auth resolution in getAuthOptions() supporting config, auth, and env sources (LMSTUDIO_API_KEY, LMSTUDIO_BASE_URL).

  4. Dynamic injection in ModelsDev.get() — when LM Studio is allowed by enabled_providers/disabled_providers config, attempts to fetch models from http://127.0.0.1:1234/v1 (or custom baseURL). On success, replaces snapshot models; on failure, gracefully falls back to snapshot.

Also fixed a pre-existing typecheck failure in packages/app/src/custom-elements.d.ts (broken symlink → reference directive).

Screenshots

before after
image image
3 static placeholder models (openai/gpt-oss-20b, qwen/qwen3-30b-a3b-2507, qwen/qwen3-coder-30b) 39 actual models from local LM Studio instance

How to Test

  1. Start LM Studio with at least one model loaded
  2. Build the project: bun run --cwd packages/opencode build
  3. Run: .\packages\opencode\dist\@kilocode\cli-windows-x64\bin\kilo.exe models lmstudio
  4. Verify output lists the actual models from your LM Studio instance (not placeholder snapshot models)
  5. Stop LM Studio, run again — should fall back to snapshot models gracefully
  6. Test with a custom baseURL in config: set provider.lmstudio.options.baseURL in .kilocode/config.json

Get in Touch

@ricardofiorani on the Kilo Code Discord

@ricardofiorani ricardofiorani changed the title Get updated list from lm studio feat: Load dynamic model list from LM Studio Apr 27, 2026
}

try {
const lmstudioModels = await ModelCache.fetch("lmstudio", lmstudioFetchOptions).catch(() => ({}))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we log errors?

if (Object.keys(apertisModels).length === 0) {
ModelCache.refresh("apertis", apertisFetchOptions).catch(() => {})
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We can't accept those changes without kilocode change markers and a changelog


// LM Studio dynamic model discovery
if (lmstudioAllowed) {
const lmstudioConfig = config.provider?.lmstudio?.options
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The logic looks pretty duplicated to below, please generalize if possible


return models
async function fetchApertisModels(options: any): Promise<Record<string, any>> {
return fetchOpenAICompatibleModels({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Refactor removes the Apertis API-key guard

Before this helper was generalized, fetchApertisModels() returned early when apiKey was missing. After this change we still call https://api.apertis.ai/v1/models without auth, and models.ts immediately schedules a second refresh() because the cached result is empty. That turns an unconfigured provider into repeated failing network traffic on every startup.

// LM Studio dynamic model discovery
if (lmstudioAllowed) {
const lmstudioConfig = config.provider?.lmstudio?.options
const lmstudioBaseURL = lmstudioConfig?.baseURL ?? "http://127.0.0.1:1234/v1"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: LMSTUDIO_BASE_URL can fetch models from one endpoint and send requests to another

ModelCache.fetch("lmstudio", ...) resolves baseURL from config, auth, and LMSTUDIO_BASE_URL, but lmstudioBaseURL here only reads config.provider?.lmstudio?.options. If a user sets only LMSTUDIO_BASE_URL, discovery will hit that URL while provider.api still stays on http://127.0.0.1:1234/v1, so the selected model can be listed from one server and invoked against another.

@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 27, 2026

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/provider/model-cache.ts 233 Apertis now calls /models without an API key, causing repeated failing refresh traffic for an unconfigured provider
packages/opencode/src/provider/models.ts 264 LMSTUDIO_BASE_URL affects model discovery but not provider.api, so listed models can be invoked against a different endpoint
Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
None n/a No additional off-diff issues found
Files Reviewed (3 files)
  • packages/app/src/custom-elements.d.ts - 0 issues
  • packages/opencode/src/provider/model-cache.ts - 1 issue
  • packages/opencode/src/provider/models.ts - 1 issue

Fix these issues in Kilo Cloud


Reviewed by gpt-5.4-2026-03-05 · 758,991 tokens

@ricardofiorani
Copy link
Copy Markdown
Contributor Author

@marius-kilocode thank you for the review! (I'm also sorry it's a bit sloppy, in the rush to use this myself I completely disregarded coding styles and everything else in the rulebook)

I'm AFK due to sickness this week, so I'll update my PR prob next week! (Sorry about that)

Best regards,
Ricardo

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