feat(vscode-ide-companion): split module & notes in english

This commit is contained in:
yiliang114
2025-11-25 00:32:51 +08:00
parent 3cf22c065f
commit f503eb2520
42 changed files with 4189 additions and 3063 deletions

View File

@@ -27,9 +27,9 @@ import { QwenSessionUpdateHandler } from './qwenSessionUpdateHandler.js';
export type { ChatMessage, PlanEntry, ToolCallUpdateData };
/**
* Qwen Agent管理器
* Qwen Agent Manager
*
* 协调各个模块,提供统一的接口
* Coordinates various modules and provides unified interface
*/
export class QwenAgentManager {
private connection: AcpConnection;
@@ -39,7 +39,7 @@ export class QwenAgentManager {
private sessionUpdateHandler: QwenSessionUpdateHandler;
private currentWorkingDir: string = process.cwd();
// 回调函数存储
// Callback storage
private callbacks: QwenAgentCallbacks = {};
constructor() {
@@ -49,7 +49,7 @@ export class QwenAgentManager {
this.connectionHandler = new QwenConnectionHandler();
this.sessionUpdateHandler = new QwenSessionUpdateHandler({});
// 设置ACP连接的回调
// Set ACP connection callbacks
this.connection.onSessionUpdate = (data: AcpSessionUpdate) => {
this.sessionUpdateHandler.handleSessionUpdate(data);
};
@@ -65,15 +65,15 @@ export class QwenAgentManager {
};
this.connection.onEndTurn = () => {
// 通知UI响应完成
// Notify UI response complete
};
}
/**
* 连接到Qwen服务
* Connect to Qwen service
*
* @param workingDir - 工作目录
* @param authStateManager - 认证状态管理器(可选)
* @param workingDir - Working directory
* @param authStateManager - Auth state manager (optional)
*/
async connect(
workingDir: string,
@@ -89,18 +89,18 @@ export class QwenAgentManager {
}
/**
* 发送消息
* Send message
*
* @param message - 消息内容
* @param message - Message content
*/
async sendMessage(message: string): Promise<void> {
await this.connection.sendPrompt(message);
}
/**
* 获取会话列表
* Get session list
*
* @returns 会话列表
* @returns Session list
*/
async getSessionList(): Promise<Array<Record<string, unknown>>> {
try {
@@ -129,10 +129,10 @@ export class QwenAgentManager {
}
/**
* 获取会话消息(从磁盘读取)
* Get session messages (read from disk)
*
* @param sessionId - 会话ID
* @returns 消息列表
* @param sessionId - Session ID
* @returns Message list
*/
async getSessionMessages(sessionId: string): Promise<ChatMessage[]> {
try {
@@ -162,12 +162,12 @@ export class QwenAgentManager {
}
/**
* 通过发送 /chat save 命令保存会话
* 由于 CLI 不支持 session/save ACP 方法,我们直接发送 /chat save 命令
* Save session via /chat save command
* Since CLI doesn't support session/save ACP method, we send /chat save command directly
*
* @param sessionId - 会话ID
* @param tag - 保存标签
* @returns 保存响应
* @param sessionId - Session ID
* @param tag - Save tag
* @returns Save response
*/
async saveSessionViaCommand(
sessionId: string,
@@ -200,12 +200,12 @@ export class QwenAgentManager {
}
/**
* 通过 ACP session/save 方法保存会话 (已废弃CLI 不支持)
* Save session via ACP session/save method (deprecated, CLI doesn't support)
*
* @deprecated Use saveSessionViaCommand instead
* @param sessionId - 会话ID
* @param tag - 保存标签
* @returns 保存响应
* @param sessionId - Session ID
* @param tag - Save tag
* @returns Save response
*/
async saveSessionViaAcp(
sessionId: string,
@@ -219,11 +219,11 @@ export class QwenAgentManager {
}
/**
* 通过发送 /chat save 命令保存会话CLI 方式)
* 这会调用 CLI 的原生保存功能,确保保存的内容完整
* Save session via /chat save command (CLI way)
* Calls CLI's native save function to ensure complete content is saved
*
* @param tag - Checkpoint 标签
* @returns 保存结果
* @param tag - Checkpoint tag
* @returns Save result
*/
async saveCheckpointViaCommand(
tag: string,
@@ -263,13 +263,13 @@ export class QwenAgentManager {
}
/**
* 保存会话为 checkpoint使用 CLI 的格式)
* 保存到 ~/.qwen/tmp/{projectHash}/checkpoint-{tag}.json
* 同时用 sessionId conversationId 保存两份,确保可以通过任一 ID 恢复
* 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 - 当前会话消息
* @param messages - Current session messages
* @param conversationId - Conversation ID (from VSCode extension)
* @returns 保存结果
* @returns Save result
*/
async saveCheckpoint(
messages: ChatMessage[],
@@ -319,11 +319,11 @@ export class QwenAgentManager {
}
/**
* 直接保存会话到文件系统(不依赖 ACP
* Save session directly to file system (without relying on ACP)
*
* @param messages - 当前会话消息
* @param sessionName - 会话名称
* @returns 保存结果
* @param messages - Current session messages
* @param sessionName - Session name
* @returns Save result
*/
async saveSessionDirect(
messages: ChatMessage[],
@@ -335,11 +335,11 @@ export class QwenAgentManager {
}
/**
* 尝试通过 ACP session/load 方法加载会话
* 这是一个测试方法,用于验证 CLI 是否支持 session/load
* Try to load session via ACP session/load method
* This is a test method to verify if CLI supports session/load
*
* @param sessionId - 会话ID
* @returns 加载响应或错误
* @param sessionId - Session ID
* @returns Load response or error
*/
async loadSessionViaAcp(sessionId: string): Promise<unknown> {
try {
@@ -385,16 +385,16 @@ export class QwenAgentManager {
}
/**
* 直接从文件系统加载会话(不依赖 ACP
* Load session directly from file system (without relying on ACP)
*
* @param sessionId - 会话ID
* @returns 加载的会话消息或null
* @param sessionId - Session ID
* @returns Loaded session messages or null
*/
async loadSessionDirect(sessionId: string): Promise<ChatMessage[] | null> {
try {
console.log('[QwenAgentManager] Loading session directly:', sessionId);
// 加载会话
// Load session
const session = await this.sessionManager.loadSession(
sessionId,
this.currentWorkingDir,
@@ -405,7 +405,7 @@ export class QwenAgentManager {
return null;
}
// 转换消息格式
// Convert message format
const messages: ChatMessage[] = session.messages.map((msg) => ({
role: msg.type === 'user' ? 'user' : 'assistant',
content: msg.content,
@@ -421,17 +421,17 @@ export class QwenAgentManager {
}
/**
* 创建新会话
* Create new session
*
* 注意认证应该在connect()方法中完成,这里只创建会话
* Note: Authentication should be done in connect() method, only create session here
*
* @param workingDir - 工作目录
* @returns 新创建的 session ID
* @param workingDir - Working directory
* @returns Newly created session ID
*/
async createNewSession(workingDir: string): Promise<string | null> {
console.log('[QwenAgentManager] Creating new session...');
// 先进行认证
// Authenticate first
console.log('[QwenAgentManager] Authenticating before creating session...');
try {
const config = vscode.workspace.getConfiguration('qwenCode');
@@ -455,16 +455,16 @@ export class QwenAgentManager {
}
/**
* 切换到指定会话
* Switch to specified session
*
* @param sessionId - 会话ID
* @param sessionId - Session ID
*/
async switchToSession(sessionId: string): Promise<void> {
await this.connection.switchSession(sessionId);
}
/**
* 取消当前提示
* Cancel current prompt
*/
async cancelCurrentPrompt(): Promise<void> {
console.log('[QwenAgentManager] Cancelling current prompt');
@@ -472,9 +472,9 @@ export class QwenAgentManager {
}
/**
* 注册消息回调
* Register message callback
*
* @param callback - 消息回调函数
* @param callback - Message callback function
*/
onMessage(callback: (message: ChatMessage) => void): void {
this.callbacks.onMessage = callback;
@@ -482,9 +482,9 @@ export class QwenAgentManager {
}
/**
* 注册流式文本块回调
* Register stream chunk callback
*
* @param callback - 流式文本块回调函数
* @param callback - Stream chunk callback function
*/
onStreamChunk(callback: (chunk: string) => void): void {
this.callbacks.onStreamChunk = callback;
@@ -492,9 +492,9 @@ export class QwenAgentManager {
}
/**
* 注册思考文本块回调
* Register thought chunk callback
*
* @param callback - 思考文本块回调函数
* @param callback - Thought chunk callback function
*/
onThoughtChunk(callback: (chunk: string) => void): void {
this.callbacks.onThoughtChunk = callback;
@@ -502,9 +502,9 @@ export class QwenAgentManager {
}
/**
* 注册工具调用回调
* Register tool call callback
*
* @param callback - 工具调用回调函数
* @param callback - Tool call callback function
*/
onToolCall(callback: (update: ToolCallUpdateData) => void): void {
this.callbacks.onToolCall = callback;
@@ -512,9 +512,9 @@ export class QwenAgentManager {
}
/**
* 注册计划回调
* Register plan callback
*
* @param callback - 计划回调函数
* @param callback - Plan callback function
*/
onPlan(callback: (entries: PlanEntry[]) => void): void {
this.callbacks.onPlan = callback;
@@ -522,9 +522,9 @@ export class QwenAgentManager {
}
/**
* 注册权限请求回调
* Register permission request callback
*
* @param callback - 权限请求回调函数
* @param callback - Permission request callback function
*/
onPermissionRequest(
callback: (request: AcpPermissionRequest) => Promise<string>,
@@ -534,21 +534,21 @@ export class QwenAgentManager {
}
/**
* 断开连接
* Disconnect
*/
disconnect(): void {
this.connection.disconnect();
}
/**
* 检查是否已连接
* Check if connected
*/
get isConnected(): boolean {
return this.connection.isConnected;
}
/**
* 获取当前会话ID
* Get current session ID
*/
get currentSessionId(): string | null {
return this.connection.currentSessionId;

View File

@@ -5,9 +5,9 @@
*/
/**
* Qwen连接处理器
* Qwen Connection Handler
*
* 负责Qwen Agent的连接建立、认证和会话创建
* Handles Qwen Agent connection establishment, authentication, and session creation
*/
import * as vscode from 'vscode';
@@ -16,17 +16,17 @@ import type { QwenSessionReader } from '../services/qwenSessionReader.js';
import type { AuthStateManager } from '../auth/authStateManager.js';
/**
* Qwen连接处理器类
* 处理连接、认证和会话初始化
* Qwen Connection Handler class
* Handles connection, authentication, and session initialization
*/
export class QwenConnectionHandler {
/**
* 连接到Qwen服务并建立会话
* Connect to Qwen service and establish session
*
* @param connection - ACP连接实例
* @param sessionReader - 会话读取器实例
* @param workingDir - 工作目录
* @param authStateManager - 认证状态管理器(可选)
* @param connection - ACP connection instance
* @param sessionReader - Session reader instance
* @param workingDir - Working directory
* @param authStateManager - Auth state manager (optional)
*/
async connect(
connection: AcpConnection,
@@ -47,7 +47,7 @@ export class QwenConnectionHandler {
const model = config.get<string>('qwen.model', '');
const proxy = config.get<string>('qwen.proxy', '');
// 构建额外的CLI参数
// Build extra CLI arguments
const extraArgs: string[] = [];
if (openaiApiKey) {
extraArgs.push('--openai-api-key', openaiApiKey);
@@ -65,10 +65,10 @@ export class QwenConnectionHandler {
await connection.connect('qwen', cliPath, workingDir, extraArgs);
// 确定认证方法
// Determine authentication method
const authMethod = openaiApiKey ? 'openai' : 'qwen-oauth';
// 检查是否有有效的缓存认证
// Check if we have valid cached authentication
if (authStateManager) {
const hasValidAuth = await authStateManager.hasValidAuth(
workingDir,
@@ -79,10 +79,10 @@ export class QwenConnectionHandler {
}
}
// 尝试恢复现有会话或创建新会话
// Try to restore existing session or create new session
let sessionRestored = false;
// 尝试从本地文件获取会话
// Try to get session from local files
console.log('[QwenAgentManager] Reading local session files...');
try {
const sessions = await sessionReader.getAllSessions(workingDir);
@@ -129,11 +129,11 @@ export class QwenConnectionHandler {
);
}
// 如果无法恢复会话则创建新会话
// Create new session if unable to restore
if (!sessionRestored) {
console.log('[QwenAgentManager] Creating new session...');
// 检查是否有有效的缓存认证
// Check if we have valid cached authentication
let hasValidAuth = false;
if (authStateManager) {
hasValidAuth = await authStateManager.hasValidAuth(
@@ -142,7 +142,7 @@ export class QwenConnectionHandler {
);
}
// 只在没有有效缓存认证时进行认证
// Only authenticate if we don't have valid cached auth
if (!hasValidAuth) {
console.log(
'[QwenAgentManager] Authenticating before creating session...',
@@ -151,7 +151,7 @@ export class QwenConnectionHandler {
await connection.authenticate(authMethod);
console.log('[QwenAgentManager] Authentication successful');
// 保存认证状态
// Save auth state
if (authStateManager) {
console.log(
'[QwenAgentManager] Saving auth state after successful authentication',
@@ -160,7 +160,7 @@ export class QwenConnectionHandler {
}
} catch (authError) {
console.error('[QwenAgentManager] Authentication failed:', authError);
// 清除可能无效的缓存
// Clear potentially invalid cache
if (authStateManager) {
console.log(
'[QwenAgentManager] Clearing auth cache due to authentication failure',
@@ -182,7 +182,7 @@ export class QwenConnectionHandler {
await this.newSessionWithRetry(connection, workingDir, 3);
console.log('[QwenAgentManager] New session created successfully');
// 确保认证状态已保存(防止重复认证)
// Ensure auth state is saved (prevent repeated authentication)
if (authStateManager && !hasValidAuth) {
console.log(
'[QwenAgentManager] Saving auth state after successful session creation',
@@ -193,7 +193,7 @@ export class QwenConnectionHandler {
console.log(`\n⚠ [SESSION FAILED] newSessionWithRetry threw error\n`);
console.log(`[QwenAgentManager] Error details:`, sessionError);
// 清除缓存
// Clear cache
if (authStateManager) {
console.log('[QwenAgentManager] Clearing auth cache due to failure');
await authStateManager.clearAuthState();
@@ -209,11 +209,11 @@ export class QwenConnectionHandler {
}
/**
* 创建新会话(带重试)
* Create new session (with retry)
*
* @param connection - ACP连接实例
* @param workingDir - 工作目录
* @param maxRetries - 最大重试次数
* @param connection - ACP connection instance
* @param workingDir - Working directory
* @param maxRetries - Maximum number of retries
*/
private async newSessionWithRetry(
connection: AcpConnection,

View File

@@ -5,17 +5,17 @@
*/
/**
* Qwen会话更新处理器
* Qwen Session Update Handler
*
* 负责处理来自ACP的会话更新并分发到相应的回调函数
* Handles session updates from ACP and dispatches them to appropriate callbacks
*/
import type { AcpSessionUpdate } from '../shared/acpTypes.js';
import type { QwenAgentCallbacks } from './qwenTypes.js';
/**
* Qwen会话更新处理器类
* 处理各种会话更新事件并调用相应的回调
* Qwen Session Update Handler class
* Processes various session update events and calls appropriate callbacks
*/
export class QwenSessionUpdateHandler {
private callbacks: QwenAgentCallbacks;
@@ -25,18 +25,18 @@ export class QwenSessionUpdateHandler {
}
/**
* 更新回调函数
* Update callbacks
*
* @param callbacks - 新的回调函数集合
* @param callbacks - New callback collection
*/
updateCallbacks(callbacks: QwenAgentCallbacks): void {
this.callbacks = callbacks;
}
/**
* 处理会话更新
* Handle session update
*
* @param data - ACP会话更新数据
* @param data - ACP session update data
*/
handleSessionUpdate(data: AcpSessionUpdate): void {
const update = data.update;
@@ -47,21 +47,21 @@ export class QwenSessionUpdateHandler {
switch (update.sessionUpdate) {
case 'user_message_chunk':
// 处理用户消息块
// Handle user message chunk
if (update.content?.text && this.callbacks.onStreamChunk) {
this.callbacks.onStreamChunk(update.content.text);
}
break;
case 'agent_message_chunk':
// 处理助手消息块
// Handle assistant message chunk
if (update.content?.text && this.callbacks.onStreamChunk) {
this.callbacks.onStreamChunk(update.content.text);
}
break;
case 'agent_thought_chunk':
// 处理思考块 - 使用特殊回调
// Handle thought chunk - use special callback
console.log(
'[SessionUpdateHandler] 🧠 THOUGHT CHUNK:',
update.content?.text,
@@ -73,7 +73,7 @@ export class QwenSessionUpdateHandler {
);
this.callbacks.onThoughtChunk(update.content.text);
} else if (this.callbacks.onStreamChunk) {
// 回退到常规流处理
// Fallback to regular stream processing
console.log(
'[SessionUpdateHandler] 🧠 Falling back to onStreamChunk',
);
@@ -83,7 +83,7 @@ export class QwenSessionUpdateHandler {
break;
case 'tool_call': {
// 处理新的工具调用
// Handle new tool call
if (this.callbacks.onToolCall && 'toolCallId' in update) {
this.callbacks.onToolCall({
toolCallId: update.toolCallId as string,
@@ -103,7 +103,7 @@ export class QwenSessionUpdateHandler {
}
case 'tool_call_update': {
// 处理工具调用状态更新
// Handle tool call status update
if (this.callbacks.onToolCall && 'toolCallId' in update) {
this.callbacks.onToolCall({
toolCallId: update.toolCallId as string,
@@ -123,7 +123,7 @@ export class QwenSessionUpdateHandler {
}
case 'plan': {
// 处理计划更新
// Handle plan update
if ('entries' in update) {
const entries = update.entries as Array<{
content: string;
@@ -134,7 +134,7 @@ export class QwenSessionUpdateHandler {
if (this.callbacks.onPlan) {
this.callbacks.onPlan(entries);
} else if (this.callbacks.onStreamChunk) {
// 回退到流处理
// Fallback to stream processing
const planText =
'\n📋 Plan:\n' +
entries