### Running the Client Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/README.md Command to run the client example from the root directory. ```bash npx tsx src/examples/client.ts ``` -------------------------------- ### Install Command Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Command to install the SDK and its peer dependency Zod. ```bash npm install @agentclientprotocol/sdk zod ``` -------------------------------- ### Implementation Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Agent.md This is an example of how to implement the Agent interface. ```typescript class MyAgent implements Agent { private sessions: Map = new Map(); async initialize(params: InitializeRequest): Promise { // Verify client protocol version if (params.protocolVersion !== PROTOCOL_VERSION) { throw RequestError.invalidRequest( { clientVersion: params.protocolVersion } ); } return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: { loadSession: true, listSessions: true, session: { close: true, mode: true, }, }, authMethods: [ { id: "oauth", name: "GitHub OAuth", provider: "github", }, ], }; } async newSession(params: NewSessionRequest): Promise { // Create session context const sessionId = crypto.randomUUID(); const context: SessionContext = { id: sessionId, cwd: params.cwd, history: [], model: "gpt-4", }; this.sessions.set(sessionId, context); return { sessionId, availableModes: [ { id: "ask", name: "Ask Mode" }, { id: "code", name: "Code Mode" }, ], }; } async authenticate(params: AuthenticateRequest): Promise { // Handle authentication if (params.methodId === "oauth") { // Verify OAuth token // Throw if invalid: // throw RequestError.authRequired(); } } async prompt(params: PromptRequest): Promise { const session = this.sessions.get(params.sessionId); if (!session) { throw RequestError.resourceNotFound(params.sessionId); } try { // Send initial message chunk await this.connection.sessionUpdate({ sessionId: params.sessionId, update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "I'll analyze this for you...", }, }, }); // Call language model (pseudo-code) const llmResponse = await this.callLLM(params.prompt); // If tool call needed, request permission if (llmResponse.toolCall) { const permission = await this.connection.requestPermission({ sessionId: params.sessionId, toolCall: llmResponse.toolCall, options: [ { kind: "allow_once", name: "Execute", optionId: "allow", }, ], }); if (permission.outcome.outcome === "selected") { // Execute tool const result = await this.executeTool(llmResponse.toolCall); // Report result await this.connection.sessionUpdate({ sessionId: params.sessionId, update: { sessionUpdate: "tool_call_update", toolCallId: llmResponse.toolCall.toolCallId, status: "completed", rawOutput: result, }, }); } } return { stopReason: "end_turn" }; } catch (error) { if (this.sessions.get(params.sessionId)?.cancelled) { return { stopReason: "cancelled" }; } throw error; } } async cancel(params: CancelNotification): Promise { const session = this.sessions.get(params.sessionId); if (session) { session.cancelled = true; // Abort ongoing operations } } // Optional methods async loadSession(params: LoadSessionRequest): Promise { // Restore session from storage const session = await loadSessionFromDB(params.sessionId); return { sessionInfo: session }; } async listSessions(params: ListSessionsRequest): Promise { const sessions = await listSessionsFromDB(params.cwd); return { sessions }; } async closeSession(params: CloseSessionRequest): Promise { this.sessions.delete(params.sessionId); // Clean up resources } async setSessionMode(params: SetSessionModeRequest): Promise { const session = this.sessions.get(params.sessionId); if (session) { session.mode = params.mode; } } async resumeSession(params: ResumeSessionRequest): Promise { const session = this.sessions.get(params.sessionId); if (!session) { throw RequestError.resourceNotFound(params.sessionId); } return { sessionInfo: { sessionId: session.id } }; } // Not implementing extension methods extMethod?: undefined; extNotification?: undefined; } ``` -------------------------------- ### waitForTerminalExit Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the waitForTerminalExit method. ```typescript async waitForTerminalExit( params: WaitForTerminalExitRequest ): Promise { const terminal = this.terminals.get(params.terminalId); if (!terminal) { throw RequestError.resourceNotFound(params.terminalId); } return await terminal.waitForExit(); } ``` -------------------------------- ### writeTextFile Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the writeTextFile method using Node.js fs/promises. ```typescript async writeTextFile( params: WriteTextFileRequest ): Promise { const fs = await import("fs/promises"); await fs.writeFile(params.path, params.content, "utf-8"); return {}; } ``` -------------------------------- ### Agent Initialization Response Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/README.md Example response from the agent after initialization. ```json {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":1,"agentCapabilities":{"loadSession":false}}} ``` -------------------------------- ### Installation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/README.md Install the ACP TypeScript SDK using npm. ```bash npm install @agentclientprotocol/sdk ``` -------------------------------- ### requestPermission Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the requestPermission method. ```typescript class MyClient implements Client { async requestPermission( params: RequestPermissionRequest ): Promise { const { toolCall, options } = params; console.log(`\nšŸ” Permission requested: ${toolCall.title}`); // Present options to user options.forEach((opt, i) => { console.log(`${i + 1}. ${opt.name} (${opt.kind})`); }); // In a real client, prompt the user const userChoice = await getUserInput(); const selectedOption = options[userChoice - 1]; return { outcome: { outcome: "selected", optionId: selectedOption.optionId, }, }; } } ``` -------------------------------- ### Constructor Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Example demonstrating how to instantiate AgentSideConnection with a custom Agent implementation and an ndJsonStream. ```typescript import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"; import { Readable, Writable } from "node:stream"; class MyAgent implements Agent { async initialize(params) { return { protocolVersion: 1, agentCapabilities: { loadSession: false }, }; } async newSession(params) { return { sessionId: "session-123" }; } async authenticate(params) { return {}; } async prompt(params) { return { stopReason: "end_turn" }; } async cancel(params) { // Handle cancellation } } const input = Writable.toWeb(process.stdout); const output = Readable.toWeb(process.stdin) as ReadableStream; const stream = ndJsonStream(input, output); const connection = new AgentSideConnection((conn) => new MyAgent(), stream); ``` -------------------------------- ### createTerminal Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the createTerminal method. ```typescript async createTerminal( params: CreateTerminalRequest ): Promise { const terminalId = generateUUID(); // Create terminal in editor await editorAPI.createTerminal(terminalId, params.cwd); // Execute command editorAPI.executeInTerminal( terminalId, params.command, params.args ); return { terminalId }; } ``` -------------------------------- ### readTextFile Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the readTextFile method using Node.js fs/promises. ```typescript async readTextFile( params: ReadTextFileRequest ): Promise { const fs = await import("fs/promises"); const content = await fs.readFile(params.path, "utf-8"); return { content }; } ``` -------------------------------- ### Logging Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of setting up debug and log level from environment variables. ```typescript const debug = process.env.DEBUG === "true"; const logLevel = process.env.LOG_LEVEL || "info"; ``` -------------------------------- ### sessionUpdate Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the sessionUpdate method. ```typescript class MyClient implements Client { async sessionUpdate(params: SessionNotification): Promise { const update = params.update; switch (update.sessionUpdate) { case "agent_message_chunk": if (update.content.type === "text") { console.log(update.content.text); } break; case "tool_call": console.log(`\nšŸ”§ ${update.title} (${update.status})`); break; case "tool_call_update": console.log(`Tool ${update.toolCallId} updated: ${update.status}`); break; case "plan": console.log("Plan:"); update.plan.entries.forEach((e) => { console.log(` - ${e.description}`); }); break; } } } ``` -------------------------------- ### extMethod Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of extMethod for a custom editor state retrieval. ```typescript async extMethod( method: string, params: Record ): Promise> { if (method === "com.myeditor.getEditorState") { return { activeFile: this.getActiveFile(), selection: this.getSelection(), }; } throw RequestError.methodNotFound(method); } ``` -------------------------------- ### Server Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of configuring server host and port from environment variables. ```typescript const port = parseInt(process.env.PORT || "8080"); const host = process.env.HOST || "localhost"; ``` -------------------------------- ### terminalOutput Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the terminalOutput method. ```typescript async terminalOutput( params: TerminalOutputRequest ): Promise { const terminal = this.terminals.get(params.terminalId); return { output: terminal?.getOutput() || "", exitStatus: terminal?.getExitStatus(), }; } ``` -------------------------------- ### extMethod Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Example usage of extMethod to send a custom method request. ```typescript const result = await connection.extMethod("com.mycompany.analyzeCode", { sessionId: "session-123", filePath: "/code.ts", }); ``` -------------------------------- ### Capability Advertisement Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example of how to advertise client capabilities during initialization. ```typescript const result = await connection.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: { fs: { readTextFile: true, // Can read files writeTextFile: true, // Can write files }, terminal: true, // Can create terminals elicitation: true, // Can create elicitations }, }); ``` -------------------------------- ### Client Implementation Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md An example implementation of the Agent Protocol Client interface in TypeScript, demonstrating how to handle various agent requests and notifications. ```typescript import { Client, ClientSideConnection, RequestPermissionRequest, RequestPermissionResponse, SessionNotification, ReadTextFileRequest, ReadTextFileResponse, WriteTextFileRequest, CreateTerminalRequest, CreateTerminalResponse, ndJsonStream, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk"; import { Writable, Readable } from "node:stream"; import { spawn } from "node:child_process"; import * as fs from "fs/promises"; class MyEditorClient implements Client { private terminals: Map = new Map(); async initialize(): Promise { const agentProcess = spawn("node", ["agent.js"], { stdio: ["pipe", "pipe", "inherit"], }); const input = Writable.toWeb(agentProcess.stdin!); const output = Readable.toWeb( agentProcess.stdout! ) as ReadableStream; const stream = ndJsonStream(input, output); this.connection = new ClientSideConnection( (_agent) => this, stream ); // Initialize connection const result = await this.connection.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: { fs: { readTextFile: true, writeTextFile: true, }, terminal: true, }, }); console.log(`Connected to agent v${result.protocolVersion}`); } async requestPermission( params: RequestPermissionRequest ): Promise { const { toolCall, options } = params; // Show permission dialog const response = await this.showPermissionDialog({ title: toolCall.title, options: options.map((o) => ({ id: o.optionId, label: o.name, kind: o.kind, })), }); return { outcome: { outcome: "selected", optionId: response, }, }; } async sessionUpdate(params: SessionNotification): Promise { const update = params.update; switch (update.sessionUpdate) { case "agent_message_chunk": this.appendToOutput(update.content.text || "[media]"); break; case "tool_call": this.appendToOutput(`\nšŸ”§ ${update.title}\n`); break; case "tool_call_update": this.appendToOutput(`āœ“ Tool completed\n`); break; } } async readTextFile( params: ReadTextFileRequest ): Promise { const content = await fs.readFile(params.path, "utf-8"); return { content }; } async writeTextFile( params: WriteTextFileRequest ): Promise { await fs.writeFile(params.path, params.content, "utf-8"); return {}; } async createTerminal( params: CreateTerminalRequest ): Promise { const terminalId = `term-${Date.now()}`; const terminal = new EditorTerminal( params.command, params.args, params.cwd ); this.terminals.set(terminalId, terminal); // Show terminal in editor this.showTerminal(terminalId, terminal); return { terminalId }; } async terminalOutput( params: any ): Promise<{ output: string; exitStatus?: any }> { const terminal = this.terminals.get(params.terminalId); return { output: terminal?.getOutput() || "", exitStatus: terminal?.getExitStatus(), }; } async waitForTerminalExit(params: any): Promise { const terminal = this.terminals.get(params.terminalId); if (!terminal) { throw new Error("Terminal not found"); } return terminal.waitForExit(); } async releaseTerminal(params: any): Promise { const terminal = this.terminals.get(params.terminalId); if (terminal) { terminal.kill(); this.closeTerminalUI(params.terminalId); this.terminals.delete(params.terminalId); } } // Helper methods private async showPermissionDialog(options: any): Promise { // Implementation specific to your editor return "option-1"; } private appendToOutput(text: string): void { // Implementation specific to your editor } private showTerminal(id: string, terminal: any): void { // Implementation specific to your editor } private closeTerminalUI(id: string): void { // Implementation specific to your editor } } // Usage const client = new MyEditorClient(); await client.initialize(); ``` -------------------------------- ### Agent-Side Initialization Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md When an agent starts, it advertises its capabilities in response to `initialize()`. ```typescript class MyAgent implements Agent { async initialize(params): Promise { // Verify client protocol version if (params.protocolVersion !== PROTOCOL_VERSION) { throw RequestError.invalidRequest(); } return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: { // Declare agent capabilities loadSession: true, listSessions: true, session: { resume: true, close: true, mode: true, fork: false, // This agent doesn't fork sessions }, prompt: { supportsImages: true, supportsAudio: false, }, authentication: { methods: [ { id: "oauth", name: "GitHub OAuth", provider: "github", }, ], }, }, // Optional: List available authentication methods authMethods: [ { id: "oauth", name: "GitHub OAuth", provider: "github", }, ], }; } } ``` -------------------------------- ### sessionUpdate Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Example of sending a session update notification to the client. ```typescript await connection.sessionUpdate({ sessionId: "session-123", update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "I'm analyzing your code...", }, }, }); ``` -------------------------------- ### unstable_createElicitation Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the unstable_createElicitation method, demonstrating form and URL-based elicitation. ```typescript async unstable_createElicitation( params: CreateElicitationRequest ): Promise { const elicitationId = generateUUID(); if (params.kind === "form") { // Show form to user const response = await showFormDialog(params.schema); return { elicitationId, result: response }; } else if (params.kind === "url") { // Open URL in browser const result = await openExternalURL(params.url); return { elicitationId, url: params.url, result }; } } ``` -------------------------------- ### Initialize Agent Message Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/README.md Example JSON-RPC message to initialize the agent. ```json {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":1}} ``` -------------------------------- ### requestPermission Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Example demonstrating how to request user permission for a sensitive tool call. ```typescript const response = await connection.requestPermission({ sessionId: "session-123", toolCall: { toolCallId: "call-1", title: "Modify critical file", kind: "edit", status: "pending", locations: [{ path: "/path/to/file.js" }], rawInput: { path: "/path/to/file.js", content: "new code" }, }, options: [ { kind: "allow_once", name: "Allow this change", optionId: "allow", }, { kind: "reject_once", name: "Skip this change", optionId: "reject", }, ], }); if (response.outcome.outcome === "selected") { console.log(`User selected: ${response.outcome.optionId}`); } ``` -------------------------------- ### killTerminal Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the killTerminal method. ```typescript async killTerminal( params: KillTerminalRequest ): Promise { const terminal = this.terminals.get(params.terminalId); if (terminal) { terminal.kill(); } } ``` -------------------------------- ### releaseTerminal Example Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Example implementation of the releaseTerminal method. ```typescript async releaseTerminal( params: ReleaseTerminalRequest ): Promise { const terminal = this.terminals.get(params.terminalId); if (terminal) { terminal.kill(); terminal.close(); this.terminals.delete(params.terminalId); } } ``` -------------------------------- ### Zed Agent Server Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/README.md Configuration to add to Zed's settings to connect to the example agent. ```json "agent_servers": { "Example Agent": { "command": "npx", "args": [ "tsx", "/path/to/agent-client-protocol/src/examples/agent.ts" ] } } ``` -------------------------------- ### initialize Method Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Shows how to use the `initialize` method to establish the connection and negotiate protocol capabilities with the agent. ```typescript const result = await connection.initialize({ protocolVersion: 1, clientCapabilities: { fs: { readTextFile: true, writeTextFile: true, }, terminal: true, }, }); console.log(`Connected to agent protocol v${result.protocolVersion}`); console.log(`Agent capabilities:`, result.agentCapabilities); ``` -------------------------------- ### Declare All Capabilities Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example demonstrating explicit declaration of agent capabilities, contrasting good and bad practices. ```typescript // āœ“ Good - declare capabilities clearly return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: { loadSession: false, // Explicitly false listSessions: true, session: { resume: true, close: false, // Not supported mode: true, }, }, }; // āœ— Avoid - unclear what's supported return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: {}, // Unclear }; ``` -------------------------------- ### Package.json Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example package.json configuration for the SDK, specifying module type and peer dependencies. ```json { "name": "@agentclientprotocol/sdk", "version": "0.22.1", "type": "module", "main": "dist/acp.js", "types": "dist/acp.d.ts", "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } } ``` -------------------------------- ### TypeScript Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example TypeScript configuration file (tsconfig.json) for using the SDK. ```json { "compilerOptions": { "target": "ES2020", "module": "ES2022", "lib": ["ES2022"], "declaration": true, "declarationMap": true, "sourceMap": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true } } ``` -------------------------------- ### Example: Node.js Client Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Stream.md Example of creating a ClientSideConnection using ndJsonStream with Node.js streams. ```typescript import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"; import { spawn } from "node:child_process"; import { Readable, Writable } from "node:stream"; class MyClient implements Client { requestPermission(params) { return { outcome: { outcome: "selected", optionId: "allow" } }; } sessionUpdate(params) { console.log("Update:", params.update); } } // Spawn an agent process const agentProcess = spawn("node", ["agent.js"], { stdio: ["pipe", "pipe", "inherit"], }); // Convert Node.js streams to Web Streams const input = Writable.toWeb(agentProcess.stdin!); const output = Readable.toWeb( agentProcess.stdout! ) as ReadableStream; // Create the bidirectional stream const stream = ndJsonStream(input, output); // Create the connection const connection = new ClientSideConnection( () => new MyClient(), stream ); // Use the connection const initialized = await connection.initialize({ protocolVersion: 1, clientCapabilities: {}, }); const session = await connection.newSession({ cwd: process.cwd() }); ``` -------------------------------- ### Error Handling Examples Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Agent.md Examples of throwing RequestError for different protocol-level errors. ```typescript if (!session) { throw RequestError.resourceNotFound(sessionId); } if (!isAuthenticated) { throw RequestError.authRequired(); } if (invalidParams) { throw RequestError.invalidParams({ expected: "format" }); } ``` -------------------------------- ### Validate on Initialization Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of validating client capabilities during agent initialization. ```typescript async initialize(params) { // Check if client supports required capabilities if (!params.clientCapabilities?.fs?.readTextFile) { console.warn("Client doesn't support reading files"); } return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: { // ... your capabilities }, }; } ``` -------------------------------- ### Handle Missing Capabilities Gracefully Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of checking for client capabilities and providing a fallback mechanism. ```typescript if (clientCapabilities.fs?.writeTextFile) { // Can write files await connection.writeTextFile({ path, content }); } else { // Fall back to alternative approach console.warn("Client doesn't support writing files"); } ``` -------------------------------- ### Client Implementation Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/README.md Demonstrates how to implement a client using the SDK, including handling various client methods and establishing a connection with an agent. ```typescript import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"; import { spawn } from "node:child_process"; class MyClient implements Client { async requestPermission(params) { // Show dialog to user, return decision return { outcome: { outcome: "selected", optionId: "allow" } }; } async sessionUpdate(params) { // Display progress, messages, tool calls to user } async readTextFile(params) { // Read from editor's file system } async writeTextFile(params) { // Write to editor's file system } async createTerminal(params) { // Create terminal in editor } // ... implement other optional methods } const agent = spawn("node", ["agent.js"], { stdio: ["pipe", "pipe", "inherit"] }); const input = Writable.toWeb(agent.stdin!); const output = Readable.toWeb(agent.stdout!); const stream = ndJsonStream(input, output); const connection = new ClientSideConnection( () => new MyClient(), stream ); await connection.initialize({ protocolVersion: 1, clientCapabilities: { /* ... */ }, }); const session = await connection.newSession({ cwd: process.cwd() }); const result = await connection.prompt({ sessionId: session.sessionId, prompt: [{ type: "text", text: "Hello, agent!" }], }); ``` -------------------------------- ### Start NES Session (Experimental) Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Starts a NES (Next Edit Suggestions) session. ```typescript unstable_startNes( params: StartNesRequest ): Promise ``` -------------------------------- ### Example: Node.js Agent Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Stream.md Example of creating an AgentSideConnection using ndJsonStream with Node.js streams. ```typescript import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"; import { Readable, Writable } from "node:stream"; class MyAgent implements Agent { async initialize(params) { return { protocolVersion: 1, agentCapabilities: {}, }; } async newSession(params) { return { sessionId: "123" }; } async authenticate(params) { return {}; } async prompt(params) { return { stopReason: "end_turn" }; } async cancel(params) {} } // Convert Node.js streams to Web Streams const input = Writable.toWeb(process.stdout); const output = Readable.toWeb(process.stdin) as ReadableStream; // Create the bidirectional stream const stream = ndJsonStream(input, output); // Create the connection new AgentSideConnection((conn) => new MyAgent(), stream); ``` -------------------------------- ### Running the Agent by itself Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/README.md Command to run the agent example directly and send messages to it. ```bash npx tsx src/examples/agent.ts ``` -------------------------------- ### Connection Cleanup Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of monitoring connection closure and performing cleanup actions. ```typescript const connection = new AgentSideConnection( (conn) => new MyAgent(), stream ); // Monitor connection closure connection.closed.then(() => { console.log("Connection closed - cleanup complete"); // Perform cleanup process.exit(0); }); // Or use async disposal pattern if (connection instanceof AgentSideConnection) { // Use with other resources in cleanup } ``` -------------------------------- ### Example: Browser WebSocket Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Stream.md Example of creating a ClientSideConnection using ndJsonStream with a browser WebSocket. ```typescript import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"; const ws = new WebSocket("ws://localhost:8080"); // Convert WebSocket to readable stream const readable = new ReadableStream({ start(controller) { ws.onmessage = (event) => { const encoder = new TextEncoder(); controller.enqueue(encoder.encode(event.data + "\n")); }; ws.onerror = () => controller.error(new Error("WebSocket error")); ws.onclose = () => controller.close(); }, }); // Convert WebSocket to writable stream const writable = new WritableStream({ async write(chunk) { const decoder = new TextDecoder(); const text = decoder.decode(chunk); ws.send(text); }, }); // Create the stream const stream = ndJsonStream(writable, readable); // Use with connection const connection = new ClientSideConnection( () => myClient, stream ); ``` -------------------------------- ### signal Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Example usage of the signal property to listen for connection closure and check status. ```typescript connection.signal.addEventListener('abort', () => { console.log('Connection closed - cleanup'); }); if (connection.signal.aborted) { console.log('Connection is already closed'); } fetch(url, { signal: connection.signal }); ``` -------------------------------- ### Clone the repository Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/README.md Command to clone the agent-client-protocol repository. ```sh $ git clone https://github.com/agentclientprotocol/typescript-sdk.git ``` -------------------------------- ### Use Type-Safe Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example demonstrating the use of TypeScript interfaces for type-safe session configuration. ```typescript interface SessionConfig { readonly cwd: string; readonly mcpServers: readonly McpServer[]; readonly timeout?: number; } async function createConfiguredSession( connection: ClientSideConnection, config: SessionConfig ) { return connection.newSession({ cwd: config.cwd, mcpServers: config.mcpServers, }); } ``` -------------------------------- ### Type System Import Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/README.md Illustrates how to import various types and constants from the SDK module. ```typescript import { Agent, Client, AgentSideConnection, ClientSideConnection, TerminalHandle, RequestError, Stream, ndJsonStream, // Types SessionId, PromptRequest, PromptResponse, InitializeRequest, InitializeResponse, // Constants PROTOCOL_VERSION, AGENT_METHODS, CLIENT_METHODS, } from "@agentclientprotocol/sdk"; ``` -------------------------------- ### WebSocket Stream (Browser) Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of creating a WebSocket stream for browser environments. ```typescript function websocketStream(url: string): Stream { const ws = new WebSocket(url); const readable = new ReadableStream({ start(controller) { ws.addEventListener("message", (event) => { try { const encoder = new TextEncoder(); controller.enqueue(encoder.encode(event.data + "\n")); } catch (err) { console.error("Error:", err); } }); ws.addEventListener("close", () => controller.close()); ws.addEventListener("error", () => controller.error(new Error("WebSocket error")) ); }, }); const writable = new WritableStream({ write(chunk) { const decoder = new TextDecoder(); const text = decoder.decode(chunk); if (ws.readyState === WebSocket.OPEN) { ws.send(text); } }, }); return { readable, writable }; } // Usage const stream = websocketStream("ws://localhost:8080"); const connection = new ClientSideConnection( () => new MyClient(), stream ); ``` -------------------------------- ### Session Configuration Options Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Get or set specific configuration options. ```typescript // Get or set specific configuration options const configResponse = await connection.setSessionConfigOption({ sessionId: session.sessionId, optionId: "temperature", valueId: "0.7", }); // Response includes full current configuration console.log(configResponse.options); // All current config ``` -------------------------------- ### Example of using parseError Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/RequestError.md Demonstrates throwing a parseError with details. ```typescript throw RequestError.parseError( { raw: malformedJson }, "Invalid UTF-8 in message" ); ``` -------------------------------- ### closed Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Example usage of the closed property for async/await style cleanup after connection closure. ```typescript await connection.closed; console.log('Connection closed - performing cleanup'); ``` -------------------------------- ### Invalid Request Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/errors.md Example of how an invalid request error might be thrown and caught. ```typescript throw RequestError.invalidRequest( { received: actualRequest }, "Request is missing 'id' field" ); ``` ```typescript try { await connection.initialize(params); } catch (error) { if (error instanceof RequestError && error.code === -32600) { console.error("Request structure invalid"); console.error(error.data); } } ``` -------------------------------- ### listSessions Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Lists existing sessions from the agent. ```typescript const result = await connection.listSessions({ cwd: "/workspace", }); result.sessions.forEach(session => { console.log(`${session.sessionId}: ${session.title}`); console.log(` Last updated: ${session.lastUpdatedTime}`); }); if (result.nextCursor) { console.log("More sessions available"); } ``` -------------------------------- ### newSession Method Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Demonstrates creating a new conversation session with the agent using the `newSession` method. ```typescript const session = await connection.newSession({ cwd: "/workspace/myproject", mcpServers: [ { id: "github", name: "GitHub API", acp: { id: "github-server-id", }, }, ], additionalDirectories: ["/workspace/shared-libs"], }); console.log(`Session ID: ${session.sessionId}`); console.log(`Available modes: ${session.availableModes.map(m => m.name).join(", ")}); ``` -------------------------------- ### Method Not Found Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/errors.md Example of how a method not found error might be thrown and caught, including prevention. ```typescript if (method === "session/load" && !agent.loadSession) { throw RequestError.methodNotFound(method); } ``` ```typescript try { const result = await connection.loadSession(params); } catch (error) { if (error instanceof RequestError && error.code === -32601) { console.error("Agent doesn't support loadSession capability"); // Fall back to creating new session const newSession = await connection.newSession(params); } } ``` ```typescript const init = await connection.initialize({ protocolVersion: 1, clientCapabilities: {}, }); // Only call if advertised if (init.agentCapabilities.loadSession) { const session = await connection.loadSession({ sessionId: "..." }); } ``` -------------------------------- ### Type Imports Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/types.md Example of how to import types directly from the main SDK module. ```typescript import { SessionId, PromptRequest, PromptResponse, RequestPermissionRequest, ClientCapabilities, AgentCapabilities, StopReason, ToolKind, // ... and more } from "@agentclientprotocol/sdk"; ``` -------------------------------- ### Parse Error Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/errors.md Example of how a parse error might be thrown and caught. ```typescript try { // Receiving malformed JSON from stream // Parser throws } catch (error) { throw RequestError.parseError( { raw: malformedJson }, "Invalid UTF-8 in message" ); } ``` ```typescript try { const response = await connection.prompt(params); } catch (error) { if (error instanceof RequestError && error.code === -32700) { console.error("Parser error - check message encoding"); } } ``` -------------------------------- ### Error Handling Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/Client.md Demonstrates how to throw RequestError for protocol errors. ```typescript if (!terminal) { throw RequestError.resourceNotFound(terminalId); } if (!canWrite) { throw RequestError.invalidRequest({ reason: "read-only" }); } ``` -------------------------------- ### Invalid Params Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/errors.md Example of how an invalid parameters error might be thrown and caught, including prevention. ```typescript case schema.AGENT_METHODS.prompt: { const validatedParams = validate.zPromptRequest.parse(params); // If validation fails, RequestError.invalidParams thrown return agent.prompt(validatedParams); } ``` ```typescript try { await connection.prompt({ sessionId: "session-123", prompt: [], // Empty - may be invalid }); } catch (error) { if (error instanceof RequestError && error.code === -32602) { console.error("Invalid parameters"); // error.data contains Zod validation errors if (error.data) { console.error(error.data); } } } ``` ```typescript // āœ“ Correct const response = await connection.prompt({ sessionId: "session-123", prompt: [{ type: "text", text: "hello" }], }); // āœ— Wrong - will throw -32602 const response = await connection.prompt({ sessionId: "session-123", prompt: "hello", // Should be array }); ``` -------------------------------- ### Agent Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/README.md Example of how to implement an agent using the SDK. ```typescript import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"; import { Readable, Writable } from "node:stream"; class MyAgent implements Agent { async initialize(params) { return { protocolVersion: 1, agentCapabilities: { /* ... */ }, }; } async newSession(params) { return { sessionId: crypto.randomUUID() }; } async authenticate(params) { return {}; } async prompt(params) { // Use connection.sessionUpdate(), .requestPermission(), etc. return { stopReason: "end_turn" }; } async cancel(params) { // Handle cancellation } } const input = Writable.toWeb(process.stdout); const output = Readable.toWeb(process.stdin); const stream = ndJsonStream(input, output); new AgentSideConnection((conn) => new MyAgent(), stream); ``` -------------------------------- ### Example of handling methodNotFound Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/RequestError.md Demonstrates catching and identifying a methodNotFound error. ```typescript try { await connection.prompt(params); } catch (error) { if (error instanceof RequestError && error.code === -32601) { console.error(`Method not found: ${(error.data as any)?.method}`); } } ``` -------------------------------- ### Zod Validators Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/types.md Example of using Zod validators from the SDK to parse and validate incoming requests. ```typescript import * as validate from "@agentclientprotocol/sdk/schema/zod.gen"; const request = JSON.parse(input); const validated = validate.zPromptRequest.parse(request); ``` -------------------------------- ### Example of using invalidRequest Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/RequestError.md Demonstrates throwing an invalidRequest error with context. ```typescript throw RequestError.invalidRequest( { received: actualRequest }, "Request is missing 'id' field" ); ``` -------------------------------- ### authenticate Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Authenticates the client using the specified authentication method. ```typescript const result = await connection.authenticate({ methodId: "oauth", }); console.log("Authentication successful"); ``` -------------------------------- ### loadSession Method Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Illustrates how to load an existing session to resume a previous conversation using the `loadSession` method. ```typescript const session = await connection.loadSession({ sessionId: "session-abc123", cwd: "/workspace/myproject", additionalDirectories: ["/workspace/shared-libs"], }); console.log(`Loaded session for: ${session.sessionInfo.title}`); ``` -------------------------------- ### Error Handling Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/AgentSideConnection.md Demonstrates how to handle RequestError exceptions when interacting with the AgentSideConnection methods. ```typescript try { await connection.readTextFile({ path: "/missing/file.txt" }); } catch (error) { if (error instanceof RequestError) { console.error(`Error code ${error.code}: ${error.message}`); console.error(`Data: ${error.data}`); } } ``` -------------------------------- ### LLM API Keys Configuration Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of accessing LLM API keys and model configuration from environment variables. ```typescript const apiKey = process.env.OPENAI_API_KEY; const model = process.env.LLM_MODEL || "gpt-4"; ``` -------------------------------- ### Method Naming Convention Example 1 (noun/noun) Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/AGENTS.md Illustrates the naming convention for protocol methods structured as 'noun/noun', including trait method names, request/response structs, and method name structs. ```rust Protocol method: `terminal/output` Trait method name: `terminal_output` Request/Response structs: `TerminalOutputRequest` / `TerminalOutputResponse` Method names struct: `terminal_output: &'static str` ``` -------------------------------- ### Application-Specific Logger Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of implementing a custom logger within an agent to log prompts and errors. ```typescript class LoggingAgent implements Agent { private log(level: string, message: string, data?: any) { console.log(`[${level}] ${message}`, data || ""); } async prompt(params) { this.log("info", "Prompt received", { sessionId: params.sessionId }); try { const result = await this.processPrompt(params); this.log("info", "Prompt processed successfully"); return result; } catch (error) { this.log("error", "Prompt processing failed", error); throw error; } } } ``` -------------------------------- ### Method Naming Convention Example 2 (noun/verb) Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/AGENTS.md Illustrates the naming convention for protocol methods structured as 'noun/verb', including trait method names, request/response structs, and method name structs. ```rust Protocol method: `terminal/new` Trait method name: `new_terminal` Request/Response structs: `NewTerminalRequest` / `NewTerminalResponse` Method names struct: `terminal_new: &'static str` ``` -------------------------------- ### Custom Stream Implementation Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of implementing a custom transport stream for the Agent Protocol SDK. ```typescript function customTransportStream(transport: CustomTransport): Stream { const readable = new ReadableStream({ async start(controller) { transport.on("message", (data: Uint8Array) => { try { const text = new TextDecoder().decode(data); const lines = text.split("\n"); for (const line of lines) { if (line.trim()) { const msg = JSON.parse(line); controller.enqueue(msg); } } } catch (err) { console.error("Parse error:", err); } }); transport.on("close", () => controller.close()); transport.on("error", (err) => controller.error(err)); }, }); const writable = new WritableStream({ async write(message) { const json = JSON.stringify(message) + "\n"; const encoded = new TextEncoder().encode(json); await transport.send(encoded); }, }); return { readable, writable }; } // Use with connection const stream = customTransportStream(transport); ``` -------------------------------- ### resumeSession Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/ClientSideConnection.md Resumes an existing session without returning previous messages. ```typescript const session = await connection.resumeSession({ sessionId: "session-abc123", }); console.log(`Resumed session`); ``` -------------------------------- ### Standard NdjsonStream Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/configuration.md Example of using the standard ndJsonStream for stdio-based communication with Node.js streams. ```typescript import { ndJsonStream } from "@agentclientprotocol/sdk"; import { Readable, Writable } from "node:stream"; // Convert Node.js streams to Web Streams const input = Writable.toWeb(process.stdout); const output = Readable.toWeb(process.stdin) as ReadableStream; // Create the bidirectional stream const stream = ndJsonStream(input, output); // Use with connection const connection = new AgentSideConnection( (conn) => new MyAgent(), stream ); ``` -------------------------------- ### Example of toResult Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/RequestError.md Shows how to use the toResult method to convert an error into a JSON-RPC result object. ```typescript const error = RequestError.invalidParams( { field: "required" } ); const result = error.toResult(); // { // error: { // code: -32602, // message: "Invalid params", // data: { field: "required" } // } // } ``` -------------------------------- ### Example of throwing a RequestError Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/api-reference/RequestError.md Demonstrates how to throw a RequestError with a custom code, message, and data. ```typescript throw new RequestError(-32600, "Invalid request", { details: "Missing required field: method", }); ``` -------------------------------- ### Resource Not Found Error Handling Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/errors.md Example of an agent throwing a 'Resource Not Found' error and how a client handles it. ```typescript async readTextFile(params) { if (!fs.existsSync(params.path)) { throw RequestError.resourceNotFound(params.path); } // Read file... } ``` ```typescript try { const content = await connection.readTextFile({ path: "/missing/file.txt", }); } catch (error) { if (error instanceof RequestError && error.code === -32002) { const uri = error.data?.uri || "unknown"; console.error(`File not found: ${uri}`); // Handle missing file (create, skip, etc.) } } ``` -------------------------------- ### Error Handling Example Source: https://github.com/agentclientprotocol/typescript-sdk/blob/main/_autodocs/README.md Shows how to catch and handle `RequestError` instances thrown by the SDK, including checking error codes and messages. ```typescript import { RequestError } from "@agentclientprotocol/sdk"; try { await connection.prompt(params); } catch (error) { if (error instanceof RequestError) { console.error(`Error ${error.code}: ${error.message}`); console.error("Details:", error.data); switch (error.code) { case -32602: console.error("Invalid parameters"); break; case -32601: console.error("Method not supported"); break; case -32000: console.error("Authentication required"); break; } } } ```