diff --git a/.opencode/agents/instruction.md b/.opencode/agents/instruction.md index a715de8..16a53f7 100644 --- a/.opencode/agents/instruction.md +++ b/.opencode/agents/instruction.md @@ -32,8 +32,8 @@ Agent 负责: 1. `render_scada_analysis` 只能在分析结论已经完成后调用,不得让前端计算、猜测或修改高中低等级。 2. 每次普通工具调用必须填写具体 `reason`。 3. 不生成 JS、JSX、HTML、CSS 或可执行前端代码。 -4. SCADA 地图结果只允许使用可信 `sensor_id` 和 `high | medium | low | unrated` 等级,不得传入自定义标签、颜色或 HTML。 -5. 同一批结果不得包含重复 `sensor_id`,每次最多 100 个点位。 +4. SCADA 地图结果只允许使用后端 API 返回的可信 `device_id` 和 `high | medium | low | unrated` 等级,不得传入自定义标签、颜色或 HTML。 +5. 同一批结果不得包含重复 `device_id`,每次最多 100 个点位。 6. 只有 SCADA 地图工具返回浏览器的成功结果后,才能声称已渲染或已清除;工具报错、超时或无活跃浏览器连接时,必须明确告知用户动作失败,不得伪造已渲染的点位、编号或等级。 ## 执行约束 diff --git a/.opencode/tools/render_scada_analysis.ts b/.opencode/tools/render_scada_analysis.ts index 6165040..d77a8dd 100644 --- a/.opencode/tools/render_scada_analysis.ts +++ b/.opencode/tools/render_scada_analysis.ts @@ -2,7 +2,7 @@ import { tool } from "@opencode-ai/plugin"; import { executeFrontendAction } from "./frontend_action.js"; -const sensorId = tool.schema.string().trim().min(1).max(128); +const deviceId = tool.schema.string().trim().min(1).max(128); export default tool({ description: @@ -16,7 +16,7 @@ export default tool({ items: tool.schema .array( tool.schema.object({ - sensor_id: sensorId.describe("Trusted SCADA sensor identifier."), + device_id: deviceId.describe("Trusted SCADA device identifier from the backend API."), level: tool.schema .enum(["high", "medium", "low", "unrated"]) .describe("Completed analysis level; use unrated only when no level was concluded."), @@ -25,8 +25,8 @@ export default tool({ .min(1) .max(100) .refine( - (items) => new Set(items.map((item) => item.sensor_id)).size === items.length, - "sensor_id values must be unique", + (items) => new Set(items.map((item) => item.device_id)).size === items.length, + "device_id values must be unique", ) .describe("One to one hundred unique SCADA analysis results."), }, diff --git a/src/frontendAction/registry.ts b/src/frontendAction/registry.ts index 535e689..0c7cb64 100644 --- a/src/frontendAction/registry.ts +++ b/src/frontendAction/registry.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import type { FrontendActionManifest } from "./types.js"; type Definition = { manifest: FrontendActionManifest; inputSchema: z.ZodTypeAny; outputSchema: z.ZodTypeAny }; -const sensorId = z.string().trim().min(1).max(128); +const deviceId = z.string().trim().min(1).max(128); const scadaLevel = z.enum(["high", "medium", "low", "unrated"]); const levelCounts = z.object({ high: z.number().int().nonnegative(), @@ -11,18 +11,18 @@ const levelCounts = z.object({ unrated: z.number().int().nonnegative(), }).strict(); const renderScadaAnalysisInput = z.object({ - items: z.array(z.object({ sensor_id: sensorId, level: scadaLevel }).strict()).min(1).max(100), + items: z.array(z.object({ device_id: deviceId, level: scadaLevel }).strict()).min(1).max(100), }).strict().superRefine((value, context) => { const seen = new Set(); value.items.forEach((item, index) => { - if (seen.has(item.sensor_id)) { + if (seen.has(item.device_id)) { context.addIssue({ code: z.ZodIssueCode.custom, - message: "sensor_id values must be unique", - path: ["items", index, "sensor_id"], + message: "device_id values must be unique", + path: ["items", index, "device_id"], }); } - seen.add(item.sensor_id); + seen.add(item.device_id); }); }); const definitions: Definition[] = [ @@ -36,8 +36,8 @@ const definitions: Definition[] = [ }, inputSchema: renderScadaAnalysisInput, outputSchema: z.object({ - rendered_ids: z.array(sensorId), - missing_ids: z.array(sensorId), + rendered_ids: z.array(deviceId), + missing_ids: z.array(deviceId), level_counts: levelCounts, fitted: z.literal(true), }).strict(), diff --git a/tests/frontendAction/coordinator.test.ts b/tests/frontendAction/coordinator.test.ts index cb61808..81527fa 100644 --- a/tests/frontendAction/coordinator.test.ts +++ b/tests/frontendAction/coordinator.test.ts @@ -8,8 +8,8 @@ import { frontendActionRegistry } from "../../src/frontendAction/registry.js"; import type { FrontendActionRequest } from "../../src/frontendAction/types.js"; const items = [ - { sensor_id: "MP01", level: "high" }, - { sensor_id: "MP02", level: "medium" }, + { device_id: "MP01", level: "high" }, + { device_id: "MP02", level: "medium" }, ] as const; const start = ( @@ -119,10 +119,10 @@ describe("FrontendActionCoordinator", () => { params: value, }); expect(() => request({ items: [] })).toThrow(FrontendActionError); - expect(() => request({ items: Array.from({ length: 101 }, (_, index) => ({ sensor_id: `MP${index}`, level: "low" })) })).toThrow("invalid frontend action params"); - expect(() => request({ items: [{ sensor_id: "MP01", level: "high" }, { sensor_id: "MP01", level: "low" }] })).toThrow("invalid frontend action params"); - expect(() => request({ items: [{ sensor_id: "x".repeat(129), level: "low" }] })).toThrow("invalid frontend action params"); - expect(() => request({ items: [{ sensor_id: "MP01", level: "critical" }] })).toThrow("invalid frontend action params"); + expect(() => request({ items: Array.from({ length: 101 }, (_, index) => ({ device_id: `MP${index}`, level: "low" })) })).toThrow("invalid frontend action params"); + expect(() => request({ items: [{ device_id: "MP01", level: "high" }, { device_id: "MP01", level: "low" }] })).toThrow("invalid frontend action params"); + expect(() => request({ items: [{ device_id: "x".repeat(129), level: "low" }] })).toThrow("invalid frontend action params"); + expect(() => request({ items: [{ device_id: "MP01", level: "critical" }] })).toThrow("invalid frontend action params"); }); it("keeps terminal results idempotent and rejects conflicts", async () => { diff --git a/tests/routes/chatUiState.test.ts b/tests/routes/chatUiState.test.ts index c774033..47923d1 100644 --- a/tests/routes/chatUiState.test.ts +++ b/tests/routes/chatUiState.test.ts @@ -12,7 +12,7 @@ describe("appendBackendToolArtifact", () => { const artifacts = appendBackendToolArtifact([], { tool: "render_scada_analysis", reason: "显示已完成的分级结论", - params: { items: [{ sensor_id: "MP01", level: "high" }] }, + params: { items: [{ device_id: "MP01", level: "high" }] }, }) as Array>; expect(artifacts[0]).toMatchObject({ diff --git a/tests/uiEnvelope/fromToolCall.test.ts b/tests/uiEnvelope/fromToolCall.test.ts index e1739d7..20682c8 100644 --- a/tests/uiEnvelope/fromToolCall.test.ts +++ b/tests/uiEnvelope/fromToolCall.test.ts @@ -12,7 +12,7 @@ describe("toUiEnvelopeFromToolCall", () => { it("does not generate duplicate UIEnvelopes for SCADA frontend actions", () => { expect(toUiEnvelopeFromToolCall({ tool: "render_scada_analysis", - params: { items: [{ sensor_id: "MP01", level: "high" }] }, + params: { items: [{ device_id: "MP01", level: "high" }] }, })).toBeNull(); expect(toUiEnvelopeFromToolCall({ tool: "clear_scada_analysis",