Repository navigation
Description
Summary
On the first message of a session OpenCode sends a background session-title request to the provider. Unlike the main agent request, this request contains no max_completion_tokens (and no stop), so on a local thinking model it enters an unbounded reasoning loop: the model generates thousands of reasoning_content tokens for ~10 minutes and never emits a title. It also competes for CPU with the main request, slowing the actual chat response to ~1 tok/s.
Environment
- opencode version: 2.0.26
- OS: Linux 7.2.9-arch1-1 (x86_64, Arch Linux)
- Terminal: TERM=xterm-256color, COLORTERM=truecolor
- Shell: /usr/bin/bash
- Install/channel: latest (release)
- Active plugins: none found in config
Provider: LM Studio (Bionic 1.1.8) local server at http://localhost:1235/v1, model qwen3.5-4b@q4_k_m (unsloth Qwen3.5-4B GGUF, Q4_K_M, CPU-only llama.cpp).
Reproduction
- Configure LM Studio with a thinking model and point the
lmstudioprovider at it (~/.config/opencode/opencode.jsonsetsmodel: "lmstudio/qwen3.5-4b@q4_k_m"). - Start opencode, create a new session, send a first message (e.g.
hello). - Watch the LM Studio server log (
~/.lmstudio/apps/bionic/server-logs/): twoPOST /v1/chat/completionsarrive at the same time — the main agent request, and a second one whose body is only:
{ "model": "qwen3.5-4b@q4_k_m",
"messages": [
{ "role": "system", "content": "You are a title generator. You output ONLY a thread title..." },
{ "role": "user", "content": "hello" }
],
"stream": true,
"stream_options": { "include_usage": true },
"store": false }- The title request keeps streaming
reasoning_contentfor many minutes.
Note the contrast with the main agent request, which does send "max_completion_tokens": 16384 (or 32000).
Expected Behavior
Session title generation should be a small, bounded request: a low output limit (e.g. max_completion_tokens: 64-128), stop sequences, and/or reasoning disabled for this auxiliary call. It should finish in seconds and not delay the main conversation.
Actual Behavior
- The title request runs effectively unbounded (only the model context limits it).
- Observed runs in LM Studio logs: one title run generating 1747 tokens over 5 minutes before a lucky stop; another never completing at all.
- A direct replay of the exact title request shape against the same model: after 75 seconds it had emitted ~870 tokens of pure
reasoning_contentat ~13 tok/s and still had not produced any title output (the model loops over draft titles in its thinking: "Let's go with 'Hello greeting'. Actually, 'Hello message' sounds better..."). Extrapolated, 10 minutes ≈ 8000-9000 tokens, matching what is observed in the UI. - Generation stops only when the HTTP client disconnects (
Client disconnected. Stopping generation...in the LM Studio log); OpenCode keeps the connection open. - Because llama.cpp here is CPU-only, the parallel title request halves the generation speed of the main request: the reply to
hellowas generated at 1.08 tok/s while the title run was active.
Additional Context
- LM Studio logs show a related warning for this model:
Reasoning setting 'medium' is not supported ... Falling back to reasoning setting 'on'— reasoning is always on for these requests, which is what the title request runs away into. The model is a hybrid thinking model (Qwen3.5), so even withoutreasoning_effortit producesreasoning_contentfirst. - Separately (may deserve its own issue): on the first message the main agent request is sent twice, byte-identical, about 1-2 seconds apart. Only one of the two starts generation; the other is dropped/queued.
- Workarounds tried: none effective; disabling reasoning in LM Studio's model loadout or capping output tokens server-side would mask the symptom.
- Logs used for this report (LM Studio side logs full request bodies):
~/.lmstudio/apps/bionic/server-logs/2026-10/. Prompts and tool schemas elided above.
Activity
opencode-agent commentedon Oct 10, 2026
Thanks for the detailed report, it made this easy to confirm.
I reproduced it with a fake LM Studio server that logs request bodies. The model was
lmstudio/qwen3.5-4b@q4_k_m, and I senthelloonce:max_completion_tokens,max_tokensorstop. The main agent request in the same run hadmax_completion_tokensof about 27k.dev(7b3d4ce): same result.In the code, the output limit is only applied to the main agent request and to compaction, so title requests go out with no limit. With a thinking model, nothing stops the title request until the model's context runs out. I couldn't run a real thinking model here, so I confirmed the missing limit but not the long reasoning loop itself.
The script below reproduces it.
The duplicated main request on the first message is probably a separate problem; please open a separate issue for it.
Related: #54185 (title agent replies conversationally), #53536 (think tags in auto-titles).
Reproduction script (repro.sh)
Run it:
bash repro.shpxzleo commentedon Oct 16, 2026
Additional real-model confirmation on OpenCode v2.0.29 on Windows, using the OpenCode executable bundled with OpenChamber. In this case, a background title consumed 36,127 completion tokens and 501.5 seconds, occupying the local backend's only inference slot while the main task waited.
Environment and observed request
qwen3.8-flash-next-unsloth-ud-q5_k_xl.context: 262144,output: 32768; normal task reasoning variant:high.limit.output.stopThe backend's effective maximum is consistent with its fallback for an omitted output limit:
262144 - 712 - 8 = 261424. Consequently, the title could exceed the configured 32,768 model output limit and still finish normally. These are completion-token counts, not the length of the visible title.To distinguish this from a long main-agent response, I reconciled a consistent read-only SQLite snapshot: the session's accumulated usage was 20,872 input / 120,290 output, while its 24 ordinary assistant records summed to 20,160 input / 84,163 output. The difference is exactly 712 input / 36,127 output, matching the backend request. The title implementation accounts for title usage at session level without adding an ordinary assistant reply. The request also began immediately after session creation.
Version-specific source confirmation
In v2.0.29 session/model-request.ts, only
primaryandcompactioninitially receivemaxTokens;titleandgeneratestart with empty options. The OpenAI protocol conversion therefore has no generation limit to serialize for the unmodified title request.The runner starts title generation asynchronously, but application-side concurrency does not prevent slot contention: on a single-slot local server, a title that gets the slot first still delays the useful task for the full generation duration. This reproduces the impact on a GPU-backed server as well as the original CPU-only report.
Local mitigation verification, separate from the proposed upstream PRs
I tested a temporary user-directory
session.titleplugin with the actual installed v2.0.29 executable, an isolated configuration/database, and a fake OpenAI-compatible backend. It waits for the current session's agent loop to become idle, then setsmaxTokens: 128andreasoningEffort: "none"for a compatible model with an explicit supported off setting. Observed wire order and parameters:max_completion_tokens: 32768,reasoning_effort: "high".max_completion_tokens: 128,reasoning_effort: "none".For an unverified/no-off configuration, the plugin returns a short local title instead of making a title model call; the isolated test observed only the main request. This is a local mitigation test, not a test of either upstream PR.
The bounded title budget in #54411 and lower-reasoning selection in #51939 both seem relevant. A small title-specific cap plus a provider-supported non-thinking mode would address the two causes without reducing normal task output/reasoning settings. Giving auxiliary titles lower priority is also valuable for single-slot backends. No private prompts, conversation text, credentials, or full logs are included here.
fix(core): bound session title generation with a small output limit
fix(core): size the title cap to leave room for a thinking budget
fix(core): bound session title generation with a small output limit
fix(core): size the title cap to leave room for a thinking budget