Skip to main content

Overview

The ACP TypeScript SDK uses JSON-RPC 2.0 for message exchange between clients and agents. This page documents the internal JSON-RPC types used by the SDK.
These types are primarily for internal use by the SDK. Most applications will use the higher-level APIs provided by AgentSideConnection and ClientSideConnection rather than working with these types directly.

Message Types

AnyMessage

type AnyMessage = AnyRequest | AnyResponse | AnyNotification;
A union type representing any valid JSON-RPC 2.0 message that can be sent or received over an ACP connection.

Request Types

AnyRequest

type AnyRequest = {
  jsonrpc: "2.0";
  id: string | number | null;
  method: string;
  params?: unknown;
};
Represents a JSON-RPC 2.0 request message. Properties:
  • jsonrpc (“2.0”) - JSON-RPC version identifier (always “2.0”)
  • id (string | number | null) - Unique identifier for matching requests with responses
  • method (string) - The method name to invoke (e.g., “session/prompt”)
  • params (unknown, optional) - Method parameters
Example:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session/prompt",
  "params": {
    "sessionId": "session-123",
    "messages": [
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }
}

Response Types

AnyResponse

type AnyResponse = {
  jsonrpc: "2.0";
  id: string | number | null;
} & Result<unknown>;
Represents a JSON-RPC 2.0 response message, which can contain either a successful result or an error. Properties:
  • jsonrpc (“2.0”) - JSON-RPC version identifier
  • id (string | number | null) - ID matching the original request
  • Either result or error (from Result<unknown>)
Success Example:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "stopReason": "end_turn"
  }
}
Error Example:
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found: unknown/method",
    "data": {
      "method": "unknown/method"
    }
  }
}

Result

type Result<T> =
  | {
      result: T;
    }
  | {
      error: ErrorResponse;
    };
A discriminated union representing either a successful result or an error. Success Variant:
  • result (T) - The successful response data
Error Variant:
  • error (ErrorResponse) - The error information

ErrorResponse

type ErrorResponse = {
  code: number;
  message: string;
  data?: unknown;
};
Represents a JSON-RPC 2.0 error object. Properties:
  • code (number) - Numeric error code (see Error Codes)
  • message (string) - Human-readable error message
  • data (unknown, optional) - Additional error information
Example:
{
  "code": -32602,
  "message": "Invalid params",
  "data": {
    "sessionId": {
      "_errors": ["Required"]
    }
  }
}

Notification Types

AnyNotification

type AnyNotification = {
  jsonrpc: "2.0";
  method: string;
  params?: unknown;
};
Represents a JSON-RPC 2.0 notification message. Notifications are like requests but do not expect a response (no id field). Properties:
  • jsonrpc (“2.0”) - JSON-RPC version identifier
  • method (string) - The notification method name
  • params (unknown, optional) - Notification parameters
Example:
{
  "jsonrpc": "2.0",
  "method": "session/update",
  "params": {
    "sessionId": "session-123",
    "message": {
      "type": "text",
      "text": "Processing your request..."
    }
  }
}

Handler Types

RequestHandler

type RequestHandler = (
  method: string,
  params: unknown
) => Promise<unknown>;
A function type for handling incoming JSON-RPC requests. Parameters:
  • method (string) - The method being invoked
  • params (unknown) - The method parameters
Returns: Promise resolving to the result value Throws: Should throw RequestError for application errors Example:
const requestHandler: RequestHandler = async (method, params) => {
  switch (method) {
    case "session/prompt":
      const validatedParams = PromptRequestSchema.parse(params);
      return await handlePrompt(validatedParams);
    
    case "session/new":
      const validatedParams = NewSessionRequestSchema.parse(params);
      return await createSession(validatedParams);
    
    default:
      throw RequestError.methodNotFound(method);
  }
};

NotificationHandler

type NotificationHandler = (
  method: string,
  params: unknown
) => Promise<void>;
A function type for handling incoming JSON-RPC notifications. Parameters:
  • method (string) - The notification method
  • params (unknown) - The notification parameters
Returns: Promise resolving when the notification is handled Example:
const notificationHandler: NotificationHandler = async (method, params) => {
  switch (method) {
    case "session/update":
      const update = SessionNotificationSchema.parse(params);
      await displayUpdate(update);
      break;
    
    case "session/cancel":
      const cancel = CancelNotificationSchema.parse(params);
      await cancelSession(cancel.sessionId);
      break;
    
    default:
      console.warn(`Unknown notification: ${method}`);
  }
};

Internal Types

PendingResponse

type PendingResponse = {
  resolve: (response: unknown) => void;
  reject: (error: ErrorResponse) => void;
};
An internal type used to track pending requests waiting for responses. Properties:
  • resolve (function) - Called when a successful response is received
  • reject (function) - Called when an error response is received
This type is used internally by the Connection class to manage the request/response lifecycle. You typically won’t interact with it directly.

Message Flow

Request-Response Flow

// Client sends request
const request: AnyRequest = {
  jsonrpc: "2.0",
  id: 1,
  method: "session/prompt",
  params: { sessionId: "session-123", messages: [...] },
};

// Agent receives request, processes it, sends response
const response: AnyResponse = {
  jsonrpc: "2.0",
  id: 1,
  result: { stopReason: "end_turn" },
};

// Or, if an error occurred:
const errorResponse: AnyResponse = {
  jsonrpc: "2.0",
  id: 1,
  error: {
    code: -32602,
    message: "Invalid params",
    data: { ... },
  },
};

Notification Flow

// Agent sends notification (no response expected)
const notification: AnyNotification = {
  jsonrpc: "2.0",
  method: "session/update",
  params: {
    sessionId: "session-123",
    message: { type: "text", text: "Thinking..." },
  },
};

// Client receives and processes notification
// No response is sent

Type Guards

Checking Message Types

You can use type guards to determine which kind of message you’re dealing with:
function isRequest(msg: AnyMessage): msg is AnyRequest {
  return "method" in msg && "id" in msg;
}

function isNotification(msg: AnyMessage): msg is AnyNotification {
  return "method" in msg && !("id" in msg);
}

function isResponse(msg: AnyMessage): msg is AnyResponse {
  return "id" in msg && !("method" in msg);
}

function isSuccessResponse(msg: AnyResponse): boolean {
  return "result" in msg;
}

function isErrorResponse(msg: AnyResponse): boolean {
  return "error" in msg;
}

Usage Example

function processMessage(message: AnyMessage) {
  if (isRequest(message)) {
    console.log(`Received request: ${message.method}`);
    // Handle request
  } else if (isNotification(message)) {
    console.log(`Received notification: ${message.method}`);
    // Handle notification
  } else if (isResponse(message)) {
    if (isSuccessResponse(message)) {
      console.log(`Received success response for id ${message.id}`);
    } else {
      console.log(`Received error response for id ${message.id}`);
    }
  }
}

Best Practices

1. Use Type-Safe Wrappers

Rather than working with unknown params, use type-safe wrappers:
import { z } from "zod";

const PromptRequestSchema = z.object({
  sessionId: z.string(),
  messages: z.array(z.object({
    role: z.enum(["user", "assistant"]),
    content: z.string(),
  })),
});

const requestHandler: RequestHandler = async (method, params) => {
  if (method === "session/prompt") {
    // Validate and get typed params
    const validated = PromptRequestSchema.parse(params);
    // Now 'validated' has proper types
    return await handlePrompt(validated);
  }
};

2. Always Return Proper Errors

Throw RequestError instances for application errors:
const requestHandler: RequestHandler = async (method, params) => {
  try {
    // ... handle request
  } catch (error) {
    if (error instanceof RequestError) {
      throw error; // Already a proper error
    }
    if (error instanceof z.ZodError) {
      throw RequestError.invalidParams(error.format());
    }
    throw RequestError.internalError({ details: error.message });
  }
};

3. Don’t Block Notification Handlers

Notifications should be handled asynchronously without blocking:
const notificationHandler: NotificationHandler = async (method, params) => {
  // Quick validation and dispatch
  const notification = parseNotification(method, params);
  
  // Don't await long-running operations
  processNotificationAsync(notification).catch(error => {
    console.error("Error processing notification:", error);
  });
  
  // Return immediately
};

See Also

Build docs developers (and LLMs) love