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
+7 -2
View File
@@ -1,8 +1,11 @@
import { Ajv } from "ajv";
import { z } from "zod";
import { createChartSampleTimeSchema } from "../frontendAction/command.js";
import catalog from "./answer-ui-catalog.json" with { type: "json" };
const ajv = new Ajv({ allErrors: false, strict: true });
const sampleTimeSchema = createChartSampleTimeSchema();
ajv.addFormat("date-time", (value: string) => sampleTimeSchema.safeParse(value).success);
const propertyValidators = Object.fromEntries(Object.entries(catalog.props).map(([name, schema]) => [name, ajv.compile(schema)]));
const key = z.string().regex(/^[a-zA-Z0-9_-]{1,80}$/);
export const answerUiSpecSchema = z.object({ root: key, elements: z.record(z.object({
@@ -15,8 +18,10 @@ export const answerUiSpecSchema = z.object({ root: key, elements: z.record(z.obj
const validate = Object.hasOwn(propertyValidators, node.type) ? propertyValidators[node.type] : undefined;
if (!validate?.(node.props) || (!["Stack", "Section"].includes(node.type) && node.children.length)) { fail(); return; }
if (node.type === "Chart") {
const props = node.props as { x_data: unknown[]; series: Array<{ data: unknown[] }> };
if (props.series.some((series) => series.data.length !== props.x_data.length)) { fail(); return; }
const props = node.props as { x_data: unknown[]; series: Array<{ data: unknown[]; sample_times?: Array<string | null> }> };
if (props.series.some((series) => series.data.length !== props.x_data.length
|| (series.sample_times !== undefined && (series.sample_times.length !== props.x_data.length
|| series.sample_times.some((at, index) => at !== null && series.data[index] === null))))) { fail(); return; }
}
if (node.type === "Table") {
const props = node.props as { columns: unknown[]; rows: unknown[][] };