feat: upgrade investigation and presentation runtime
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { viewCommandVariants } from "./command.js";
|
||||
import type { FrontendActionManifest } from "./types.js";
|
||||
|
||||
type Definition = { manifest: FrontendActionManifest; inputSchema: z.ZodTypeAny; outputSchema: z.ZodTypeAny };
|
||||
export { safeChartInput } from "./command.js";
|
||||
const deviceId = z.string().trim().min(1).max(128);
|
||||
const scadaLevel = z.enum(["high", "medium", "low", "unrated"]);
|
||||
const levelCounts = z.object({
|
||||
@@ -10,68 +10,21 @@ const levelCounts = z.object({
|
||||
low: z.number().int().nonnegative(),
|
||||
unrated: z.number().int().nonnegative(),
|
||||
}).strict();
|
||||
const renderScadaAnalysisInput = z.object({
|
||||
items: z.array(z.object({ device_id: deviceId, level: scadaLevel }).strict()).min(1).max(100),
|
||||
}).strict().superRefine((value, context) => {
|
||||
const seen = new Set<string>();
|
||||
value.items.forEach((item, index) => {
|
||||
if (seen.has(item.device_id)) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "device_id values must be unique",
|
||||
path: ["items", index, "device_id"],
|
||||
});
|
||||
}
|
||||
seen.add(item.device_id);
|
||||
});
|
||||
const cleared = z.object({ cleared: z.literal(true) }).strict();
|
||||
const outputs: Record<string, z.ZodTypeAny> = {
|
||||
highlight_features: z.object({ highlighted_ids: z.array(deviceId).min(1), missing_ids: z.array(deviceId), fitted: z.boolean() }).strict(),
|
||||
close_chart: z.object({ closed: z.literal(true) }).strict(),
|
||||
set_overlay: z.object({ displayed: z.literal(true), feature_count: z.number().int().positive() }).strict(),
|
||||
locate_features: z.object({ located_ids: z.array(deviceId).min(1), missing_ids: z.array(deviceId), fitted: z.literal(true) }).strict(),
|
||||
zoom_to_map: z.object({ fitted: z.literal(true) }).strict(),
|
||||
open_chart: z.object({ displayed: z.literal(true), series_count: z.number().int().positive() }).strict(),
|
||||
render_scada_analysis: z.object({ rendered_ids: z.array(deviceId), missing_ids: z.array(deviceId), level_counts: levelCounts, fitted: z.literal(true) }).strict(),
|
||||
};
|
||||
const definitions = viewCommandVariants.map(inputSchema => {
|
||||
const id = inputSchema.shape.action.value;
|
||||
const manifest: FrontendActionManifest = { id, version: "frontend-action@2", risk: "view", timeoutMs: 15000, supportedSurfaces: id.includes("chart") ? ["side_panel", "canvas"] : ["map_overlay"] };
|
||||
return { manifest, inputSchema, outputSchema: outputs[id] ?? cleared };
|
||||
});
|
||||
const viewManifest = (id: string, map = false): FrontendActionManifest => ({ id, version: "frontend-action@1", risk: "view", timeoutMs: 15_000, supportedSurfaces: map ? ["map_overlay"] : ["side_panel", "canvas"] });
|
||||
export const safeChartInput = z.object({
|
||||
title: z.string().max(200), chart_type: z.enum(["line", "bar"]),
|
||||
x_data: z.array(z.string().max(128)).min(1).max(100),
|
||||
series: z.array(z.object({ name: z.string().max(128), data: z.array(z.number().finite()).min(1).max(100) }).strict()).min(1).max(8),
|
||||
}).strict().refine((value) => value.series.every((series) => series.data.length === value.x_data.length), "series must align with x_data");
|
||||
const definitions: Definition[] = [
|
||||
{ manifest: viewManifest("locate_features", true),
|
||||
inputSchema: z.object({ layer: z.enum(["junctions", "pipes", "valves", "pumps", "tanks", "reservoirs", "scada"]), feature_ids: z.array(deviceId).min(1).max(100) }).strict(),
|
||||
outputSchema: z.object({ located_ids: z.array(deviceId).min(1), missing_ids: z.array(deviceId), fitted: z.literal(true) }).strict() },
|
||||
{ manifest: viewManifest("zoom_to_map", true),
|
||||
inputSchema: z.object({ center: z.tuple([z.number().min(-180).max(180), z.number().min(-90).max(90)]), zoom: z.number().min(0).max(24) }).strict(),
|
||||
outputSchema: z.object({ fitted: z.literal(true) }).strict() },
|
||||
{ manifest: viewManifest("show_chart"), inputSchema: safeChartInput,
|
||||
outputSchema: z.object({ displayed: z.literal(true), series_count: z.number().int().positive() }).strict() },
|
||||
{ manifest: viewManifest("view_history"),
|
||||
inputSchema: z.object({ element_type: z.enum(["junction", "pipe"]), element_id: deviceId, start: z.string().datetime({ offset: true }), end: z.string().datetime({ offset: true }), chart: safeChartInput.optional() }).strict(),
|
||||
outputSchema: z.object({ displayed: z.literal(true), series_count: z.number().int().positive() }).strict() },
|
||||
{
|
||||
manifest: {
|
||||
id: "render_scada_analysis",
|
||||
version: "frontend-action@1",
|
||||
risk: "view",
|
||||
timeoutMs: 15_000,
|
||||
supportedSurfaces: ["map_overlay"],
|
||||
},
|
||||
inputSchema: renderScadaAnalysisInput,
|
||||
outputSchema: z.object({
|
||||
rendered_ids: z.array(deviceId),
|
||||
missing_ids: z.array(deviceId),
|
||||
level_counts: levelCounts,
|
||||
fitted: z.literal(true),
|
||||
}).strict(),
|
||||
},
|
||||
{
|
||||
manifest: {
|
||||
id: "clear_scada_analysis",
|
||||
version: "frontend-action@1",
|
||||
risk: "view",
|
||||
timeoutMs: 15_000,
|
||||
supportedSurfaces: ["map_overlay"],
|
||||
},
|
||||
inputSchema: z.object({}).strict(),
|
||||
outputSchema: z.object({ cleared: z.literal(true) }).strict(),
|
||||
},
|
||||
];
|
||||
|
||||
export const frontendActionRegistry = definitions.map((item) => item.manifest);
|
||||
export const getFrontendActionDefinition = (name: string) => definitions.find((item) => item.manifest.id === name);
|
||||
export const frontendActionRegistryResponse = { schema_version: "frontend-action-registry@1" as const, actions: frontendActionRegistry };
|
||||
export const frontendActionRegistry = definitions.map(item => item.manifest);
|
||||
export const getFrontendActionDefinition = (name: string) => definitions.find(item => item.manifest.id === name);
|
||||
export const frontendActionRegistryResponse = { schema_version: "frontend-action-registry@2" as const, actions: frontendActionRegistry };
|
||||
|
||||
Reference in New Issue
Block a user