assistant/tests/test_conversation_controls.py

43 lines
2.0 KiB
Python

"""Conversation control never revises a goal or starts a model/browser call."""
import copy
from unittest.mock import AsyncMock
import pytest
from backend.prospecting import orchestrator as module
@pytest.fixture
def engine(monkeypatch, tmp_path):
row = {"id": "control", "knowledge_id": "xiaohongshu_prospecting", "status": "running", "current_step": "search_read",
"inputs": {"goal": "寻找装修需求", "_goal_version": 1}, "artifacts": {"sources": [{"source_id": "n", "source_type": "note"}]}, "pause_reason": None}
def update(tid, **fields):
row.update(copy.deepcopy(fields))
return copy.deepcopy(row)
monkeypatch.setattr(module.db, "get_task", lambda tid: copy.deepcopy(row))
monkeypatch.setattr(module.db, "update_task", update)
monkeypatch.setattr(module, "task_doc_dir", lambda tid: tmp_path)
monkeypatch.setattr(module, "append_progress", lambda *args, **kwargs: None)
monkeypatch.setattr(module.runner, "close_live_session", AsyncMock())
monkeypatch.setattr(module, "interpret_message", AsyncMock(side_effect=AssertionError("control must not call model")))
return module.ProspectingOrchestrator(), row
async def test_status_does_not_interrupt_running_goal(engine, monkeypatch):
subject, row = engine
interrupt = AsyncMock(side_effect=AssertionError("status must not interrupt"))
monkeypatch.setattr(subject, "_interrupt_for_revision", interrupt)
result = await subject.message("control", "进度怎么样?")
assert result["status"] == "running"
assert result["inputs"] == {"goal": "寻找装修需求", "_goal_version": 1}
assert "1篇笔记" in result["artifacts"]["messages"][-1]["text"]
async def test_natural_stop_preserves_goal_and_sources(engine):
subject, row = engine
result = await subject.message("control", "先停一下")
assert result["status"] == "cancelled"
assert result["inputs"]["goal"] == "寻找装修需求"
assert result["artifacts"]["sources"][0]["source_id"] == "n"
assert result["artifacts"]["stop_reason"] == "user_stopped"