LM Studio Copilot Provider

Configure one or more LM Studio instances in VS Code settings. Each instance can use a different address and API key:
{
"lmStudio.instances": [
{
"name": "Workstation",
"url": "http://192.168.1.12:1234",
"apiKey": "<workstation-api-key>"
},
{
"name": "Second server",
"url": "http://192.168.1.13:1234",
"apiKey": "<second-server-api-key>"
}
]
}
Reload VS Code after installation, then open Copilot Chat's standard model selector. Discovered models appear under LM Studio. Use LM Studio: Refresh Models to refresh every configured server without restarting VS Code.
The list also refreshes automatically every 60 seconds. Set lmStudio.modelRefreshIntervalSeconds to another interval,
or to 0 to disable background synchronization. A new poll starts only after the previous poll finishes, and temporarily
unreachable instances keep their last known models. Changing LM Studio settings triggers an immediate refresh.
The provider reads each model's architecture, maximum context, loaded context, vision support, and tool-use support from LM Studio's native /api/v1/models endpoint. With multiple configured servers, model names receive an instance suffix: <model-key>/<instance.name>. The suffix is hidden when only one instance is configured. For loaded models, the advertised context uses loaded_instances[].config.context_length; unloaded models use max_context_length. Embedding models are not exposed as chat models.
Optional per-instance overrides can be configured alongside the URL:
{
"family": "qwen",
"version": "1"
}
maxOutputTokens is sent to LM Studio's Responses API as max_output_tokens. If it is omitted, the default is
4096 for smaller or unknown contexts and 16384 when the currently loaded (or advertised fallback) context is at
least 65536 tokens. An explicitly configured value always wins.
The provider uses /v1/responses and reads each model's advertised reasoning modes. By default,
lmStudio.showReasoning is enabled and streamed reasoning appears in VS Code's collapsible thinking section.
lmStudio.reasoningEffort controls the default minimal, low, medium, high, or xhigh effort. Reasoning-capable
models also expose a per-model Reasoning effort selector in VS Code's model picker; its value is persisted by VS Code
and overrides the global default for that model. The available entries are derived from LM Studio's advertised
capabilities. Models advertising the generic on mode expose the concrete effort values accepted by the Responses API.
Changing the effort starts a stateless turn with the complete chat history; stored continuation resumes only when the
instance, model, and effective effort all match. This prevents an earlier response's reasoning state from being reused
after a level switch. A persisted value unsupported by another selected model is normalized to that model's default.
If the installed VS Code build does not expose the thinking-part API, the provider emits a visible Markdown reasoning
block instead. Disabling showReasoning makes none the default when supported.
The thinking-part API is still proposed in VS Code 1.134; launch Code with
code --enable-proposed-api MikhailKashin.lms-copilot-provider to use its native disclosure UI. Normal launches remain
functional and use the visible Markdown fallback because stable VS Code has no collapsible response-part API.
The modern path leaves tool_choice in automatic mode, so capable models can select the right tool, while an explicit
workspace action adds an instruction that prose alone cannot complete the request. Streamed final text and reasoning
are held until the result is known. Reasoning does not count toward the safety threshold and may legitimately precede
a tool call; only tentative final text is stopped after 1024 buffered characters. If the automatic attempt still omits
a tool, the provider retries once through Responses with required tool choice and reasoning disabled. This behavioral
miss is never remembered as evidence that the model needs a legacy protocol. Gemma models, whose LM Studio Responses
endpoint may ignore required tools and continue generating text, use the streamed Chat Completions tool path directly.
The provider does not truncate the tool array; large-context models receive every tool supplied by VS Code.
Responses are stored by LM Studio and the provider emits VS Code's stateful_marker. On the next agent step it sends
only new tool results or messages with previous_response_id, preserving the model's reasoning state and allowing LM
Studio to reuse its prompt cache. If an older LM Studio server rejects stateful fields, the provider retries once with
the complete stateless history and caches that compatibility decision for the model.
Set lmStudio.unloadPreviousModelOnSwitch to true to keep a single provider model loaded per LM Studio instance.
Before serving a newly selected model, the provider refreshes the instance, unloads other loaded chat-model instances
through /api/v1/models/unload, and then loads the selected model. Requests on one instance are serialized. A short
grace period suppresses the zero-tool background request Copilot Chat sends to the previous model during a switch, so
manually unloading all models followed by selecting another model does not trigger two competing loads. The setting is
off by default because unloading a model can affect other applications sharing the same LM Studio server.
When the provider loads a model, it sends only the model key. LM Studio remains the source of truth for the context
size and applies its own server-side default; the provider never sends context_length or reloads a model to change
its context. Once loaded, VS Code is given the actual loaded_instances[].config.context_length reported by LM Studio.
The provider caches that actual value while the model remains loaded and refreshes it during instance discovery and
load polling. If no actual loaded value is known, it uses the model maximum reported as max_context_length without
caching that fallback. A server-side context rejection is rendered as a short recovery message instead of exposing an
exception and extension stack trace in chat.
After every completed response, the provider records LM Studio's actual usage.input_tokens. The model detail and
tooltip are refreshed with Context N% and the exact last-request input/output/reasoning token counts. The same usage
is emitted to VS Code so the session context indicator updates after every completed model turn. This value is
authoritative for the last request; before the first completed request the tooltip explicitly says that no usage is
available. lmStudio.requestTimeoutMs (120000 by default) limits discovery, load, and other non-streaming API requests.
Inference through both the Responses API and the Chat Completions compatibility path uses
lmStudio.inferenceIdleTimeoutMs (600000 by default): the timer resets whenever LM Studio sends a stream chunk, so an
active generation can run for any total duration. The compatibility path requests streamed tool calls, reconstructs
fragmented arguments before running any tool, and explicitly disables reasoning so its bounded output budget is
reserved for the required tool call. Set the idle timeout to 0 to disable it. VS Code cancellation still aborts the
active stream immediately.
If a model spends its entire output budget on reasoning and completes without text or a tool call, the provider retries
that inference step once with reasoning disabled and an explicit instruction to return the final answer immediately.
For models such as GPT-OSS that expose only low, medium, and high in the selector, the recovery request still uses
LM Studio's accepted none control so it cannot exhaust the retry budget at low a second time.
This prevents the retry from exhausting the same budget on reasoning again. A second empty result becomes a normal
assistant fallback message, so VS Code does not display an exception card and previously completed tool calls or
workspace edits remain intact. Malformed JSON tool arguments receive the same single reasoning-free recovery, with a
required tool call; if recovery also fails, the invalid tool is not run and chat receives a safe diagnostic message.
Connection, authentication, cancellation, and server failures are still real errors.
For an explicit workspace action, the primary Responses request keeps automatic tool selection but includes a clear
instruction that a tool call is required to complete the action. Reasoning may precede that call and is not counted as
tentative final text. If the model nevertheless completes or prints too much final text without a tool, the provider
discards the tentative output and retries once through Responses with required tool choice and reasoning disabled.
A missed automatic call never permanently reclassifies a modern model as legacy; streamed Chat Completions compatibility
is reserved for model families covered by the provider's explicit compatibility policy.
Connection and request errors identify the affected instance by name and endpoint.
VS Code stores configuration values in its settings files. Restrict access to those files when API keys are configured.