from __future__ import annotations from .shared import * class LLMTaskHelpersMixin: async def generate_task_breakdown_async(self, description: str, **kwargs: Any) -> list[dict]: if not description.strip(): return [] prompt = ( "请将以下需求拆解为 5-8 条执行任务,返回 JSON 数组," "每项格式: {\"task_name\":\"\",\"type\":\"backend|frontend|database|ai|devops\"," "\"estimated_hours\":4,\"priority\":\"high|medium|low\"}。\n" f"需求:{description[:1200]}" ) text = await self.generate(prompt, function_name="generate_task_breakdown", **kwargs) rows = self._parse_json_array(text) if rows: return rows return [ { "task_name": "需求分析", "type": "ai", "priority": "medium", "estimated_hours": 4, "description": description[:200], } ] async def get_embedding_async(self, text: str, **kwargs: Any) -> list[float]: db = kwargs.get("db") or kwargs.get("db_session") tenant_id = int(kwargs.get("tenant_id") or 1) if db is None: async with AsyncSessionLocal() as session: return await self.get_embedding_async(text, db=session, tenant_id=tenant_id) try: engine = await self._resolve_active_engine(db, tenant_id=tenant_id) provider = str(engine.get("provider") or "") if provider == "openai": endpoint = f"{str(engine.get('base_url') or '').rstrip('/')}/embeddings" headers = { "Authorization": f"Bearer {str(engine.get('api_key') or '').strip()}", "Content-Type": "application/json", } payload = { "model": str(engine.get("model") or "text-embedding-3-small"), "input": text, } async with httpx.AsyncClient(timeout=self.request_timeout, trust_env=False) as client: resp = await client.post(endpoint, headers=headers, json=payload) resp.raise_for_status() data = resp.json() return list(data.get("data", [{}])[0].get("embedding") or []) except Exception: pass # DeepSeek/GLM 及失败场景:回退伪向量,保持功能可用。 seed = hashlib.md5(text.encode("utf-8")).digest() return [((seed[i % 16] / 255.0) * 2 - 1) for i in range(64)] async def extract_context_insights_async(self, text: str, **kwargs: Any) -> dict: prompt = ( "请提炼以下技术文档上下文的关键结论,返回 JSON:" "{\"summary\":\"\",\"keywords\":[\"\",\"\"],\"risks\":[\"\",\"\"]}\n" f"上下文:{text[:2000]}" ) raw = await self.generate(prompt, function_name="extract_context_insights", **kwargs) parsed = self._parse_json_object(raw) if parsed: return parsed return {"summary": text[:120], "keywords": []} async def find_relevant_context(self, **_: Any) -> list[dict]: return [] async def evaluate_with_voting_async(self, signal_content: str, impact_score: float, **_: Any) -> dict: is_strategic = impact_score >= 0.8 return { "is_strategic": is_strategic, "confidence": min(1.0, max(0.2, impact_score)), "decision_proposal": { "summary": signal_content[:120], "action": "follow_up" if is_strategic else "observe", }, "tasks": [], "_voting": { "enabled": False, "models_used": [], "strategic_votes": 0, "total_votes": 0, "unanimous": True, }, } async def audit_code_change_async( self, task_name: str, commit_message: str, code_diff: str, **_: Any, ) -> dict: passed = bool(task_name and commit_message and code_diff is not None) return { "passed": passed, "reason": "basic_stub_check_passed" if passed else "invalid_input", }