import { tool } from "../tool.js"; import { answerUiInputSchema } from "../../src/chat/answer-ui.js"; import catalog from "../../src/chat/answer-ui-catalog.json" with { type: "json" }; // These complete call pairs also serve as executable contract examples in tests. export const answerUiExamples: Array<{ present_answer: ReturnType; final_answer: { answer: string; ui_block_ids: string[] }; }> = [ { present_answer: { phase: "final" as const, block_id: "demo_comparison", fallback_text: "演练资料:甲管径 300 mm,乙管径 200 mm。", spec: { root: "table", elements: { table: { type: "Table", props: { title: "管径比较(用户提供的演练资料)", columns: ["对象", "管径(mm)"], rows: [["甲", "300"], ["乙", "200"]] }, children: [], } } }, }, final_answer: { answer: "甲的管径较大,不能仅凭管径判断实际供水能力。\n\n[[ui:demo_comparison]]", ui_block_ids: ["demo_comparison"] }, }, { present_answer: { phase: "final" as const, block_id: "demo_trend", fallback_text: "演练资料:08:00、09:00、10:00 压力依次为 0.30、0.28、0.18 MPa。", spec: { root: "chart", elements: { chart: { type: "Chart", props: { title: "压力变化(MPa)", chart_type: "line", x_data: ["08:00", "09:00", "10:00"], series: [{ name: "压力(MPa)", data: [0.30, 0.28, 0.18] }], source: "用户提供的演练资料,非现场实测" }, children: [], } } }, }, final_answer: { answer: "演练序列中后一个时段下降更明显,原因仍需其他证据判断。\n\n[[ui:demo_trend]]", ui_block_ids: ["demo_trend"] }, }, ]; export default tool({ description: "把已有资料发布为保留在聊天中的交互内容。多对象同类字段比较优先用 Table,数值时间序列分析优先用 Chart,不等用户指定组件;简单解释、单个事实和简短确认直接用文字。用户明确要求纯文字时遵从。工作台窗口与地图动作另用 present_view。spec 是 root + elements 的扁平树,每个元素包括 type、props、children;单个组件可以直接作为 root。关键指标用 Metric,复杂结果用 Result(status 必须有真实依据),可复核依据用 Evidence,反复定位入口用 MapLocation,最终答复后的可选补充用 FollowUpForm。只组织查询结果或用户提供的资料,保留来源、单位、范围及演练标识;缺数不补造、不补零,不为布局凑卡片。无脚本、URL、CSS 或任意代码。Result 不执行动作,演练或记录成功不等于现场成功;发布不执行地图或业务动作,也不等待浏览器。Stack 的 columns/gap 仍必填,可选 intent=response|comparison|report、density=compact|comfortable;Section 可选 role=result|analysis|evidence|follow_up,Text 可选 title。需要保留的内容直接显式 phase=final,无须先发布 process;仅临时过程材料用 phase=process,省略仍默认 process。相同 block_id 只能同 phase 更新;过程材料转为最终内容须另用 block_id。final_answer 前完成所有更新,并通过独立正文锚点和 ui_block_ids 引用 final 块,正文不抄写整表或重复全文。下列是两组独立的最小调用示例,实际调用必须替换为本轮资料和 ID,不能复用演练数值:" + JSON.stringify(answerUiExamples) + "。组件参数的 JSON Schema:" + JSON.stringify(catalog.props), args: { phase: tool.schema.enum(["process", "final"]).optional().describe("保留在最终答复中的内容显式填 final;临时核查材料填 process。省略默认 process。"), block_id: tool.schema.string().regex(/^[a-zA-Z0-9_-]{1,80}$/), fallback_text: tool.schema.string().min(1).max(4000), spec: tool.schema.object({ root: tool.schema.string(), elements: tool.schema.record(tool.schema.string(), tool.schema.object({ type: tool.schema.string(), props: tool.schema.record(tool.schema.string(), tool.schema.unknown()), children: tool.schema.array(tool.schema.string()).max(48), }).strict()) }).strict(), }, async execute(args) { const value = answerUiInputSchema.parse(args); return JSON.stringify({ version: "answer-ui@1", ...value, phase: value.phase ?? "process", recorded: true }); }, });