mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix(vscode-ide-companion): Interactive unification of first login and login
This commit is contained in:
@@ -686,7 +686,38 @@ export class QwenAgentManager {
|
||||
);
|
||||
}
|
||||
|
||||
// Try to create a new ACP session. If the backend asks for auth despite our
|
||||
// cached flag (e.g. fresh process or expired tokens), re-authenticate and retry.
|
||||
try {
|
||||
await this.connection.newSession(workingDir);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const requiresAuth =
|
||||
msg.includes('Authentication required') ||
|
||||
msg.includes('(code: -32000)');
|
||||
|
||||
if (requiresAuth) {
|
||||
console.warn(
|
||||
'[QwenAgentManager] session/new requires authentication. Retrying with authenticate...',
|
||||
);
|
||||
try {
|
||||
await this.connection.authenticate(authMethod);
|
||||
// Persist auth cache so subsequent calls can skip the web flow.
|
||||
if (effectiveAuth) {
|
||||
await effectiveAuth.saveAuthState(workingDir, authMethod);
|
||||
}
|
||||
await this.connection.newSession(workingDir);
|
||||
} catch (reauthErr) {
|
||||
// Clear potentially stale cache on failure and rethrow
|
||||
if (effectiveAuth) {
|
||||
await effectiveAuth.clearAuthState();
|
||||
}
|
||||
throw reauthErr;
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
const newSessionId = this.connection.currentSessionId;
|
||||
console.log(
|
||||
'[QwenAgentManager] New session created with ID:',
|
||||
|
||||
@@ -39,10 +39,7 @@ export class QwenConnectionHandler {
|
||||
cliPath?: string,
|
||||
): Promise<void> {
|
||||
const connectId = Date.now();
|
||||
console.log(`\n========================================`);
|
||||
console.log(`[QwenAgentManager] 🚀 CONNECT() CALLED - ID: ${connectId}`);
|
||||
console.log(`[QwenAgentManager] Call stack:\n${new Error().stack}`);
|
||||
console.log(`========================================\n`);
|
||||
|
||||
// Check CLI version and features
|
||||
const cliVersionManager = CliVersionManager.getInstance();
|
||||
@@ -166,7 +163,9 @@ export class QwenConnectionHandler {
|
||||
|
||||
// Create new session if unable to restore
|
||||
if (!sessionRestored) {
|
||||
console.log('[QwenAgentManager] Creating new session...');
|
||||
console.log(
|
||||
'[QwenAgentManager] no sessionRestored, Creating new session...',
|
||||
);
|
||||
|
||||
// Check if we have valid cached authentication
|
||||
let hasValidAuth = false;
|
||||
@@ -217,7 +216,13 @@ export class QwenConnectionHandler {
|
||||
console.log(
|
||||
'[QwenAgentManager] Creating new session after authentication...',
|
||||
);
|
||||
await this.newSessionWithRetry(connection, workingDir, 3);
|
||||
await this.newSessionWithRetry(
|
||||
connection,
|
||||
workingDir,
|
||||
3,
|
||||
authMethod,
|
||||
authStateManager,
|
||||
);
|
||||
console.log('[QwenAgentManager] New session created successfully');
|
||||
|
||||
// Ensure auth state is saved (prevent repeated authentication)
|
||||
@@ -257,6 +262,8 @@ export class QwenConnectionHandler {
|
||||
connection: AcpConnection,
|
||||
workingDir: string,
|
||||
maxRetries: number,
|
||||
authMethod: string,
|
||||
authStateManager?: AuthStateManager,
|
||||
): Promise<void> {
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
@@ -274,6 +281,38 @@ export class QwenConnectionHandler {
|
||||
errorMessage,
|
||||
);
|
||||
|
||||
// If the backend reports that authentication is required, try to
|
||||
// authenticate on-the-fly once and retry without waiting.
|
||||
const requiresAuth =
|
||||
errorMessage.includes('Authentication required') ||
|
||||
errorMessage.includes('(code: -32000)');
|
||||
if (requiresAuth) {
|
||||
console.log(
|
||||
'[QwenAgentManager] Backend requires authentication. Authenticating and retrying session/new...',
|
||||
);
|
||||
try {
|
||||
await connection.authenticate(authMethod);
|
||||
if (authStateManager) {
|
||||
await authStateManager.saveAuthState(workingDir, authMethod);
|
||||
}
|
||||
// Retry immediately after successful auth
|
||||
await connection.newSession(workingDir);
|
||||
console.log(
|
||||
'[QwenAgentManager] Session created successfully after auth',
|
||||
);
|
||||
return;
|
||||
} catch (authErr) {
|
||||
console.error(
|
||||
'[QwenAgentManager] Re-authentication failed:',
|
||||
authErr,
|
||||
);
|
||||
if (authStateManager) {
|
||||
await authStateManager.clearAuthState();
|
||||
}
|
||||
// Fall through to retry logic below
|
||||
}
|
||||
}
|
||||
|
||||
if (attempt === maxRetries) {
|
||||
throw new Error(
|
||||
`Session creation failed after ${maxRetries} attempts: ${errorMessage}`,
|
||||
|
||||
@@ -60,10 +60,16 @@ export const App: React.FC = () => {
|
||||
toolCall: PermissionToolCall;
|
||||
} | null>(null);
|
||||
const [planEntries, setPlanEntries] = useState<PlanEntry[]>([]);
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const messagesEndRef = useRef<HTMLDivElement>(
|
||||
null,
|
||||
) as React.RefObject<HTMLDivElement>;
|
||||
// Scroll container for message list; used to keep the view anchored to the latest content
|
||||
const messagesContainerRef = useRef<HTMLDivElement>(null);
|
||||
const inputFieldRef = useRef<HTMLDivElement>(null);
|
||||
const messagesContainerRef = useRef<HTMLDivElement>(
|
||||
null,
|
||||
) as React.RefObject<HTMLDivElement>;
|
||||
const inputFieldRef = useRef<HTMLDivElement>(
|
||||
null,
|
||||
) as React.RefObject<HTMLDivElement>;
|
||||
const [showBanner, setShowBanner] = useState(true);
|
||||
const [editMode, setEditMode] = useState<EditMode>('ask');
|
||||
const [thinkingEnabled, setThinkingEnabled] = useState(false);
|
||||
|
||||
@@ -309,58 +309,14 @@ export class WebViewProvider {
|
||||
});
|
||||
}
|
||||
|
||||
// // Initialize empty conversation immediately for fast UI rendering
|
||||
// await this.initializeEmptyConversation();
|
||||
|
||||
// // Perform background CLI detection and connection without blocking UI
|
||||
// this.performBackgroundInitialization();
|
||||
|
||||
// Smart login restore: Check if we have valid cached auth and restore connection if available
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
const openaiApiKey = config.get<string>('qwen.openaiApiKey', '');
|
||||
const authMethod = openaiApiKey ? 'openai' : 'qwen-oauth';
|
||||
|
||||
// Check if we have valid cached authentication
|
||||
let hasValidAuth = false;
|
||||
if (this.authStateManager) {
|
||||
hasValidAuth = await this.authStateManager.hasValidAuth(
|
||||
workingDir,
|
||||
authMethod,
|
||||
);
|
||||
// Lazy initialization: Do not attempt to connect/auth on WebView show.
|
||||
// Render the chat UI immediately; we will connect/login on-demand when the
|
||||
// user sends a message or requests a session action.
|
||||
console.log(
|
||||
'[WebViewProvider] Has valid cached auth on show:',
|
||||
hasValidAuth,
|
||||
'[WebViewProvider] Lazy init: rendering empty conversation only',
|
||||
);
|
||||
}
|
||||
|
||||
if (hasValidAuth && !this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Found valid cached auth, attempting to restore connection...',
|
||||
);
|
||||
try {
|
||||
await this.initializeAgentConnection();
|
||||
console.log('[WebViewProvider] Connection restored successfully');
|
||||
} catch (error) {
|
||||
console.error('[WebViewProvider] Failed to restore connection:', error);
|
||||
// Fall back to empty conversation if restore fails
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
} else if (this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Agent already initialized, reusing existing connection',
|
||||
);
|
||||
// Reload current session messages
|
||||
await this.loadCurrentSessionMessages();
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] No valid cached auth or agent already initialized, showing empty conversation',
|
||||
);
|
||||
// Just initialize empty conversation for the UI
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize agent connection and session
|
||||
@@ -459,124 +415,6 @@ export class WebViewProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform background initialization without blocking UI
|
||||
* This method runs CLI detection and connection in the background
|
||||
*/
|
||||
private async performBackgroundInitialization(): Promise<void> {
|
||||
try {
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
const qwenEnabled = config.get<boolean>('qwen.enabled', true);
|
||||
|
||||
if (qwenEnabled) {
|
||||
// Check if we have valid cached authentication
|
||||
const openaiApiKey = config.get<string>('qwen.openaiApiKey', '');
|
||||
const authMethod = openaiApiKey ? 'openai' : 'qwen-oauth';
|
||||
|
||||
let hasValidAuth = false;
|
||||
if (this.authStateManager) {
|
||||
hasValidAuth = await this.authStateManager.hasValidAuth(
|
||||
workingDir,
|
||||
authMethod,
|
||||
);
|
||||
console.log(
|
||||
'[WebViewProvider] Has valid cached auth in background init:',
|
||||
hasValidAuth,
|
||||
);
|
||||
}
|
||||
|
||||
// Perform CLI detection in background
|
||||
const cliDetection = await CliDetector.detectQwenCli();
|
||||
|
||||
if (!cliDetection.isInstalled) {
|
||||
console.log(
|
||||
'[WebViewProvider] Qwen CLI not detected in background check',
|
||||
);
|
||||
console.log(
|
||||
'[WebViewProvider] CLI detection error:',
|
||||
cliDetection.error,
|
||||
);
|
||||
|
||||
// Notify webview that CLI is not installed
|
||||
this.sendMessageToWebView({
|
||||
type: 'cliNotInstalled',
|
||||
data: {
|
||||
error: cliDetection.error,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] Qwen CLI detected in background check, attempting connection...',
|
||||
);
|
||||
console.log('[WebViewProvider] CLI path:', cliDetection.cliPath);
|
||||
console.log('[WebViewProvider] CLI version:', cliDetection.version);
|
||||
|
||||
if (hasValidAuth && !this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Found valid cached auth, attempting to restore connection in background...',
|
||||
);
|
||||
try {
|
||||
// Pass the detected CLI path to ensure we use the correct installation
|
||||
await this.agentManager.connect(
|
||||
workingDir,
|
||||
this.authStateManager,
|
||||
cliDetection.cliPath,
|
||||
);
|
||||
console.log(
|
||||
'[WebViewProvider] Connection restored successfully in background',
|
||||
);
|
||||
this.agentInitialized = true;
|
||||
|
||||
// Load messages from the current Qwen session
|
||||
await this.loadCurrentSessionMessages();
|
||||
|
||||
// Notify webview that agent is connected
|
||||
this.sendMessageToWebView({
|
||||
type: 'agentConnected',
|
||||
data: {},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'[WebViewProvider] Failed to restore connection in background:',
|
||||
error,
|
||||
);
|
||||
// Clear auth cache on error
|
||||
await this.authStateManager.clearAuthState();
|
||||
|
||||
// Notify webview that agent connection failed
|
||||
this.sendMessageToWebView({
|
||||
type: 'agentConnectionError',
|
||||
data: {
|
||||
message:
|
||||
error instanceof Error ? error.message : String(error),
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Agent already initialized, no need to reconnect in background',
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] No valid cached auth, skipping background connection',
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] Qwen agent is disabled in settings (background)',
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'[WebViewProvider] Background initialization failed:',
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force re-login by clearing auth cache and reconnecting
|
||||
* Called when user explicitly uses /login command
|
||||
@@ -588,6 +426,16 @@ export class WebViewProvider {
|
||||
!!this.authStateManager,
|
||||
);
|
||||
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: 'Logging in to Qwen Code... ',
|
||||
cancellable: false,
|
||||
},
|
||||
async (progress) => {
|
||||
try {
|
||||
progress.report({ message: 'Preparing sign-in...' });
|
||||
|
||||
// Clear existing auth cache
|
||||
if (this.authStateManager) {
|
||||
await this.authStateManager.clearAuthState();
|
||||
@@ -608,12 +456,17 @@ export class WebViewProvider {
|
||||
}
|
||||
|
||||
// Wait a moment for cleanup to complete
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
|
||||
progress.report({
|
||||
message: 'Connecting to CLI and starting sign-in...',
|
||||
});
|
||||
|
||||
// Reinitialize connection (will trigger fresh authentication)
|
||||
try {
|
||||
await this.initializeAgentConnection();
|
||||
console.log('[WebViewProvider] Force re-login completed successfully');
|
||||
console.log(
|
||||
'[WebViewProvider] Force re-login completed successfully',
|
||||
);
|
||||
|
||||
// Send success notification to WebView
|
||||
this.sendMessageToWebView({
|
||||
@@ -637,6 +490,8 @@ export class WebViewProvider {
|
||||
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -873,64 +728,12 @@ export class WebViewProvider {
|
||||
|
||||
console.log('[WebViewProvider] Panel restored successfully');
|
||||
|
||||
// TODO:
|
||||
// await this.initializeEmptyConversation();
|
||||
// // Perform background initialization without blocking UI
|
||||
// this.performBackgroundInitialization();
|
||||
|
||||
// Smart login restore: Check if we have valid cached auth and restore connection if available
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
const openaiApiKey = config.get<string>('qwen.openaiApiKey', '');
|
||||
const authMethod = openaiApiKey ? 'openai' : 'qwen-oauth';
|
||||
|
||||
// Check if we have valid cached authentication
|
||||
let hasValidAuth = false;
|
||||
if (this.authStateManager) {
|
||||
hasValidAuth = await this.authStateManager.hasValidAuth(
|
||||
workingDir,
|
||||
authMethod,
|
||||
);
|
||||
// Lazy init on restore as well: do not auto-connect; just render UI.
|
||||
console.log(
|
||||
'[WebViewProvider] Has valid cached auth on restore:',
|
||||
hasValidAuth,
|
||||
'[WebViewProvider] Lazy restore: rendering empty conversation only',
|
||||
);
|
||||
}
|
||||
|
||||
if (hasValidAuth && !this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Found valid cached auth, attempting to restore connection...',
|
||||
);
|
||||
try {
|
||||
await this.initializeAgentConnection();
|
||||
console.log('[WebViewProvider] Connection restored successfully');
|
||||
} catch (error) {
|
||||
console.error('[WebViewProvider] Failed to restore connection:', error);
|
||||
// Fall back to empty conversation if restore fails
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
} else if (this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Agent already initialized, refreshing connection...',
|
||||
);
|
||||
try {
|
||||
await this.refreshConnection();
|
||||
console.log('[WebViewProvider] Connection refreshed successfully');
|
||||
} catch (error) {
|
||||
console.error('[WebViewProvider] Failed to refresh connection:', error);
|
||||
// Fall back to empty conversation if refresh fails
|
||||
this.agentInitialized = false;
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] No valid cached auth or agent already initialized, showing empty conversation',
|
||||
);
|
||||
// Just initialize empty conversation for the UI
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state for serialization
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// Use explicit Vitest imports instead of relying on globals.
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { ToolCallData } from '../toolcalls/shared/types.js';
|
||||
import { hasToolCallOutput } from '../toolcalls/shared/utils.js';
|
||||
|
||||
describe('Message Ordering', () => {
|
||||
it('should correctly identify tool calls with output', () => {
|
||||
// Test failed tool call (should show)
|
||||
const failedToolCall: ToolCallData = {
|
||||
toolCallId: 'test-1',
|
||||
kind: 'read',
|
||||
title: 'Read file',
|
||||
status: 'failed',
|
||||
timestamp: 1000,
|
||||
};
|
||||
expect(hasToolCallOutput(failedToolCall)).toBe(true);
|
||||
|
||||
// Test execute tool call with title (should show)
|
||||
const executeToolCall: ToolCallData = {
|
||||
toolCallId: 'test-2',
|
||||
kind: 'execute',
|
||||
title: 'ls -la',
|
||||
status: 'completed',
|
||||
timestamp: 2000,
|
||||
};
|
||||
expect(hasToolCallOutput(executeToolCall)).toBe(true);
|
||||
|
||||
// Test tool call with content (should show)
|
||||
const contentToolCall: ToolCallData = {
|
||||
toolCallId: 'test-3',
|
||||
kind: 'read',
|
||||
title: 'Read file',
|
||||
status: 'completed',
|
||||
content: [
|
||||
{
|
||||
type: 'content',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: 'File content',
|
||||
},
|
||||
},
|
||||
],
|
||||
timestamp: 3000,
|
||||
};
|
||||
expect(hasToolCallOutput(contentToolCall)).toBe(true);
|
||||
|
||||
// Test tool call with locations (should show)
|
||||
const locationToolCall: ToolCallData = {
|
||||
toolCallId: 'test-4',
|
||||
kind: 'read',
|
||||
title: 'Read file',
|
||||
status: 'completed',
|
||||
locations: [
|
||||
{
|
||||
path: '/path/to/file.txt',
|
||||
},
|
||||
],
|
||||
timestamp: 4000,
|
||||
};
|
||||
expect(hasToolCallOutput(locationToolCall)).toBe(true);
|
||||
|
||||
// Test tool call with title (should show)
|
||||
const titleToolCall: ToolCallData = {
|
||||
toolCallId: 'test-5',
|
||||
kind: 'generic',
|
||||
title: 'Generic tool call',
|
||||
status: 'completed',
|
||||
timestamp: 5000,
|
||||
};
|
||||
expect(hasToolCallOutput(titleToolCall)).toBe(true);
|
||||
|
||||
// Test tool call without output (should not show)
|
||||
const noOutputToolCall: ToolCallData = {
|
||||
toolCallId: 'test-6',
|
||||
kind: 'generic',
|
||||
title: '',
|
||||
status: 'completed',
|
||||
timestamp: 6000,
|
||||
};
|
||||
expect(hasToolCallOutput(noOutputToolCall)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -376,17 +376,23 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
// Check for session not found error and handle it appropriately
|
||||
if (
|
||||
errorMsg.includes('Session not found') ||
|
||||
errorMsg.includes('No active ACP session')
|
||||
errorMsg.includes('No active ACP session') ||
|
||||
errorMsg.includes('Authentication required') ||
|
||||
errorMsg.includes('(code: -32000)')
|
||||
) {
|
||||
// Clear auth cache since session is invalid
|
||||
// Note: We would need access to authStateManager for this, but for now we'll just show login prompt
|
||||
const result = await vscode.window.showWarningMessage(
|
||||
'Your session has expired. Please login again to continue using Qwen Code.',
|
||||
'Your login has expired. Please login again to continue using Qwen Code.',
|
||||
'Login Now',
|
||||
);
|
||||
|
||||
if (result === 'Login Now') {
|
||||
vscode.commands.executeCommand('qwenCode.login');
|
||||
if (this.loginHandler) {
|
||||
await this.loginHandler();
|
||||
} else {
|
||||
await vscode.commands.executeCommand('qwenCode.login');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vscode.window.showErrorMessage(`Error sending message: ${error}`);
|
||||
@@ -405,6 +411,23 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
try {
|
||||
console.log('[SessionMessageHandler] Creating new Qwen session...');
|
||||
|
||||
// Ensure connection (login) before creating a new session
|
||||
if (!this.agentManager.isConnected) {
|
||||
const result = await vscode.window.showWarningMessage(
|
||||
'You need to login before creating a new session.',
|
||||
'Login Now',
|
||||
);
|
||||
if (result === 'Login Now') {
|
||||
if (this.loginHandler) {
|
||||
await this.loginHandler();
|
||||
} else {
|
||||
await vscode.commands.executeCommand('qwenCode.login');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Save current session before creating new one
|
||||
if (this.currentConversationId && this.agentManager.isConnected) {
|
||||
try {
|
||||
@@ -450,6 +473,39 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
try {
|
||||
console.log('[SessionMessageHandler] Switching to session:', sessionId);
|
||||
|
||||
// If not connected yet, offer to login or view offline
|
||||
if (!this.agentManager.isConnected) {
|
||||
const selection = await vscode.window.showWarningMessage(
|
||||
'You are not logged in. Login now to fully restore this session, or view it offline.',
|
||||
'Login Now',
|
||||
'View Offline',
|
||||
);
|
||||
|
||||
if (selection === 'Login Now') {
|
||||
if (this.loginHandler) {
|
||||
await this.loginHandler();
|
||||
} else {
|
||||
await vscode.commands.executeCommand('qwenCode.login');
|
||||
}
|
||||
} else if (selection === 'View Offline') {
|
||||
// Show messages from local cache only
|
||||
const messages =
|
||||
await this.agentManager.getSessionMessages(sessionId);
|
||||
this.currentConversationId = sessionId;
|
||||
this.sendToWebView({
|
||||
type: 'qwenSessionSwitched',
|
||||
data: { sessionId, messages },
|
||||
});
|
||||
vscode.window.showInformationMessage(
|
||||
'Showing cached session content. Login to interact with the AI.',
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
// User dismissed; do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Save current session before switching
|
||||
if (
|
||||
this.currentConversationId &&
|
||||
@@ -489,7 +545,7 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
|
||||
// Try to load session via ACP
|
||||
// Try to load session via ACP (now we should be connected)
|
||||
try {
|
||||
const loadResponse =
|
||||
await this.agentManager.loadSessionViaAcp(sessionId);
|
||||
@@ -514,6 +570,8 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
// Fallback: create new session
|
||||
const messages = await this.agentManager.getSessionMessages(sessionId);
|
||||
|
||||
// If we are connected, try to create a fresh ACP session so user can interact
|
||||
if (this.agentManager.isConnected) {
|
||||
try {
|
||||
const newAcpSessionId =
|
||||
await this.agentManager.createNewSession(workingDir);
|
||||
@@ -535,6 +593,17 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
);
|
||||
throw createError;
|
||||
}
|
||||
} else {
|
||||
// Offline view only
|
||||
this.currentConversationId = sessionId;
|
||||
this.sendToWebView({
|
||||
type: 'qwenSessionSwitched',
|
||||
data: { sessionId, messages, session: sessionDetails },
|
||||
});
|
||||
vscode.window.showWarningMessage(
|
||||
'Showing cached session content. Login to interact with the AI.',
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[SessionMessageHandler] Failed to switch session:', error);
|
||||
@@ -620,6 +689,37 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
*/
|
||||
private async handleResumeSession(sessionId: string): Promise<void> {
|
||||
try {
|
||||
// If not connected, offer to login or view offline
|
||||
if (!this.agentManager.isConnected) {
|
||||
const selection = await vscode.window.showWarningMessage(
|
||||
'You are not logged in. Login now to fully restore this session, or view it offline.',
|
||||
'Login Now',
|
||||
'View Offline',
|
||||
);
|
||||
|
||||
if (selection === 'Login Now') {
|
||||
if (this.loginHandler) {
|
||||
await this.loginHandler();
|
||||
} else {
|
||||
await vscode.commands.executeCommand('qwenCode.login');
|
||||
}
|
||||
} else if (selection === 'View Offline') {
|
||||
const messages =
|
||||
await this.agentManager.getSessionMessages(sessionId);
|
||||
this.currentConversationId = sessionId;
|
||||
this.sendToWebView({
|
||||
type: 'qwenSessionSwitched',
|
||||
data: { sessionId, messages },
|
||||
});
|
||||
vscode.window.showInformationMessage(
|
||||
'Showing cached session content. Login to interact with the AI.',
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try ACP load first
|
||||
try {
|
||||
await this.agentManager.loadSessionViaAcp(sessionId);
|
||||
|
||||
Reference in New Issue
Block a user