diff --git a/examples/client.py b/examples/client.py index be38edb..2abcc1a 100644 --- a/examples/client.py +++ b/examples/client.py @@ -28,7 +28,7 @@ EnvVariable, ImageContentBlock, Implementation, - KillTerminalCommandResponse, + KillTerminalResponse, PermissionOption, ReadTextFileResponse, ReleaseTerminalResponse, @@ -86,9 +86,7 @@ async def wait_for_terminal_exit( ) -> WaitForTerminalExitResponse: raise RequestError.method_not_found("terminal/wait_for_exit") - async def kill_terminal( - self, session_id: str, terminal_id: str, **kwargs: Any - ) -> KillTerminalCommandResponse | None: + async def kill_terminal(self, session_id: str, terminal_id: str, **kwargs: Any) -> KillTerminalResponse | None: raise RequestError.method_not_found("terminal/kill") async def session_update( diff --git a/examples/gemini.py b/examples/gemini.py index 937bbe7..60eed0a 100644 --- a/examples/gemini.py +++ b/examples/gemini.py @@ -33,8 +33,8 @@ EmbeddedResourceContentBlock, EnvVariable, FileEditToolCallContent, - FileSystemCapability, - KillTerminalCommandResponse, + FileSystemCapabilities, + KillTerminalResponse, PermissionOption, ReadTextFileResponse, ReleaseTerminalResponse, @@ -183,11 +183,9 @@ async def wait_for_terminal_exit( print(f"[Client] waitForTerminalExit: {session_id} {terminal_id}") return WaitForTerminalExitResponse() - async def kill_terminal( - self, session_id: str, terminal_id: str, **kwargs: Any - ) -> KillTerminalCommandResponse | None: + async def kill_terminal(self, session_id: str, terminal_id: str, **kwargs: Any) -> KillTerminalResponse | None: print(f"[Client] killTerminal: {session_id} {terminal_id}") - return KillTerminalCommandResponse() + return KillTerminalResponse() def _pick_preferred_option(options: Iterable[PermissionOption]) -> PermissionOption | None: @@ -320,7 +318,7 @@ async def run(argv: list[str]) -> int: # noqa: C901 init_resp = await conn.initialize( protocol_version=PROTOCOL_VERSION, client_capabilities=ClientCapabilities( - fs=FileSystemCapability(read_text_file=True, write_text_file=True), + fs=FileSystemCapabilities(read_text_file=True, write_text_file=True), terminal=True, ), ) diff --git a/schema/VERSION b/schema/VERSION index 3222b17..62d2bd0 100644 --- a/schema/VERSION +++ b/schema/VERSION @@ -1 +1 @@ -refs/tags/v0.10.8 +refs/tags/v0.11.2 diff --git a/schema/meta.json b/schema/meta.json index 507c21d..bfa8448 100644 --- a/schema/meta.json +++ b/schema/meta.json @@ -3,6 +3,7 @@ "authenticate": "authenticate", "initialize": "initialize", "session_cancel": "session/cancel", + "session_close": "session/close", "session_fork": "session/fork", "session_list": "session/list", "session_load": "session/load", diff --git a/schema/schema.json b/schema/schema.json index ba61b43..f679c1a 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -172,11 +172,11 @@ { "allOf": [ { - "$ref": "#/$defs/KillTerminalCommandRequest" + "$ref": "#/$defs/KillTerminalRequest" } ], - "description": "Kills the terminal command without releasing the terminal\n\nWhile `terminal/release` will also kill the command, this method will keep\nthe `TerminalId` valid so it can be used with other methods.\n\nThis method can be helpful when implementing command timeouts which terminate\nthe command as soon as elapsed, and then get the final output so it can be sent\nto the model.\n\nNote: `terminal/release` when `TerminalId` is no longer needed.\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", - "title": "KillTerminalCommandRequest" + "description": "Kills the terminal command without releasing the terminal\n\nWhile `terminal/release` will also kill the command, this method will keep\nthe `TerminalId` valid so it can be used with other methods.\n\nThis method can be helpful when implementing command timeouts which terminate\nthe command as soon as elapsed, and then get the final output so it can be sent\nto the model.\n\nNote: Call `terminal/release` when `TerminalId` is no longer needed.\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", + "title": "KillTerminalRequest" }, { "allOf": [ @@ -268,6 +268,14 @@ ], "title": "ResumeSessionResponse" }, + { + "allOf": [ + { + "$ref": "#/$defs/CloseSessionResponse" + } + ], + "title": "CloseSessionResponse" + }, { "allOf": [ { @@ -408,8 +416,115 @@ ], "type": "object" }, + "AuthCapabilities": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication capabilities supported by the client.\n\nAdvertised during initialization to inform the agent which authentication\nmethod types the client can handle. This governs opt-in types that require\nadditional client-side support.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + }, + "terminal": { + "default": false, + "description": "Whether the client supports `terminal` authentication methods.\n\nWhen `true`, the agent may include `terminal` entries in its authentication methods.", + "type": "boolean" + } + }, + "type": "object" + }, + "AuthEnvVar": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDescribes a single environment variable for an [`AuthMethodEnvVar`] authentication method.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + }, + "label": { + "description": "Human-readable label for this variable, displayed in client UI.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "The environment variable name (e.g. `\"OPENAI_API_KEY\"`).", + "type": "string" + }, + "optional": { + "default": false, + "description": "Whether this variable is optional.\n\nDefaults to `false`.", + "type": "boolean" + }, + "secret": { + "default": true, + "description": "Whether this value is a secret (e.g. API key, token).\nClients should use a password-style input for secret vars.\n\nDefaults to `true`.", + "type": "boolean" + } + }, + "required": [ + "name" + ], + "type": "object" + }, "AuthMethod": { - "description": "Describes an available authentication method.", + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/$defs/AuthMethodEnvVar" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nUser provides a key that the client passes to the agent as an environment variable.", + "properties": { + "type": { + "const": "env_var", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/AuthMethodTerminal" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nClient runs an interactive terminal for the user to authenticate via a TUI.", + "properties": { + "type": { + "const": "terminal", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/AuthMethodAgent" + } + ], + "description": "Agent handles authentication itself.\n\nThis is the default when no `type` is specified.", + "title": "agent" + } + ], + "description": "Describes an available authentication method.\n\nThe `type` field acts as the discriminator in the serialized JSON form.\nWhen no `type` is present, the method is treated as `agent`." + }, + "AuthMethodAgent": { + "description": "Agent handles authentication itself.\n\nThis is the default authentication method type.", "properties": { "_meta": { "additionalProperties": true, @@ -441,6 +556,101 @@ ], "type": "object" }, + "AuthMethodEnvVar": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nEnvironment variable authentication method.\n\nThe user provides credentials that the client passes to the agent as environment variables.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + }, + "description": { + "description": "Optional description providing more details about this authentication method.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Unique identifier for this authentication method.", + "type": "string" + }, + "link": { + "description": "Optional link to a page where the user can obtain their credentials.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "Human-readable name of the authentication method.", + "type": "string" + }, + "vars": { + "description": "The environment variables the client should set.", + "items": { + "$ref": "#/$defs/AuthEnvVar" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "vars" + ], + "type": "object" + }, + "AuthMethodTerminal": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nTerminal-based authentication method.\n\nThe client runs an interactive terminal for the user to authenticate via a TUI.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + }, + "args": { + "description": "Additional arguments to pass when running the agent binary for terminal auth.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Optional description providing more details about this authentication method.", + "type": [ + "string", + "null" + ] + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "description": "Additional environment variables to set when running the agent binary for terminal auth.", + "type": "object" + }, + "id": { + "description": "Unique identifier for this authentication method.", + "type": "string" + }, + "name": { + "description": "Human-readable name of the authentication method.", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, "AuthenticateRequest": { "description": "Request parameters for the authenticate method.\n\nSpecifies which authentication method to use.", "properties": { @@ -650,10 +860,21 @@ "null" ] }, + "auth": { + "allOf": [ + { + "$ref": "#/$defs/AuthCapabilities" + } + ], + "default": { + "terminal": false + }, + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication capabilities supported by the client.\nDetermines which authentication method types the agent may include\nin its `InitializeResponse`." + }, "fs": { "allOf": [ { - "$ref": "#/$defs/FileSystemCapability" + "$ref": "#/$defs/FileSystemCapabilities" } ], "default": { @@ -766,7 +987,7 @@ "$ref": "#/$defs/ListSessionsRequest" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLists existing sessions known to the agent.\n\nThis method is only available if the agent advertises the `listSessions` capability.\n\nThe agent should return metadata about sessions with optional filtering and pagination support.", + "description": "Lists existing sessions known to the agent.\n\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\n\nThe agent should return metadata about sessions with optional filtering and pagination support.", "title": "ListSessionsRequest" }, { @@ -787,6 +1008,15 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResumes an existing session without returning previous messages.\n\nThis method is only available if the agent advertises the `session.resume` capability.\n\nThe agent should resume the session context, allowing the conversation to continue\nwithout replaying the message history (unlike `session/load`).", "title": "ResumeSessionRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/CloseSessionRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCloses an active session and frees up any resources associated with it.\n\nThis method is only available if the agent advertises the `session.close` capability.\n\nThe agent must cancel any ongoing work (as if `session/cancel` was called)\nand then free up any resources associated with the session.", + "title": "CloseSessionRequest" + }, { "allOf": [ { @@ -916,7 +1146,7 @@ { "allOf": [ { - "$ref": "#/$defs/KillTerminalCommandResponse" + "$ref": "#/$defs/KillTerminalResponse" } ], "title": "KillTerminalResponse" @@ -959,6 +1189,49 @@ ], "x-docs-ignore": true }, + "CloseSessionRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for closing an active session.\n\nIf supported, the agent **must** cancel any ongoing work related to the session\n(treat it as if `session/cancel` was called) and then free up any resources\nassociated with the session.\n\nOnly available if the Agent supports the `session.close` capability.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + }, + "sessionId": { + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ], + "description": "The ID of the session to close." + } + }, + "required": [ + "sessionId" + ], + "type": "object", + "x-method": "session/close", + "x-side": "agent" + }, + "CloseSessionResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse from closing a session.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + } + }, + "type": "object", + "x-method": "session/close", + "x-side": "agent" + }, "ConfigOptionUpdate": { "description": "Session configuration options have been updated.", "properties": { @@ -1124,6 +1397,13 @@ } ], "description": "A single item of content" + }, + "messageId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started.\nBoth clients and agents MUST use UUID format for message IDs.", + "type": [ + "string", + "null" + ] } }, "required": [ @@ -1471,8 +1751,8 @@ "ExtResponse": { "description": "Allows for sending an arbitrary response to an [`ExtRequest`] that is not part of the ACP spec.\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)" }, - "FileSystemCapability": { - "description": "Filesystem capabilities supported by the client.\nFile system capabilities that a client may support.\n\nSee protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)", + "FileSystemCapabilities": { + "description": "File system capabilities that a client may support.\n\nSee protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)", "properties": { "_meta": { "additionalProperties": true, @@ -1710,6 +1990,9 @@ } ], "default": { + "auth": { + "terminal": false + }, "fs": { "readTextFile": false, "writeTextFile": false @@ -1812,8 +2095,8 @@ "x-method": "initialize", "x-side": "agent" }, - "KillTerminalCommandRequest": { - "description": "Request to kill a terminal command without releasing the terminal.", + "KillTerminalRequest": { + "description": "Request to kill a terminal without releasing it.", "properties": { "_meta": { "additionalProperties": true, @@ -1844,8 +2127,8 @@ "x-method": "terminal/kill", "x-side": "client" }, - "KillTerminalCommandResponse": { - "description": "Response to terminal/kill command method", + "KillTerminalResponse": { + "description": "Response to `terminal/kill` method", "properties": { "_meta": { "additionalProperties": true, @@ -1861,7 +2144,7 @@ "x-side": "client" }, "ListSessionsRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for listing existing sessions.\n\nOnly available if the Agent supports the `listSessions` capability.", + "description": "Request parameters for listing existing sessions.\n\nOnly available if the Agent supports the `sessionCapabilities.list` capability.", "properties": { "_meta": { "additionalProperties": true, @@ -1891,7 +2174,7 @@ "x-side": "agent" }, "ListSessionsResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse from listing sessions.", + "description": "Response from listing sessions.", "properties": { "_meta": { "additionalProperties": true, @@ -2537,6 +2820,13 @@ "null" ] }, + "messageId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA client-generated unique identifier for this user message.\n\nIf provided, the Agent SHOULD echo this value as `userMessageId` in the\n[`PromptResponse`] to confirm it was recorded.\nBoth clients and agents MUST use UUID format for message IDs.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "The blocks of content that compose the user's message.\n\nAs a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],\nwhile other variants are optionally enabled via [`PromptCapabilities`].\n\nThe Client MUST adapt its interface according to [`PromptCapabilities`].\n\nThe client MAY include referenced pieces of context as either\n[`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].\n\nWhen available, [`ContentBlock::Resource`] is preferred\nas it avoids extra round-trips and allows the message to include\npieces of context from sources the agent may not have access to.", "items": { @@ -2590,6 +2880,13 @@ } ], "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nToken usage for this turn (optional)." + }, + "userMessageId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nThe acknowledged user message ID.\n\nIf the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here\nto confirm it was recorded. If the client did not provide one, the agent MAY assign one\nand return it here. Absence of this field indicates the agent did not record a message ID.", + "type": [ + "string", + "null" + ] } }, "required": [ @@ -3044,6 +3341,17 @@ "null" ] }, + "close": { + "anyOf": [ + { + "$ref": "#/$defs/SessionCloseCapabilities" + }, + { + "type": "null" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/close`." + }, "fork": { "anyOf": [ { @@ -3064,7 +3372,7 @@ "type": "null" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/list`." + "description": "Whether the agent supports `session/list`." }, "resume": { "anyOf": [ @@ -3080,6 +3388,33 @@ }, "type": "object" }, + "SessionCloseCapabilities": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for the `session/close` method.\n\nBy supplying `{}` it means that the agent supports closing of sessions.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": [ + "object", + "null" + ] + } + }, + "type": "object" + }, + "SessionConfigBoolean": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA boolean on/off toggle session configuration option payload.", + "properties": { + "currentValue": { + "description": "The current value of the boolean option.", + "type": "boolean" + } + }, + "required": [ + "currentValue" + ], + "type": "object" + }, "SessionConfigGroupId": { "description": "Unique identifier for a session configuration option value group.", "type": "string" @@ -3111,6 +3446,24 @@ "type" ], "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/SessionConfigBoolean" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nBoolean on/off toggle.", + "properties": { + "type": { + "const": "boolean", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" } ], "properties": { @@ -3329,7 +3682,7 @@ "type": "string" }, "SessionInfo": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInformation about a session returned by session/list", + "description": "Information about a session returned by session/list", "properties": { "_meta": { "additionalProperties": true, @@ -3401,7 +3754,7 @@ "type": "object" }, "SessionListCapabilities": { - "description": "Capabilities for the `session/list` method.\n\nBy supplying `{}` it means that the agent supports listing of sessions.\n\nFurther capabilities can be added in the future for other means of filtering or searching the list.", + "description": "Capabilities for the `session/list` method.\n\nBy supplying `{}` it means that the agent supports listing of sessions.", "properties": { "_meta": { "additionalProperties": true, @@ -3771,6 +4124,44 @@ ] }, "SetSessionConfigOptionRequest": { + "anyOf": [ + { + "description": "A boolean value (`type: \"boolean\"`).", + "properties": { + "type": { + "const": "boolean", + "type": "string" + }, + "value": { + "description": "The boolean value.", + "type": "boolean" + } + }, + "required": [ + "type", + "value" + ], + "type": "object" + }, + { + "description": "A [`SessionConfigValueId`] string value.\n\nThis is the default when `type` is absent on the wire. Unknown `type`\nvalues with string payloads also gracefully deserialize into this\nvariant.", + "properties": { + "value": { + "allOf": [ + { + "$ref": "#/$defs/SessionConfigValueId" + } + ], + "description": "The value ID." + } + }, + "required": [ + "value" + ], + "title": "value_id", + "type": "object" + } + ], "description": "Request parameters for setting a session configuration option.", "properties": { "_meta": { @@ -3796,20 +4187,11 @@ } ], "description": "The ID of the session to set the configuration option for." - }, - "value": { - "allOf": [ - { - "$ref": "#/$defs/SessionConfigValueId" - } - ], - "description": "The ID of the configuration option value to set." } }, "required": [ "sessionId", - "configId", - "value" + "configId" ], "type": "object", "x-method": "session/set_config_option", @@ -3882,6 +4264,7 @@ "properties": { "_meta": { "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": [ "object", "null" @@ -4807,7 +5190,7 @@ "$ref": "#/$defs/CancelRequestNotification" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or\nchanged at any point.\n\nCancels an ongoing request.\n\nThis is a notification sent by the the side that sent a request to cancel that request.\n\nUpon receiving this notification, the receiver:\n\n1. MUST cancel the corresponding request activity and all nested activities\n2. MAY send any pending notifications.\n3. MUST send one of these responses for the original request:\n - Valid response with appropriate data (partial results or cancellation marker)\n - Error response with code `-32800` (Cancelled)\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or\nchanged at any point.\n\nCancels an ongoing request.\n\nThis is a notification sent by the side that sent a request to cancel that request.\n\nUpon receiving this notification, the receiver:\n\n1. MUST cancel the corresponding request activity and all nested activities\n2. MAY send any pending notifications.\n3. MUST send one of these responses for the original request:\n - Valid response with appropriate data (partial results or cancellation marker)\n - Error response with code `-32800` (Cancelled)\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)", "title": "CancelRequestNotification" } ], diff --git a/scripts/gen_schema.py b/scripts/gen_schema.py index 74a8790..ad9c6fb 100644 --- a/scripts/gen_schema.py +++ b/scripts/gen_schema.py @@ -51,7 +51,12 @@ "McpServer2": "SseMcpServer", "RequestPermissionOutcome1": "DeniedOutcome", "RequestPermissionOutcome2": "AllowedOutcome", + "AuthMethod1": "EnvVarAuthMethod", + "AuthMethod2": "TerminalAuthMethod", "SessionConfigOption1": "SessionConfigOptionSelect", + "SessionConfigOption2": "SessionConfigOptionBoolean", + "SetSessionConfigOptionRequest1": "SetSessionConfigOptionBooleanRequest", + "SetSessionConfigOptionRequest2": "SetSessionConfigOptionSelectRequest", "SessionUpdate1": "UserMessageChunk", "SessionUpdate2": "AgentMessageChunk", "SessionUpdate3": "AgentThoughtChunk", @@ -101,7 +106,7 @@ "prompt_capabilities", "PromptCapabilities()", ), - ("ClientCapabilities", "fs", "FileSystemCapability()"), + ("ClientCapabilities", "fs", "FileSystemCapabilities()"), ("ClientCapabilities", "terminal", "False"), ( "InitializeRequest", diff --git a/src/acp/__init__.py b/src/acp/__init__.py index 7cbde3c..c49b187 100644 --- a/src/acp/__init__.py +++ b/src/acp/__init__.py @@ -45,8 +45,8 @@ CreateTerminalResponse, InitializeRequest, InitializeResponse, - KillTerminalCommandRequest, - KillTerminalCommandResponse, + KillTerminalRequest, + KillTerminalResponse, LoadSessionRequest, LoadSessionResponse, NewSessionRequest, @@ -60,8 +60,8 @@ RequestPermissionRequest, RequestPermissionResponse, SessionNotification, - SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, + SetSessionConfigOptionSelectRequest, SetSessionModelRequest, SetSessionModelResponse, SetSessionModeRequest, @@ -117,7 +117,7 @@ "SetSessionModeResponse", "SetSessionModelRequest", "SetSessionModelResponse", - "SetSessionConfigOptionRequest", + "SetSessionConfigOptionSelectRequest", "SetSessionConfigOptionResponse", # terminal types "CreateTerminalRequest", @@ -126,8 +126,8 @@ "TerminalOutputResponse", "WaitForTerminalExitRequest", "WaitForTerminalExitResponse", - "KillTerminalCommandRequest", - "KillTerminalCommandResponse", + "KillTerminalRequest", + "KillTerminalResponse", "ReleaseTerminalRequest", "ReleaseTerminalResponse", # core diff --git a/src/acp/agent/connection.py b/src/acp/agent/connection.py index b3b0351..64c96d9 100644 --- a/src/acp/agent/connection.py +++ b/src/acp/agent/connection.py @@ -17,8 +17,8 @@ CreateTerminalResponse, CurrentModeUpdate, EnvVariable, - KillTerminalCommandRequest, - KillTerminalCommandResponse, + KillTerminalRequest, + KillTerminalResponse, PermissionOption, ReadTextFileRequest, ReadTextFileResponse, @@ -191,15 +191,13 @@ async def wait_for_terminal_exit( WaitForTerminalExitResponse, ) - @param_model(KillTerminalCommandRequest) - async def kill_terminal( - self, session_id: str, terminal_id: str, **kwargs: Any - ) -> KillTerminalCommandResponse | None: + @param_model(KillTerminalRequest) + async def kill_terminal(self, session_id: str, terminal_id: str, **kwargs: Any) -> KillTerminalResponse | None: return await request_optional_model( self._conn, CLIENT_METHODS["terminal_kill"], - KillTerminalCommandRequest(session_id=session_id, terminal_id=terminal_id, field_meta=kwargs or None), - KillTerminalCommandResponse, + KillTerminalRequest(session_id=session_id, terminal_id=terminal_id, field_meta=kwargs or None), + KillTerminalResponse, ) async def ext_method(self, method: str, params: dict[str, Any]) -> dict[str, Any]: diff --git a/src/acp/agent/router.py b/src/acp/agent/router.py index 8477716..26db13f 100644 --- a/src/acp/agent/router.py +++ b/src/acp/agent/router.py @@ -9,6 +9,7 @@ from ..schema import ( AuthenticateRequest, CancelNotification, + CloseSessionRequest, ForkSessionRequest, InitializeRequest, ListSessionsRequest, @@ -16,7 +17,7 @@ NewSessionRequest, PromptRequest, ResumeSessionRequest, - SetSessionConfigOptionRequest, + SetSessionConfigOptionSelectRequest, SetSessionModelRequest, SetSessionModeRequest, ) @@ -37,7 +38,15 @@ def build_agent_router(agent: Agent, use_unstable_protocol: bool = False) -> Mes "load_session", adapt_result=normalize_result, ) - router.route_request(AGENT_METHODS["session_list"], ListSessionsRequest, agent, "list_sessions", unstable=True) + router.route_request(AGENT_METHODS["session_list"], ListSessionsRequest, agent, "list_sessions") + router.route_request( + AGENT_METHODS["session_close"], + CloseSessionRequest, + agent, + "close_session", + adapt_result=normalize_result, + unstable=True, + ) router.route_request( AGENT_METHODS["session_set_mode"], SetSessionModeRequest, @@ -56,7 +65,7 @@ def build_agent_router(agent: Agent, use_unstable_protocol: bool = False) -> Mes ) router.route_request( AGENT_METHODS["session_set_config_option"], - SetSessionConfigOptionRequest, + SetSessionConfigOptionSelectRequest, agent, "set_config_option", adapt_result=normalize_result, diff --git a/src/acp/client/connection.py b/src/acp/client/connection.py index 7d0396e..d3471b6 100644 --- a/src/acp/client/connection.py +++ b/src/acp/client/connection.py @@ -13,6 +13,8 @@ AuthenticateResponse, CancelNotification, ClientCapabilities, + CloseSessionRequest, + CloseSessionResponse, EmbeddedResourceContentBlock, ForkSessionRequest, ForkSessionResponse, @@ -33,8 +35,8 @@ ResourceContentBlock, ResumeSessionRequest, ResumeSessionResponse, - SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, + SetSessionConfigOptionSelectRequest, SetSessionModelRequest, SetSessionModelResponse, SetSessionModeRequest, @@ -152,14 +154,14 @@ async def set_session_model(self, model_id: str, session_id: str, **kwargs: Any) SetSessionModelResponse, ) - @param_model(SetSessionConfigOptionRequest) + @param_model(SetSessionConfigOptionSelectRequest) async def set_config_option( self, config_id: str, session_id: str, value: str, **kwargs: Any ) -> SetSessionConfigOptionResponse: return await request_model_from_dict( self._conn, AGENT_METHODS["session_set_config_option"], - SetSessionConfigOptionRequest( + SetSessionConfigOptionSelectRequest( config_id=config_id, session_id=session_id, value=value, field_meta=kwargs or None ), SetSessionConfigOptionResponse, @@ -185,6 +187,7 @@ async def prompt( | EmbeddedResourceContentBlock ], session_id: str, + message_id: str | None = None, **kwargs: Any, ) -> PromptResponse: return await request_model( @@ -224,6 +227,15 @@ async def resume_session( ResumeSessionResponse, ) + @param_model(CloseSessionRequest) + async def close_session(self, session_id: str, **kwargs: Any) -> CloseSessionResponse | None: + return await request_model_from_dict( + self._conn, + AGENT_METHODS["session_close"], + CloseSessionRequest(session_id=session_id, field_meta=kwargs or None), + CloseSessionResponse, + ) + @param_model(CancelNotification) async def cancel(self, session_id: str, **kwargs: Any) -> None: await notify_model( diff --git a/src/acp/client/router.py b/src/acp/client/router.py index 4bab2d9..5b9049b 100644 --- a/src/acp/client/router.py +++ b/src/acp/client/router.py @@ -8,7 +8,7 @@ from ..router import MessageRouter from ..schema import ( CreateTerminalRequest, - KillTerminalCommandRequest, + KillTerminalRequest, ReadTextFileRequest, ReleaseTerminalRequest, RequestPermissionRequest, @@ -68,7 +68,7 @@ def build_client_router(client: Client, use_unstable_protocol: bool = False) -> ) router.route_request( CLIENT_METHODS["terminal_kill"], - KillTerminalCommandRequest, + KillTerminalRequest, client, "kill_terminal", optional=True, diff --git a/src/acp/interfaces.py b/src/acp/interfaces.py index 1fd572f..f33f403 100644 --- a/src/acp/interfaces.py +++ b/src/acp/interfaces.py @@ -12,6 +12,8 @@ AvailableCommandsUpdate, CancelNotification, ClientCapabilities, + CloseSessionRequest, + CloseSessionResponse, ConfigOptionUpdate, CreateTerminalRequest, CreateTerminalResponse, @@ -25,8 +27,8 @@ Implementation, InitializeRequest, InitializeResponse, - KillTerminalCommandRequest, - KillTerminalCommandResponse, + KillTerminalRequest, + KillTerminalResponse, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest, @@ -48,8 +50,8 @@ ResumeSessionResponse, SessionInfoUpdate, SessionNotification, - SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, + SetSessionConfigOptionSelectRequest, SetSessionModelRequest, SetSessionModelResponse, SetSessionModeRequest, @@ -132,10 +134,8 @@ async def wait_for_terminal_exit( self, session_id: str, terminal_id: str, **kwargs: Any ) -> WaitForTerminalExitResponse: ... - @param_model(KillTerminalCommandRequest) - async def kill_terminal( - self, session_id: str, terminal_id: str, **kwargs: Any - ) -> KillTerminalCommandResponse | None: ... + @param_model(KillTerminalRequest) + async def kill_terminal(self, session_id: str, terminal_id: str, **kwargs: Any) -> KillTerminalResponse | None: ... async def ext_method(self, method: str, params: dict[str, Any]) -> dict[str, Any]: ... @@ -181,7 +181,7 @@ async def set_session_model( self, model_id: str, session_id: str, **kwargs: Any ) -> SetSessionModelResponse | None: ... - @param_model(SetSessionConfigOptionRequest) + @param_model(SetSessionConfigOptionSelectRequest) async def set_config_option( self, config_id: str, session_id: str, value: str, **kwargs: Any ) -> SetSessionConfigOptionResponse | None: ... @@ -200,6 +200,7 @@ async def prompt( | EmbeddedResourceContentBlock ], session_id: str, + message_id: str | None = None, **kwargs: Any, ) -> PromptResponse: ... @@ -221,6 +222,9 @@ async def resume_session( **kwargs: Any, ) -> ResumeSessionResponse: ... + @param_model(CloseSessionRequest) + async def close_session(self, session_id: str, **kwargs: Any) -> CloseSessionResponse | None: ... + @param_model(CancelNotification) async def cancel(self, session_id: str, **kwargs: Any) -> None: ... diff --git a/src/acp/meta.py b/src/acp/meta.py index 82aae7e..bc57869 100644 --- a/src/acp/meta.py +++ b/src/acp/meta.py @@ -1,9 +1,10 @@ # Generated from schema/meta.json. Do not edit by hand. -# Schema ref: refs/tags/v0.10.8 +# Schema ref: refs/tags/v0.11.2 AGENT_METHODS = { "authenticate": "authenticate", "initialize": "initialize", "session_cancel": "session/cancel", + "session_close": "session/close", "session_fork": "session/fork", "session_list": "session/list", "session_load": "session/load", diff --git a/src/acp/schema.py b/src/acp/schema.py index e449e4a..32031c4 100644 --- a/src/acp/schema.py +++ b/src/acp/schema.py @@ -1,5 +1,5 @@ # Generated from schema/schema.json. Do not edit by hand. -# Schema ref: refs/tags/v0.10.8 +# Schema ref: refs/tags/v0.11.2 from __future__ import annotations @@ -30,7 +30,7 @@ class Jsonrpc(Enum): field_2_0 = "2.0" -class AuthMethod(BaseModel): +class AuthCapabilities(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at # these keys. @@ -43,11 +43,145 @@ class AuthMethod(BaseModel): description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", ), ] = None + # Whether the client supports `terminal` authentication methods. + # + # When `true`, the agent may include `terminal` entries in its authentication methods. + terminal: Annotated[ + Optional[bool], + Field( + description="Whether the client supports `terminal` authentication methods.\n\nWhen `true`, the agent may include `terminal` entries in its authentication methods." + ), + ] = False + + +class AuthEnvVar(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # Human-readable label for this variable, displayed in client UI. + label: Annotated[ + Optional[str], + Field(description="Human-readable label for this variable, displayed in client UI."), + ] = None + # The environment variable name (e.g. `"OPENAI_API_KEY"`). + name: Annotated[ + str, + Field(description='The environment variable name (e.g. `"OPENAI_API_KEY"`).'), + ] + # Whether this variable is optional. + # + # Defaults to `false`. + optional: Annotated[ + Optional[bool], + Field(description="Whether this variable is optional.\n\nDefaults to `false`."), + ] = False + # Whether this value is a secret (e.g. API key, token). + # Clients should use a password-style input for secret vars. + # + # Defaults to `true`. + secret: Annotated[ + Optional[bool], + Field( + description="Whether this value is a secret (e.g. API key, token).\nClients should use a password-style input for secret vars.\n\nDefaults to `true`." + ), + ] = True + + +class AuthMethodAgent(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # Optional description providing more details about this authentication method. + description: Annotated[ + Optional[str], + Field(description="Optional description providing more details about this authentication method."), + ] = None + # Unique identifier for this authentication method. + id: Annotated[str, Field(description="Unique identifier for this authentication method.")] + # Human-readable name of the authentication method. + name: Annotated[str, Field(description="Human-readable name of the authentication method.")] + + +class AuthMethodEnvVar(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # Optional description providing more details about this authentication method. + description: Annotated[ + Optional[str], + Field(description="Optional description providing more details about this authentication method."), + ] = None + # Unique identifier for this authentication method. + id: Annotated[str, Field(description="Unique identifier for this authentication method.")] + # Optional link to a page where the user can obtain their credentials. + link: Annotated[ + Optional[str], + Field(description="Optional link to a page where the user can obtain their credentials."), + ] = None + # Human-readable name of the authentication method. + name: Annotated[str, Field(description="Human-readable name of the authentication method.")] + # The environment variables the client should set. + vars: Annotated[ + List[AuthEnvVar], + Field(description="The environment variables the client should set."), + ] + + +class AuthMethodTerminal(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # Additional arguments to pass when running the agent binary for terminal auth. + args: Annotated[ + Optional[List[str]], + Field(description="Additional arguments to pass when running the agent binary for terminal auth."), + ] = None # Optional description providing more details about this authentication method. description: Annotated[ Optional[str], Field(description="Optional description providing more details about this authentication method."), ] = None + # Additional environment variables to set when running the agent binary for terminal auth. + env: Annotated[ + Optional[Dict[str, str]], + Field(description="Additional environment variables to set when running the agent binary for terminal auth."), + ] = None # Unique identifier for this authentication method. id: Annotated[str, Field(description="Unique identifier for this authentication method.")] # Human-readable name of the authentication method. @@ -111,6 +245,21 @@ class BlobResourceContents(BaseModel): uri: str +class CloseSessionResponse(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + + class Cost(BaseModel): # Total cumulative cost for session. amount: Annotated[float, Field(description="Total cumulative cost for session.")] @@ -184,7 +333,7 @@ class EnvVariable(BaseModel): value: Annotated[str, Field(description="The value to set for the environment variable.")] -class FileSystemCapability(BaseModel): +class FileSystemCapabilities(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at # these keys. @@ -275,7 +424,7 @@ class Implementation(BaseModel): ] -class KillTerminalCommandResponse(BaseModel): +class KillTerminalResponse(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at # these keys. @@ -524,6 +673,29 @@ class SelectedPermissionOutcome(BaseModel): ] +class SessionCloseCapabilities(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + + +class SessionConfigBoolean(BaseModel): + # The current value of the boolean option. + current_value: Annotated[ + bool, + Field(alias="currentValue", description="The current value of the boolean option."), + ] + + class SessionForkCapabilities(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at @@ -658,7 +830,38 @@ class SessionInfoUpdate(_SessionInfoUpdate): session_update: Annotated[Literal["session_info_update"], Field(alias="sessionUpdate")] -class SetSessionConfigOptionRequest(BaseModel): +class SetSessionConfigOptionBooleanRequest(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # The ID of the configuration option to set. + config_id: Annotated[ + str, + Field(alias="configId", description="The ID of the configuration option to set."), + ] + # The ID of the session to set the configuration option for. + session_id: Annotated[ + str, + Field( + alias="sessionId", + description="The ID of the session to set the configuration option for.", + ), + ] + type: Literal["boolean"] + # The boolean value. + value: Annotated[bool, Field(description="The boolean value.")] + + +class SetSessionConfigOptionSelectRequest(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at # these keys. @@ -684,8 +887,8 @@ class SetSessionConfigOptionRequest(BaseModel): description="The ID of the session to set the configuration option for.", ), ] - # The ID of the configuration option value to set. - value: Annotated[str, Field(description="The ID of the configuration option value to set.")] + # The value ID. + value: Annotated[str, Field(description="The value ID.")] class SetSessionModeRequest(BaseModel): @@ -711,7 +914,18 @@ class SetSessionModeRequest(BaseModel): class SetSessionModeResponse(BaseModel): - field_meta: Annotated[Optional[Dict[str, Any]], Field(alias="_meta")] = None + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None class SetSessionModelRequest(BaseModel): @@ -1096,6 +1310,14 @@ class AudioContent(BaseModel): mime_type: Annotated[str, Field(alias="mimeType")] +class EnvVarAuthMethod(AuthMethodEnvVar): + type: Literal["env_var"] + + +class TerminalAuthMethod(AuthMethodTerminal): + type: Literal["terminal"] + + class AvailableCommandInput(RootModel[UnstructuredCommandInput]): # The input specification for a command. root: Annotated[ @@ -1160,14 +1382,27 @@ class ClientCapabilities(BaseModel): description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", ), ] = None + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # + # Authentication capabilities supported by the client. + # Determines which authentication method types the agent may include + # in its `InitializeResponse`. + auth: Annotated[ + Optional[AuthCapabilities], + Field( + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication capabilities supported by the client.\nDetermines which authentication method types the agent may include\nin its `InitializeResponse`." + ), + ] = {"terminal": False} # File system capabilities supported by the client. # Determines which file operations the agent can request. fs: Annotated[ - Optional[FileSystemCapability], + Optional[FileSystemCapabilities], Field( description="File system capabilities supported by the client.\nDetermines which file operations the agent can request." ), - ] = FileSystemCapability() + ] = FileSystemCapabilities() # Whether the Client support all `terminal/*` methods. terminal: Annotated[ Optional[bool], @@ -1180,6 +1415,23 @@ class ClientNotification(BaseModel): params: Optional[Union[CancelNotification, Any]] = None +class CloseSessionRequest(BaseModel): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # The ID of the session to close. + session_id: Annotated[str, Field(alias="sessionId", description="The ID of the session to close.")] + + class AudioContentBlock(AudioContent): type: Literal["audio"] @@ -1337,7 +1589,7 @@ class InitializeRequest(BaseModel): ] -class KillTerminalCommandRequest(BaseModel): +class KillTerminalRequest(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at # these keys. @@ -1507,6 +1759,22 @@ class PromptResponse(BaseModel): description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nToken usage for this turn (optional)." ), ] = None + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # + # The acknowledged user message ID. + # + # If the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here + # to confirm it was recorded. If the client did not provide one, the agent MAY assign one + # and return it here. Absence of this field indicates the agent did not record a message ID. + user_message_id: Annotated[ + Optional[str], + Field( + alias="userMessageId", + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nThe acknowledged user message ID.\n\nIf the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here\nto confirm it was recorded. If the client did not provide one, the agent MAY assign one\nand return it here. Absence of this field indicates the agent did not record a message ID.", + ), + ] = None class ReadTextFileRequest(BaseModel): @@ -1647,23 +1915,28 @@ class SessionCapabilities(BaseModel): # # This capability is not part of the spec yet, and may be removed or changed at any point. # - # Whether the agent supports `session/fork`. - fork: Annotated[ - Optional[SessionForkCapabilities], + # Whether the agent supports `session/close`. + close: Annotated[ + Optional[SessionCloseCapabilities], Field( - description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/fork`." + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/close`." ), ] = None # **UNSTABLE** # # This capability is not part of the spec yet, and may be removed or changed at any point. # + # Whether the agent supports `session/fork`. + fork: Annotated[ + Optional[SessionForkCapabilities], + Field( + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/fork`." + ), + ] = None # Whether the agent supports `session/list`. list: Annotated[ Optional[SessionListCapabilities], - Field( - description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/list`." - ), + Field(description="Whether the agent supports `session/list`."), ] = None # **UNSTABLE** # @@ -1678,6 +1951,36 @@ class SessionCapabilities(BaseModel): ] = None +class SessionConfigOptionBoolean(SessionConfigBoolean): + # The _meta property is reserved by ACP to allow clients and agents to attach additional + # metadata to their interactions. Implementations MUST NOT make assumptions about values at + # these keys. + # + # See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + field_meta: Annotated[ + Optional[Dict[str, Any]], + Field( + alias="_meta", + description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + ), + ] = None + # Optional semantic category for this option (UX only). + category: Annotated[ + Optional[str], + Field(description="Optional semantic category for this option (UX only)."), + ] = None + # Optional description for the Client to display to the user. + description: Annotated[ + Optional[str], + Field(description="Optional description for the Client to display to the user."), + ] = None + # Unique identifier for the configuration option. + id: Annotated[str, Field(description="Unique identifier for the configuration option.")] + # Human-readable label for the option. + name: Annotated[str, Field(description="Human-readable label for the option.")] + type: Literal["boolean"] + + class SessionConfigSelectOption(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at @@ -1910,7 +2213,7 @@ class ClientResponseMessage(BaseModel): TerminalOutputResponse, ReleaseTerminalResponse, WaitForTerminalExitResponse, - KillTerminalCommandResponse, + KillTerminalResponse, Any, ], Field( @@ -2035,7 +2338,7 @@ class InitializeResponse(BaseModel): ] = None # Authentication methods supported by the agent. auth_methods: Annotated[ - Optional[List[AuthMethod]], + Optional[List[Union[EnvVarAuthMethod, TerminalAuthMethod, AuthMethodAgent]]], Field( alias="authMethods", description="Authentication methods supported by the agent.", @@ -2164,6 +2467,22 @@ class ContentChunk(BaseModel): ], Field(description="A single item of content", discriminator="type"), ] + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # + # A unique identifier for the message this chunk belongs to. + # + # All chunks belonging to the same message share the same `messageId`. + # A change in `messageId` indicates a new message has started. + # Both clients and agents MUST use UUID format for message IDs. + message_id: Annotated[ + Optional[str], + Field( + alias="messageId", + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started.\nBoth clients and agents MUST use UUID format for message IDs.", + ), + ] = None class PromptRequest(BaseModel): @@ -2179,6 +2498,22 @@ class PromptRequest(BaseModel): description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", ), ] = None + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # + # A client-generated unique identifier for this user message. + # + # If provided, the Agent SHOULD echo this value as `userMessageId` in the + # [`PromptResponse`] to confirm it was recorded. + # Both clients and agents MUST use UUID format for message IDs. + message_id: Annotated[ + Optional[str], + Field( + alias="messageId", + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA client-generated unique identifier for this user message.\n\nIf provided, the Agent SHOULD echo this value as `userMessageId` in the\n[`PromptResponse`] to confirm it was recorded.\nBoth clients and agents MUST use UUID format for message IDs.", + ), + ] = None # The blocks of content that compose the user's message. # # As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`], @@ -2264,10 +2599,11 @@ class ClientRequest(BaseModel): ListSessionsRequest, ForkSessionRequest, ResumeSessionRequest, + CloseSessionRequest, SetSessionModeRequest, - SetSessionConfigOptionRequest, PromptRequest, SetSessionModelRequest, + Union[SetSessionConfigOptionBooleanRequest, SetSessionConfigOptionSelectRequest], Any, ] ] = None @@ -2325,17 +2661,6 @@ class SessionConfigOptionSelect(SessionConfigSelect): type: Literal["select"] -class SessionConfigOption(RootModel[SessionConfigOptionSelect]): - # A session configuration option selector and its current state. - root: Annotated[ - SessionConfigOptionSelect, - Field( - description="A session configuration option selector and its current state.", - discriminator="type", - ), - ] - - class SetSessionConfigOptionResponse(BaseModel): # The _meta property is reserved by ACP to allow clients and agents to attach additional # metadata to their interactions. Implementations MUST NOT make assumptions about values at @@ -2351,7 +2676,7 @@ class SetSessionConfigOptionResponse(BaseModel): ] = None # The full set of configuration options and their current values. config_options: Annotated[ - List[SessionConfigOption], + List[Union[SessionConfigOptionSelect, SessionConfigOptionBoolean]], Field( alias="configOptions", description="The full set of configuration options and their current values.", @@ -2418,7 +2743,7 @@ class _ConfigOptionUpdate(BaseModel): ] = None # The full set of configuration options and their current values. config_options: Annotated[ - List[SessionConfigOption], + List[Union[SessionConfigOptionSelect, SessionConfigOptionBoolean]], Field( alias="configOptions", description="The full set of configuration options and their current values.", @@ -2441,7 +2766,7 @@ class ForkSessionResponse(BaseModel): ] = None # Initial session configuration options if supported by the Agent. config_options: Annotated[ - Optional[List[SessionConfigOption]], + Optional[List[Union[SessionConfigOptionSelect, SessionConfigOptionBoolean]]], Field( alias="configOptions", description="Initial session configuration options if supported by the Agent.", @@ -2492,7 +2817,7 @@ class LoadSessionResponse(BaseModel): ] = None # Initial session configuration options if supported by the Agent. config_options: Annotated[ - Optional[List[SessionConfigOption]], + Optional[List[Union[SessionConfigOptionSelect, SessionConfigOptionBoolean]]], Field( alias="configOptions", description="Initial session configuration options if supported by the Agent.", @@ -2535,7 +2860,7 @@ class NewSessionResponse(BaseModel): ] = None # Initial session configuration options if supported by the Agent. config_options: Annotated[ - Optional[List[SessionConfigOption]], + Optional[List[Union[SessionConfigOptionSelect, SessionConfigOptionBoolean]]], Field( alias="configOptions", description="Initial session configuration options if supported by the Agent.", @@ -2618,7 +2943,7 @@ class ResumeSessionResponse(BaseModel): ] = None # Initial session configuration options if supported by the Agent. config_options: Annotated[ - Optional[List[SessionConfigOption]], + Optional[List[Union[SessionConfigOptionSelect, SessionConfigOptionBoolean]]], Field( alias="configOptions", description="Initial session configuration options if supported by the Agent.", @@ -2739,7 +3064,7 @@ class AgentRequest(BaseModel): TerminalOutputRequest, ReleaseTerminalRequest, WaitForTerminalExitRequest, - KillTerminalCommandRequest, + KillTerminalRequest, Any, ] ] = None @@ -2776,6 +3101,7 @@ class AgentResponseMessage(BaseModel): ListSessionsResponse, ForkSessionResponse, ResumeSessionResponse, + CloseSessionResponse, SetSessionModeResponse, SetSessionConfigOptionResponse, PromptResponse, diff --git a/tests/conftest.py b/tests/conftest.py index a2a373d..825610a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ AuthenticateResponse, CreateTerminalResponse, InitializeResponse, - KillTerminalCommandResponse, + KillTerminalResponse, LoadSessionResponse, NewSessionResponse, PromptRequest, @@ -43,6 +43,7 @@ HttpMcpServer, ImageContentBlock, Implementation, + ListSessionsResponse, McpServerStdio, PermissionOption, ResourceContentBlock, @@ -211,7 +212,7 @@ async def wait_for_terminal_exit( async def kill_terminal( self, session_id: str, terminal_id: str | None = None, **kwargs: Any - ) -> KillTerminalCommandResponse | None: + ) -> KillTerminalResponse | None: raise NotImplementedError async def ext_method(self, method: str, params: dict) -> dict: @@ -274,6 +275,11 @@ async def prompt( async def cancel(self, session_id: str, **kwargs: Any) -> None: self.cancellations.append(session_id) + async def list_sessions( + self, cursor: str | None = None, cwd: str | None = None, **kwargs: Any + ) -> ListSessionsResponse: + return ListSessionsResponse(sessions=[]) + async def set_session_mode(self, mode_id: str, session_id: str, **kwargs: Any) -> SetSessionModeResponse | None: return SetSessionModeResponse() diff --git a/tests/test_golden.py b/tests/test_golden.py index 181945f..2420ed2 100644 --- a/tests/test_golden.py +++ b/tests/test_golden.py @@ -51,8 +51,8 @@ RequestPermissionRequest, RequestPermissionResponse, ResourceContentBlock, - SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, + SetSessionConfigOptionSelectRequest, TerminalToolCallContent, TextContentBlock, ToolCallLocation, @@ -96,7 +96,7 @@ "session_update_tool_call_update_content": ToolCallProgress, "session_update_tool_call_update_more_fields": ToolCallProgress, "session_update_user_message_chunk": UserMessageChunk, - "set_session_config_option_request": SetSessionConfigOptionRequest, + "set_session_config_option_request": SetSessionConfigOptionSelectRequest, "set_session_config_option_response": SetSessionConfigOptionResponse, "tool_content_content_text": ContentToolCallContent, "tool_content_diff": FileEditToolCallContent, diff --git a/tests/test_rpc.py b/tests/test_rpc.py index 7b4c37e..bcf068e 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -38,6 +38,7 @@ HttpMcpServer, ImageContentBlock, Implementation, + ListSessionsResponse, McpServerStdio, PermissionOption, ResourceContentBlock, @@ -263,6 +264,15 @@ async def test_set_config_option(connect, agent, client): assert resp.config_options == [] +@pytest.mark.asyncio +async def test_list_sessions_stable(connect, agent, client): + _, agent_conn = connect() + + resp = await agent_conn.list_sessions() + assert isinstance(resp, ListSessionsResponse) + assert resp.sessions == [] + + @pytest.mark.asyncio async def test_ignore_invalid_messages(connect, server): connect(connect_agent=True, connect_client=False) diff --git a/tests/test_unstable.py b/tests/test_unstable.py index afdbb28..0a25e47 100644 --- a/tests/test_unstable.py +++ b/tests/test_unstable.py @@ -4,6 +4,7 @@ from acp.exceptions import RequestError from acp.schema import ( + CloseSessionResponse, ForkSessionResponse, HttpMcpServer, ListSessionsResponse, @@ -19,6 +20,9 @@ class UnstableAgent(TestAgent): async def list_sessions(self, cursor: str | None = None, cwd: str | None = None, **kwargs) -> ListSessionsResponse: return ListSessionsResponse(sessions=[]) + async def close_session(self, session_id: str, **kwargs) -> CloseSessionResponse | None: + return CloseSessionResponse() + async def set_session_model(self, model_id: str, session_id: str, **kwargs: Any) -> SetSessionModelResponse | None: return SetSessionModelResponse() @@ -58,6 +62,9 @@ async def test_call_unstable_protocol(connect): resp = await agent_conn.resume_session(cwd="/workspace", session_id="sess") assert isinstance(resp, ResumeSessionResponse) + resp = await agent_conn.close_session(session_id="sess") + assert isinstance(resp, CloseSessionResponse) + @pytest.mark.parametrize("agent", [UnstableAgent()]) @pytest.mark.asyncio @@ -66,10 +73,10 @@ async def test_call_unstable_protocol_warning(connect): with pytest.warns(UserWarning) as record: with pytest.raises(RequestError): - await agent_conn.list_sessions() + await agent_conn.set_session_model(session_id="sess", model_id="gpt-4o-mini") assert len(record) == 1 with pytest.warns(UserWarning) as record: with pytest.raises(RequestError): - await agent_conn.set_session_model(session_id="sess", model_id="gpt-4o-mini") + await agent_conn.close_session(session_id="sess") assert len(record) == 1