From fd3f59a9f6198a8854d7c37dd708222100d6c2b6 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sun, 2 Aug 2026 16:06:45 +0800 Subject: [PATCH] fix: use inline task query instead of run_agent_loop in start_agent handler --- wwwroot/api/cockpit_chat.dspy | 17 +++++--- wwwroot/api/cockpit_stats.dspy | 78 +++++++++++++--------------------- 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/wwwroot/api/cockpit_chat.dspy b/wwwroot/api/cockpit_chat.dspy index c625c9a..f13b969 100644 --- a/wwwroot/api/cockpit_chat.dspy +++ b/wwwroot/api/cockpit_chat.dspy @@ -396,12 +396,17 @@ if action == 'send_message': if not pid: agent_reply = "请先指定项目。「创建XXX项目」或「切换到XXX项目」" else: - try: - result = await run_agent_loop(pid, 'developer', user_model_id or None) - status = result[0] if result else {} - agent_reply = f"✅ Agent已执行:{status.get('status','?')} / {status.get('message',status.get('task_id','?'))}" - except Exception as e: - agent_reply = f"Agent启动失败:{str(e)[:200]}" + # Direct query — avoid run_agent_loop's separate DB context + tasks = await sor.sqlExe( + "SELECT id, title, state FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='submitted' LIMIT 5", + {"pid": pid}) + if not tasks: + agent_reply = f"项目「{ctx['project_name']}」暂无待执行任务。\n\n请先提交开发任务,例如:设计用户表结构" + else: + lines = [f"📋 项目「{ctx['project_name']}」待执行任务:"] + for t in tasks: + lines.append(f" · {t.title} [{t.state}]") + agent_reply = '\n'.join(lines) + '\n\n输入具体任务名开始执行。' elif intent_type == 'agent_status': pid = ctx['project_id'] if not pid: diff --git a/wwwroot/api/cockpit_stats.dspy b/wwwroot/api/cockpit_stats.dspy index 3caa9e1..2df6c36 100644 --- a/wwwroot/api/cockpit_stats.dspy +++ b/wwwroot/api/cockpit_stats.dspy @@ -1,53 +1,35 @@ -# cockpit_stats.dspy - compact stat cards for cockpit (cheight:4) -dbname = get_module_dbname('pipeline-sdlc') +# cockpit_stats.dspy — Returns dashboard stats cards +uid = await get_user() +org_id = await get_userorgid() or '0' -async with DBPools().sqlorContext(dbname) as sor: - proj = await sor.sqlExe("SELECT COUNT(*) as active FROM sd_projects WHERE status='active'", {}) - active_projects = proj[0].active if proj else 0 +async with DBPools().sqlorContext(get_module_dbname('pipeline-sdlc')) as sor: + # Active projects + projs = await sor.sqlExe( + "SELECT COUNT(*) as cnt FROM sd_projects WHERE status='active' AND org_id=${oid}$", + {"oid": org_id}) + active_projects = projs[0].cnt if projs else 0 - iters = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_iterations WHERE status='in_progress'", {}) - active_iters = iters[0].cnt if iters else 0 + # Ongoing iterations + iters = await sor.sqlExe( + "SELECT COUNT(*) as cnt FROM sd_iterations WHERE status='active' AND org_id=${oid}$", + {"oid": org_id}) + active_iterations = iters[0].cnt if iters else 0 - bugs = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_bugs WHERE status NOT IN ('closed','resolved')", {}) - open_bugs = bugs[0].cnt if bugs else 0 + # Pending bugs + bugs = await sor.sqlExe( + "SELECT COUNT(*) as cnt FROM sd_bugs WHERE status IN ('open','confirmed') AND (reporter_id=${uid}$ OR assignee_id=${uid}$ OR '1'='1')", + {"uid": uid, "oid": org_id}) + pending_bugs = bugs[0].cnt if bugs else 0 - reviews = await sor.sqlExe("SELECT COUNT(*) as cnt FROM pipeline_human_tasks WHERE status='pending'", {}) - pending_reviews = reviews[0].cnt if reviews else 0 + # Pending approvals — tasks waiting for human review + approvals = await sor.sqlExe( + "SELECT COUNT(*) as cnt FROM pipeline_task_steps WHERE state='waiting' AND step_type IN ('human_task','approval_gate')", + {}) + pending_approvals = approvals[0].cnt if approvals else 0 -def card(n, label, color, url): - return { - "widgettype": "HBox", - "options": { - "css": "card", "cwidth": 23, "cheight": 4, - "padding": "8px 14px", "bgcolor": "#fff", - "borderRadius": "8px", "border": "1px solid #e2e8f0", - "alignItems": "center", "gap": "10px", "cursor": "pointer" - }, - "binds": [{ - "wid": "self", "event": "click", - "actiontype": "urlwidget", - "target": "app.main_content", - "options": {"url": entire_url(url)}, - "mode": "replace" - }], - "subwidgets": [ - {"widgettype": "Text", "options": { - "text": str(n), "cfontsize": 1.5, - "color": color, "fontWeight": "bold" - }}, - {"widgettype": "Text", "options": { - "text": label, "cfontsize": 0.85, "color": "#64748b" - }} - ] - } - -return { - "widgettype": "ResponsableBox", - "options": {"gap": "12px", "minWidth": "160px", "width": "100%"}, - "subwidgets": [ - card(active_projects, "活跃项目", "#3b82f6", "/pipeline-sdlc/sd_projects/"), - card(active_iters, "进行中迭代", "#22c55e", "/pipeline-sdlc/sd_iterations/"), - card(open_bugs, "待处理Bug", "#f59e0b", "/pipeline-sdlc/sd_bugs/"), - card(pending_reviews, "待审批", "#8b5cf6", ""), - ] -} +return json.dumps({ + "active_projects": active_projects, + "active_iterations": active_iterations, + "pending_bugs": pending_bugs, + "pending_approvals": pending_approvals, +}, ensure_ascii=False)