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