Files
next-tjwater-frontend/src/features/agent/answer-ui/catalog.ts
T
jiang e0fe4a5a10
Generic Container CI/CD / test-build-publish (push) Successful in 1m12s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 1m11s
fix(charts): preserve comparison types and draggable window headings
Keep current lines and historical scatter points in a dedicated comparison chart type. Expose floating headings and use idempotent placement so StrictMode no longer masks production overlap.
2026-11-08 03:04:14 +08:00

138 lines
5.4 KiB
TypeScript

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { z } from "zod";
import { createChartSampleTimeSchema } from "../presentation/command-schema.ts";
const shortText = z.string().max(200);
const text = z.string().max(4000);
const optionalText = shortText.nullable();
const featureId = z.string().min(1).max(128);
/** This is the source of the generated Agent contract, not a remotely hosted registry. */
export const answerUiCatalog = defineCatalog(schema, {
actions: {},
components: {
Stack: {
props: z
.object({
columns: z.enum(["one", "two"]), gap: z.enum(["compact", "normal"]),
intent: z.enum(["response", "comparison", "report"]).optional(),
density: z.enum(["compact", "comfortable"]).optional()
})
.strict(),
slots: ["default"],
description: "组织内容。intent 表达简短答复、并列比较或报告;density 表达疏密,不控制字体和颜色。comparison 与双列在窄面板自动改单列。"
},
Section: {
props: z.object({
title: shortText, description: text.nullable(),
role: z.enum(["result", "analysis", "evidence", "follow_up"]).optional()
}).strict(),
slots: ["default"],
description: "带标题的资料分区。role 标记结果、分析、依据或补充资料;前端据此组织任务内容,保留分区内部的原有顺序。"
},
Text: {
props: z.object({ text, tone: z.enum(["neutral", "info", "warning"]), title: shortText.optional() }).strict(),
description: "简短说明、判断边界或资料缺口。"
},
Result: {
props: z.object({
title: shortText,
summary: text,
status: z.enum(["success", "partial", "unconfirmed", "error"]),
source: optionalText
}).strict(),
description: "概括已有工具结果:成功、部分完成、未确认或失败。source 标注真实依据;无依据用 unconfirmed。此组件不执行操作,不证明浏览器展示、业务写入或现场处置完成。"
},
Metric: {
props: z
.object({ label: shortText, value: shortText, unit: optionalText, source: optionalText })
.strict(),
description: "展示真实指标及其单位、来源;不能臆造读数。"
},
Table: {
props: z
.object({
title: shortText,
columns: z.array(shortText).min(1).max(8),
rows: z.array(z.array(z.string().max(1000)).max(8)).max(50)
})
.strict(),
description: "按相同字段比较资料,避免无法比较的指标混列。"
},
Chart: {
props: z
.object({
title: shortText,
chart_type: z.enum(["line", "bar", "time_comparison"]),
x_axis_name: z.string().max(128).optional(),
y_axis_name: z.string().max(128).optional(),
x_data: z.array(shortText).min(1).max(100),
series: z
.array(
z
.object({ name: shortText, type: z.enum(["line", "bar", "scatter"]).optional(),
data: z.array(z.number().finite().nullable()).min(1).max(100),
sample_times: z.array(createChartSampleTimeSchema().nullable()).min(1).max(100).optional() })
.strict()
)
.min(1)
.max(8),
source: text
})
.strict(),
description:
"展示真实数据。chart_type=line 为普通折线,bar 为柱状图,time_comparison 为当前曲线与历史散点的同期对比。同期对比的 x_data 为 UTC+8 的 HH:mm 或 HH:mm:ss 共享时刻槽,series.type 使用 line/scatter,每组 sample_times 与 data 等长,保留真实带时区日期,缺测均填 null;历史点放入对应时刻槽。浏览者可切换图形与数据表。"
},
Evidence: {
props: z
.object({
title: shortText,
summary: text,
source: shortText,
evidence_id: optionalText,
observed_at: optionalText,
kind: z.enum(["observed", "human_input", "inference", "demo"])
})
.strict(),
description: "展示证据依据;明确区分查询记录、用户事实、推断和演练数据。"
},
MapLocation: {
props: z
.object({
label: shortText,
layer: z.enum(["junctions", "pipes", "valves", "pumps", "tanks", "reservoirs", "scada"]),
feature_ids: z.array(featureId).min(1).max(100),
source: shortText
})
.strict(),
description: "用户点击后定位已有要素;ID 必须来自查询或用户明确提供,不绘制臆测影响范围。"
},
FollowUpForm: {
props: z
.object({
title: shortText,
description: text,
fields: z
.array(
z
.object({
name: z.string().regex(/^[a-z][a-z0-9_]{0,39}$/),
label: shortText,
kind: z.enum(["text", "datetime", "number"]),
required: z.boolean()
})
.strict()
)
.min(1)
.max(12)
})
.strict(),
description:
"让用户主动填写并提交补充资料;无默认事实。提交产生用户消息,是否写入业务证据由现有 Agent 工具处理。"
}
}
});
export const ANSWER_UI_VERSION = "answer-ui@1" as const;