"""个人总结再生成:显式请求(finish 按钮 / 对话指令)必须无视已有总结强制重生成。""" from __future__ import annotations from typing import Any import pytest from fastapi.testclient import TestClient from app.builder_conversation.summary_regen import requests_summary_regen from builder_flow_helpers import active_component, create_builder_session, event, send_message @pytest.mark.parametrize( "text", ["重新生成个人总结", "帮我重新生成一下个人总结", "更新个人总结", "生成个人总结", "再生成一版总结", "换一版个人总结"], ) def test_summary_regen_predicate_matches_requests(text: str) -> None: assert requests_summary_regen(text) @pytest.mark.parametrize( "text", ["我在项目中生成了总结报告", "我的个人总结是:认真负责", "帮忙看看这段经历", "总结一下这个项目怎么写"], ) def test_summary_regen_predicate_rejects_non_requests(text: str) -> None: assert not requests_summary_regen(text) def _counting_generator(agent: Any, calls: dict[str, int]) -> Any: original = agent.profile_summary_generator class _Counting: def generate(self, content: dict[str, Any]) -> str: calls["n"] += 1 return original.generate(content) return _Counting() def test_finish_button_regenerates_existing_summary(client: TestClient, monkeypatch: pytest.MonkeyPatch) -> None: """已有(非 stale)总结时点 finish 按钮也必须重新生成(闸门放行根因修复)。""" calls = {"n": 0} agent = client.app.state.resume_agent monkeypatch.setattr(agent, "profile_summary_generator", _counting_generator(agent, calls)) session_id, body = create_builder_session(client) first = event(client, session_id, body, "select", {"value": "builder_finish"}) assert first.status_code == 200, first.text assert calls["n"] == 1 reply = send_message(client, session_id, "好的") second = event(client, session_id, reply, "select", {"value": "builder_finish"}) assert second.status_code == 200, second.text assert calls["n"] == 2 def test_chat_regen_summary_writes_after_confirm(client: TestClient, monkeypatch: pytest.MonkeyPatch) -> None: """对话"重新生成个人总结":立即生成候选文本,确认后写入简历。""" calls = {"n": 0} agent = client.app.state.resume_agent monkeypatch.setattr(agent, "profile_summary_generator", _counting_generator(agent, calls)) session_id, body = create_builder_session(client) finished = event(client, session_id, body, "select", {"value": "builder_finish"}) assert finished.status_code == 200, finished.text assert calls["n"] == 1 reply = send_message(client, session_id, "重新生成个人总结") assert calls["n"] == 2 assert "个人总结" in reply["turn"]["content"] card = active_component(reply) assert card["data"]["module"] == "builder_summary_apply" applied = event(client, session_id, reply, "select", {"value": "apply"}) assert applied.status_code == 200, applied.text summary = applied.json()["resume"]["content"]["profile_summary"] first_summary = finished.json()["resume"]["content"]["profile_summary"]["content"] assert summary["content"] == first_summary # rule 生成器确定性输出,内容一致但确实重新生成过 assert summary["stale"] is False assert calls["n"] == 2 # 确认写入复用候选文本,不重复调用生成器 def test_chat_regen_summary_dismiss_keeps_current(client: TestClient) -> None: session_id, body = create_builder_session(client) finished = event(client, session_id, body, "select", {"value": "builder_finish"}) assert finished.status_code == 200, finished.text reply = send_message(client, session_id, "重新生成个人总结") dismissed = event(client, session_id, reply, "select", {"value": "dismiss"}) assert dismissed.status_code == 200, dismissed.text summary = dismissed.json()["resume"]["content"]["profile_summary"] assert summary["content"] == finished.json()["resume"]["content"]["profile_summary"]["content"]