import unittest from unittest.mock import AsyncMock from app.services.ai_steward import AIStewardService class AIStewardTitleExtractTest(unittest.IsolatedAsyncioTestCase): async def test_extract_title_from_plain_project_create_instruction(self) -> None: title = AIStewardService._extract_project_title_from_instruction("给我新增个项目,openclaw自动化部署。") self.assertEqual(title, "openclaw自动化部署") async def test_extract_title_from_requirement_name_instruction(self) -> None: title = AIStewardService._extract_project_title_from_instruction("给我新增个项目,需求名字为openclaw自动化部署。") self.assertEqual(title, "openclaw自动化部署") async def test_extract_title_from_project_name_instruction(self) -> None: title = AIStewardService._extract_project_title_from_instruction("给我新增个项目,项目名为openclaw自动化部署。") self.assertEqual(title, "openclaw自动化部署") async def test_extract_title_from_correction_sentence(self) -> None: title = AIStewardService._extract_project_title_from_instruction("不是创建信号,是创建项目名为openclaw自动化部署。") self.assertEqual(title, "openclaw自动化部署") async def test_normalize_project_draft_should_not_use_instruction_sentence_as_title(self) -> None: service = AIStewardService(db=None) # type: ignore[arg-type] normalized = await service._normalize_project_creation_draft( draft={ "analysis": {}, "project": { "title": "不是创建信号,是创建项目名为openclaw自动化部署。", "description": "不是创建信号,是创建项目名为openclaw自动化部署。", }, "tasks": [], }, input_text="不是创建信号,是创建项目名为openclaw自动化部署。", creator_id=1, tenant_id=1, ) self.assertEqual(normalized["project"]["title"], "openclaw自动化部署") self.assertEqual(normalized["project"]["description"], "项目:openclaw自动化部署") async def test_project_creation_text_retries_with_glm47_fallback_function(self) -> None: service = AIStewardService(db=None) # type: ignore[arg-type] called_functions: list[str] = [] async def _mock_generate(_: str, **kwargs): fn = str(kwargs.get("function_name") or "") called_functions.append(fn) if len(called_functions) <= 2: return "我暂时无法生成可靠回答(模型服务异常)。请稍后重试。" return '{"project_name":"openclaw自动化部署"}' service.llm.generate = AsyncMock(side_effect=_mock_generate) # type: ignore[method-assign] text = await service._generate_project_creation_text( prompt="生成分析结果", tenant_id=1, function_name="project_from_text_analysis", timeout_seconds=5.0, ) self.assertEqual(text, '{"project_name":"openclaw自动化部署"}') self.assertEqual( called_functions, [ "project_from_text_analysis", "project_from_text_analysis", "project_draft_analysis_glm47_fallback", ], )