mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix(vscode-ide-companion): improve ACP connection and session management
Enhance session/load and session/list ACP methods with proper cwd handling and pagination support - Add workingDir tracking in AcpConnection - Improve parameter handling in loadSession and listSessions - Add pagination support for session listing - Fix null/undefined checks in message handling
This commit is contained in:
@@ -26,29 +26,15 @@ import { determineNodePathForCli } from '../cli/cliPathDetector.js';
|
||||
* ACP Connection Handler for VSCode Extension
|
||||
*
|
||||
* This class implements the client side of the ACP (Agent Communication Protocol).
|
||||
*
|
||||
* Implementation Status:
|
||||
*
|
||||
* Client Methods (Methods this class implements, called by CLI):
|
||||
* ✅ session/update - Handle session updates via onSessionUpdate callback
|
||||
* ✅ session/request_permission - Request user permission for tool execution
|
||||
* ✅ fs/read_text_file - Read file from workspace
|
||||
* ✅ fs/write_text_file - Write file to workspace
|
||||
*
|
||||
* Agent Methods (Methods CLI implements, called by this class):
|
||||
* ✅ initialize - Initialize ACP protocol connection
|
||||
* ✅ authenticate - Authenticate with selected auth method
|
||||
* ✅ session/new - Create new chat session
|
||||
* ✅ session/prompt - Send user message to agent
|
||||
* ✅ session/cancel - Cancel current generation
|
||||
* ✅ session/load - Load previous session
|
||||
* ✅ session/save - Save current session
|
||||
*/
|
||||
export class AcpConnection {
|
||||
private child: ChildProcess | null = null;
|
||||
private pendingRequests = new Map<number, PendingRequest<unknown>>();
|
||||
private nextRequestId = { value: 0 };
|
||||
private backend: AcpBackend | null = null;
|
||||
// Remember the working dir provided at connect() so later ACP calls
|
||||
// that require cwd (e.g. session/list) can include it.
|
||||
private workingDir: string = process.cwd();
|
||||
|
||||
private messageHandler: AcpMessageHandler;
|
||||
private sessionManager: AcpSessionManager;
|
||||
@@ -83,6 +69,7 @@ export class AcpConnection {
|
||||
}
|
||||
|
||||
this.backend = backend;
|
||||
this.workingDir = workingDir;
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
const env = { ...process.env };
|
||||
@@ -327,12 +314,16 @@ export class AcpConnection {
|
||||
* @param sessionId - Session ID
|
||||
* @returns Load response
|
||||
*/
|
||||
async loadSession(sessionId: string): Promise<AcpResponse> {
|
||||
async loadSession(
|
||||
sessionId: string,
|
||||
cwdOverride?: string,
|
||||
): Promise<AcpResponse> {
|
||||
return this.sessionManager.loadSession(
|
||||
sessionId,
|
||||
this.child,
|
||||
this.pendingRequests,
|
||||
this.nextRequestId,
|
||||
cwdOverride || this.workingDir,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -341,11 +332,16 @@ export class AcpConnection {
|
||||
*
|
||||
* @returns Session list response
|
||||
*/
|
||||
async listSessions(): Promise<AcpResponse> {
|
||||
async listSessions(options?: {
|
||||
cursor?: number;
|
||||
size?: number;
|
||||
}): Promise<AcpResponse> {
|
||||
return this.sessionManager.listSessions(
|
||||
this.child,
|
||||
this.pendingRequests,
|
||||
this.nextRequestId,
|
||||
this.workingDir,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ export class AcpMessageHandler {
|
||||
if ('result' in message) {
|
||||
console.log(
|
||||
`[ACP] Response for ${method}:`,
|
||||
JSON.stringify(message.result).substring(0, 200),
|
||||
// JSON.stringify(message.result).substring(0, 200),
|
||||
message.result,
|
||||
);
|
||||
if (
|
||||
message.result &&
|
||||
@@ -204,11 +205,11 @@ export class AcpMessageHandler {
|
||||
}> {
|
||||
try {
|
||||
const response = await callbacks.onPermissionRequest(params);
|
||||
const optionId = response.optionId;
|
||||
const optionId = response?.optionId;
|
||||
console.log('[ACP] Permission request:', optionId);
|
||||
// Handle cancel, deny, or allow
|
||||
let outcome: string;
|
||||
if (optionId.includes('reject') || optionId === 'cancel') {
|
||||
if (optionId && (optionId.includes('reject') || optionId === 'cancel')) {
|
||||
outcome = 'cancelled';
|
||||
} else {
|
||||
outcome = 'selected';
|
||||
|
||||
@@ -196,7 +196,7 @@ export class AcpSessionManager {
|
||||
nextRequestId,
|
||||
);
|
||||
|
||||
this.sessionId = response.sessionId || null;
|
||||
this.sessionId = (response && response.sessionId) || null;
|
||||
console.log('[ACP] Session created with ID:', this.sessionId);
|
||||
return response;
|
||||
}
|
||||
@@ -247,11 +247,12 @@ export class AcpSessionManager {
|
||||
child: ChildProcess | null,
|
||||
pendingRequests: Map<number, PendingRequest<unknown>>,
|
||||
nextRequestId: { value: number },
|
||||
cwd: string = process.cwd(),
|
||||
): Promise<AcpResponse> {
|
||||
console.log('[ACP] Sending session/load request for session:', sessionId);
|
||||
console.log('[ACP] Request parameters:', {
|
||||
sessionId,
|
||||
cwd: process.cwd(),
|
||||
cwd,
|
||||
mcpServers: [],
|
||||
});
|
||||
|
||||
@@ -260,7 +261,7 @@ export class AcpSessionManager {
|
||||
AGENT_METHODS.session_load,
|
||||
{
|
||||
sessionId,
|
||||
cwd: process.cwd(),
|
||||
cwd,
|
||||
mcpServers: [],
|
||||
},
|
||||
child,
|
||||
@@ -274,10 +275,13 @@ export class AcpSessionManager {
|
||||
);
|
||||
|
||||
// Check if response contains an error
|
||||
if (response.error) {
|
||||
if (response && response.error) {
|
||||
console.error('[ACP] Session load returned error:', response.error);
|
||||
} else {
|
||||
console.log('[ACP] Session load succeeded');
|
||||
// session/load returns null on success per schema; update local sessionId
|
||||
// so subsequent prompts use the loaded session.
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -302,12 +306,19 @@ export class AcpSessionManager {
|
||||
child: ChildProcess | null,
|
||||
pendingRequests: Map<number, PendingRequest<unknown>>,
|
||||
nextRequestId: { value: number },
|
||||
cwd: string = process.cwd(),
|
||||
options?: { cursor?: number; size?: number },
|
||||
): Promise<AcpResponse> {
|
||||
console.log('[ACP] Requesting session list...');
|
||||
try {
|
||||
// session/list requires cwd in params per ACP schema
|
||||
const params: Record<string, unknown> = { cwd };
|
||||
if (options?.cursor !== undefined) params.cursor = options.cursor;
|
||||
if (options?.size !== undefined) params.size = options.size;
|
||||
|
||||
const response = await this.sendRequest<AcpResponse>(
|
||||
AGENT_METHODS.session_list,
|
||||
{},
|
||||
params,
|
||||
child,
|
||||
pendingRequests,
|
||||
nextRequestId,
|
||||
|
||||
Reference in New Issue
Block a user