Skip to content

Commit c27049d

Browse files
author
Eric Wheeler
committed
refactor: make attemptApiRequest history truncation atomic
Refactors `attemptApiRequest` to ensure the conversation history truncation is a fully atomic operation. Previously, the truncation logic was performed and then conditionally saved, which introduced a race condition and relied on an unsafe object reference comparison. This change moves the call to `truncateConversationIfNeeded` inside the `modifyApiConversationHistory` callback. This guarantees that reading the history, truncating it, and writing it back to storage happens as a single, indivisible transaction. Calls to `say` were also moved outside of the critical section to prevent side-effects during the atomic update. Additionally, the `TruncateResponse` type is now exported from the sliding-window module to satisfy type checking in `Task.ts`. Signed-off-by: Eric Wheeler <[email protected]>
1 parent d9a73b5 commit c27049d

File tree

2 files changed

+23
-23
lines changed

2 files changed

+23
-23
lines changed

src/core/sliding-window/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ type TruncateOptions = {
7878
currentProfileId: string
7979
}
8080

81-
type TruncateResponse = SummarizeResponse & { prevContextTokens: number }
81+
export type TruncateResponse = SummarizeResponse & { prevContextTokens: number }
8282

8383
/**
8484
* Conditionally truncates the conversation messages if the total token count

src/core/task/Task.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ import { FileContextTracker } from "../context-tracking/FileContextTracker"
7474
import { RooIgnoreController } from "../ignore/RooIgnoreController"
7575
import { RooProtectedController } from "../protect/RooProtectedController"
7676
import { type AssistantMessageContent, parseAssistantMessage, presentAssistantMessage } from "../assistant-message"
77-
import { truncateConversationIfNeeded } from "../sliding-window"
77+
import { TruncateResponse, truncateConversationIfNeeded } from "../sliding-window"
7878
import { ClineProvider } from "../webview/ClineProvider"
7979
import { MultiSearchReplaceDiffStrategy } from "../diff/strategies/multi-search-replace"
8080
import { MultiFileSearchReplaceDiffStrategy } from "../diff/strategies/multi-file-search-replace"
@@ -1865,29 +1865,29 @@ export class Task extends EventEmitter<ClineEvents> {
18651865
state?.listApiConfigMeta.find((profile) => profile.name === state?.currentApiConfigName)?.id ??
18661866
"default"
18671867

1868-
const truncateResult = await truncateConversationIfNeeded({
1869-
messages: this.apiConversationHistory,
1870-
totalTokens: contextTokens,
1871-
maxTokens,
1872-
contextWindow,
1873-
apiHandler: this.api,
1874-
autoCondenseContext,
1875-
autoCondenseContextPercent,
1876-
systemPrompt,
1877-
taskId: this.taskId,
1878-
customCondensingPrompt,
1879-
condensingApiHandler,
1880-
profileThresholds,
1881-
currentProfileId,
1882-
})
1883-
if (truncateResult.messages !== this.apiConversationHistory) {
1884-
await this.modifyApiConversationHistory(async () => {
1885-
return truncateResult.messages
1868+
let truncateResult: TruncateResponse | undefined
1869+
await this.modifyApiConversationHistory(async (history) => {
1870+
truncateResult = await truncateConversationIfNeeded({
1871+
messages: history,
1872+
totalTokens: contextTokens,
1873+
maxTokens,
1874+
contextWindow,
1875+
apiHandler: this.api,
1876+
autoCondenseContext,
1877+
autoCondenseContextPercent,
1878+
systemPrompt,
1879+
taskId: this.taskId,
1880+
customCondensingPrompt,
1881+
condensingApiHandler,
1882+
profileThresholds,
1883+
currentProfileId,
18861884
})
1887-
}
1888-
if (truncateResult.error) {
1885+
return truncateResult.messages
1886+
})
1887+
1888+
if (truncateResult?.error) {
18891889
await this.say("condense_context_error", truncateResult.error)
1890-
} else if (truncateResult.summary) {
1890+
} else if (truncateResult?.summary) {
18911891
const { summary, cost, prevContextTokens, newContextTokens = 0 } = truncateResult
18921892
const contextCondense: ContextCondense = { summary, cost, newContextTokens, prevContextTokens }
18931893
await this.say(

0 commit comments

Comments
 (0)