mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix(vscode-ide-companion): optimize stream termination handling and fix style layering issues
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user