feat: 圆桌第3步大屏多页改用专职智能体 + 健壮 report-json 抽取
修复「大屏多页抽取 json 又失败」:旧实现复用画 HTML 的 roundtable-report 智能体 + rfind 围栏 + 单次 json.loads 的简单粗暴抽取,弱模型跑偏/格式偏差即失败。 - 新内置专职单例 roundtable-dashboard「大屏多页数据智能体」:SOUL 专讲逐席位 分析 → report-json 契约,禁工具/禁文件/禁 HTML;新 run policy dashboard 禁用一切工具 - harness 新增 report_json.py:多策略抽取(report-json/json/裸 JSON/截断)+ schema 归一化(移植前端 extractReportData/coerceReportData),返回可直接渲染的归一化 JSON - 后台 run_dashboard_data 改用专职 agent + dashboard policy + 健壮抽取 - 新增 /api/multi-agent/dashboard/init;前端 initDashboardThread + useStep3Dashboard 改用之 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bb05f7b1de
commit
ed887f762e
9 files changed
+452
-29
No files matched your search
@@ -835,6 +835,32 @@ export async function initReportThread(
|
||||
return { agentName: json.agent_name, threadId: json.thread_id };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a thread for the Step 3「大屏多页」dashboard-data agent
|
||||
* (`roundtable-dashboard`, a built-in singleton — distinct from `roundtable-report`;
|
||||
* its run policy disables ALL tools so it only emits a ```report-json block). Run it
|
||||
* with {@link streamMultiAgent} (`agentType: "special"`, `agentName: "roundtable-dashboard"`,
|
||||
* `dAgentThreadId: { [agentName]: threadId }`); the frontend then `extractReportData`s
|
||||
* the streamed text. Follow-up Q&A / refinements reuse the SAME thread (do not re-init)
|
||||
* so the agent keeps the prior dashboard context.
|
||||
*/
|
||||
export async function initDashboardThread(
|
||||
options: { signal?: AbortSignal } = {},
|
||||
): Promise<ReportThreadResponse> {
|
||||
const res = await apiFetch(`${getBackendBaseURL()}/api/multi-agent/dashboard/init`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: "{}",
|
||||
signal: options.signal,
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => "");
|
||||
throw new Error(`init dashboard thread failed (${res.status}): ${text}`);
|
||||
}
|
||||
const json = (await res.json()) as { agent_name: string; thread_id: string };
|
||||
return { agentName: json.agent_name, threadId: json.thread_id };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a thread for the Step 3「总结报告」summary agent (`roundtable-summary`,
|
||||
* a built-in singleton — distinct from `roundtable-report`; this only spins up a
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useArtifacts } from "@/components/workspace/artifacts";
|
||||
import type { DraftStep3Snapshot } from "@/roundtable-planning/api/drafts";
|
||||
import {
|
||||
initReportThread,
|
||||
initDashboardThread,
|
||||
streamMultiAgent,
|
||||
type StreamPhase,
|
||||
} from "@/roundtable-planning/api/multi-agent";
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
} from "@/roundtable-planning/lib/report-template";
|
||||
import { nowTime } from "@/roundtable-planning/lib/roundtable-constants";
|
||||
|
||||
const DASH_AGENT_FALLBACK = "roundtable-report";
|
||||
const DASH_AGENT_FALLBACK = "roundtable-dashboard";
|
||||
|
||||
export type DashboardPhase = "idle" | "creating" | "streaming" | "done" | "error";
|
||||
|
||||
@@ -269,7 +269,7 @@ export function useStep3Dashboard(options: UseStep3DashboardOptions): UseStep3Da
|
||||
const { bubbleId, message, aborter } = args;
|
||||
let threadId = liveThreadRef.current;
|
||||
if (!threadId) {
|
||||
const init = await initReportThread({ signal: aborter.signal });
|
||||
const init = await initDashboardThread({ signal: aborter.signal });
|
||||
if (aborter.signal.aborted) return;
|
||||
threadId = init.threadId;
|
||||
agentNameRef.current = init.agentName || DASH_AGENT_FALLBACK;
|
||||
|
||||
Reference in new issue
Block a user