diff --git a/src/acp.ts b/src/acp.ts index a79d870..51355bf 100644 --- a/src/acp.ts +++ b/src/acp.ts @@ -31,7 +31,7 @@ type ConnectionPendingResponse = { * See protocol docs: [Agent](https://agentclientprotocol.com/protocol/overview#agent) */ export class AgentSideConnection { - #connection: Connection; + private connection: Connection; /** * Creates a new agent-side connection to a client. @@ -228,7 +228,7 @@ export class AgentSideConnection { } }; - this.#connection = new Connection( + this.connection = new Connection( requestHandler, notificationHandler, stream, @@ -249,7 +249,7 @@ export class AgentSideConnection { * See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) */ async sessionUpdate(params: schema.SessionNotification): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.CLIENT_METHODS.session_update, params, ); @@ -270,7 +270,7 @@ export class AgentSideConnection { async requestPermission( params: schema.RequestPermissionRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.CLIENT_METHODS.session_request_permission, params, ); @@ -287,7 +287,7 @@ export class AgentSideConnection { async readTextFile( params: schema.ReadTextFileRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.CLIENT_METHODS.fs_read_text_file, params, ); @@ -305,7 +305,7 @@ export class AgentSideConnection { params: schema.WriteTextFileRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.CLIENT_METHODS.fs_write_text_file, params, )) ?? {} @@ -327,7 +327,7 @@ export class AgentSideConnection { async createTerminal( params: schema.CreateTerminalRequest, ): Promise { - const response = await this.#connection.sendRequest< + const response = await this.connection.sendRequest< schema.CreateTerminalRequest, schema.CreateTerminalResponse >(schema.CLIENT_METHODS.terminal_create, params); @@ -335,7 +335,7 @@ export class AgentSideConnection { return new TerminalHandle( response.terminalId, params.sessionId, - this.#connection, + this.connection, ); } @@ -351,7 +351,7 @@ export class AgentSideConnection { async unstable_createElicitation( params: schema.CreateElicitationRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.CLIENT_METHODS.elicitation_create, params, ); @@ -369,7 +369,7 @@ export class AgentSideConnection { async unstable_completeElicitation( params: schema.CompleteElicitationNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.CLIENT_METHODS.elicitation_complete, params, ); @@ -384,7 +384,7 @@ export class AgentSideConnection { method: string, params: Record, ): Promise> { - return await this.#connection.sendRequest(method, params); + return await this.connection.sendRequest(method, params); } /** @@ -396,7 +396,7 @@ export class AgentSideConnection { method: string, params: Record, ): Promise { - return await this.#connection.sendNotification(method, params); + return await this.connection.sendNotification(method, params); } /** @@ -428,7 +428,7 @@ export class AgentSideConnection { * ``` */ get signal(): AbortSignal { - return this.#connection.signal; + return this.connection.signal; } /** @@ -447,7 +447,7 @@ export class AgentSideConnection { * ``` */ get closed(): Promise { - return this.#connection.closed; + return this.connection.closed; } } @@ -468,26 +468,26 @@ export class AgentSideConnection { * goes out of scope. */ export class TerminalHandle { - #sessionId: string; - #connection: Connection; + private sessionId: string; + private connection: Connection; constructor( public id: string, sessionId: string, conn: Connection, ) { - this.#sessionId = sessionId; - this.#connection = conn; + this.sessionId = sessionId; + this.connection = conn; } /** * Gets the current terminal output without waiting for the command to exit. */ async currentOutput(): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.CLIENT_METHODS.terminal_output, { - sessionId: this.#sessionId, + sessionId: this.sessionId, terminalId: this.id, }, ); @@ -497,10 +497,10 @@ export class TerminalHandle { * Waits for the terminal command to complete and returns its exit status. */ async waitForExit(): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.CLIENT_METHODS.terminal_wait_for_exit, { - sessionId: this.#sessionId, + sessionId: this.sessionId, terminalId: this.id, }, ); @@ -518,8 +518,8 @@ export class TerminalHandle { */ async kill(): Promise { return ( - (await this.#connection.sendRequest(schema.CLIENT_METHODS.terminal_kill, { - sessionId: this.#sessionId, + (await this.connection.sendRequest(schema.CLIENT_METHODS.terminal_kill, { + sessionId: this.sessionId, terminalId: this.id, })) ?? {} ); @@ -539,10 +539,10 @@ export class TerminalHandle { */ async release(): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.CLIENT_METHODS.terminal_release, { - sessionId: this.#sessionId, + sessionId: this.sessionId, terminalId: this.id, }, )) ?? {} @@ -565,7 +565,7 @@ export class TerminalHandle { * See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) */ export class ClientSideConnection implements Agent { - #connection: Connection; + private connection: Connection; /** * Creates a new client-side connection to an agent. @@ -666,7 +666,7 @@ export class ClientSideConnection implements Agent { } }; - this.#connection = new Connection( + this.connection = new Connection( requestHandler, notificationHandler, stream, @@ -688,7 +688,7 @@ export class ClientSideConnection implements Agent { async initialize( params: schema.InitializeRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.initialize, params, ); @@ -714,7 +714,7 @@ export class ClientSideConnection implements Agent { async newSession( params: schema.NewSessionRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_new, params, ); @@ -739,7 +739,7 @@ export class ClientSideConnection implements Agent { params: schema.LoadSessionRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.AGENT_METHODS.session_load, params, )) ?? {} @@ -766,7 +766,7 @@ export class ClientSideConnection implements Agent { async unstable_forkSession( params: schema.ForkSessionRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_fork, params, ); @@ -784,7 +784,7 @@ export class ClientSideConnection implements Agent { async listSessions( params: schema.ListSessionsRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_list, params, ); @@ -810,7 +810,7 @@ export class ClientSideConnection implements Agent { async unstable_resumeSession( params: schema.ResumeSessionRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_resume, params, ); @@ -833,7 +833,7 @@ export class ClientSideConnection implements Agent { async unstable_closeSession( params: schema.CloseSessionRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_close, params, ); @@ -858,7 +858,7 @@ export class ClientSideConnection implements Agent { params: schema.SetSessionModeRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.AGENT_METHODS.session_set_mode, params, )) ?? {} @@ -878,7 +878,7 @@ export class ClientSideConnection implements Agent { params: schema.SetSessionModelRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.AGENT_METHODS.session_set_model, params, )) ?? {} @@ -894,7 +894,7 @@ export class ClientSideConnection implements Agent { async setSessionConfigOption( params: schema.SetSessionConfigOptionRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_set_config_option, params, ); @@ -915,7 +915,7 @@ export class ClientSideConnection implements Agent { params: schema.AuthenticateRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.AGENT_METHODS.authenticate, params, )) ?? {} @@ -933,7 +933,7 @@ export class ClientSideConnection implements Agent { params: schema.LogoutRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.AGENT_METHODS.logout, params, )) ?? {} @@ -954,7 +954,7 @@ export class ClientSideConnection implements Agent { * See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn) */ async prompt(params: schema.PromptRequest): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.session_prompt, params, ); @@ -974,7 +974,7 @@ export class ClientSideConnection implements Agent { * See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) */ async cancel(params: schema.CancelNotification): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.session_cancel, params, ); @@ -990,7 +990,7 @@ export class ClientSideConnection implements Agent { async unstable_startNes( params: schema.StartNesRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.nes_start, params, ); @@ -1006,7 +1006,7 @@ export class ClientSideConnection implements Agent { async unstable_suggestNes( params: schema.SuggestNesRequest, ): Promise { - return await this.#connection.sendRequest( + return await this.connection.sendRequest( schema.AGENT_METHODS.nes_suggest, params, ); @@ -1023,7 +1023,7 @@ export class ClientSideConnection implements Agent { params: schema.CloseNesRequest, ): Promise { return ( - (await this.#connection.sendRequest( + (await this.connection.sendRequest( schema.AGENT_METHODS.nes_close, params, )) ?? {} @@ -1040,7 +1040,7 @@ export class ClientSideConnection implements Agent { async unstable_didOpenDocument( params: schema.DidOpenDocumentNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.document_did_open, params, ); @@ -1056,7 +1056,7 @@ export class ClientSideConnection implements Agent { async unstable_didChangeDocument( params: schema.DidChangeDocumentNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.document_did_change, params, ); @@ -1072,7 +1072,7 @@ export class ClientSideConnection implements Agent { async unstable_didCloseDocument( params: schema.DidCloseDocumentNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.document_did_close, params, ); @@ -1088,7 +1088,7 @@ export class ClientSideConnection implements Agent { async unstable_didSaveDocument( params: schema.DidSaveDocumentNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.document_did_save, params, ); @@ -1104,7 +1104,7 @@ export class ClientSideConnection implements Agent { async unstable_didFocusDocument( params: schema.DidFocusDocumentNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.document_did_focus, params, ); @@ -1120,7 +1120,7 @@ export class ClientSideConnection implements Agent { async unstable_acceptNes( params: schema.AcceptNesNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.nes_accept, params, ); @@ -1136,7 +1136,7 @@ export class ClientSideConnection implements Agent { async unstable_rejectNes( params: schema.RejectNesNotification, ): Promise { - return await this.#connection.sendNotification( + return await this.connection.sendNotification( schema.AGENT_METHODS.nes_reject, params, ); @@ -1151,7 +1151,7 @@ export class ClientSideConnection implements Agent { method: string, params: Record, ): Promise> { - return await this.#connection.sendRequest(method, params); + return await this.connection.sendRequest(method, params); } /** @@ -1163,7 +1163,7 @@ export class ClientSideConnection implements Agent { method: string, params: Record, ): Promise { - return await this.#connection.sendNotification(method, params); + return await this.connection.sendNotification(method, params); } /** @@ -1195,7 +1195,7 @@ export class ClientSideConnection implements Agent { * ``` */ get signal(): AbortSignal { - return this.#connection.signal; + return this.connection.signal; } /** @@ -1214,35 +1214,37 @@ export class ClientSideConnection implements Agent { * ``` */ get closed(): Promise { - return this.#connection.closed; + return this.connection.closed; } } export type { AnyMessage } from "./jsonrpc.js"; class Connection { - #pendingResponses: Map = - new Map(); - #nextRequestId: number = 0; - #requestHandler: RequestHandler; - #notificationHandler: NotificationHandler; - #stream: Stream; - #writeQueue: Promise = Promise.resolve(); - #abortController = new AbortController(); - #closedPromise: Promise; + private pendingResponses: Map< + string | number | null, + ConnectionPendingResponse + > = new Map(); + private nextRequestId: number = 0; + private requestHandler: RequestHandler; + private notificationHandler: NotificationHandler; + private stream: Stream; + private writeQueue: Promise = Promise.resolve(); + private abortController = new AbortController(); + private closedPromise: Promise; constructor( requestHandler: RequestHandler, notificationHandler: NotificationHandler, stream: Stream, ) { - this.#requestHandler = requestHandler; - this.#notificationHandler = notificationHandler; - this.#stream = stream; - this.#closedPromise = new Promise((resolve) => { - this.#abortController.signal.addEventListener("abort", () => resolve()); + this.requestHandler = requestHandler; + this.notificationHandler = notificationHandler; + this.stream = stream; + this.closedPromise = new Promise((resolve) => { + this.abortController.signal.addEventListener("abort", () => resolve()); }); - void this.#receive(); + void this.receive(); } /** @@ -1254,7 +1256,7 @@ class Connection { * - Pass to other APIs (fetch, setTimeout) for automatic cancellation */ get signal(): AbortSignal { - return this.#abortController.signal; + return this.abortController.signal; } /** @@ -1272,16 +1274,16 @@ class Connection { * ``` */ get closed(): Promise { - return this.#closedPromise; + return this.closedPromise; } - async #receive() { + private async receive() { let closeError: unknown = undefined; try { - const reader = this.#stream.readable.getReader(); + const reader = this.stream.readable.getReader(); try { - while (!this.#abortController.signal.aborted) { + while (!this.abortController.signal.aborted) { const { value: message, done } = await reader.read(); if (done) { break; @@ -1291,7 +1293,7 @@ class Connection { } try { - this.#processMessage(message); + this.processMessage(message); } catch (err) { console.error( "Unexpected error during message processing:", @@ -1300,7 +1302,7 @@ class Connection { ); // Only send error response if the message had an id (was a request) if ("id" in message && message.id !== undefined) { - this.#sendMessage({ + this.sendMessage({ jsonrpc: "2.0", id: message.id, error: { @@ -1317,27 +1319,27 @@ class Connection { } catch (error) { closeError = error; } finally { - this.#close(closeError); + this.close(closeError); } } - #close(error?: unknown) { - if (this.#abortController.signal.aborted) { + private close(error?: unknown) { + if (this.abortController.signal.aborted) { return; } const closeError: unknown = error ?? new Error("ACP connection closed"); - for (const pendingResponse of this.#pendingResponses.values()) { + for (const pendingResponse of this.pendingResponses.values()) { pendingResponse.reject(closeError); } - this.#pendingResponses.clear(); - this.#abortController.abort(closeError); + this.pendingResponses.clear(); + this.abortController.abort(closeError); } - async #processMessage(message: AnyMessage) { + private async processMessage(message: AnyMessage) { if ("method" in message && "id" in message) { // It's a request - const response = await this.#tryCallRequestHandler( + const response = await this.tryCallRequestHandler( message.method, message.params, ); @@ -1345,14 +1347,14 @@ class Connection { console.error("Error handling request", message, response.error); } - await this.#sendMessage({ + await this.sendMessage({ jsonrpc: "2.0", id: message.id, ...response, }); } else if ("method" in message) { // It's a notification - const response = await this.#tryCallNotificationHandler( + const response = await this.tryCallNotificationHandler( message.method, message.params, ); @@ -1361,18 +1363,18 @@ class Connection { } } else if ("id" in message) { // It's a response - this.#handleResponse(message); + this.handleResponse(message); } else { console.error("Invalid message", { message }); } } - async #tryCallRequestHandler( + private async tryCallRequestHandler( method: string, params: unknown, ): Promise> { try { - const result = await this.#requestHandler(method, params); + const result = await this.requestHandler(method, params); return { result: result ?? null }; } catch (error: unknown) { if (error instanceof RequestError) { @@ -1406,12 +1408,12 @@ class Connection { } } - async #tryCallNotificationHandler( + private async tryCallNotificationHandler( method: string, params: unknown, ): Promise> { try { - await this.#notificationHandler(method, params); + await this.notificationHandler(method, params); return { result: null }; } catch (error: unknown) { if (error instanceof RequestError) { @@ -1445,8 +1447,8 @@ class Connection { } } - #handleResponse(response: AnyResponse) { - const pendingResponse = this.#pendingResponses.get(response.id); + private handleResponse(response: AnyResponse) { + const pendingResponse = this.pendingResponses.get(response.id); if (pendingResponse) { if ("result" in response) { pendingResponse.resolve(response.result); @@ -1454,40 +1456,39 @@ class Connection { const { code, message, data } = response.error; pendingResponse.reject(new RequestError(code, message, data)); } - this.#pendingResponses.delete(response.id); + this.pendingResponses.delete(response.id); } else { console.error("Got response to unknown request", response.id); } } async sendRequest(method: string, params?: Req): Promise { - this.#throwIfClosed(); - const id = this.#nextRequestId++; + this.throwIfClosed(); + const id = this.nextRequestId++; const responsePromise = new Promise((resolve, reject) => { - this.#pendingResponses.set(id, { resolve, reject }); + this.pendingResponses.set(id, { resolve, reject }); }); - await this.#sendMessage({ jsonrpc: "2.0", id, method, params }); + await this.sendMessage({ jsonrpc: "2.0", id, method, params }); return responsePromise as Promise; } async sendNotification(method: string, params?: N): Promise { - this.#throwIfClosed(); - await this.#sendMessage({ jsonrpc: "2.0", method, params }); + this.throwIfClosed(); + await this.sendMessage({ jsonrpc: "2.0", method, params }); } - #throwIfClosed() { - if (this.#abortController.signal.aborted) { + private throwIfClosed() { + if (this.abortController.signal.aborted) { throw ( - this.#abortController.signal.reason ?? - new Error("ACP connection closed") + this.abortController.signal.reason ?? new Error("ACP connection closed") ); } } - async #sendMessage(message: AnyMessage) { - this.#writeQueue = this.#writeQueue + private async sendMessage(message: AnyMessage) { + this.writeQueue = this.writeQueue .then(async () => { - const writer = this.#stream.writable.getWriter(); + const writer = this.stream.writable.getWriter(); try { await writer.write(message); } finally { @@ -1495,9 +1496,9 @@ class Connection { } }) .catch((error) => { - this.#close(error); + this.close(error); }); - return this.#writeQueue; + return this.writeQueue; } }