From 372b9c91fef44772e4ca0bce72da90034f20e70c Mon Sep 17 00:00:00 2001 From: Barragek0 Date: Tue, 18 Aug 2026 14:44:40 +0100 Subject: [PATCH 1/2] fix(thinking): force think-tag stripping for subagent/tool-call requests --- src/core/transport.ts | 6 ++++++ src/provider/OpenCodeProvider.ts | 13 +++++++++++-- src/transports/anthropic.ts | 2 +- src/transports/chatCompletions.ts | 2 +- src/transports/google.ts | 2 +- src/transports/responses.ts | 2 +- src/transports/thinkTags.ts | 9 +++++++-- 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/core/transport.ts b/src/core/transport.ts index 1efbb85..0cab2e2 100644 --- a/src/core/transport.ts +++ b/src/core/transport.ts @@ -42,6 +42,12 @@ export interface StreamRequestOptions { * - "always" — strip for every model */ stripThinkTags?: "never" | "auto" | "always"; + /** + * Force think-tag stripping regardless of stripThinkTags mode. + * Set to true when the request is a subagent/tool-call invocation + * to prevent tags in content from rendering as blank code blocks. + */ + forceStripThinkTags?: boolean; } export interface TransportRequestSummary { diff --git a/src/provider/OpenCodeProvider.ts b/src/provider/OpenCodeProvider.ts index 96d80a0..34948cb 100644 --- a/src/provider/OpenCodeProvider.ts +++ b/src/provider/OpenCodeProvider.ts @@ -678,8 +678,8 @@ export class OpenCodeProvider implements vscode.LanguageModelChatProvider 0) { this.log( `Models registered: count=${String(registeredCount)} provider=${this.definition.vendor}` + - ` first=${firstModelId} last=${lastModelId}` + - (this.definition.isAgentVariant ? " (agents)" : ""), + ` first=${firstModelId} last=${lastModelId}` + + (this.definition.isAgentVariant ? " (agents)" : ""), ); } @@ -901,6 +901,11 @@ export class OpenCodeProvider implements vscode.LanguageModelChatProvider tags + // in content from rendering as blank code blocks in the chat UI. + const isToolCallRequest = Array.isArray(options.tools) && options.tools.length > 0; + const forceStripThinkTags = isToolCallRequest || undefined; if (routing.endpointKind === "messages") { await runStreamAnthropicMessages({ @@ -921,6 +926,7 @@ export class OpenCodeProvider implements vscode.LanguageModelChatProvider { this.storeReasoningContent(toolCallIds, reasoningContent); }, @@ -971,6 +978,7 @@ export class OpenCodeProvider implements vscode.LanguageModelChatProvider { this.storeReasoningContent(toolCallIds, reasoningContent); }, @@ -997,6 +1005,7 @@ export class OpenCodeProvider implements vscode.LanguageModelChatProvider { this.storeReasoningContent(toolCallIds, reasoningContent); diff --git a/src/transports/anthropic.ts b/src/transports/anthropic.ts index 2318286..01e5b8e 100644 --- a/src/transports/anthropic.ts +++ b/src/transports/anthropic.ts @@ -6,7 +6,7 @@ import { extractAnthropicParts } from "./extract"; /** Anthropic Messages API transport (Claude-family / MiniMax m2.x / Qwen 3.x-plus). */ export async function streamAnthropicMessages(options: StreamRequestOptions): Promise { - const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId); + const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId, options.forceStripThinkTags); const extractor = new AnthropicResponseExtractor( options.onReasoningContent, createReasoningDebugger(options.output, options.debugReasoning), diff --git a/src/transports/chatCompletions.ts b/src/transports/chatCompletions.ts index 64afce1..c10fcab 100644 --- a/src/transports/chatCompletions.ts +++ b/src/transports/chatCompletions.ts @@ -8,7 +8,7 @@ import { reportProgressPart } from "./streamParts"; /** OpenAI-compatible chat-completions transport. */ export async function streamChatCompletions(options: StreamRequestOptions): Promise { - const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId); + const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId, options.forceStripThinkTags); // Display decision: whether `reasoning_content` should be surfaced as visible // text instead of a thinking part. Computed UPSTREAM by the thinking provider // strategy from the resolved thinking config — not inferred from the body diff --git a/src/transports/google.ts b/src/transports/google.ts index 14c2ab5..715c0ad 100644 --- a/src/transports/google.ts +++ b/src/transports/google.ts @@ -7,7 +7,7 @@ import { extractChatCompletionParts } from "./extract"; /** Google Generative Language API transport (Gemini via Zen). */ export async function streamGoogleGenerateContent(options: StreamRequestOptions): Promise { - const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId); + const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId, options.forceStripThinkTags); const extractor = new OpenAiResponseExtractor( options.onReasoningContent, createReasoningDebugger(options.output, options.debugReasoning), diff --git a/src/transports/responses.ts b/src/transports/responses.ts index 1d9204b..b20df01 100644 --- a/src/transports/responses.ts +++ b/src/transports/responses.ts @@ -7,7 +7,7 @@ import { extractChatCompletionParts } from "./extract"; /** OpenAI Responses API transport (GPT-family models). */ export async function streamResponsesApi(options: StreamRequestOptions): Promise { - const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId); + const thinkFilter = createThinkTagFilter(options.stripThinkTags, options.modelId, options.forceStripThinkTags); const extractor = new OpenAiResponseExtractor( options.onReasoningContent, createReasoningDebugger(options.output, options.debugReasoning), diff --git a/src/transports/thinkTags.ts b/src/transports/thinkTags.ts index 784bf1f..195f4b9 100644 --- a/src/transports/thinkTags.ts +++ b/src/transports/thinkTags.ts @@ -32,8 +32,13 @@ export function shouldStripThinkTags(mode: "never" | "auto" | "always" | undefin return /^minimax-m/i.test(modelId); } -export function createThinkTagFilter(mode: "never" | "auto" | "always" | undefined, modelId: string): ThinkTagFilter | undefined { - return shouldStripThinkTags(mode, modelId) ? new ThinkTagFilter() : undefined; +export function createThinkTagFilter( + mode: "never" | "auto" | "always" | undefined, + modelId: string, + forceOverride?: boolean, +): ThinkTagFilter | undefined { + const effective = forceOverride ? "always" : mode; + return shouldStripThinkTags(effective, modelId) ? new ThinkTagFilter() : undefined; } export class ThinkTagFilter { From 34e887fa83d1c6cf692cb13d24010aa4cb72a3c1 Mon Sep 17 00:00:00 2001 From: Barragek0 Date: Tue, 18 Aug 2026 15:08:11 +0100 Subject: [PATCH 2/2] style: fix prettier formatting in OpenCodeProvider.ts --- src/provider/OpenCodeProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/provider/OpenCodeProvider.ts b/src/provider/OpenCodeProvider.ts index 34948cb..237c1e8 100644 --- a/src/provider/OpenCodeProvider.ts +++ b/src/provider/OpenCodeProvider.ts @@ -678,8 +678,8 @@ export class OpenCodeProvider implements vscode.LanguageModelChatProvider 0) { this.log( `Models registered: count=${String(registeredCount)} provider=${this.definition.vendor}` + - ` first=${firstModelId} last=${lastModelId}` + - (this.definition.isAgentVariant ? " (agents)" : ""), + ` first=${firstModelId} last=${lastModelId}` + + (this.definition.isAgentVariant ? " (agents)" : ""), ); }