diff --git a/wwwroot/api/cockpit_chat.dspy b/wwwroot/api/cockpit_chat.dspy index 6932fbe..9a0cc69 100644 --- a/wwwroot/api/cockpit_chat.dspy +++ b/wwwroot/api/cockpit_chat.dspy @@ -73,25 +73,10 @@ def _guess_role(title): return 'develop' async def _find_project(sor, name): - """Match project by name. Exact first, then substring. Returns (record, match_type).""" + """Exact match only — LLM has full project list in env and should pick exact name.""" if not name: return None - # Exact match recs = await sor.sqlExe("SELECT id,name FROM sd_projects WHERE name=${n}$",{"n":name}) - if recs: return recs[0] - # Substring match — find projects containing the keyword - kw = name.strip() - if len(kw) < 2: return None - allp = await sor.sqlExe("SELECT id,name FROM sd_projects ORDER BY created_at DESC",{}) - matches = [] - for r in (allp or []): - rn = (getattr(r,'name','') or '') - if kw in rn: - matches.append(r) - if len(matches) == 1: - return matches[0] - if len(matches) > 1: - return None # Ambiguous — caller should report options - return None + return recs[0] if recs else None async def _load_ctx(sor, uid): recs = await sor.sqlExe("SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$",{"u":uid}) @@ -221,14 +206,8 @@ async def _exec_tool(sor, tool, params, ctx, uid, org_id): return '可用项目:\n'+'\n'.join(lines) proj = await _find_project(sor, name) if not proj: - # Check if ambiguous (multiple substring matches) - kw = name.strip() - allp2 = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC",{}) - matches = [getattr(r,'name','') for r in (allp2 or []) if kw in (getattr(r,'name','') or '')] - if len(matches) > 1: - return 'FAIL: 多个匹配:\n'+'\n'.join(matches) - allp3 = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 15",{}) - return 'FAIL: 未找到。可用: '+', '.join([getattr(r,'name','') for r in (allp3 or [])]) + allp = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 15",{}) + return 'FAIL: 未找到。可用: '+', '.join([getattr(r,'name','') for r in (allp or [])]) if proj.id == ctx['pid']: return f'已在「{proj.name}」项目中,无需切换' await _save_ctx(sor, uid, proj.id) @@ -466,7 +445,10 @@ if action == 'send_message': return repos_str = ', '.join([r['n'] for r in ctx['repos']]) or '无' - env_text = f"【当前项目: {ctx['pname'] or '未选择'}】— 所有操作在当前项目内完成\n工作空间: {ctx['ws'] or '未设置'} | 仓库: {repos_str}" + # Load all project names so LLM can match user's input + all_projects = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 20",{}) + proj_list = ', '.join([getattr(p,'name','') for p in (all_projects or [])]) + env_text = f"【当前项目: {ctx['pname'] or '未选择'}】\n所有项目: {proj_list}\n工作空间: {ctx['ws'] or '未设置'} | 仓库: {repos_str}" system = AGENT_PROMPT.replace('__TOOLS__',TOOLS_TEXT).replace('__ENV__',env_text) msgs = [{"role":"system","content":system}] for h in (await sor.sqlExe("SELECT role,content FROM pipeline_conversations WHERE created_by=${u}$ ORDER BY created_at ASC LIMIT 20",{"u":uid}) or []):