From 54fd63f04b72a8bf1eead0c6b0b44ae10eebec3e Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Mon, 15 Dec 2025 22:41:38 +0800 Subject: [PATCH 1/4] fix(vscode-ide-companion): optimize stream termination handling and fix style layering issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify stream termination using the `sendStreamEnd` method to avoid duplicate code. Add stream termination reason identification and handling for timeout and session expiration scenarios. Centralize cleanup logic for various stream termination states in the WebView message hooks. Adjust Tailwind CSS styles to resolve component layering display issues. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../scripts/prepackage.js | 2 +- .../webview/handlers/SessionMessageHandler.ts | 41 +++++++++++++++---- .../src/webview/hooks/useWebViewMessages.ts | 21 +++++++--- .../src/webview/styles/tailwind.css | 2 +- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/packages/vscode-ide-companion/scripts/prepackage.js b/packages/vscode-ide-companion/scripts/prepackage.js index 8db18a69..de76a335 100644 --- a/packages/vscode-ide-companion/scripts/prepackage.js +++ b/packages/vscode-ide-companion/scripts/prepackage.js @@ -35,7 +35,7 @@ function npmBin() { function run(cmd, args, opts = {}) { const res = spawnSync(cmd, args, { stdio: 'inherit', - shell: process.platform === 'win32' ? true : false, + shell: process.platform === 'win32', ...opts, }); if (res.error) { diff --git a/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts b/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts index 51dfbdd9..130ca107 100644 --- a/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts +++ b/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts @@ -152,6 +152,24 @@ export class SessionMessageHandler extends BaseMessageHandler { this.currentStreamContent = ''; } + /** + * Notify the webview that streaming has finished. + */ + private sendStreamEnd(reason?: string): void { + const data: { timestamp: number; reason?: string } = { + timestamp: Date.now(), + }; + + if (reason) { + data.reason = reason; + } + + this.sendToWebView({ + type: 'streamEnd', + data, + }); + } + /** * Prompt user to login and invoke the registered login handler/command. * Returns true if a login was initiated. @@ -373,10 +391,7 @@ export class SessionMessageHandler extends BaseMessageHandler { ); } - this.sendToWebView({ - type: 'streamEnd', - data: { timestamp: Date.now() }, - }); + this.sendStreamEnd(); } catch (error) { console.error('[SessionMessageHandler] Error sending message:', error); @@ -398,10 +413,7 @@ export class SessionMessageHandler extends BaseMessageHandler { if (isAbortLike) { // Do not show VS Code error popup for intentional cancellations. // Ensure the webview knows the stream ended due to user action. - this.sendToWebView({ - type: 'streamEnd', - data: { timestamp: Date.now(), reason: 'user_cancelled' }, - }); + this.sendStreamEnd('user_cancelled'); return; } // Check for session not found error and handle it appropriately @@ -423,12 +435,23 @@ export class SessionMessageHandler extends BaseMessageHandler { type: 'sessionExpired', data: { message: 'Session expired. Please login again.' }, }); + this.sendStreamEnd('session_expired'); } else { - vscode.window.showErrorMessage(`Error sending message: ${error}`); + const isTimeoutError = + lower.includes('timeout') || lower.includes('timed out'); + if (!isTimeoutError) { + vscode.window.showErrorMessage(`Error sending message: ${error}`); + } else { + // 超时对用户没有可执行的操作,因此只在面板内重置信息,不弹出 VS Code 错误提醒 + console.warn( + '[SessionMessageHandler] Prompt timed out; suppressing popup', + ); + } this.sendToWebView({ type: 'error', data: { message: errorMsg }, }); + this.sendStreamEnd(isTimeoutError ? 'timeout' : 'error'); } } } diff --git a/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts b/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts index c8d507f2..8336825c 100644 --- a/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts +++ b/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts @@ -15,6 +15,14 @@ import type { ToolCallUpdate } from '../../types/chatTypes.js'; import type { ApprovalModeValue } from '../../types/approvalModeValueTypes.js'; import type { PlanEntry } from '../../types/chatTypes.js'; +const FORCE_CLEAR_STREAM_END_REASONS = new Set([ + 'user_cancelled', + 'cancelled', + 'timeout', + 'error', + 'session_expired', +]); + interface UseWebViewMessagesProps { // Session management sessionManagement: { @@ -364,12 +372,12 @@ export const useWebViewMessages = ({ ).toLowerCase(); /** - * Handle different types of stream end reasons: - * - 'user_cancelled': User explicitly cancelled operation - * - 'cancelled': General cancellation - * For these cases, immediately clear all active states + * Handle different types of stream end reasons that require a full reset: + * - 'user_cancelled' / 'cancelled': user explicitly cancelled + * - 'timeout' / 'error' / 'session_expired': request failed unexpectedly + * For these cases, immediately clear all active states. */ - if (reason === 'user_cancelled' || reason === 'cancelled') { + if (FORCE_CLEAR_STREAM_END_REASONS.has(reason)) { // Clear active execution tool call tracking, reset state activeExecToolCallsRef.current.clear(); // Clear waiting response state to ensure UI returns to normal @@ -393,6 +401,9 @@ export const useWebViewMessages = ({ } case 'error': + handlers.messageHandling.endStreaming(); + handlers.messageHandling.clearThinking(); + activeExecToolCallsRef.current.clear(); handlers.messageHandling.clearWaitingForResponse(); break; diff --git a/packages/vscode-ide-companion/src/webview/styles/tailwind.css b/packages/vscode-ide-companion/src/webview/styles/tailwind.css index 46d803d5..a48c172f 100644 --- a/packages/vscode-ide-companion/src/webview/styles/tailwind.css +++ b/packages/vscode-ide-companion/src/webview/styles/tailwind.css @@ -43,7 +43,7 @@ /* Composer: form wrapper */ .composer-form { - @apply relative flex flex-col max-w-[680px] mx-auto rounded-large border shadow-sm transition-colors duration-200; + @apply relative flex flex-col max-w-[680px] mx-auto rounded-large border shadow-sm transition-colors duration-200 z-[1]; background: var(--app-input-secondary-background); border-color: var(--app-input-border); color: var(--app-input-foreground); From 725843f9b353f88f2d308c8a015df8d410c69b19 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Mon, 15 Dec 2025 23:41:36 +0800 Subject: [PATCH 2/4] fix(vscode-ide-companion): optimize stream termination handling and fix style layering issues --- .../webview/components/layout/InputForm.tsx | 5 +-- .../webview/handlers/SessionMessageHandler.ts | 33 ++++++++++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/vscode-ide-companion/src/webview/components/layout/InputForm.tsx b/packages/vscode-ide-companion/src/webview/components/layout/InputForm.tsx index 86ba42be..6bd3289a 100644 --- a/packages/vscode-ide-companion/src/webview/components/layout/InputForm.tsx +++ b/packages/vscode-ide-companion/src/webview/components/layout/InputForm.tsx @@ -144,10 +144,7 @@ export const InputForm: React.FC = ({ : ''; return ( -
+
{/* Inner background layer */} diff --git a/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts b/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts index 130ca107..4b4ca09c 100644 --- a/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts +++ b/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts @@ -439,19 +439,34 @@ export class SessionMessageHandler extends BaseMessageHandler { } else { const isTimeoutError = lower.includes('timeout') || lower.includes('timed out'); - if (!isTimeoutError) { - vscode.window.showErrorMessage(`Error sending message: ${error}`); - } else { - // 超时对用户没有可执行的操作,因此只在面板内重置信息,不弹出 VS Code 错误提醒 + if (isTimeoutError) { + // Timeout has no action for the user to perform, so only reset the information in the panel and no VS Code error alert will pop up. console.warn( '[SessionMessageHandler] Prompt timed out; suppressing popup', ); + + const timeoutMessage: ChatMessage = { + role: 'assistant', + content: + 'Request timed out (no response within 120 seconds). Please try again or simplify the request.', + timestamp: Date.now(), + }; + + // Send a timeout message to the WebView without terminating the stream + // In this way, the long-term task can continue to receive subsequent messages after timeout. + this.sendToWebView({ + type: 'message', + data: timeoutMessage, + }); + } else { + // Handling of Non-Timeout Errors + vscode.window.showErrorMessage(`Error sending message: ${error}`); + this.sendToWebView({ + type: 'error', + data: { message: errorMsg }, + }); + this.sendStreamEnd('error'); } - this.sendToWebView({ - type: 'error', - data: { message: errorMsg }, - }); - this.sendStreamEnd(isTimeoutError ? 'timeout' : 'error'); } } } From 25d9c4f1a7dd36301b44a1061b1ad134cd95abbd Mon Sep 17 00:00:00 2001 From: "mingholy.lmh" Date: Tue, 16 Dec 2025 17:09:42 +0800 Subject: [PATCH 3/4] fix: default values of sampling params --- packages/core/src/core/baseLlmClient.test.ts | 5 ++--- packages/core/src/core/baseLlmClient.ts | 3 +-- packages/core/src/core/client.test.ts | 2 +- packages/core/src/core/client.ts | 3 +-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/core/src/core/baseLlmClient.test.ts b/packages/core/src/core/baseLlmClient.test.ts index 999a6903..b074e836 100644 --- a/packages/core/src/core/baseLlmClient.test.ts +++ b/packages/core/src/core/baseLlmClient.test.ts @@ -151,8 +151,7 @@ describe('BaseLlmClient', () => { contents: defaultOptions.contents, config: { abortSignal: defaultOptions.abortSignal, - temperature: 0, - topP: 1, + topP: 0.8, tools: [ { functionDeclarations: [ @@ -189,7 +188,7 @@ describe('BaseLlmClient', () => { expect.objectContaining({ config: expect.objectContaining({ temperature: 0.8, - topP: 1, // Default should remain if not overridden + topP: 0.8, // Default should remain if not overridden topK: 10, tools: expect.any(Array), }), diff --git a/packages/core/src/core/baseLlmClient.ts b/packages/core/src/core/baseLlmClient.ts index b8ce2a68..6b87b13d 100644 --- a/packages/core/src/core/baseLlmClient.ts +++ b/packages/core/src/core/baseLlmClient.ts @@ -66,8 +66,7 @@ export interface GenerateJsonOptions { export class BaseLlmClient { // Default configuration for utility tasks private readonly defaultUtilityConfig: GenerateContentConfig = { - temperature: 0, - topP: 1, + topP: 0.8, }; constructor( diff --git a/packages/core/src/core/client.test.ts b/packages/core/src/core/client.test.ts index 8adaf4f6..01374805 100644 --- a/packages/core/src/core/client.test.ts +++ b/packages/core/src/core/client.test.ts @@ -2310,7 +2310,7 @@ ${JSON.stringify( abortSignal, systemInstruction: getCoreSystemPrompt(''), temperature: 0.5, - topP: 1, + topP: 0.8, }, contents, }, diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index 6e3be209..38f02099 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -94,8 +94,7 @@ const MAX_TURNS = 100; export class GeminiClient { private chat?: GeminiChat; private readonly generateContentConfig: GenerateContentConfig = { - temperature: 0, - topP: 1, + topP: 0.8, }; private sessionTurnCount = 0; From 12f84fb730e5972262beae544f04fc7f9de351b6 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Wed, 17 Dec 2025 21:00:26 +0800 Subject: [PATCH 4/4] fix(vscode-ide-companion): optimize stream termination handling and remove timeout for session_prompt --- .../src/services/acpSessionManager.ts | 32 +++++++++++-------- .../webview/handlers/SessionMessageHandler.ts | 11 ++++--- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/vscode-ide-companion/src/services/acpSessionManager.ts b/packages/vscode-ide-companion/src/services/acpSessionManager.ts index cfa299bf..e2055a3a 100644 --- a/packages/vscode-ide-companion/src/services/acpSessionManager.ts +++ b/packages/vscode-ide-companion/src/services/acpSessionManager.ts @@ -54,27 +54,31 @@ export class AcpSessionManager { }; return new Promise((resolve, reject) => { - // different timeout durations based on methods - let timeoutDuration = 60000; // default 60 seconds - if ( - method === AGENT_METHODS.session_prompt || - method === AGENT_METHODS.initialize - ) { - timeoutDuration = 120000; // 2min for session_prompt and initialize - } + // No timeout for session_prompt as LLM tasks can take 5-10 minutes or longer + // The request should always terminate with a stop_reason + let timeoutId: NodeJS.Timeout | undefined; + let timeoutDuration: number | undefined; - const timeoutId = setTimeout(() => { - pendingRequests.delete(id); - reject(new Error(`Request ${method} timed out`)); - }, timeoutDuration); + if (method !== AGENT_METHODS.session_prompt) { + // Set timeout for other methods + timeoutDuration = method === AGENT_METHODS.initialize ? 120000 : 60000; + timeoutId = setTimeout(() => { + pendingRequests.delete(id); + reject(new Error(`Request ${method} timed out`)); + }, timeoutDuration); + } const pendingRequest: PendingRequest = { resolve: (value: T) => { - clearTimeout(timeoutId); + if (timeoutId) { + clearTimeout(timeoutId); + } resolve(value); }, reject: (error: Error) => { - clearTimeout(timeoutId); + if (timeoutId) { + clearTimeout(timeoutId); + } reject(error); }, timeoutId, diff --git a/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts b/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts index 4b4ca09c..d8861b95 100644 --- a/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts +++ b/packages/vscode-ide-companion/src/webview/handlers/SessionMessageHandler.ts @@ -440,24 +440,25 @@ export class SessionMessageHandler extends BaseMessageHandler { const isTimeoutError = lower.includes('timeout') || lower.includes('timed out'); if (isTimeoutError) { - // Timeout has no action for the user to perform, so only reset the information in the panel and no VS Code error alert will pop up. + // Note: session_prompt no longer has a timeout, so this should rarely occur + // This path may still be hit for other methods (initialize, etc.) or network-level timeouts console.warn( - '[SessionMessageHandler] Prompt timed out; suppressing popup', + '[SessionMessageHandler] Request timed out; suppressing popup', ); const timeoutMessage: ChatMessage = { role: 'assistant', content: - 'Request timed out (no response within 120 seconds). Please try again or simplify the request.', + 'Request timed out. This may be due to a network issue. Please try again.', timestamp: Date.now(), }; - // Send a timeout message to the WebView without terminating the stream - // In this way, the long-term task can continue to receive subsequent messages after timeout. + // Send a timeout message to the WebView this.sendToWebView({ type: 'message', data: timeoutMessage, }); + this.sendStreamEnd('timeout'); } else { // Handling of Non-Timeout Errors vscode.window.showErrorMessage(`Error sending message: ${error}`);