From 4f50af0317ca51190b045a861df18d6064cacb62 Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Fri, 9 Oct 2026 17:09:56 +0800 Subject: [PATCH] chore: migrate to bub's tool exposure option bub replaced `preserve=` and `agent_use=` with a single `exposure` option (bubbuild/bub#347). Switch bub-acp-server client tools to `exposure="direct"` and bub-qq ops commands to `exposure="command"`, and bump the locked bub revision. Co-Authored-By: Claude Opus 5.5 --- .../src/bub_acp_server/client_tools.py | 12 ++++++------ packages/bub-acp-server/tests/test_client_tools.py | 2 +- packages/bub-acp-server/tests/test_subagents.py | 2 +- packages/bub-qq/README.md | 2 +- packages/bub-qq/README.zh-CN.md | 2 +- packages/bub-qq/src/bub_qq/tools.py | 4 ++-- packages/bub-qq/tests/test_ops_commands.py | 4 ++-- uv.lock | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/bub-acp-server/src/bub_acp_server/client_tools.py b/packages/bub-acp-server/src/bub_acp_server/client_tools.py index 2f5a003..7112e50 100644 --- a/packages/bub-acp-server/src/bub_acp_server/client_tools.py +++ b/packages/bub-acp-server/src/bub_acp_server/client_tools.py @@ -242,7 +242,7 @@ def _require_terminal_client(self) -> Client: def build_client_tools(runtime: ACPClientToolRuntime) -> dict[str, Tool]: """Build supported client tools, leaving unsupported tools on the agent intact.""" - @partial(Tool.from_callable, name="bash", context=True, preserve=True) + @partial(Tool.from_callable, name="bash", context=True, exposure="direct") async def bash( command: str, cwd: str | None = None, @@ -254,7 +254,7 @@ async def bash( """Run a shell command through the ACP client terminal.""" return await runtime.bash(command, cwd, timeout_seconds, background, context) - @partial(Tool.from_callable, name="bash.output", context=True, preserve=True) + @partial(Tool.from_callable, name="bash.output", context=True, exposure="direct") async def bash_output( shell_id: str, offset: int = 0, @@ -265,12 +265,12 @@ async def bash_output( """Read buffered output from an ACP client terminal.""" return await runtime.bash_output(shell_id, offset, limit, context) - @partial(Tool.from_callable, name="bash.kill", context=True, preserve=True) + @partial(Tool.from_callable, name="bash.kill", context=True, exposure="direct") async def kill_bash(shell_id: str, *, context: ToolContext) -> str: """Terminate an ACP client terminal process.""" return await runtime.kill_bash(shell_id, context) - @partial(Tool.from_callable, name="fs.read", context=True, preserve=True) + @partial(Tool.from_callable, name="fs.read", context=True, exposure="direct") async def fs_read( path: str, offset: int = 0, @@ -281,7 +281,7 @@ async def fs_read( """Read a text file through the ACP client filesystem.""" return await runtime.read_file(path, offset, limit, context) - @partial(Tool.from_callable, name="fs.write", context=True, preserve=True) + @partial(Tool.from_callable, name="fs.write", context=True, exposure="direct") async def fs_write( path: str, content: str, @@ -291,7 +291,7 @@ async def fs_write( """Write a text file through the ACP client filesystem.""" return await runtime.write_file(path, content, context) - @partial(Tool.from_callable, name="fs.edit", context=True, preserve=True) + @partial(Tool.from_callable, name="fs.edit", context=True, exposure="direct") async def fs_edit( path: str, old: str, diff --git a/packages/bub-acp-server/tests/test_client_tools.py b/packages/bub-acp-server/tests/test_client_tools.py index 929edab..25548cf 100644 --- a/packages/bub-acp-server/tests/test_client_tools.py +++ b/packages/bub-acp-server/tests/test_client_tools.py @@ -399,7 +399,7 @@ async def test_initialize_selects_client_tools_by_capability( }.items(): assert (selected[name] is not originals[name]) == client_backed, name # Client-backed overrides stay model-facing in code mode like the builtins. - assert selected[name].preserve == originals[name].preserve, name + assert selected[name].exposure == originals[name].exposure, name assert REGISTRY == originals diff --git a/packages/bub-acp-server/tests/test_subagents.py b/packages/bub-acp-server/tests/test_subagents.py index 1e1f264..5d61756 100644 --- a/packages/bub-acp-server/tests/test_subagents.py +++ b/packages/bub-acp-server/tests/test_subagents.py @@ -411,7 +411,7 @@ async def test_negotiated_session_replaces_only_this_session_tool() -> None: assert installed.description == REGISTRY["subagent"].description assert installed.parameters == REGISTRY["subagent"].parameters assert installed.renderer is REGISTRY["subagent"].renderer - assert installed.preserve == REGISTRY["subagent"].preserve + assert installed.exposure == REGISTRY["subagent"].exposure assert installed.output_schema == REGISTRY["subagent"].output_schema assert installed.handler is not REGISTRY["subagent"].handler assert REGISTRY["subagent"].handler is not installed.handler diff --git a/packages/bub-qq/README.md b/packages/bub-qq/README.md index 8b751a0..a97ded8 100644 --- a/packages/bub-qq/README.md +++ b/packages/bub-qq/README.md @@ -221,7 +221,7 @@ Note: with no configuration, comma commands are unusable in C2C (fail-closed). S ### Ops comma commands -The plugin ships model-invisible comma commands (registered with `agent_use=False`) for authorized senders: +The plugin ships model-invisible comma commands (registered with `exposure="command"`) for authorized senders: | Command | Description | | --- | --- | diff --git a/packages/bub-qq/README.zh-CN.md b/packages/bub-qq/README.zh-CN.md index bb71490..12f17a4 100644 --- a/packages/bub-qq/README.zh-CN.md +++ b/packages/bub-qq/README.zh-CN.md @@ -221,7 +221,7 @@ export BUB_QQ_RECEIVE_MODE=websocket ### 运维逗号命令 -插件内置了对模型不可见(`agent_use=False`)、仅授权发送者可用的逗号命令: +插件内置了对模型不可见(`exposure="command"`)、仅授权发送者可用的逗号命令: | 命令 | 说明 | | --- | --- | diff --git a/packages/bub-qq/src/bub_qq/tools.py b/packages/bub-qq/src/bub_qq/tools.py index 4ea1a87..ca6b2cf 100644 --- a/packages/bub-qq/src/bub_qq/tools.py +++ b/packages/bub-qq/src/bub_qq/tools.py @@ -7,7 +7,7 @@ ``msg_id``/``msg_seq`` targeting, dedupe and the active-message fallback all behave exactly as in direct mode. -Tools registered with ``agent_use=False`` are ops comma commands: they +Tools registered with ``exposure="command"`` are ops comma commands: they never appear in the model's tool list and can only be run as ``,name`` by senders who pass the comma-command gate (group owners/admins or ``admin_users``). @@ -101,7 +101,7 @@ async def qq_send(content: str, *, context: ToolContext) -> QQSendResult: return {"status": "sent"} -@tool(name="qq.version", agent_use=False) +@tool(name="qq.version", exposure="command") def qq_version() -> str: """Show the installed bub-qq plugin version (ops comma command).""" diff --git a/packages/bub-qq/tests/test_ops_commands.py b/packages/bub-qq/tests/test_ops_commands.py index 5210a7c..83a2921 100644 --- a/packages/bub-qq/tests/test_ops_commands.py +++ b/packages/bub-qq/tests/test_ops_commands.py @@ -10,8 +10,8 @@ def test_qq_version_is_registered_as_command_only() -> None: tool = REGISTRY["qq.version"] - assert tool.agent_use is False - assert REGISTRY["qq.send"].agent_use is True + assert tool.exposure == "command" + assert REGISTRY["qq.send"].exposure == "auto" def test_qq_version_reports_package_version() -> None: diff --git a/uv.lock b/uv.lock index 3399e09..e59940a 100644 --- a/uv.lock +++ b/uv.lock @@ -371,8 +371,8 @@ wheels = [ [[package]] name = "bub" -version = "0.5.1.dev11+gb4a61bf13" -source = { git = "https://github.com/bubbuild/bub.git#b4a61bf1326729a024161d22ba20019b8500f907" } +version = "0.5.1.dev15+g085dcd9ab" +source = { git = "https://github.com/bubbuild/bub.git#085dcd9ab558cc05c9ccda9bb264c9e643552cb6" } dependencies = [ { name = "aiohttp" }, { name = "any-llm-sdk" },