-
Notifications
You must be signed in to change notification settings - Fork 2.4k
fix: prevent grey screen when VS Code LM API hits context window limits #8595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2456,7 +2456,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike { | |
| ) | ||
| } | ||
|
|
||
| private async handleContextWindowExceededError(): Promise<void> { | ||
| public async handleContextWindowExceededError(): Promise<void> { | ||
| const state = await this.providerRef.deref()?.getState() | ||
| const { profileThresholds = {} } = state ?? {} | ||
|
|
||
|
|
@@ -2481,38 +2481,62 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike { | |
| `Forcing truncation to ${FORCED_CONTEXT_REDUCTION_PERCENT}% of current context.`, | ||
| ) | ||
|
|
||
| // Force aggressive truncation by keeping only 75% of the conversation history | ||
| const truncateResult = await truncateConversationIfNeeded({ | ||
| messages: this.apiConversationHistory, | ||
| totalTokens: contextTokens || 0, | ||
| maxTokens, | ||
| contextWindow, | ||
| apiHandler: this.api, | ||
| autoCondenseContext: true, | ||
| autoCondenseContextPercent: FORCED_CONTEXT_REDUCTION_PERCENT, | ||
| systemPrompt: await this.getSystemPrompt(), | ||
| taskId: this.taskId, | ||
| profileThresholds, | ||
| currentProfileId, | ||
| }) | ||
| try { | ||
| // Force aggressive truncation by keeping only 75% of the conversation history | ||
| const truncateResult = await truncateConversationIfNeeded({ | ||
| messages: this.apiConversationHistory, | ||
| totalTokens: contextTokens || 0, | ||
| maxTokens, | ||
| contextWindow, | ||
| apiHandler: this.api, | ||
| autoCondenseContext: true, | ||
| autoCondenseContextPercent: FORCED_CONTEXT_REDUCTION_PERCENT, | ||
| systemPrompt: await this.getSystemPrompt(), | ||
| taskId: this.taskId, | ||
| profileThresholds, | ||
| currentProfileId, | ||
| }) | ||
|
|
||
| if (truncateResult.messages !== this.apiConversationHistory) { | ||
| await this.overwriteApiConversationHistory(truncateResult.messages) | ||
| } | ||
| if (truncateResult.messages !== this.apiConversationHistory) { | ||
| await this.overwriteApiConversationHistory(truncateResult.messages) | ||
| } | ||
|
|
||
| if (truncateResult.summary) { | ||
| const { summary, cost, prevContextTokens, newContextTokens = 0 } = truncateResult | ||
| const contextCondense: ContextCondense = { summary, cost, newContextTokens, prevContextTokens } | ||
| await this.say( | ||
| "condense_context", | ||
| undefined /* text */, | ||
| undefined /* images */, | ||
| false /* partial */, | ||
| undefined /* checkpoint */, | ||
| undefined /* progressStatus */, | ||
| { isNonInteractive: true } /* options */, | ||
| contextCondense, | ||
| ) | ||
| if (truncateResult.summary) { | ||
| const { summary, cost, prevContextTokens, newContextTokens = 0 } = truncateResult | ||
| const contextCondense: ContextCondense = { summary, cost, newContextTokens, prevContextTokens } | ||
| await this.say( | ||
| "condense_context", | ||
| undefined /* text */, | ||
| undefined /* images */, | ||
| false /* partial */, | ||
| undefined /* checkpoint */, | ||
| undefined /* progressStatus */, | ||
| { isNonInteractive: true } /* options */, | ||
| contextCondense, | ||
| ) | ||
| } | ||
| } catch (error) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: The fallback truncation strategy keeps only the first message and last 2 messages. Consider if this is sufficient for maintaining conversation coherence. The first message might be the initial task description, but keeping only 2 recent messages might lose important context. Suggestion: Document why this specific strategy (first + last 2) was chosen, or consider keeping a few more messages (e.g., first + last 5) to maintain better context. |
||
| // If truncation fails, log the error but don't throw to prevent UI from freezing | ||
| console.error(`[Task#${this.taskId}] Failed to handle context window error:`, error) | ||
|
|
||
| // Try a more aggressive truncation as a last resort | ||
| if (this.apiConversationHistory.length > 2) { | ||
| const fallbackMessages = [ | ||
| this.apiConversationHistory[0], // Keep first message | ||
| ...this.apiConversationHistory.slice(-2), // Keep last 2 messages | ||
| ] | ||
| await this.overwriteApiConversationHistory(fallbackMessages) | ||
|
|
||
| await this.say( | ||
| "error", | ||
| "Context window exceeded. Conversation history has been significantly reduced to continue.", | ||
| undefined, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| { isNonInteractive: true }, | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -2715,7 +2739,23 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike { | |
| `Retry attempt ${retryAttempt + 1}/${MAX_CONTEXT_WINDOW_RETRIES}. ` + | ||
| `Attempting automatic truncation...`, | ||
| ) | ||
|
|
||
| // Notify UI that we're handling a context window error to prevent grey screen | ||
| await this.say( | ||
| "text", | ||
| "⚠️ Context window limit reached. Automatically reducing conversation size to continue...", | ||
| undefined, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| { isNonInteractive: true }, | ||
| ) | ||
|
|
||
| await this.handleContextWindowExceededError() | ||
|
|
||
| // Give UI time to update before retrying | ||
| await delay(500) | ||
|
|
||
| // Retry the request after handling the context window error | ||
| yield* this.attemptApiRequest(retryAttempt + 1) | ||
| return | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: The
isContextWindowError()method uses simple string pattern matching which may not catch all VS Code LM API context window errors. Consider checking if the VS Code LM API provides specific error codes or types for context window errors that could be used for more reliable detection.The current implementation relies on message text patterns which could produce false positives if error messages change or contain these keywords in different contexts.