From d4d59aa97e120c7a234d988b89c05937e5515147 Mon Sep 17 00:00:00 2001 From: ymq Date: Sun, 9 Aug 2026 23:06:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=5Ffind=5Fproject=20substring=20matching?= =?UTF-8?q?=20=E2=80=94=20=E4=BA=BA=E4=BA=8B=E7=B3=BB=E7=BB=9F=20matches?= =?UTF-8?q?=20=E4=BA=BA=E4=BA=8B=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wwwroot/api/cockpit_chat.dspy | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/wwwroot/api/cockpit_chat.dspy b/wwwroot/api/cockpit_chat.dspy index d29db7f..6932fbe 100644 --- a/wwwroot/api/cockpit_chat.dspy +++ b/wwwroot/api/cockpit_chat.dspy @@ -73,10 +73,25 @@ def _guess_role(title): return 'develop' async def _find_project(sor, name): - """Exact match only — LLM should use list_projects first to discover names.""" + """Match project by name. Exact first, then substring. Returns (record, match_type).""" if not name: return None + # Exact match recs = await sor.sqlExe("SELECT id,name FROM sd_projects WHERE name=${n}$",{"n":name}) - return recs[0] if recs else None + 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 async def _load_ctx(sor, uid): recs = await sor.sqlExe("SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$",{"u":uid}) @@ -206,8 +221,14 @@ 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: - 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 [])]) + # 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 [])]) if proj.id == ctx['pid']: return f'已在「{proj.name}」项目中,无需切换' await _save_ctx(sor, uid, proj.id)