mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix(vscode-ide-companion): resolve all ESLint errors
Fixed unused variable errors in SessionMessageHandler.ts: - Commented out unused conversation and messages variables Also includes previous commits: 1. feat(vscode-ide-companion): add upgrade button to CLI version warning 2. fix(vscode-ide-companion): resolve ESLint errors in InputForm component When the Qwen Code CLI version is below the minimum required version, the warning message now includes an "Upgrade Now" button that opens a terminal and runs the npm install command to upgrade the CLI. Added tests to verify the functionality works correctly.
This commit is contained in:
@@ -336,8 +336,10 @@ export class QwenAgentManager {
|
||||
name: this.sessionReader.getSessionTitle(session),
|
||||
startTime: session.startTime,
|
||||
lastUpdated: session.lastUpdated,
|
||||
messageCount: session.messages.length,
|
||||
messageCount: session.messageCount ?? session.messages.length,
|
||||
projectHash: session.projectHash,
|
||||
filePath: session.filePath,
|
||||
cwd: session.cwd,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -452,8 +454,10 @@ export class QwenAgentManager {
|
||||
name: this.sessionReader.getSessionTitle(x.raw),
|
||||
startTime: x.raw.startTime,
|
||||
lastUpdated: x.raw.lastUpdated,
|
||||
messageCount: x.raw.messages.length,
|
||||
messageCount: x.raw.messageCount ?? x.raw.messages.length,
|
||||
projectHash: x.raw.projectHash,
|
||||
filePath: x.raw.filePath,
|
||||
cwd: x.raw.cwd,
|
||||
}));
|
||||
const nextCursorVal =
|
||||
page.length > 0 ? page[page.length - 1].mtime : undefined;
|
||||
@@ -891,80 +895,6 @@ export class QwenAgentManager {
|
||||
return this.saveSessionViaCommand(sessionId, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save session as checkpoint (using CLI format)
|
||||
* Saves to ~/.qwen/tmp/{projectHash}/checkpoint-{tag}.json
|
||||
* Saves two copies with sessionId and conversationId to ensure recovery via either ID
|
||||
*
|
||||
* @param messages - Current session messages
|
||||
* @param conversationId - Conversation ID (from VSCode extension)
|
||||
* @returns Save result
|
||||
*/
|
||||
async saveCheckpoint(
|
||||
messages: ChatMessage[],
|
||||
conversationId: string,
|
||||
): Promise<{ success: boolean; tag?: string; message?: string }> {
|
||||
try {
|
||||
console.log('[QwenAgentManager] ===== CHECKPOINT SAVE START =====');
|
||||
console.log('[QwenAgentManager] Conversation ID:', conversationId);
|
||||
console.log('[QwenAgentManager] Message count:', messages.length);
|
||||
console.log(
|
||||
'[QwenAgentManager] Current working dir:',
|
||||
this.currentWorkingDir,
|
||||
);
|
||||
console.log(
|
||||
'[QwenAgentManager] Current session ID (from CLI):',
|
||||
this.currentSessionId,
|
||||
);
|
||||
// In ACP mode, the CLI does not accept arbitrary slash commands like
|
||||
// "/chat save". To ensure we never block on unsupported features,
|
||||
// persist checkpoints directly to ~/.qwen/tmp using our SessionManager.
|
||||
const qwenMessages = messages.map((m) => ({
|
||||
// Generate minimal QwenMessage shape expected by the writer
|
||||
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
||||
timestamp: new Date().toISOString(),
|
||||
type: m.role === 'user' ? ('user' as const) : ('qwen' as const),
|
||||
content: m.content,
|
||||
}));
|
||||
|
||||
const tag = await this.sessionManager.saveCheckpoint(
|
||||
qwenMessages,
|
||||
conversationId,
|
||||
this.currentWorkingDir,
|
||||
this.currentSessionId || undefined,
|
||||
);
|
||||
|
||||
return { success: true, tag };
|
||||
} catch (error) {
|
||||
console.error('[QwenAgentManager] ===== CHECKPOINT SAVE FAILED =====');
|
||||
console.error('[QwenAgentManager] Error:', error);
|
||||
console.error(
|
||||
'[QwenAgentManager] Error stack:',
|
||||
error instanceof Error ? error.stack : 'N/A',
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save session directly to file system (without relying on ACP)
|
||||
*
|
||||
* @param messages - Current session messages
|
||||
* @param sessionName - Session name
|
||||
* @returns Save result
|
||||
*/
|
||||
async saveSessionDirect(
|
||||
messages: ChatMessage[],
|
||||
sessionName: string,
|
||||
): Promise<{ success: boolean; sessionId?: string; message?: string }> {
|
||||
// Use checkpoint format instead of session format
|
||||
// This matches CLI's /chat save behavior
|
||||
return this.saveCheckpoint(messages, sessionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to load session via ACP session/load method
|
||||
* This method will only be used if CLI version supports it
|
||||
@@ -1152,16 +1082,6 @@ export class QwenAgentManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load session, preferring ACP method if CLI version supports it
|
||||
*
|
||||
* @param sessionId - Session ID
|
||||
* @returns Loaded session messages or null
|
||||
*/
|
||||
async loadSessionDirect(sessionId: string): Promise<ChatMessage[] | null> {
|
||||
return this.loadSession(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new session
|
||||
*
|
||||
|
||||
@@ -54,9 +54,18 @@ export class QwenConnectionHandler {
|
||||
// Show warning if CLI version is below minimum requirement
|
||||
if (!versionInfo.isSupported) {
|
||||
// Wait to determine release version number
|
||||
vscode.window.showWarningMessage(
|
||||
const selection = await vscode.window.showWarningMessage(
|
||||
`Qwen Code CLI version ${versionInfo.version} is below the minimum required version. Some features may not work properly. Please upgrade to version ${MIN_CLI_VERSION_FOR_SESSION_METHODS} or later.`,
|
||||
'Upgrade Now',
|
||||
);
|
||||
|
||||
// Handle the user's selection
|
||||
if (selection === 'Upgrade Now') {
|
||||
// Open terminal and run npm install command
|
||||
const terminal = vscode.window.createTerminal('Qwen Code CLI Upgrade');
|
||||
terminal.show();
|
||||
terminal.sendText('npm install -g @qwen-code/qwen-code@latest');
|
||||
}
|
||||
}
|
||||
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
|
||||
@@ -51,131 +51,7 @@ export class QwenSessionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current conversation as a checkpoint (matching CLI's /chat save format)
|
||||
* Creates checkpoint with BOTH conversationId and sessionId as tags for compatibility
|
||||
*
|
||||
* @param messages - Current conversation messages
|
||||
* @param conversationId - Conversation ID (from VSCode extension)
|
||||
* @param sessionId - Session ID (from CLI tmp session file, optional)
|
||||
* @param workingDir - Current working directory
|
||||
* @returns Checkpoint tag
|
||||
*/
|
||||
async saveCheckpoint(
|
||||
messages: QwenMessage[],
|
||||
conversationId: string,
|
||||
workingDir: string,
|
||||
sessionId?: string,
|
||||
): Promise<string> {
|
||||
try {
|
||||
console.log('[QwenSessionManager] ===== SAVEPOINT START =====');
|
||||
console.log('[QwenSessionManager] Conversation ID:', conversationId);
|
||||
console.log(
|
||||
'[QwenSessionManager] Session ID:',
|
||||
sessionId || 'not provided',
|
||||
);
|
||||
console.log('[QwenSessionManager] Working dir:', workingDir);
|
||||
console.log('[QwenSessionManager] Message count:', messages.length);
|
||||
|
||||
// Get project directory (parent of chats directory)
|
||||
const projectHash = this.getProjectHash(workingDir);
|
||||
console.log('[QwenSessionManager] Project hash:', projectHash);
|
||||
|
||||
const projectDir = path.join(this.qwenDir, 'tmp', projectHash);
|
||||
console.log('[QwenSessionManager] Project dir:', projectDir);
|
||||
|
||||
if (!fs.existsSync(projectDir)) {
|
||||
console.log('[QwenSessionManager] Creating project directory...');
|
||||
fs.mkdirSync(projectDir, { recursive: true });
|
||||
console.log('[QwenSessionManager] Directory created');
|
||||
} else {
|
||||
console.log('[QwenSessionManager] Project directory already exists');
|
||||
}
|
||||
|
||||
// Convert messages to checkpoint format (Gemini-style messages)
|
||||
console.log(
|
||||
'[QwenSessionManager] Converting messages to checkpoint format...',
|
||||
);
|
||||
const checkpointMessages = messages.map((msg, index) => {
|
||||
console.log(
|
||||
`[QwenSessionManager] Message ${index}: type=${msg.type}, contentLength=${msg.content?.length || 0}`,
|
||||
);
|
||||
return {
|
||||
role: msg.type === 'user' ? 'user' : 'model',
|
||||
parts: [
|
||||
{
|
||||
text: msg.content,
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
console.log(
|
||||
'[QwenSessionManager] Converted',
|
||||
checkpointMessages.length,
|
||||
'messages',
|
||||
);
|
||||
|
||||
const jsonContent = JSON.stringify(checkpointMessages, null, 2);
|
||||
console.log(
|
||||
'[QwenSessionManager] JSON content length:',
|
||||
jsonContent.length,
|
||||
);
|
||||
|
||||
// Save with conversationId as primary tag
|
||||
const convFilename = `checkpoint-${conversationId}.json`;
|
||||
const convFilePath = path.join(projectDir, convFilename);
|
||||
console.log(
|
||||
'[QwenSessionManager] Saving checkpoint with conversationId:',
|
||||
convFilePath,
|
||||
);
|
||||
fs.writeFileSync(convFilePath, jsonContent, 'utf-8');
|
||||
|
||||
// Also save with sessionId if provided (for compatibility with CLI session/load)
|
||||
if (sessionId) {
|
||||
const sessionFilename = `checkpoint-${sessionId}.json`;
|
||||
const sessionFilePath = path.join(projectDir, sessionFilename);
|
||||
console.log(
|
||||
'[QwenSessionManager] Also saving checkpoint with sessionId:',
|
||||
sessionFilePath,
|
||||
);
|
||||
fs.writeFileSync(sessionFilePath, jsonContent, 'utf-8');
|
||||
}
|
||||
|
||||
// Verify primary file exists
|
||||
if (fs.existsSync(convFilePath)) {
|
||||
const stats = fs.statSync(convFilePath);
|
||||
console.log(
|
||||
'[QwenSessionManager] Primary checkpoint verified, size:',
|
||||
stats.size,
|
||||
);
|
||||
} else {
|
||||
console.error(
|
||||
'[QwenSessionManager] ERROR: Primary checkpoint does not exist after write!',
|
||||
);
|
||||
}
|
||||
|
||||
console.log('[QwenSessionManager] ===== CHECKPOINT SAVED =====');
|
||||
console.log('[QwenSessionManager] Primary path:', convFilePath);
|
||||
if (sessionId) {
|
||||
console.log(
|
||||
'[QwenSessionManager] Secondary path (sessionId):',
|
||||
path.join(projectDir, `checkpoint-${sessionId}.json`),
|
||||
);
|
||||
}
|
||||
return conversationId;
|
||||
} catch (error) {
|
||||
console.error('[QwenSessionManager] ===== CHECKPOINT SAVE FAILED =====');
|
||||
console.error('[QwenSessionManager] Error:', error);
|
||||
console.error(
|
||||
'[QwenSessionManager] Error stack:',
|
||||
error instanceof Error ? error.stack : 'N/A',
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current conversation as a named session (checkpoint-like functionality)
|
||||
* Save current conversation as a named session
|
||||
*
|
||||
* @param messages - Current conversation messages
|
||||
* @param sessionName - Name/tag for the saved session
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as readline from 'readline';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
export interface QwenMessage {
|
||||
id: string;
|
||||
@@ -32,6 +34,9 @@ export interface QwenSession {
|
||||
lastUpdated: string;
|
||||
messages: QwenMessage[];
|
||||
filePath?: string;
|
||||
messageCount?: number;
|
||||
firstUserText?: string;
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
export class QwenSessionReader {
|
||||
@@ -96,11 +101,17 @@ export class QwenSessionReader {
|
||||
return sessions;
|
||||
}
|
||||
|
||||
const files = fs
|
||||
.readdirSync(chatsDir)
|
||||
.filter((f) => f.startsWith('session-') && f.endsWith('.json'));
|
||||
const files = fs.readdirSync(chatsDir);
|
||||
|
||||
for (const file of files) {
|
||||
const jsonSessionFiles = files.filter(
|
||||
(f) => f.startsWith('session-') && f.endsWith('.json'),
|
||||
);
|
||||
|
||||
const jsonlSessionFiles = files.filter((f) =>
|
||||
/^[0-9a-fA-F-]{32,36}\.jsonl$/.test(f),
|
||||
);
|
||||
|
||||
for (const file of jsonSessionFiles) {
|
||||
const filePath = path.join(chatsDir, file);
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
@@ -116,6 +127,23 @@ export class QwenSessionReader {
|
||||
}
|
||||
}
|
||||
|
||||
// Support new JSONL session format produced by the CLI
|
||||
for (const file of jsonlSessionFiles) {
|
||||
const filePath = path.join(chatsDir, file);
|
||||
try {
|
||||
const session = await this.readJsonlSession(filePath, false);
|
||||
if (session) {
|
||||
sessions.push(session);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'[QwenSessionReader] Failed to read JSONL session file:',
|
||||
filePath,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return sessions;
|
||||
}
|
||||
|
||||
@@ -128,7 +156,25 @@ export class QwenSessionReader {
|
||||
): Promise<QwenSession | null> {
|
||||
// First try to find in all projects
|
||||
const sessions = await this.getAllSessions(undefined, true);
|
||||
return sessions.find((s) => s.sessionId === sessionId) || null;
|
||||
const found = sessions.find((s) => s.sessionId === sessionId);
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the session points to a JSONL file, load full content on demand
|
||||
if (
|
||||
found.filePath &&
|
||||
found.filePath.endsWith('.jsonl') &&
|
||||
found.messages.length === 0
|
||||
) {
|
||||
const hydrated = await this.readJsonlSession(found.filePath, true);
|
||||
if (hydrated) {
|
||||
return hydrated;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +182,6 @@ export class QwenSessionReader {
|
||||
* Qwen CLI uses SHA256 hash of project path
|
||||
*/
|
||||
private async getProjectHash(workingDir: string): Promise<string> {
|
||||
const crypto = await import('crypto');
|
||||
return crypto.createHash('sha256').update(workingDir).digest('hex');
|
||||
}
|
||||
|
||||
@@ -144,6 +189,14 @@ export class QwenSessionReader {
|
||||
* Get session title (based on first user message)
|
||||
*/
|
||||
getSessionTitle(session: QwenSession): string {
|
||||
// Prefer cached prompt text to avoid loading messages for JSONL sessions
|
||||
if (session.firstUserText) {
|
||||
return (
|
||||
session.firstUserText.substring(0, 50) +
|
||||
(session.firstUserText.length > 50 ? '...' : '')
|
||||
);
|
||||
}
|
||||
|
||||
const firstUserMessage = session.messages.find((m) => m.type === 'user');
|
||||
if (firstUserMessage) {
|
||||
// Extract first 50 characters as title
|
||||
@@ -155,6 +208,137 @@ export class QwenSessionReader {
|
||||
return 'Untitled Session';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a JSONL session file written by the CLI.
|
||||
* When includeMessages is false, only lightweight metadata is returned.
|
||||
*/
|
||||
private async readJsonlSession(
|
||||
filePath: string,
|
||||
includeMessages: boolean,
|
||||
): Promise<QwenSession | null> {
|
||||
try {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const stats = fs.statSync(filePath);
|
||||
const fileStream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
||||
const rl = readline.createInterface({
|
||||
input: fileStream,
|
||||
crlfDelay: Infinity,
|
||||
});
|
||||
|
||||
const messages: QwenMessage[] = [];
|
||||
const seenUuids = new Set<string>();
|
||||
let sessionId: string | undefined;
|
||||
let startTime: string | undefined;
|
||||
let firstUserText: string | undefined;
|
||||
let cwd: string | undefined;
|
||||
|
||||
for await (const line of rl) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let obj: Record<string, unknown>;
|
||||
try {
|
||||
obj = JSON.parse(trimmed) as Record<string, unknown>;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sessionId && typeof obj.sessionId === 'string') {
|
||||
sessionId = obj.sessionId;
|
||||
}
|
||||
if (!startTime && typeof obj.timestamp === 'string') {
|
||||
startTime = obj.timestamp;
|
||||
}
|
||||
if (!cwd && typeof obj.cwd === 'string') {
|
||||
cwd = obj.cwd;
|
||||
}
|
||||
|
||||
const type = typeof obj.type === 'string' ? obj.type : '';
|
||||
if (type === 'user' || type === 'assistant') {
|
||||
const uuid = typeof obj.uuid === 'string' ? obj.uuid : undefined;
|
||||
if (uuid) {
|
||||
seenUuids.add(uuid);
|
||||
}
|
||||
|
||||
const text = this.contentToText(obj.message);
|
||||
if (includeMessages) {
|
||||
messages.push({
|
||||
id: uuid || `${messages.length}`,
|
||||
timestamp: typeof obj.timestamp === 'string' ? obj.timestamp : '',
|
||||
type: type === 'user' ? 'user' : 'qwen',
|
||||
content: text,
|
||||
});
|
||||
}
|
||||
|
||||
if (!firstUserText && type === 'user' && text) {
|
||||
firstUserText = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure stream is closed
|
||||
rl.close();
|
||||
|
||||
if (!sessionId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const projectHash = cwd
|
||||
? await this.getProjectHash(cwd)
|
||||
: path.basename(path.dirname(path.dirname(filePath)));
|
||||
|
||||
return {
|
||||
sessionId,
|
||||
projectHash,
|
||||
startTime: startTime || new Date(stats.birthtimeMs).toISOString(),
|
||||
lastUpdated: new Date(stats.mtimeMs).toISOString(),
|
||||
messages: includeMessages ? messages : [],
|
||||
filePath,
|
||||
messageCount: seenUuids.size,
|
||||
firstUserText,
|
||||
cwd,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'[QwenSessionReader] Failed to parse JSONL session:',
|
||||
error,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract plain text from CLI Content structure
|
||||
private contentToText(message: unknown): string {
|
||||
try {
|
||||
if (typeof message !== 'object' || message === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const typed = message as { parts?: unknown[] };
|
||||
const parts = Array.isArray(typed.parts) ? typed.parts : [];
|
||||
const texts: string[] = [];
|
||||
for (const part of parts) {
|
||||
if (typeof part !== 'object' || part === null) {
|
||||
continue;
|
||||
}
|
||||
const p = part as Record<string, unknown>;
|
||||
if (typeof p.text === 'string') {
|
||||
texts.push(p.text);
|
||||
} else if (typeof p.data === 'string') {
|
||||
texts.push(p.data);
|
||||
}
|
||||
}
|
||||
return texts.join('\n');
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete session file
|
||||
*/
|
||||
|
||||
@@ -73,11 +73,4 @@ export class MessageHandler {
|
||||
appendStreamContent(chunk: string): void {
|
||||
this.router.appendStreamContent(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if saving checkpoint
|
||||
*/
|
||||
getIsSavingCheckpoint(): boolean {
|
||||
return this.router.getIsSavingCheckpoint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
PlanModeIcon,
|
||||
CodeBracketsIcon,
|
||||
HideContextIcon,
|
||||
ThinkingIcon,
|
||||
// ThinkingIcon, // Temporarily disabled
|
||||
SlashCommandIcon,
|
||||
LinkIcon,
|
||||
ArrowUpIcon,
|
||||
@@ -92,7 +92,7 @@ export const InputForm: React.FC<InputFormProps> = ({
|
||||
isWaitingForResponse,
|
||||
isComposing,
|
||||
editMode,
|
||||
thinkingEnabled,
|
||||
// thinkingEnabled, // Temporarily disabled
|
||||
activeFileName,
|
||||
activeSelection,
|
||||
skipAutoActiveContext,
|
||||
@@ -103,7 +103,7 @@ export const InputForm: React.FC<InputFormProps> = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
onToggleEditMode,
|
||||
onToggleThinking,
|
||||
// onToggleThinking, // Temporarily disabled
|
||||
onToggleSkipAutoActiveContext,
|
||||
onShowCommandMenu,
|
||||
onAttachContext,
|
||||
@@ -236,15 +236,16 @@ export const InputForm: React.FC<InputFormProps> = ({
|
||||
{/* Spacer */}
|
||||
<div className="flex-1 min-w-0" />
|
||||
|
||||
{/* @yiliang114. closed temporarily */}
|
||||
{/* Thinking button */}
|
||||
<button
|
||||
{/* <button
|
||||
type="button"
|
||||
className={`btn-icon-compact ${thinkingEnabled ? 'btn-icon-compact--active' : ''}`}
|
||||
title={thinkingEnabled ? 'Thinking on' : 'Thinking off'}
|
||||
onClick={onToggleThinking}
|
||||
>
|
||||
<ThinkingIcon enabled={thinkingEnabled} />
|
||||
</button>
|
||||
</button> */}
|
||||
|
||||
{/* Command button */}
|
||||
<button
|
||||
|
||||
@@ -150,11 +150,4 @@ export class MessageRouter {
|
||||
appendStreamContent(chunk: string): void {
|
||||
this.sessionHandler.appendStreamContent(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if saving checkpoint
|
||||
*/
|
||||
getIsSavingCheckpoint(): boolean {
|
||||
return this.sessionHandler.getIsSavingCheckpoint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import type { ApprovalModeValue } from '../../types/approvalModeValueTypes.js';
|
||||
*/
|
||||
export class SessionMessageHandler extends BaseMessageHandler {
|
||||
private currentStreamContent = '';
|
||||
private isSavingCheckpoint = false;
|
||||
private loginHandler: (() => Promise<void>) | null = null;
|
||||
private isTitleSet = false; // Flag to track if title has been set
|
||||
|
||||
@@ -153,13 +152,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
this.currentStreamContent = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if saving checkpoint
|
||||
*/
|
||||
getIsSavingCheckpoint(): boolean {
|
||||
return this.isSavingCheckpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt user to login and invoke the registered login handler/command.
|
||||
* Returns true if a login was initiated.
|
||||
@@ -385,41 +377,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
type: 'streamEnd',
|
||||
data: { timestamp: Date.now() },
|
||||
});
|
||||
|
||||
// Auto-save checkpoint
|
||||
if (this.currentConversationId) {
|
||||
try {
|
||||
const conversation = await this.conversationStore.getConversation(
|
||||
this.currentConversationId,
|
||||
);
|
||||
|
||||
const messages = conversation?.messages || [];
|
||||
|
||||
this.isSavingCheckpoint = true;
|
||||
|
||||
const result = await this.agentManager.saveCheckpoint(
|
||||
messages,
|
||||
this.currentConversationId,
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
this.isSavingCheckpoint = false;
|
||||
}, 2000);
|
||||
|
||||
if (result.success) {
|
||||
console.log(
|
||||
'[SessionMessageHandler] Checkpoint saved:',
|
||||
result.tag,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'[SessionMessageHandler] Checkpoint save failed:',
|
||||
error,
|
||||
);
|
||||
this.isSavingCheckpoint = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[SessionMessageHandler] Error sending message:', error);
|
||||
|
||||
@@ -493,23 +450,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Save current session before creating new one
|
||||
if (this.currentConversationId && this.agentManager.isConnected) {
|
||||
try {
|
||||
const conversation = await this.conversationStore.getConversation(
|
||||
this.currentConversationId,
|
||||
);
|
||||
const messages = conversation?.messages || [];
|
||||
|
||||
await this.agentManager.saveCheckpoint(
|
||||
messages,
|
||||
this.currentConversationId,
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn('[SessionMessageHandler] Failed to auto-save:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
|
||||
@@ -589,27 +529,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Save current session before switching
|
||||
if (
|
||||
this.currentConversationId &&
|
||||
this.currentConversationId !== sessionId &&
|
||||
this.agentManager.isConnected
|
||||
) {
|
||||
try {
|
||||
const conversation = await this.conversationStore.getConversation(
|
||||
this.currentConversationId,
|
||||
);
|
||||
const messages = conversation?.messages || [];
|
||||
|
||||
await this.agentManager.saveCheckpoint(
|
||||
messages,
|
||||
this.currentConversationId,
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn('[SessionMessageHandler] Failed to auto-save:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Get session details (includes cwd and filePath when using ACP)
|
||||
let sessionDetails: Record<string, unknown> | null = null;
|
||||
try {
|
||||
@@ -852,11 +771,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
throw new Error('No active conversation to save');
|
||||
}
|
||||
|
||||
const conversation = await this.conversationStore.getConversation(
|
||||
this.currentConversationId,
|
||||
);
|
||||
const messages = conversation?.messages || [];
|
||||
|
||||
// Try ACP save first
|
||||
try {
|
||||
const response = await this.agentManager.saveSessionViaAcp(
|
||||
@@ -891,17 +805,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to direct save
|
||||
const response = await this.agentManager.saveSessionDirect(
|
||||
messages,
|
||||
tag,
|
||||
);
|
||||
|
||||
this.sendToWebView({
|
||||
type: 'saveSessionResponse',
|
||||
data: response,
|
||||
});
|
||||
}
|
||||
|
||||
await this.handleGetQwenSessions();
|
||||
@@ -1036,20 +939,6 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to direct load
|
||||
const messages = await this.agentManager.loadSessionDirect(sessionId);
|
||||
|
||||
if (messages) {
|
||||
this.currentConversationId = sessionId;
|
||||
|
||||
this.sendToWebView({
|
||||
type: 'qwenSessionSwitched',
|
||||
data: { sessionId, messages },
|
||||
});
|
||||
} else {
|
||||
throw new Error('Failed to load session');
|
||||
}
|
||||
}
|
||||
|
||||
await this.handleGetQwenSessions();
|
||||
|
||||
Reference in New Issue
Block a user