From 9233be07bcb4df2aabcf9511083dc9f7f3f06fcf Mon Sep 17 00:00:00 2001 From: Daniel Smolsky Date: Wed, 14 Jan 2026 01:06:08 -0500 Subject: [PATCH 1/2] fix: require reasoning block before injecting context for Claude models - Add hasReasoningInCurrentAssistantTurn to verify Claude has emitted its required thinking block before we inject context - Add isIgnoredUserMessage to skip UI-only messages when checking turn state - Update getLastUserMessage to skip ignored messages for accurate model detection - Split GitHub Copilot and Anthropic injection guards into separate checks --- lib/messages/inject.ts | 14 ++++++++++++-- lib/messages/utils.ts | 34 ++++++++++++++++++++++++++++++++++ lib/shared-utils.ts | 3 ++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/messages/inject.ts b/lib/messages/inject.ts index d19aec9..52f1cf7 100644 --- a/lib/messages/inject.ts +++ b/lib/messages/inject.ts @@ -7,6 +7,8 @@ import { extractParameterKey, buildToolIdList, createSyntheticAssistantMessageWithToolPart, + isIgnoredUserMessage, + hasReasoningInCurrentAssistantTurn, } from "./utils" import { getFilePathFromParameters, isProtectedFilePath } from "../protected-file-patterns" import { getLastUserMessage } from "../shared-utils" @@ -144,9 +146,17 @@ export const insertPruneToolContext = ( providerID === "github-copilot" || providerID === "github-copilot-enterprise" const isAnthropic = modelID.includes("claude") - if (isGitHubCopilot || isAnthropic) { + if (isGitHubCopilot) { const lastMessage = messages[messages.length - 1] - if (lastMessage?.info?.role === "user") { + if (lastMessage?.info?.role === "user" && !isIgnoredUserMessage(lastMessage)) { + return + } + } + + // Anthropic extended thinking models require a thinking block at the start of its turn + // This can probably be improved further to only trigger for the appropriate thinking settings + if (isAnthropic) { + if (!hasReasoningInCurrentAssistantTurn(messages)) { return } } diff --git a/lib/messages/utils.ts b/lib/messages/utils.ts index 99f02b9..26fc29a 100644 --- a/lib/messages/utils.ts +++ b/lib/messages/utils.ts @@ -193,3 +193,37 @@ export function buildToolIdList( } return toolIds } + +export const isIgnoredUserMessage = (message: WithParts): boolean => { + if (!message.parts || message.parts.length === 0) { + return true + } + + for (const part of message.parts) { + if (!(part as any).ignored) { + return false + } + } + + return true +} + +export const hasReasoningInCurrentAssistantTurn = (messages: WithParts[]): boolean => { + for (let i = messages.length - 1; i >= 0; i--) { + const message = messages[i] + if (message.info?.role === "user") { + if (isIgnoredUserMessage(message)) { + continue + } + return false + } + if (message.info?.role === "assistant" && message.parts) { + for (const part of message.parts) { + if (part.type === "reasoning") { + return true + } + } + } + } + return false +} diff --git a/lib/shared-utils.ts b/lib/shared-utils.ts index ce3be56..902ea40 100644 --- a/lib/shared-utils.ts +++ b/lib/shared-utils.ts @@ -1,4 +1,5 @@ import { SessionState, WithParts } from "./state" +import { isIgnoredUserMessage } from "./messages/utils" export const isMessageCompacted = (state: SessionState, msg: WithParts): boolean => { return msg.info.time.created < state.lastCompaction @@ -7,7 +8,7 @@ export const isMessageCompacted = (state: SessionState, msg: WithParts): boolean export const getLastUserMessage = (messages: WithParts[]): WithParts | null => { for (let i = messages.length - 1; i >= 0; i--) { const msg = messages[i] - if (msg.info.role === "user") { + if (msg.info.role === "user" && !isIgnoredUserMessage(msg)) { return msg } } From 549aac2472e9cdf4915ec5e39f6cce2f11d623c8 Mon Sep 17 00:00:00 2001 From: Daniel Smolsky Date: Wed, 14 Jan 2026 01:14:53 -0500 Subject: [PATCH 2/2] todo notes --- lib/messages/inject.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/messages/inject.ts b/lib/messages/inject.ts index 52f1cf7..76c72dd 100644 --- a/lib/messages/inject.ts +++ b/lib/messages/inject.ts @@ -144,6 +144,10 @@ export const insertPruneToolContext = ( const modelID = userInfo.model.modelID const isGitHubCopilot = providerID === "github-copilot" || providerID === "github-copilot-enterprise" + + // TODO: This can probably be improved further to only trigger for the appropriate thinking settings + // This setting is also potentially only necessary for claude subscription, API seems to not need this + // validation. See more here: https://platform.claude.com/docs/en/build-with-claude/extended-thinking const isAnthropic = modelID.includes("claude") if (isGitHubCopilot) { @@ -154,7 +158,6 @@ export const insertPruneToolContext = ( } // Anthropic extended thinking models require a thinking block at the start of its turn - // This can probably be improved further to only trigger for the appropriate thinking settings if (isAnthropic) { if (!hasReasoningInCurrentAssistantTurn(messages)) { return