refactor: route file edit progress via channel capability
This commit is contained in:
@@ -283,7 +283,7 @@ class TestToolEventProgress:
|
||||
assert finish["result"] == "file.txt"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bus_progress_forwards_file_edit_events_for_websocket_only(self, tmp_path: Path) -> None:
|
||||
async def test_bus_progress_forwards_file_edit_events_without_channel_branch(self, tmp_path: Path) -> None:
|
||||
bus = MessageBus()
|
||||
provider = MagicMock()
|
||||
provider.get_default_model.return_value = "test-model"
|
||||
@@ -299,27 +299,18 @@ class TestToolEventProgress:
|
||||
"status": "editing",
|
||||
}]
|
||||
|
||||
websocket_progress = await loop._build_bus_progress_callback(InboundMessage(
|
||||
channel="websocket",
|
||||
progress = await loop._build_bus_progress_callback(InboundMessage(
|
||||
channel="telegram",
|
||||
sender_id="u1",
|
||||
chat_id="chat1",
|
||||
content="edit",
|
||||
))
|
||||
assert on_progress_accepts_file_edit_events(websocket_progress) is True
|
||||
await websocket_progress("", file_edit_events=edit_events)
|
||||
assert on_progress_accepts_file_edit_events(progress) is True
|
||||
await invoke_file_edit_progress(progress, edit_events)
|
||||
outbound = await bus.consume_outbound()
|
||||
assert outbound.channel == "telegram"
|
||||
assert outbound.metadata["_file_edit_events"] == edit_events
|
||||
|
||||
telegram_progress = await loop._build_bus_progress_callback(InboundMessage(
|
||||
channel="telegram",
|
||||
sender_id="u1",
|
||||
chat_id="chat2",
|
||||
content="edit",
|
||||
))
|
||||
assert on_progress_accepts_file_edit_events(telegram_progress) is False
|
||||
await invoke_file_edit_progress(telegram_progress, edit_events)
|
||||
assert bus.outbound_size == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_goal_turn_keeps_live_file_edit_progress_for_webui(self, tmp_path: Path) -> None:
|
||||
"""The /goal command rewrites the prompt but must not bypass WebUI file-edit progress."""
|
||||
|
||||
@@ -37,6 +37,7 @@ class _MockChannel(BaseChannel):
|
||||
self._send_mock = AsyncMock()
|
||||
self._delta_mock = AsyncMock()
|
||||
self._end_mock = AsyncMock()
|
||||
self._file_edit_mock = AsyncMock()
|
||||
|
||||
async def start(self): # pragma: no cover - not exercised
|
||||
pass
|
||||
@@ -53,6 +54,9 @@ class _MockChannel(BaseChannel):
|
||||
async def send_reasoning_end(self, chat_id, metadata=None):
|
||||
return await self._end_mock(chat_id, metadata)
|
||||
|
||||
async def send_file_edit_events(self, chat_id, edits, metadata=None):
|
||||
return await self._file_edit_mock(chat_id, edits, metadata)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def manager() -> ChannelManager:
|
||||
@@ -195,6 +199,44 @@ async def test_base_channel_reasoning_primitives_are_noop_safe():
|
||||
) is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_file_edit_events_route_to_channel_capability(manager):
|
||||
channel = manager.channels["mock"]
|
||||
edits = [{"version": 1, "phase": "start", "path": "src/app.py"}]
|
||||
msg = OutboundMessage(
|
||||
channel="mock",
|
||||
chat_id="c1",
|
||||
content="",
|
||||
metadata={"_progress": True, "_file_edit_events": edits},
|
||||
)
|
||||
|
||||
await manager._send_once(channel, msg)
|
||||
|
||||
channel._file_edit_mock.assert_awaited_once_with(
|
||||
"c1", edits, {"_progress": True, "_file_edit_events": edits}
|
||||
)
|
||||
channel._send_mock.assert_not_awaited()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_base_channel_file_edit_events_are_noop_safe():
|
||||
class _Plain(BaseChannel):
|
||||
name = "plain"
|
||||
display_name = "Plain"
|
||||
|
||||
async def start(self): # pragma: no cover
|
||||
pass
|
||||
|
||||
async def stop(self): # pragma: no cover
|
||||
pass
|
||||
|
||||
async def send(self, msg): # pragma: no cover
|
||||
raise AssertionError("file edit events should not call send")
|
||||
|
||||
channel = _Plain({}, MessageBus())
|
||||
assert await channel.send_file_edit_events("c", [{"path": "a.py"}]) is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reasoning_routing_does_not_consult_send_progress(manager):
|
||||
"""`show_reasoning` is orthogonal to `send_progress` — turning off
|
||||
|
||||
Reference in New Issue
Block a user