Skip to content

Commit e8e6c72

Browse files
authored
feat: update to unstable schema and metadata (#42)
* feat: update to unstable schema and metadata Signed-off-by: Frost Ming <me@frostming.com> * feat: adapt to the 0.7.0 schema Signed-off-by: Frost Ming <me@frostming.com> --------- Signed-off-by: Frost Ming <me@frostming.com>
1 parent 8556f0d commit e8e6c72

File tree

21 files changed

+1913
-1184
lines changed

21 files changed

+1913
-1184
lines changed

examples/agent.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
Implementation,
2929
ResourceContentBlock,
3030
SseMcpServer,
31-
StdioMcpServer,
31+
McpServerStdio,
3232
TextContentBlock,
3333
)
3434

@@ -66,7 +66,7 @@ async def authenticate(self, method_id: str, **kwargs: Any) -> AuthenticateRespo
6666
return AuthenticateResponse()
6767

6868
async def new_session(
69-
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | StdioMcpServer], **kwargs: Any
69+
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio], **kwargs: Any
7070
) -> NewSessionResponse:
7171
logging.info("Received new session request")
7272
session_id = str(self._next_session_id)
@@ -75,7 +75,7 @@ async def new_session(
7575
return NewSessionResponse(session_id=session_id, modes=None)
7676

7777
async def load_session(
78-
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | StdioMcpServer], session_id: str, **kwargs: Any
78+
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio], session_id: str, **kwargs: Any
7979
) -> LoadSessionResponse | None:
8080
logging.info("Received load session request %s", session_id)
8181
self._sessions.add(session_id)

examples/echo_agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
Implementation,
2323
ResourceContentBlock,
2424
SseMcpServer,
25-
StdioMcpServer,
25+
McpServerStdio,
2626
TextContentBlock,
2727
)
2828

@@ -43,7 +43,7 @@ async def initialize(
4343
return InitializeResponse(protocol_version=protocol_version)
4444

4545
async def new_session(
46-
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | StdioMcpServer], **kwargs: Any
46+
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio], **kwargs: Any
4747
) -> NewSessionResponse:
4848
return NewSessionResponse(session_id=uuid4().hex)
4949

schema/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
refs/tags/v0.6.3
1+
refs/tags/v0.7.0

schema/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"authenticate": "authenticate",
44
"initialize": "initialize",
55
"session_cancel": "session/cancel",
6+
"session_list": "session/list",
67
"session_load": "session/load",
78
"session_new": "session/new",
89
"session_prompt": "session/prompt",

schema/schema.json

Lines changed: 1170 additions & 669 deletions
Large diffs are not rendered by default.

scripts/gen_all.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ def resolve_ref(version: str | None) -> str:
109109

110110
def download_schema(repo: str, ref: str) -> None:
111111
SCHEMA_DIR.mkdir(parents=True, exist_ok=True)
112-
schema_url = f"https://raw.githubusercontent.com/{repo}/{ref}/schema/schema.json"
113-
meta_url = f"https://raw.githubusercontent.com/{repo}/{ref}/schema/meta.json"
112+
schema_url = f"https://raw.githubusercontent.com/{repo}/{ref}/schema/schema.unstable.json"
113+
meta_url = f"https://raw.githubusercontent.com/{repo}/{ref}/schema/meta.unstable.json"
114114
try:
115115
schema_data = fetch_json(schema_url)
116116
meta_data = fetch_json(meta_url)

scripts/gen_schema.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
STDIO_TYPE_LITERAL = 'Literal["2#-datamodel-code-generator-#-object-#-special-#"]'
3030
STDIO_TYPE_PATTERN = re.compile(
31-
r"^ type:\s*Literal\[['\"]2#-datamodel-code-generator-#-object-#-special-#['\"]\]"
31+
r"^ type:\s*Literal\[['\"]McpServerStdio['\"]\]"
3232
r"(?:\s*=\s*['\"][^'\"]+['\"])?\s*$",
3333
re.MULTILINE,
3434
)
@@ -40,7 +40,6 @@
4040
"AgentOutgoingMessage2": "AgentResponseMessage",
4141
"AgentOutgoingMessage3": "AgentErrorMessage",
4242
"AgentOutgoingMessage4": "AgentNotificationMessage",
43-
"AvailableCommandInput1": "CommandInputHint",
4443
"ClientOutgoingMessage1": "ClientRequestMessage",
4544
"ClientOutgoingMessage2": "ClientResponseMessage",
4645
"ClientOutgoingMessage3": "ClientErrorMessage",
@@ -52,7 +51,6 @@
5251
"ContentBlock5": "EmbeddedResourceContentBlock",
5352
"McpServer1": "HttpMcpServer",
5453
"McpServer2": "SseMcpServer",
55-
"McpServer3": "StdioMcpServer",
5654
"RequestPermissionOutcome1": "DeniedOutcome",
5755
"RequestPermissionOutcome2": "AllowedOutcome",
5856
"SessionUpdate1": "UserMessageChunk",
@@ -68,6 +66,10 @@
6866
"ToolCallContent3": "TerminalToolCallContent",
6967
}
7068

69+
ALIASES_MAP = {
70+
"StdioMcpServer": "McpServerStdio",
71+
}
72+
7173
ENUM_LITERAL_MAP: dict[str, tuple[str, ...]] = {
7274
"PermissionOptionKind": (
7375
"allow_once",
@@ -87,16 +89,15 @@
8789
("PlanEntry", "priority", "PlanEntryPriority", False),
8890
("PlanEntry", "status", "PlanEntryStatus", False),
8991
("PromptResponse", "stop_reason", "StopReason", False),
90-
("ToolCallProgress", "kind", "ToolKind", True),
91-
("ToolCallProgress", "status", "ToolCallStatus", True),
92-
("ToolCallStart", "kind", "ToolKind", True),
93-
("ToolCallStart", "status", "ToolCallStatus", True),
9492
("ToolCall", "kind", "ToolKind", True),
9593
("ToolCall", "status", "ToolCallStatus", True),
94+
("ToolCallUpdate", "kind", "ToolKind", True),
95+
("ToolCallUpdate", "status", "ToolCallStatus", True),
9696
)
9797

9898
DEFAULT_VALUE_OVERRIDES: tuple[tuple[str, str, str], ...] = (
9999
("AgentCapabilities", "mcp_capabilities", "McpCapabilities()"),
100+
("AgentCapabilities", "session_capabilities", "SessionCapabilities()"),
100101
(
101102
"AgentCapabilities",
102103
"prompt_capabilities",
@@ -222,6 +223,7 @@ def _build_header_block() -> str:
222223

223224
def _build_alias_block() -> str:
224225
alias_lines = [f"{old} = {new}" for old, new in sorted(RENAME_MAP.items())]
226+
alias_lines += [f"{old} = {new}" for old, new in sorted(ALIASES_MAP.items())]
225227
return BACKCOMPAT_MARKER + "\n" + "\n".join(alias_lines) + "\n"
226228

227229

@@ -421,6 +423,7 @@ def _normalize_stdio_model(content: str) -> str:
421423
replacement_line = ' type: Literal["stdio"] = "stdio"'
422424
new_content, count = STDIO_TYPE_PATTERN.subn(replacement_line, content)
423425
if count == 0:
426+
print("Warning: stdio type placeholder not found; no replacements made.", file=sys.stderr)
424427
return content
425428
if count > 1:
426429
print(

src/acp/agent/connection.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
SessionNotification,
2929
TerminalOutputRequest,
3030
TerminalOutputResponse,
31-
ToolCall,
3231
ToolCallProgress,
3332
ToolCallStart,
33+
ToolCallUpdate,
3434
UserMessageChunk,
3535
WaitForTerminalExitRequest,
3636
WaitForTerminalExitResponse,
@@ -56,12 +56,14 @@ def __init__(
5656
input_stream: Any,
5757
output_stream: Any,
5858
listening: bool = True,
59+
*,
60+
use_unstable_protocol: bool = False,
5961
**connection_kwargs: Any,
6062
) -> None:
6163
agent = to_agent(cast(Client, self)) if callable(to_agent) else to_agent
6264
if not isinstance(input_stream, asyncio.StreamWriter) or not isinstance(output_stream, asyncio.StreamReader):
6365
raise TypeError(_AGENT_CONNECTION_ERROR)
64-
handler = build_agent_router(cast(Agent, agent))
66+
handler = build_agent_router(cast(Agent, agent), use_unstable_protocol=use_unstable_protocol)
6567
self._conn = Connection(handler, input_stream, output_stream, listening=listening, **connection_kwargs)
6668
if on_connect := getattr(agent, "on_connect", None):
6769
on_connect(self)
@@ -92,7 +94,7 @@ async def session_update(
9294

9395
@param_model(RequestPermissionRequest)
9496
async def request_permission(
95-
self, options: list[PermissionOption], session_id: str, tool_call: ToolCall, **kwargs: Any
97+
self, options: list[PermissionOption], session_id: str, tool_call: ToolCallUpdate, **kwargs: Any
9698
) -> RequestPermissionResponse:
9799
return await request_model(
98100
self._conn,

src/acp/agent/router.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
AuthenticateRequest,
1111
CancelNotification,
1212
InitializeRequest,
13+
ListSessionsRequest,
1314
LoadSessionRequest,
1415
NewSessionRequest,
1516
PromptRequest,
@@ -21,8 +22,8 @@
2122
__all__ = ["build_agent_router"]
2223

2324

24-
def build_agent_router(agent: Agent) -> MessageRouter:
25-
router = MessageRouter()
25+
def build_agent_router(agent: Agent, use_unstable_protocol: bool = False) -> MessageRouter:
26+
router = MessageRouter(use_unstable_protocol=use_unstable_protocol)
2627

2728
router.route_request(AGENT_METHODS["initialize"], InitializeRequest, agent, "initialize")
2829
router.route_request(AGENT_METHODS["session_new"], NewSessionRequest, agent, "new_session")
@@ -33,6 +34,7 @@ def build_agent_router(agent: Agent) -> MessageRouter:
3334
"load_session",
3435
adapt_result=normalize_result,
3536
)
37+
router.route_request(AGENT_METHODS["session_list"], ListSessionsRequest, agent, "list_sessions", unstable=True)
3638
router.route_request(
3739
AGENT_METHODS["session_set_mode"],
3840
SetSessionModeRequest,
@@ -47,6 +49,7 @@ def build_agent_router(agent: Agent) -> MessageRouter:
4749
agent,
4850
"set_session_model",
4951
adapt_result=normalize_result,
52+
unstable=True,
5053
)
5154
router.route_request(
5255
AGENT_METHODS["authenticate"],

src/acp/client/connection.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
Implementation,
2020
InitializeRequest,
2121
InitializeResponse,
22+
ListSessionsRequest,
23+
ListSessionsResponse,
2224
LoadSessionRequest,
2325
LoadSessionResponse,
26+
McpServerStdio,
2427
NewSessionRequest,
2528
NewSessionResponse,
2629
PromptRequest,
@@ -31,7 +34,6 @@
3134
SetSessionModeRequest,
3235
SetSessionModeResponse,
3336
SseMcpServer,
34-
StdioMcpServer,
3537
TextContentBlock,
3638
)
3739
from ..utils import compatible_class, notify_model, param_model, request_model, request_model_from_dict
@@ -51,12 +53,14 @@ def __init__(
5153
to_client: Callable[[Agent], Client] | Client,
5254
input_stream: Any,
5355
output_stream: Any,
56+
*,
57+
use_unstable_protocol: bool = False,
5458
**connection_kwargs: Any,
5559
) -> None:
5660
if not isinstance(input_stream, asyncio.StreamWriter) or not isinstance(output_stream, asyncio.StreamReader):
5761
raise TypeError(_CLIENT_CONNECTION_ERROR)
5862
client = to_client(cast(Agent, self)) if callable(to_client) else to_client
59-
handler = build_client_router(cast(Client, client))
63+
handler = build_client_router(cast(Client, client), use_unstable_protocol=use_unstable_protocol)
6064
self._conn = Connection(handler, input_stream, output_stream, **connection_kwargs)
6165
if on_connect := getattr(client, "on_connect", None):
6266
on_connect(self)
@@ -83,7 +87,7 @@ async def initialize(
8387

8488
@param_model(NewSessionRequest)
8589
async def new_session(
86-
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | StdioMcpServer], **kwargs: Any
90+
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio], **kwargs: Any
8791
) -> NewSessionResponse:
8892
return await request_model(
8993
self._conn,
@@ -94,7 +98,7 @@ async def new_session(
9498

9599
@param_model(LoadSessionRequest)
96100
async def load_session(
97-
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | StdioMcpServer], session_id: str, **kwargs: Any
101+
self, cwd: str, mcp_servers: list[HttpMcpServer | SseMcpServer | McpServerStdio], session_id: str, **kwargs: Any
98102
) -> LoadSessionResponse:
99103
return await request_model_from_dict(
100104
self._conn,
@@ -103,6 +107,17 @@ async def load_session(
103107
LoadSessionResponse,
104108
)
105109

110+
@param_model(ListSessionsRequest)
111+
async def list_sessions(
112+
self, cursor: str | None = None, cwd: str | None = None, **kwargs: Any
113+
) -> ListSessionsResponse:
114+
return await request_model_from_dict(
115+
self._conn,
116+
AGENT_METHODS["session_list"],
117+
ListSessionsRequest(cursor=cursor, cwd=cwd, field_meta=kwargs or None),
118+
ListSessionsResponse,
119+
)
120+
106121
@param_model(SetSessionModeRequest)
107122
async def set_session_mode(self, mode_id: str, session_id: str, **kwargs: Any) -> SetSessionModeResponse:
108123
return await request_model_from_dict(

0 commit comments

Comments
 (0)