From beef72ead7dc8860cd35f210badec0f05f3eaf75 Mon Sep 17 00:00:00 2001 From: Chaos Date: Tue, 4 Aug 2026 11:08:38 +0200 Subject: [PATCH] fix(openai): preserve reasoning for local OpenAI-compatible models via R1 toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The openAiR1FormatEnabled toggle (UI + provider-settings) only forced the R1 request format, but getModel() never set info.preserveReasoning. As a result Task.ts (shouldPreserveForApi = info.preserveReasoning === true) stripped reasoning_content from follow-up context for every local OpenAI-compatible reasoning model (llama.cpp, LM Studio, Ollama) — there was no way to feed the chain back. Enable the toggle and getModel() now sets preserveReasoning: true so the reasoning chain is preserved in the next-turn context. Default behaviour unchanged. --- src/api/providers/__tests__/openai.spec.ts | 14 ++++++++++++++ src/api/providers/openai.ts | 10 +++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/api/providers/__tests__/openai.spec.ts b/src/api/providers/__tests__/openai.spec.ts index 3e18f03a4c..ec4daef5d9 100644 --- a/src/api/providers/__tests__/openai.spec.ts +++ b/src/api/providers/__tests__/openai.spec.ts @@ -837,6 +837,20 @@ describe("OpenAiHandler", () => { expect(model.id).toBe("") expect(model.info).toBeDefined() }) + + it("should set preserveReasoning when openAiR1FormatEnabled is on", () => { + const r1Handler = new OpenAiHandler({ + ...mockOptions, + openAiR1FormatEnabled: true, + }) + const model = r1Handler.getModel() + expect(model.info.preserveReasoning).toBe(true) + }) + + it("should not set preserveReasoning by default", () => { + const model = handler.getModel() + expect(model.info.preserveReasoning).toBeUndefined() + }) }) describe("Azure AI Inference Service", () => { diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index 9545068794..0774642bcf 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -293,7 +293,15 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl settings: this.options, defaultTemperature: 0, }) - return { id, info, ...params } + // Local OpenAI-compatible reasoning models (llama.cpp, LM Studio, Ollama) + // stream reasoning_content, but Roo strips it from the follow-up context + // unless info.preserveReasoning is set. When the user enables the R1 format + // toggle, treat the model as preserving reasoning so the chain is fed back. + return { + id, + info: this.options.openAiR1FormatEnabled ? { ...info, preserveReasoning: true } : info, + ...params, + } } async completePrompt(prompt: string, options?: CompletePromptOptions): Promise {