feat(agent): improve investigation contracts and runtime readiness
Generic Container CI/CD / test-build-publish (push) Successful in 1m53s
Agent CI/CD / build-test-publish-and-deploy (push) Successful in 1m53s

This commit is contained in:
2026-11-07 19:43:57 +08:00
parent c7b750b099
commit b8f7edb3ee
29 changed files with 1465 additions and 119 deletions
+21
View File
@@ -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 = [
+43
View File
@@ -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);
});