diff --git a/schema/VERSION b/schema/VERSION index 939db70..babc878 100644 --- a/schema/VERSION +++ b/schema/VERSION @@ -1 +1 @@ -refs/tags/v0.9.1 +refs/tags/v0.10.3 diff --git a/schema/meta.json b/schema/meta.json index 7fad892..e58853e 100644 --- a/schema/meta.json +++ b/schema/meta.json @@ -3,10 +3,12 @@ "authenticate": "authenticate", "initialize": "initialize", "session_cancel": "session/cancel", + "session_fork": "session/fork", "session_list": "session/list", "session_load": "session/load", "session_new": "session/new", "session_prompt": "session/prompt", + "session_resume": "session/resume", "session_set_mode": "session/set_mode", "session_set_model": "session/set_model" }, @@ -21,5 +23,8 @@ "terminal_release": "terminal/release", "terminal_wait_for_exit": "terminal/wait_for_exit" }, + "protocolMethods": { + "cancel_request": "$/cancel_request" + }, "version": 1 } diff --git a/schema/schema.json b/schema/schema.json index 938b199..9d1f974 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -216,6 +216,12 @@ { "$ref": "#/$defs/ListSessionsResponse" }, + { + "$ref": "#/$defs/ForkSessionResponse" + }, + { + "$ref": "#/$defs/ResumeSessionResponse" + }, { "$ref": "#/$defs/SetSessionModeResponse" }, @@ -529,6 +535,33 @@ "x-method": "session/cancel", "x-side": "agent" }, + "CancelRequestNotification": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nNotification to cancel an ongoing request.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)", + "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" + ] + }, + "requestId": { + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ], + "description": "The ID of the request to cancel." + } + }, + "required": [ + "requestId" + ], + "type": "object", + "x-method": "$/cancel_request", + "x-side": "protocol" + }, "ClientCapabilities": { "description": "Capabilities supported by the client.\n\nAdvertised during initialization to inform the agent about\navailable features and methods.\n\nSee protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)", "properties": { @@ -652,6 +685,22 @@ ], "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." }, + { + "allOf": [ + { + "$ref": "#/$defs/ForkSessionRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nForks an existing session to create a new independent session.\n\nThis method is only available if the agent advertises the `session.fork` capability.\n\nThe agent should create a new session with the same conversation context as the\noriginal, allowing operations like generating summaries without affecting the\noriginal session's history." + }, + { + "allOf": [ + { + "$ref": "#/$defs/ResumeSessionRequest" + } + ], + "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`)." + }, { "allOf": [ { @@ -1126,9 +1175,12 @@ "description": "JSON-RPC error object.\n\nRepresents an error that occurred during method execution, following the\nJSON-RPC 2.0 error object specification with optional additional data.\n\nSee protocol docs: [JSON-RPC Error Object](https://www.jsonrpc.org/specification#error_object)", "properties": { "code": { - "description": "A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification.", - "format": "int32", - "type": "integer" + "allOf": [ + { + "$ref": "#/$defs/ErrorCode" + } + ], + "description": "A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification." }, "data": { "description": "Optional primitive or structured value that contains additional information about the error.\nThis may include debugging information or context-specific details." @@ -1144,6 +1196,64 @@ ], "type": "object" }, + "ErrorCode": { + "anyOf": [ + { + "const": -32700, + "description": "**Parse error**: Invalid JSON was received by the server.\nAn error occurred on the server while parsing the JSON text.", + "format": "int32", + "type": "integer" + }, + { + "const": -32600, + "description": "**Invalid request**: The JSON sent is not a valid Request object.", + "format": "int32", + "type": "integer" + }, + { + "const": -32601, + "description": "**Method not found**: The method does not exist or is not available.", + "format": "int32", + "type": "integer" + }, + { + "const": -32602, + "description": "**Invalid params**: Invalid method parameter(s).", + "format": "int32", + "type": "integer" + }, + { + "const": -32603, + "description": "**Internal error**: Internal JSON-RPC error.\nReserved for implementation-defined server errors.", + "format": "int32", + "type": "integer" + }, + { + "const": -32800, + "description": "**Request cancelled**: **UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nExecution of the method was aborted either due to a cancellation request from the caller or\nbecause of resource constraints or shutdown.", + "format": "int32", + "type": "integer" + }, + { + "const": -32000, + "description": "**Authentication required**: Authentication is required before this operation can be performed.", + "format": "int32", + "type": "integer" + }, + { + "const": -32002, + "description": "**Resource not found**: A given resource, such as a file, was not found.", + "format": "int32", + "type": "integer" + }, + { + "description": "Other undefined error code.", + "format": "int32", + "type": "integer" + } + ], + "description": "Predefined error codes for common JSON-RPC and ACP-specific errors.\n\nThese codes follow the JSON-RPC 2.0 specification for standard errors\nand use the reserved range (-32000 to -32099) for protocol-specific errors." + }, "ExtNotification": { "description": "Allows the Agent to send an arbitrary notification that is not part of the ACP spec.\nExtension notifications provide a way to send one-way messages for custom functionality\nwhile maintaining protocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)" }, @@ -1177,6 +1287,94 @@ }, "type": "object" }, + "ForkSessionRequest": { + "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 forking an existing session.\n\nCreates a new session based on the context of an existing one, allowing\noperations like generating summaries without affecting the original session's history.\n\nOnly available if the Agent supports the `session.fork` 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" + ] + }, + "cwd": { + "description": "The working directory for this session.", + "type": "string" + }, + "mcpServers": { + "description": "List of MCP servers to connect to for this session.", + "items": { + "$ref": "#/$defs/McpServer" + }, + "type": "array" + }, + "sessionId": { + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ], + "description": "The ID of the session to fork." + } + }, + "required": [ + "sessionId", + "cwd" + ], + "type": "object", + "x-method": "session/fork", + "x-side": "agent" + }, + "ForkSessionResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse from forking an existing 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" + ] + }, + "models": { + "anyOf": [ + { + "$ref": "#/$defs/SessionModelState" + }, + { + "type": "null" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInitial model state if supported by the Agent" + }, + "modes": { + "anyOf": [ + { + "$ref": "#/$defs/SessionModeState" + }, + { + "type": "null" + } + ], + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)" + }, + "sessionId": { + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ], + "description": "Unique identifier for the newly created forked session." + } + }, + "required": [ + "sessionId" + ], + "type": "object", + "x-method": "session/fork", + "x-side": "agent" + }, "HttpHeader": { "description": "An HTTP header to set when making requests to the MCP server.", "properties": { @@ -2462,6 +2660,83 @@ ], "type": "object" }, + "ResumeSessionRequest": { + "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 resuming an existing session.\n\nResumes an existing session without returning previous messages (unlike `session/load`).\nThis is useful for agents that can resume sessions but don't implement full session loading.\n\nOnly available if the Agent supports the `session.resume` 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" + ] + }, + "cwd": { + "description": "The working directory for this session.", + "type": "string" + }, + "mcpServers": { + "description": "List of MCP servers to connect to for this session.", + "items": { + "$ref": "#/$defs/McpServer" + }, + "type": "array" + }, + "sessionId": { + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ], + "description": "The ID of the session to resume." + } + }, + "required": [ + "sessionId", + "cwd" + ], + "type": "object", + "x-method": "session/resume", + "x-side": "agent" + }, + "ResumeSessionResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse from resuming an existing 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" + ] + }, + "models": { + "anyOf": [ + { + "$ref": "#/$defs/SessionModelState" + }, + { + "type": "null" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInitial model state if supported by the Agent" + }, + "modes": { + "anyOf": [ + { + "$ref": "#/$defs/SessionModeState" + }, + { + "type": "null" + } + ], + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)" + } + }, + "type": "object", + "x-method": "session/resume", + "x-side": "agent" + }, "Role": { "description": "The sender or recipient of messages and data in a conversation.", "enum": [ @@ -2506,6 +2781,17 @@ "null" ] }, + "fork": { + "anyOf": [ + { + "$ref": "#/$defs/SessionForkCapabilities" + }, + { + "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/fork`." + }, "list": { "anyOf": [ { @@ -2516,6 +2802,31 @@ } ], "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`." + }, + "resume": { + "anyOf": [ + { + "$ref": "#/$defs/SessionResumeCapabilities" + }, + { + "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/resume`." + } + }, + "type": "object" + }, + "SessionForkCapabilities": { + "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/fork` method.\n\nBy supplying `{}` it means that the agent supports forking 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" @@ -2568,6 +2879,34 @@ ], "type": "object" }, + "SessionInfoUpdate": { + "description": "Update to session metadata. All fields are optional to support partial updates.\n\nAgents send this notification to update session information like title or custom metadata.\nThis allows clients to display dynamic session names and track session state changes.", + "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" + ] + }, + "title": { + "description": "Human-readable title for the session. Set to null to clear.", + "type": [ + "string", + "null" + ] + }, + "updatedAt": { + "description": "ISO 8601 timestamp of last activity. Set to null to clear.", + "type": [ + "string", + "null" + ] + } + }, + "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.", "properties": { @@ -2718,6 +3057,20 @@ "x-method": "session/update", "x-side": "client" }, + "SessionResumeCapabilities": { + "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/resume` method.\n\nBy supplying `{}` it means that the agent supports resuming 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" + }, "SessionUpdate": { "description": "Different types of updates that can be sent during session processing.\n\nThese updates provide real-time feedback about the agent's progress.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)", "discriminator": { @@ -2867,6 +3220,24 @@ "sessionUpdate" ], "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/SessionInfoUpdate" + } + ], + "description": "Session metadata has been updated (title, timestamps, custom metadata)", + "properties": { + "sessionUpdate": { + "const": "session_info_update", + "type": "string" + } + }, + "required": [ + "sessionUpdate" + ], + "type": "object" } ] }, @@ -3698,6 +4069,20 @@ "jsonrpc" ], "type": "object" + }, + { + "anyOf": [ + { + "allOf": [ + { + "$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": "General protocol-level notifications that all sides are expected to\nimplement.\n\nNotifications whose methods start with '$/' are messages which\nare protocol implementation dependent and might not be implementable in all\nclients or agents. For example if the implementation uses a single threaded\nsynchronous programming language then there is little it can do to react to\na `$/cancel_request` notification. If an agent or client receives\nnotifications starting with '$/' it is free to ignore the notification.\n\nNotifications do not expect a response." } - ] + ], + "title": "Agent Client Protocol" } diff --git a/scripts/gen_schema.py b/scripts/gen_schema.py index c03eab4..2a951a2 100644 --- a/scripts/gen_schema.py +++ b/scripts/gen_schema.py @@ -27,12 +27,15 @@ ) STDIO_TYPE_LITERAL = 'Literal["2#-datamodel-code-generator-#-object-#-special-#"]' -STDIO_TYPE_PATTERN = re.compile( - r"^ type:\s*Literal\[['\"]McpServerStdio['\"]\]" - r"(?:\s*=\s*['\"][^'\"]+['\"])?\s*$", - re.MULTILINE, -) -MODELS_TO_REMOVE = ["Model1", "Model2", "Model3", "Model4", "Model5", "Model6", "Model"] +MODELS_TO_REMOVE = [ + "AgentClientProtocol", + "AgentClientProtocol1", + "AgentClientProtocol2", + "AgentClientProtocol3", + "AgentClientProtocol4", + "AgentClientProtocol5", + "AgentClientProtocol6", +] # Map of numbered classes produced by datamodel-code-generator to descriptive names. # Keep this in sync with the Rust/TypeScript SDK nomenclature. @@ -58,6 +61,7 @@ "SessionUpdate6": "AgentPlanUpdate", "SessionUpdate7": "AvailableCommandsUpdate", "SessionUpdate8": "CurrentModeUpdate", + "SessionUpdate9": "SessionInfoUpdate", "ToolCallContent1": "ContentToolCallContent", "ToolCallContent2": "FileEditToolCallContent", "ToolCallContent3": "TerminalToolCallContent", @@ -175,7 +179,6 @@ def postprocess_generated_schema(output_path: Path) -> list[str]: processing_steps: tuple[_ProcessingStep, ...] = ( _ProcessingStep("apply field overrides", _apply_field_overrides), _ProcessingStep("apply default overrides", _apply_default_overrides), - _ProcessingStep("normalize stdio literal", _normalize_stdio_model), _ProcessingStep("attach description comments", _add_description_comments), _ProcessingStep("ensure custom BaseModel", _ensure_custom_base_model), ) @@ -242,6 +245,8 @@ def _remove_backcompat_block(content: str) -> str: def _rename_numbered_models(content: str) -> tuple[str, list[str]]: renamed = content for old, new in sorted(RENAME_MAP.items(), key=lambda item: len(item[0]), reverse=True): + if re.search(rf"\b{re.escape(new)}\b", renamed) is not None: + renamed = re.sub(rf"\b{re.escape(new)}\b", f"_{new}", renamed) pattern = re.compile(rf"\b{re.escape(old)}\b") renamed = pattern.sub(new, renamed) @@ -417,20 +422,6 @@ def replace_block( return content -def _normalize_stdio_model(content: str) -> str: - replacement_line = ' type: Literal["stdio"] = "stdio"' - new_content, count = STDIO_TYPE_PATTERN.subn(replacement_line, content) - if count == 0: - print("Warning: stdio type placeholder not found; no replacements made.", file=sys.stderr) - return content - if count > 1: - print( - "Warning: multiple stdio type placeholders detected; manual review required.", - file=sys.stderr, - ) - return new_content - - def _add_description_comments(content: str) -> str: lines = content.splitlines() new_lines: list[str] = [] diff --git a/src/acp/agent/connection.py b/src/acp/agent/connection.py index 5a96af5..587ad43 100644 --- a/src/acp/agent/connection.py +++ b/src/acp/agent/connection.py @@ -25,6 +25,7 @@ ReleaseTerminalResponse, RequestPermissionRequest, RequestPermissionResponse, + SessionInfoUpdate, SessionNotification, TerminalOutputRequest, TerminalOutputResponse, @@ -83,7 +84,8 @@ async def session_update( | ToolCallProgress | AgentPlanUpdate | AvailableCommandsUpdate - | CurrentModeUpdate, + | CurrentModeUpdate + | SessionInfoUpdate, **kwargs: Any, ) -> None: await notify_model( diff --git a/src/acp/agent/router.py b/src/acp/agent/router.py index c80b42c..8221ede 100644 --- a/src/acp/agent/router.py +++ b/src/acp/agent/router.py @@ -9,11 +9,13 @@ from ..schema import ( AuthenticateRequest, CancelNotification, + ForkSessionRequest, InitializeRequest, ListSessionsRequest, LoadSessionRequest, NewSessionRequest, PromptRequest, + ResumeSessionRequest, SetSessionModelRequest, SetSessionModeRequest, ) @@ -58,6 +60,8 @@ def build_agent_router(agent: Agent, use_unstable_protocol: bool = False) -> Mes "authenticate", adapt_result=normalize_result, ) + router.route_request(AGENT_METHODS["session_fork"], ForkSessionRequest, agent, "fork_session", unstable=True) + router.route_request(AGENT_METHODS["session_resume"], ResumeSessionRequest, agent, "resume_session", unstable=True) router.route_notification(AGENT_METHODS["session_cancel"], CancelNotification, agent, "cancel") diff --git a/src/acp/client/connection.py b/src/acp/client/connection.py index 88cf2ac..7a5cdcb 100644 --- a/src/acp/client/connection.py +++ b/src/acp/client/connection.py @@ -14,6 +14,8 @@ CancelNotification, ClientCapabilities, EmbeddedResourceContentBlock, + ForkSessionRequest, + ForkSessionResponse, HttpMcpServer, ImageContentBlock, Implementation, @@ -29,6 +31,8 @@ PromptRequest, PromptResponse, ResourceContentBlock, + ResumeSessionRequest, + ResumeSessionResponse, SetSessionModelRequest, SetSessionModelResponse, SetSessionModeRequest, @@ -165,6 +169,36 @@ async def prompt( PromptResponse, ) + @param_model(ForkSessionRequest) + async def fork_session( + self, + cwd: str, + session_id: str, + mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio] | None = None, + **kwargs: Any, + ) -> ForkSessionResponse: + return await request_model( + self._conn, + AGENT_METHODS["session_fork"], + ForkSessionRequest(session_id=session_id, cwd=cwd, mcp_servers=mcp_servers, field_meta=kwargs or None), + ForkSessionResponse, + ) + + @param_model(ResumeSessionRequest) + async def resume_session( + self, + cwd: str, + session_id: str, + mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio] | None = None, + **kwargs: Any, + ) -> ResumeSessionResponse: + return await request_model( + self._conn, + AGENT_METHODS["session_resume"], + ResumeSessionRequest(session_id=session_id, cwd=cwd, mcp_servers=mcp_servers, field_meta=kwargs or None), + ResumeSessionResponse, + ) + @param_model(CancelNotification) async def cancel(self, session_id: str, **kwargs: Any) -> None: await notify_model( diff --git a/src/acp/interfaces.py b/src/acp/interfaces.py index f0049e0..0e82240 100644 --- a/src/acp/interfaces.py +++ b/src/acp/interfaces.py @@ -17,6 +17,8 @@ CurrentModeUpdate, EmbeddedResourceContentBlock, EnvVariable, + ForkSessionRequest, + ForkSessionResponse, HttpMcpServer, ImageContentBlock, Implementation, @@ -41,6 +43,9 @@ RequestPermissionRequest, RequestPermissionResponse, ResourceContentBlock, + ResumeSessionRequest, + ResumeSessionResponse, + SessionInfoUpdate, SessionNotification, SetSessionModelRequest, SetSessionModelResponse, @@ -81,7 +86,8 @@ async def session_update( | ToolCallProgress | AgentPlanUpdate | AvailableCommandsUpdate - | CurrentModeUpdate, + | CurrentModeUpdate + | SessionInfoUpdate, **kwargs: Any, ) -> None: ... @@ -182,6 +188,24 @@ async def prompt( **kwargs: Any, ) -> PromptResponse: ... + @param_model(ForkSessionRequest) + async def fork_session( + self, + cwd: str, + session_id: str, + mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio] | None = None, + **kwargs: Any, + ) -> ForkSessionResponse: ... + + @param_model(ResumeSessionRequest) + async def resume_session( + self, + cwd: str, + session_id: str, + mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio] | None = None, + **kwargs: Any, + ) -> ResumeSessionResponse: ... + @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 9f9768c..d5512a1 100644 --- a/src/acp/meta.py +++ b/src/acp/meta.py @@ -1,13 +1,15 @@ # Generated from schema/meta.json. Do not edit by hand. -# Schema ref: refs/tags/v0.9.1 +# Schema ref: refs/tags/v0.10.3 AGENT_METHODS = { "authenticate": "authenticate", "initialize": "initialize", "session_cancel": "session/cancel", + "session_fork": "session/fork", "session_list": "session/list", "session_load": "session/load", "session_new": "session/new", "session_prompt": "session/prompt", + "session_resume": "session/resume", "session_set_mode": "session/set_mode", "session_set_model": "session/set_model", } diff --git a/src/acp/schema.py b/src/acp/schema.py index a1a8ed7..aaa7c6a 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.9.1 +# Schema ref: refs/tags/v0.10.3 from __future__ import annotations @@ -177,33 +177,6 @@ class EnvVariable(BaseModel): value: Annotated[str, Field(description="The value to set for the environment variable.")] -class Error(BaseModel): - # A number indicating the error type that occurred. - # This must be an integer as defined in the JSON-RPC specification. - code: Annotated[ - int, - Field( - description="A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification." - ), - ] - # Optional primitive or structured value that contains additional information about the error. - # This may include debugging information or context-specific details. - data: Annotated[ - Optional[Any], - Field( - description="Optional primitive or structured value that contains additional information about the error.\nThis may include debugging information or context-specific details." - ), - ] = None - # A string providing a short description of the error. - # The message should be limited to a concise single sentence. - message: Annotated[ - str, - Field( - description="A string providing a short description of the error.\nThe message should be limited to a concise single sentence." - ), - ] - - class FileSystemCapability(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 @@ -544,6 +517,21 @@ class SelectedPermissionOutcome(BaseModel): ] +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 + # 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 SessionInfo(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 @@ -573,6 +561,34 @@ class SessionInfo(BaseModel): ] = None +class _SessionInfoUpdate(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 title for the session. Set to null to clear. + title: Annotated[ + Optional[str], + Field(description="Human-readable title for the session. Set to null to clear."), + ] = None + # ISO 8601 timestamp of last activity. Set to null to clear. + updated_at: Annotated[ + Optional[str], + Field( + alias="updatedAt", + description="ISO 8601 timestamp of last activity. Set to null to clear.", + ), + ] = None + + class SessionListCapabilities(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 @@ -616,6 +632,25 @@ class SessionModelState(BaseModel): ] +class SessionResumeCapabilities(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 SessionInfoUpdate(_SessionInfoUpdate): + session_update: Annotated[Literal["session_info_update"], Field(alias="sessionUpdate")] + + class SetSessionModeRequest(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 @@ -922,25 +957,6 @@ class WriteTextFileResponse(BaseModel): ] = None -class AgentErrorMessage(BaseModel): - error: Error - # JSON RPC Request Id - # - # An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] - # - # The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. - # - # [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. - # - # [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. - id: Annotated[ - Optional[Union[int, str]], - Field( - description="JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." - ), - ] = None - - class Annotations(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 @@ -1008,6 +1024,26 @@ class CancelNotification(BaseModel): ] +class CancelRequestNotification(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 request to cancel. + request_id: Annotated[ + Optional[Union[int, str]], + Field(alias="requestId", description="The ID of the request to cancel."), + ] = None + + class ClientCapabilities(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 @@ -1041,25 +1077,6 @@ class ClientNotification(BaseModel): params: Optional[Union[CancelNotification, Any]] = None -class ClientErrorMessage(BaseModel): - error: Error - # JSON RPC Request Id - # - # An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] - # - # The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. - # - # [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. - # - # [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. - id: Annotated[ - Optional[Union[int, str]], - Field( - description="JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." - ), - ] = None - - class AudioContentBlock(AudioContent): type: Literal["audio"] @@ -1111,7 +1128,7 @@ class CreateTerminalRequest(BaseModel): session_id: Annotated[str, Field(alias="sessionId", description="The session ID for this request.")] -class CurrentModeUpdate(BaseModel): +class _CurrentModeUpdate(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. @@ -1128,6 +1145,33 @@ class CurrentModeUpdate(BaseModel): current_mode_id: Annotated[str, Field(alias="currentModeId", description="The ID of the current mode")] +class Error(BaseModel): + # A number indicating the error type that occurred. + # This must be an integer as defined in the JSON-RPC specification. + code: Annotated[ + int, + Field( + description="A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification." + ), + ] + # Optional primitive or structured value that contains additional information about the error. + # This may include debugging information or context-specific details. + data: Annotated[ + Optional[Any], + Field( + description="Optional primitive or structured value that contains additional information about the error.\nThis may include debugging information or context-specific details." + ), + ] = None + # A string providing a short description of the error. + # The message should be limited to a concise single sentence. + message: Annotated[ + str, + Field( + description="A string providing a short description of the error.\nThe message should be limited to a concise single sentence." + ), + ] + + class ImageContent(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 @@ -1445,6 +1489,33 @@ class ResourceLink(BaseModel): uri: str +class ResumeSessionRequest(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 working directory for this session. + cwd: Annotated[str, Field(description="The working directory for this session.")] + # List of MCP servers to connect to for this session. + mcp_servers: Annotated[ + Optional[List[Union[HttpMcpServer, SseMcpServer, McpServerStdio]]], + Field( + alias="mcpServers", + description="List of MCP servers to connect to for this session.", + ), + ] = None + # The ID of the session to resume. + session_id: Annotated[str, Field(alias="sessionId", description="The ID of the session to resume.")] + + class SessionCapabilities(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 @@ -1462,6 +1533,17 @@ 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], + 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 + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # # Whether the agent supports `session/list`. list: Annotated[ Optional[SessionListCapabilities], @@ -1469,6 +1551,17 @@ class SessionCapabilities(BaseModel): 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`." ), ] = 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/resume`. + resume: Annotated[ + Optional[SessionResumeCapabilities], + 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/resume`." + ), + ] = None class SessionMode(BaseModel): @@ -1518,7 +1611,7 @@ class SessionModeState(BaseModel): ] -class CurrentModeUpdate(CurrentModeUpdate): +class CurrentModeUpdate(_CurrentModeUpdate): session_update: Annotated[Literal["current_mode_update"], Field(alias="sessionUpdate")] @@ -1581,6 +1674,25 @@ class AgentCapabilities(BaseModel): ) +class AgentErrorMessage(BaseModel): + error: Error + # JSON RPC Request Id + # + # An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] + # + # The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. + # + # [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. + # + # [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. + id: Annotated[ + Optional[Union[int, str]], + Field( + description="JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." + ), + ] = None + + class AvailableCommand(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 @@ -1608,7 +1720,7 @@ class AvailableCommand(BaseModel): ] -class AvailableCommandsUpdate(BaseModel): +class _AvailableCommandsUpdate(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. @@ -1668,6 +1780,25 @@ class ClientResponseMessage(BaseModel): ] +class ClientErrorMessage(BaseModel): + error: Error + # JSON RPC Request Id + # + # An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] + # + # The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. + # + # [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. + # + # [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. + id: Annotated[ + Optional[Union[int, str]], + Field( + description="JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." + ), + ] = None + + class ClientResponse(RootModel[Union[ClientResponseMessage, ClientErrorMessage]]): root: Union[ClientResponseMessage, ClientErrorMessage] @@ -1705,6 +1836,76 @@ class EmbeddedResource(BaseModel): ] +class ForkSessionRequest(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 working directory for this session. + cwd: Annotated[str, Field(description="The working directory for this session.")] + # List of MCP servers to connect to for this session. + mcp_servers: Annotated[ + Optional[List[Union[HttpMcpServer, SseMcpServer, McpServerStdio]]], + Field( + alias="mcpServers", + description="List of MCP servers to connect to for this session.", + ), + ] = None + # The ID of the session to fork. + session_id: Annotated[str, Field(alias="sessionId", description="The ID of the session to fork.")] + + +class ForkSessionResponse(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 + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # + # Initial model state if supported by the Agent + models: Annotated[ + Optional[SessionModelState], + Field( + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInitial model state if supported by the Agent" + ), + ] = None + # Initial mode state if supported by the Agent + # + # See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) + modes: Annotated[ + Optional[SessionModeState], + Field( + description="Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)" + ), + ] = None + # Unique identifier for the newly created forked session. + session_id: Annotated[ + str, + Field( + alias="sessionId", + description="Unique identifier for the newly created forked session.", + ), + ] + + class InitializeResponse(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 @@ -1891,11 +2092,46 @@ class Plan(BaseModel): ] +class ResumeSessionResponse(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 + # **UNSTABLE** + # + # This capability is not part of the spec yet, and may be removed or changed at any point. + # + # Initial model state if supported by the Agent + models: Annotated[ + Optional[SessionModelState], + Field( + description="**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInitial model state if supported by the Agent" + ), + ] = None + # Initial mode state if supported by the Agent + # + # See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) + modes: Annotated[ + Optional[SessionModeState], + Field( + description="Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)" + ), + ] = None + + class AgentPlanUpdate(Plan): session_update: Annotated[Literal["plan"], Field(alias="sessionUpdate")] -class AvailableCommandsUpdate(AvailableCommandsUpdate): +class AvailableCommandsUpdate(_AvailableCommandsUpdate): session_update: Annotated[Literal["available_commands_update"], Field(alias="sessionUpdate")] @@ -1928,6 +2164,8 @@ class AgentResponseMessage(BaseModel): NewSessionResponse, LoadSessionResponse, ListSessionsResponse, + ForkSessionResponse, + ResumeSessionResponse, SetSessionModeResponse, PromptResponse, SetSessionModelResponse, @@ -2055,6 +2293,8 @@ class ClientRequest(BaseModel): NewSessionRequest, LoadSessionRequest, ListSessionsRequest, + ForkSessionRequest, + ResumeSessionRequest, SetSessionModeRequest, PromptRequest, SetSessionModelRequest, @@ -2290,6 +2530,7 @@ class SessionNotification(BaseModel): AgentPlanUpdate, AvailableCommandsUpdate, CurrentModeUpdate, + SessionInfoUpdate, ], Field(description="The actual update content.", discriminator="session_update"), ] @@ -2322,6 +2563,7 @@ class AgentNotification(BaseModel): SessionUpdate6 = AgentPlanUpdate SessionUpdate7 = AvailableCommandsUpdate SessionUpdate8 = CurrentModeUpdate +SessionUpdate9 = SessionInfoUpdate ToolCallContent1 = ContentToolCallContent ToolCallContent2 = FileEditToolCallContent ToolCallContent3 = TerminalToolCallContent diff --git a/tests/conftest.py b/tests/conftest.py index 72fb232..787abf2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,7 +20,6 @@ RequestError, RequestPermissionResponse, SessionNotification, - SetSessionModelResponse, SetSessionModeResponse, TerminalOutputResponse, WaitForTerminalExitResponse, @@ -42,7 +41,6 @@ HttpMcpServer, ImageContentBlock, Implementation, - ListSessionsResponse, McpServerStdio, PermissionOption, ResourceContentBlock, @@ -246,11 +244,6 @@ async def load_session( ) -> LoadSessionResponse | None: return LoadSessionResponse() - async def list_sessions( - self, cursor: str | None = None, cwd: str | None = None, **kwargs: Any - ) -> ListSessionsResponse: - return ListSessionsResponse(sessions=[], next_cursor=None) - async def authenticate(self, method_id: str, **kwargs: Any) -> AuthenticateResponse | None: return AuthenticateResponse() @@ -275,9 +268,6 @@ async def cancel(self, session_id: str, **kwargs: Any) -> None: async def set_session_mode(self, mode_id: str, session_id: str, **kwargs: Any) -> SetSessionModeResponse | None: return SetSessionModeResponse() - async def set_session_model(self, model_id: str, session_id: str, **kwargs: Any) -> SetSessionModelResponse | None: - return SetSessionModelResponse() - async def ext_method(self, method: str, params: dict) -> dict: self.ext_calls.append((method, params)) if method == "example.com/echo": diff --git a/tests/test_rpc.py b/tests/test_rpc.py index 25b5457..7c11dfb 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -24,7 +24,6 @@ update_agent_message_text, update_tool_call, ) -from acp.exceptions import RequestError from acp.schema import ( AgentMessageChunk, AllowedOutcome, @@ -35,11 +34,9 @@ HttpMcpServer, ImageContentBlock, Implementation, - ListSessionsResponse, McpServerStdio, PermissionOption, ResourceContentBlock, - SetSessionModelResponse, SseMcpServer, TextContentBlock, ToolCallLocation, @@ -73,10 +70,6 @@ async def test_initialize_and_new_session(connect): mode_resp = await agent_conn.set_session_mode(session_id=new_sess.session_id, mode_id="ask") assert isinstance(mode_resp, SetSessionModeResponse) - with pytest.raises(RequestError), pytest.warns(UserWarning) as record: - await agent_conn.set_session_model(session_id=new_sess.session_id, model_id="gpt-4o") - assert len(record) == 1 - @pytest.mark.asyncio async def test_bidirectional_file_ops(client, connect): @@ -191,10 +184,6 @@ async def test_set_session_mode_and_extensions(connect, agent, client): resp = await agent_conn.set_session_mode(session_id="sess", mode_id="yolo") assert isinstance(resp, SetSessionModeResponse) - with pytest.raises(RequestError), pytest.warns(UserWarning) as record: - await agent_conn.set_session_model(session_id="sess", model_id="gpt-4o-mini") - assert len(record) == 1 - # extMethod echo = await agent_conn.ext_method("example.com/echo", {"x": 1}) assert echo == {"echo": {"x": 1}} @@ -432,14 +421,3 @@ async def test_spawn_agent_process_roundtrip(tmp_path): assert test_client.notifications assert process.returncode is not None - - -@pytest.mark.asyncio -async def test_call_unstable_protocol(connect): - _, agent_conn = connect(use_unstable_protocol=True) - - resp = await agent_conn.list_sessions() - assert isinstance(resp, ListSessionsResponse) - - resp = await agent_conn.set_session_model(session_id="sess", model_id="gpt-4o-mini") - assert isinstance(resp, SetSessionModelResponse) diff --git a/tests/test_unstable.py b/tests/test_unstable.py new file mode 100644 index 0000000..afdbb28 --- /dev/null +++ b/tests/test_unstable.py @@ -0,0 +1,75 @@ +from typing import Any + +import pytest + +from acp.exceptions import RequestError +from acp.schema import ( + ForkSessionResponse, + HttpMcpServer, + ListSessionsResponse, + McpServerStdio, + ResumeSessionResponse, + SetSessionModelResponse, + SseMcpServer, +) +from tests.conftest import TestAgent + + +class UnstableAgent(TestAgent): + async def list_sessions(self, cursor: str | None = None, cwd: str | None = None, **kwargs) -> ListSessionsResponse: + return ListSessionsResponse(sessions=[]) + + async def set_session_model(self, model_id: str, session_id: str, **kwargs: Any) -> SetSessionModelResponse | None: + return SetSessionModelResponse() + + async def fork_session( + self, + cwd: str, + session_id: str, + mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio] | None = None, + **kwargs: Any, + ) -> ForkSessionResponse: + return ForkSessionResponse(session_id="forked_sess") + + async def resume_session( + self, + cwd: str, + session_id: str, + mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio] | None = None, + **kwargs: Any, + ) -> ResumeSessionResponse: + return ResumeSessionResponse() + + +@pytest.mark.parametrize("agent", [UnstableAgent()]) +@pytest.mark.asyncio +async def test_call_unstable_protocol(connect): + _, agent_conn = connect(use_unstable_protocol=True) + + resp = await agent_conn.list_sessions() + assert isinstance(resp, ListSessionsResponse) + + resp = await agent_conn.set_session_model(session_id="sess", model_id="gpt-4o-mini") + assert isinstance(resp, SetSessionModelResponse) + + resp = await agent_conn.fork_session(cwd="/workspace", session_id="sess") + assert isinstance(resp, ForkSessionResponse) + + resp = await agent_conn.resume_session(cwd="/workspace", session_id="sess") + assert isinstance(resp, ResumeSessionResponse) + + +@pytest.mark.parametrize("agent", [UnstableAgent()]) +@pytest.mark.asyncio +async def test_call_unstable_protocol_warning(connect): + _, agent_conn = connect(use_unstable_protocol=False) + + with pytest.warns(UserWarning) as record: + with pytest.raises(RequestError): + await agent_conn.list_sessions() + 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") + assert len(record) == 1