feat(agent): improve investigation contracts and runtime readiness
This commit is contained in:
@@ -58,6 +58,27 @@ describe("locally rendered answers", () => {
|
||||
for (const data of [[0.3, 0.4], [Infinity], [NaN]]) expect(parseAnswerUiInput(withNode({ ...node, props: { ...node.props, series: [{ name: "压力", data }] } }))).toBeNull();
|
||||
expect(parseAnswerUiInput({ ...input, spec: { ...input.spec, elements: { ...input.spec.elements, unused: node } } })).toBeNull();
|
||||
});
|
||||
it("preserves historical scatter timestamps and missing slots in comparison charts", () => {
|
||||
const props = {
|
||||
title: "压力七天对比", chart_type: "line", source: "冻结SCADA观测",
|
||||
x_data: ["19:30", "19:45", "20:00"], y_axis_name: "压力(m)",
|
||||
series: [
|
||||
{ name: "当前", type: "line", data: [32.1, null, 31.9] },
|
||||
{ name: "前一天", type: "scatter", data: [null, 32.4, 32.2],
|
||||
sample_times: [null, "2026-06-13T19:45:00+08:00", "2026-06-13T20:00:00+08:00"] },
|
||||
],
|
||||
};
|
||||
const withProps = (value: unknown) => ({ ...input, spec: { root: "chart", elements: {
|
||||
chart: { type: "Chart", props: value, children: [] },
|
||||
} } });
|
||||
expect(parseAnswerUiInput(withProps(props))?.spec.elements.chart.props).toEqual(props);
|
||||
for (const sample_times of [
|
||||
[null],
|
||||
["2026-06-13T19:30:00+08:00", null, null],
|
||||
[null, "2026-06-13T19:45:00", null],
|
||||
[null, "2026-02-30T19:45:00+08:00", null],
|
||||
]) expect(parseAnswerUiInput(withProps({ ...props, series: [{ ...props.series[1], sample_times }] }))).toBeNull();
|
||||
});
|
||||
it("flushes prose before the interface, publishes once per tool call, and suppresses background UI", async () => {
|
||||
const part = { id: "ui-call", type: "tool", tool: "present_answer", sessionID: "s", messageID: "m", state: { status: "completed", input, output: "{}", time: { start: 1, end: 2 } } };
|
||||
const events = [
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { expect, it } from "bun:test";
|
||||
import { createViewCommandSchema } from "../../src/frontendAction/command.js";
|
||||
import { parseAnswerUiInput } from "../../src/chat/answer-ui.js";
|
||||
|
||||
// Keep this matrix in sync with Agent and Server chart timestamp conformance tests.
|
||||
const cases: Array<[string, boolean]> = [
|
||||
["2026-06-14T12:00:00Z", true], ["2026-06-14T12:00:00+08:00", true],
|
||||
["2026-06-14T12:00:00-03:30", true], ["2024-02-29T23:59:59.123456Z", true],
|
||||
["2026-06-14T12:00:00+23:59", true], [`2026-06-14T12:00:00.${"1".repeat(43)}Z`, true],
|
||||
["2026-06-14 12:00:00+08:00", false], ["2026-W24-7T12:00:00+08:00", false],
|
||||
["2026-06-14T12:00+08:00", false], ["2026-06-14T12:00:00+0800", false],
|
||||
["2026-02-30T12:00:00Z", false], ["2026-13-14T12:00:00Z", false],
|
||||
["2026-06-00T12:00:00Z", false], ["2026-02-29T12:00:00Z", false],
|
||||
["2026-06-14T24:00:00Z", false], ["2026-06-14T12:00:60Z", false],
|
||||
["2026-06-14T12:00:00+24:00", false], ["2026-06-14T12:00:00+08:60", false],
|
||||
["2026-06-14T12:00:00", false], ["2026-06-14T12:00:00z", false],
|
||||
["0000-06-14T12:00:00Z", false], [`2026-06-14T12:00:00.${"1".repeat(44)}Z`, false]
|
||||
];
|
||||
const chart = (data: Array<number | null>, sample_times: Array<string | null>) => ({
|
||||
title: "压力", chart_type: "line", x_data: ["12:00"], series: [{ name: "测点", data, sample_times }]
|
||||
});
|
||||
const input = (value: ReturnType<typeof chart>) => ({
|
||||
block_id: "pressure", fallback_text: "压力数据", spec: { root: "chart", elements: {
|
||||
chart: { type: "Chart", props: { ...value, source: "实测" }, children: [] }
|
||||
} }
|
||||
});
|
||||
const schemas = [createViewCommandSchema({ publication: false }), createViewCommandSchema({ publication: true })];
|
||||
|
||||
it.each(cases)("uses the same timestamp boundary for chart commands and answer blocks: %s", (time, accepted) => {
|
||||
const value = chart([1], [time]);
|
||||
for (const schema of schemas)
|
||||
expect(schema.safeParse({ action: "open_chart", chart_id: "pressure", evidence_refs: ["e"], chart: value }).success).toBe(accepted);
|
||||
expect(parseAnswerUiInput(input(value)) !== null).toBe(accepted);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[[0], [null], true], [[null], [null], true], [[null], ["2026-06-14T12:00:00Z"], false], [[1], [], false]
|
||||
] as Array<[Array<number | null>, Array<string | null>, boolean]>)("preserves zero, null and sample alignment: %j %j", (data, times, accepted) => {
|
||||
const value = chart(data, times);
|
||||
for (const schema of schemas)
|
||||
expect(schema.safeParse({ action: "open_chart", chart_id: "pressure", evidence_refs: ["e"], chart: value }).success).toBe(accepted);
|
||||
expect(parseAnswerUiInput(input(value)) !== null).toBe(accepted);
|
||||
});
|
||||
Reference in New Issue
Block a user