aps-agent/tests/golden/test_assistant.py

135 lines
5.0 KiB
Python
Raw Normal View History

# ============================================================
# 通用助理:拒识不再甩清单;概念题正面回答
# ============================================================
from __future__ import annotations
import pytest
from server.agent_core.assistant import reply as assistant_reply
from server.agent_core.intent import parse_fast, recognize
from server.agent_core.providers import reset_provider
from server.contracts import IntentResult
from server.aps_domain.workflow import handle_intent
from server.state.seed import seed_world
class FakeStore:
def __init__(self):
self.data = seed_world()
self._counters: dict[str, int] = {}
def next_id(self, kind: str) -> int:
self._counters[kind] = self._counters.get(kind, 0) + 1
return self._counters[kind]
def save(self) -> None:
pass
@pytest.fixture(autouse=True)
def _no_llm(monkeypatch):
monkeypatch.delenv("LLM_API_KEY", raising=False)
monkeypatch.delenv("LLM_PROVIDER", raising=False)
reset_provider()
yield
reset_provider()
@pytest.mark.asyncio
async def test_recognize_falls_back_to_assistant():
world = seed_world()
r = await recognize("今天天气怎么样顺便聊聊排产", world)
assert r.intent == "assistant.reply"
assert r.params.get("query")
def test_fast_greeting_and_howto():
world = seed_world()
assert parse_fast("你好", world).intent == "assistant.reply"
assert parse_fast("你能做什么", world).intent == "assistant.reply"
assert parse_fast("现在项目怎么样", world).intent == "assistant.reply"
assert parse_fast("你给我解释什么叫排产", world).intent == "assistant.reply"
assert parse_fast("你会排产吗", world).intent == "assistant.reply"
def test_imperative_schedule_not_assistant_menu():
"""「给我排产」必须直接开排,不能落到助理四选一。"""
world = seed_world()
for phrase in (
"给我排产", "我要你排产", "你给我排产", "开始排产", "排产吧",
"给我模拟排产一下", "帮我排产一下", "模拟排产", "模拟排产一下",
"给我模拟排产", "帮我模拟排产", "试排一版", "试排一下", "模拟排一下",
):
r = parse_fast(phrase, world)
assert r is not None, phrase
assert r.intent in ("flex.schedule", "folder.schedule", "schedule.run"), (
phrase, r.intent
)
def test_simulate_schedule_does_not_hijack_other_intents():
"""「模拟排产」新增快路不得误吞向导/报工/提问句。"""
world = seed_world()
assert parse_fast("带我排一版", world).intent == "schedule.wizard"
assert parse_fast("怎么排产", world).intent == "schedule.wizard"
assert parse_fast("模拟报工", world).intent == "mes.report"
r = parse_fast("帮我看看现在能不能排", world)
assert r is not None and r.intent == "assistant.reply"
assert parse_fast("解析项目文件夹", world).intent == "folder.analyze"
assert parse_fast("帮我分析一下当前项目里面的数据", world).intent == "folder.analyze"
@pytest.mark.asyncio
async def test_what_time_is_it():
world = seed_world()
reply = await assistant_reply(world, "现在几点了")
assert "现在是" in reply.text
assert "排产无关" not in reply.text
assert "帮不上" not in reply.text
@pytest.mark.asyncio
async def test_unknown_handle_gives_project_brief_not_tip_spam():
store = FakeStore()
intent = IntentResult(intent="unknown", params={"query": "随便说说"}, confidence=0.1, source="LLM")
reply = await handle_intent(store, "s1", intent)
assert "置信度不足" not in reply.text
assert "我还没锁定" not in reply.text
assert "排产无关" not in reply.text
assert "你可以任选一句" not in reply.text
@pytest.mark.asyncio
async def test_explain_scheduling_not_inventory_dump():
world = seed_world()
reply = await assistant_reply(world, "你给我解释什么叫排产")
assert "排产是啥" in reply.text or "把这些事提前安排清楚" in reply.text
assert "要排的单子" not in reply.text
assert "你可以任选一句" not in reply.text
assert not reply.blocks
@pytest.mark.asyncio
async def test_can_schedule_not_inventory_dump():
world = seed_world()
reply = await assistant_reply(world, "你会排产吗?")
assert "本职" in reply.text or "会" in reply.text
assert "要排的单子" not in reply.text
assert not reply.blocks
@pytest.mark.asyncio
async def test_assistant_offline_analyze_style():
world = seed_world()
reply = await assistant_reply(world, "分析一下现状")
assert "手头有啥" in reply.text or "我帮你看了看" in reply.text
@pytest.mark.asyncio
async def test_assistant_chitchat_warm_guide():
world = seed_world()
reply = await assistant_reply(world, "今天好累不想干")
assert "置信度不足" not in reply.text
assert "排产" in reply.text or "单子" in reply.text
assert "你可以任选一句" not in reply.text