diff --git a/core/llm/index.ts b/core/llm/index.ts index f7d97b73e3c..d917a273520 100644 --- a/core/llm/index.ts +++ b/core/llm/index.ts @@ -964,6 +964,11 @@ export abstract class BaseLLM implements ILLM { ) { let completion = ""; for await (const message of this.streamChat(messages, signal, options)) { + // Skip thinking/reasoning messages so the returned completion only + // contains the visible assistant response, not internal reasoning text. + if (message.role === "thinking") { + continue; + } completion += renderChatMessage(message); } return { role: "assistant" as const, content: completion }; diff --git a/core/util/chatDescriber.test.ts b/core/util/chatDescriber.test.ts index 64ba683143e..0c48a5a6063 100644 --- a/core/util/chatDescriber.test.ts +++ b/core/util/chatDescriber.test.ts @@ -65,5 +65,23 @@ describe("ChatDescriber", () => { ChatDescriber.describe(testLLM, completionOptions, message), ).rejects.toThrow(); }); + + it("should exclude thinking/reasoning content from the generated title", async () => { + const message = "Help me write a sorting algorithm"; + + // Simulate a model that emits a thinking chunk followed by an assistant chunk + testLLM.chatStreams = [ + [ + { role: "thinking", content: "Here is my thinking process, I need to consider various sorting algorithms..." }, + { role: "assistant", content: "Sorting Algorithm Help" }, + ], + ]; + + const result = await ChatDescriber.describe(testLLM, {}, message); + + // The title should come from the assistant chunk, not the thinking chunk + expect(result).toBe("Sorting Algorithm Help"); + expect(result).not.toContain("thinking process"); + }); }); });