fix(acp): use modes for edit auto-approval
This commit is contained in:
@@ -24,6 +24,7 @@ from acp.schema import (
|
||||
PromptResponse,
|
||||
ResumeSessionResponse,
|
||||
SessionModelState,
|
||||
SessionModeState,
|
||||
SetSessionConfigOptionResponse,
|
||||
SetSessionModelResponse,
|
||||
SetSessionModeResponse,
|
||||
@@ -52,31 +53,34 @@ def agent(mock_manager):
|
||||
"""HermesACPAgent backed by a mock session manager."""
|
||||
return HermesACPAgent(session_manager=mock_manager)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_new_session_includes_edit_approval_config_option(self, agent):
|
||||
resp = await agent.new_session(cwd="/tmp")
|
||||
|
||||
assert resp.config_options
|
||||
option = resp.config_options[0]
|
||||
assert option.id == "edit_approval_policy"
|
||||
assert option.current_value == "ask"
|
||||
assert {choice.value for choice in option.options} == {
|
||||
"ask",
|
||||
"workspace_session",
|
||||
"session",
|
||||
}
|
||||
@pytest.mark.asyncio
|
||||
async def test_new_session_exposes_edit_approvals_as_modes_not_config_options(agent):
|
||||
resp = await agent.new_session(cwd="/tmp")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_set_config_option_persists_edit_approval_policy(self, agent):
|
||||
resp = await agent.new_session(cwd="/tmp")
|
||||
update = await agent.set_config_option(
|
||||
"edit_approval_policy",
|
||||
resp.session_id,
|
||||
"workspace_session",
|
||||
)
|
||||
assert resp.config_options is None
|
||||
assert isinstance(resp.modes, SessionModeState)
|
||||
assert resp.modes.current_mode_id == "default"
|
||||
assert [(mode.id, mode.name) for mode in resp.modes.available_modes] == [
|
||||
("default", "Default"),
|
||||
("accept_edits", "Accept Edits"),
|
||||
("dont_ask", "Don't Ask"),
|
||||
]
|
||||
|
||||
assert isinstance(update, SetSessionConfigOptionResponse)
|
||||
assert update.config_options[0].current_value == "workspace_session"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_set_config_option_persists_edit_approval_policy_without_advertising_config(agent):
|
||||
resp = await agent.new_session(cwd="/tmp")
|
||||
update = await agent.set_config_option(
|
||||
"edit_approval_policy",
|
||||
resp.session_id,
|
||||
"workspace_session",
|
||||
)
|
||||
state = agent.session_manager.get_session(resp.session_id)
|
||||
|
||||
assert isinstance(update, SetSessionConfigOptionResponse)
|
||||
assert update.config_options == []
|
||||
assert getattr(state, "mode", None) == "accept_edits"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -891,11 +895,11 @@ class TestSessionConfiguration:
|
||||
@pytest.mark.asyncio
|
||||
async def test_set_session_mode_returns_response(self, agent):
|
||||
new_resp = await agent.new_session(cwd="/tmp")
|
||||
resp = await agent.set_session_mode(mode_id="chat", session_id=new_resp.session_id)
|
||||
resp = await agent.set_session_mode(mode_id="accept_edits", session_id=new_resp.session_id)
|
||||
state = agent.session_manager.get_session(new_resp.session_id)
|
||||
|
||||
assert isinstance(resp, SetSessionModeResponse)
|
||||
assert getattr(state, "mode", None) == "chat"
|
||||
assert getattr(state, "mode", None) == "accept_edits"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_router_accepts_stable_session_config_methods(self, agent):
|
||||
@@ -904,7 +908,7 @@ class TestSessionConfiguration:
|
||||
|
||||
mode_result = await router(
|
||||
"session/set_mode",
|
||||
{"modeId": "chat", "sessionId": new_resp.session_id},
|
||||
{"modeId": "accept_edits", "sessionId": new_resp.session_id},
|
||||
False,
|
||||
)
|
||||
config_result = await router(
|
||||
@@ -918,8 +922,7 @@ class TestSessionConfiguration:
|
||||
)
|
||||
|
||||
assert mode_result == {}
|
||||
assert config_result["configOptions"]
|
||||
assert config_result["configOptions"][0]["id"] == "edit_approval_policy"
|
||||
assert config_result["configOptions"] == []
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_router_accepts_unstable_model_switch_when_enabled(self, agent):
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from acp_adapter.edit_approval import EditProposal
|
||||
from acp_adapter.tools import (
|
||||
TOOL_KIND_MAP,
|
||||
build_tool_complete,
|
||||
@@ -174,6 +175,25 @@ class TestBuildToolStart:
|
||||
assert "Approval prompt shows the diff" in item.content.text
|
||||
assert "new_file.py" in item.content.text
|
||||
|
||||
def test_auto_approved_edit_start_shows_diff_content(self):
|
||||
"""Auto-approved edit starts need the diff because no approval card exists."""
|
||||
args = {"path": "/tmp/acp.txt", "old_string": "old", "new_string": "new"}
|
||||
result = build_tool_start(
|
||||
"tc-auto-edit",
|
||||
"patch",
|
||||
args,
|
||||
edit_diff=EditProposal("patch", "/tmp/acp.txt", "old\n", "new\n", args),
|
||||
)
|
||||
|
||||
assert isinstance(result, ToolCallStart)
|
||||
assert result.kind == "edit"
|
||||
assert len(result.content) == 1
|
||||
item = result.content[0]
|
||||
assert isinstance(item, FileEditToolCallContent)
|
||||
assert item.path == "/tmp/acp.txt"
|
||||
assert item.old_text == "old\n"
|
||||
assert item.new_text == "new\n"
|
||||
|
||||
def test_build_tool_start_for_terminal(self):
|
||||
"""terminal should produce text content with the command."""
|
||||
args = {"command": "ls -la /tmp"}
|
||||
|
||||
Reference in New Issue
Block a user