fix: render think tags as reasoning blocks + fix MCP MaxListeners overflow#15382
Closed
erwinh22 wants to merge 2 commits intoanomalyco:devfrom
Closed
fix: render think tags as reasoning blocks + fix MCP MaxListeners overflow#15382erwinh22 wants to merge 2 commits intoanomalyco:devfrom
erwinh22 wants to merge 2 commits intoanomalyco:devfrom
Conversation
Models that emit <think>/<thinking> tags (e.g. kimi-k2-thinking via NVIDIA NIM) currently display raw tag content in the UI instead of rendering it as collapsible reasoning blocks. The extractReasoningMiddleware was intentionally removed in PR anomalyco#11270 because stripping tags at the middleware layer prevents them from being stored in messages, breaking multi-turn LLM context. This fix takes the rendering-layer approach: tags are preserved in storage for faithful multi-turn context, but parsed and rendered as reasoning blocks at display time in all three rendering surfaces: - TUI: TextPart in session/index.tsx uses splitThinkBlocks() to separate reasoning from display text, rendering reasoning with the same dim/italic styling as native ReasoningPart - Web UI: TextPartDisplay in message-part.tsx renders extracted reasoning in a reasoning-part div above the text content - CLI: run.ts strips think tags from text output and shows reasoning with dim/italic styling when --thinking flag is set Shared utility functions (stripThinkTags, splitThinkBlocks) are added to both @opencode-ai/util/think (for web UI) and the core packages/opencode/src/util/format.ts (for TUI and CLI). Fixes anomalyco#15380 Relates to anomalyco#11439
Contributor
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
This was referenced Feb 27, 2026
Each StdioClientTransport spawns a child process and adds listeners to its stdin/stdout/stderr pipes. The MCP protocol layer also sends many concurrent requests (getPrompt, listTools, etc.) that each add a 'drain' listener on the child process's stdin. With 7+ MCP servers, the default Node.js EventEmitter limit of ~10 is easily exceeded, causing MaxListeners overflow warnings and potential crashes. Dynamically calculate the needed limit based on the number of configured local (stdio) MCP servers and increase both EventEmitter.defaultMaxListeners and process stream limits before connecting.
bb4e9f4 to
c92846c
Compare
Contributor
|
This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window. Feel free to open a new pull request that follows our guidelines. |
|
It would be great to get this landed, it's been a pretty annoying UX issue when using EDIT: I found a workaround in LM Studio at least: |
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two fixes in this PR:
1. Render
<think>tags as reasoning blocks at display layerModels like Kimi K2 Thinking embed reasoning in raw
<think>...</think>tags within text parts. Previously these were displayed as raw HTML to the user.Approach: Parse and render
<think>/<thinking>tags at the display layer (TUI, Web UI, CLI) rather than stripping them from the message storage. This preserves the full model output for multi-turn context while giving users clean, styled reasoning blocks.Changes:
packages/util/src/think.ts-- Shared utility:stripThinkTags(),splitThinkBlocks()with regex matching both<think>and<thinking>variantspackages/opencode/src/util/format.ts-- Same utilities for the core package (@/util/formatpath alias)packages/opencode/src/cli/cmd/tui/routes/session/index.tsx--TextPartrenders think blocks with dim/italic/bordered styling matchingReasoningPartpackages/ui/src/components/message-part.tsx--TextPartDisplayrenders think blocks in<div data-component="reasoning-part">packages/opencode/src/cli/cmd/run.ts-- CLI strips think tags from output, shows reasoning with--thinkingflag2. Fix MCP MaxListeners overflow with many servers
When 7+ stdio-based MCP servers are configured, the default Node.js EventEmitter limit of ~10 is exceeded. Each
StdioClientTransportspawns a child process and adds listeners to its stdin/stdout/stderr pipes. The MCP protocol layer also sends many concurrent requests (getPrompt,listTools, etc.) that each add adrainlistener.Fix: Dynamically calculate the needed listener limit based on the number of configured local MCP servers and increase both
EventEmitter.defaultMaxListenersand process stream limits before connecting.Changes:
packages/opencode/src/mcp/index.ts-- Count local MCP servers, setEventEmitter.defaultMaxListenersand process stream limits proportionallyRelated Issues
<think>and<thinking>tags as reasoning blocks #11439 (think tag rendering regression from removal ofextractReasoningMiddleware)Testing
bun turbo typecheck-- 0 errors in opencode and ui packages