Compare commits
2
Commits
v2026.11.7.3
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8eb29466a | ||
|
|
e1ca2f56f9 |
@@ -2,7 +2,7 @@
|
||||
name: instruction
|
||||
description: 供水 Agent 的公共数据边界、工具选择和交互规则。
|
||||
metadata:
|
||||
version: "1.0.4"
|
||||
version: "1.0.5"
|
||||
---
|
||||
|
||||
你是 TJWater 供水运维平台人工智能,承担 TJWater 实验性供水数据 Agent 角色。使用简体中文,简洁准确地区分事实、有依据的估计或假设、模型候选和待现场核验项。
|
||||
@@ -24,7 +24,7 @@ metadata:
|
||||
- MCP 未启用时报告能力状态;权限、认证、接口与超时错误按执行异常记录。逐项区分尚未查询、查询为空、部分覆盖和执行失败,再检查相关授权入口。
|
||||
- 实测、模型基线、情景模拟和估计分别标注。采用有来源的数据、明确假设和 schema 默认值形成候选方案,并保留方法、单位与覆盖范围。设备状态、监测值和现场记录按实际来源呈现。
|
||||
- 工单是业务记录,故障原因按证据核验。调查证据使用工具实际保存并返回的 evidence_id;业务流程和 question_request_id 用于流程接续。
|
||||
- 阅读时区统一为 Asia/Shanghai(UTC+8):正文、表格、图表标题、横轴、系列名和引用时间都按UTC+8表达。存储来源为UTC,工具展示层将同一时间点转换为+08:00并返回display_time_zone;按返回偏移读取,已有+08:00保持原值。例如2026-07-16T00:00:00Z显示为2026-07-16 08:00。查询参数与sample_times保留明确偏移,跨日同步更新日期;用户可读的无时区钟点按UTC+8阅读,来源时间缺少时区时注明待确认。
|
||||
- 阅读时区统一为 Asia/Shanghai(UTC+8):正文、表格、图表标题、横轴、系列名和引用时间都按UTC+8表达。存储来源为UTC,工具展示层将同一时间点转换为+08:00并返回display_time_zone;按返回偏移读取,已有+08:00保持原值。例如2026-07-16T00:00:00Z显示为2026-07-16 08:00。查询参数与sample_times保留明确偏移,跨日同步更新日期;用户可读的无时区钟点按UTC+8阅读,来源时间缺少时区时注明待确认。图表标题、横轴和系列名省略“上海时间”“Asia/Shanghai”“UTC+8”等字样,只显示日期、时刻与单位,横轴用“时间”;查询和sample_times继续保留明确偏移。
|
||||
- 事件流程及版本以 Server handling_skill 为准;本地 Skill 保存通用方法。证据、审批和执行回执按各自系统事实核对。
|
||||
|
||||
## 查询范围
|
||||
@@ -32,7 +32,8 @@ metadata:
|
||||
先限定对象、来源、字段和时间窗,再按当前问题所需证据扩大范围。
|
||||
|
||||
- get_task_context 默认返回 preview_only 摘要;按 available_sections 选择 section,再用 data_path、limit、offset 读取详情。指定报告保留 report_revision。
|
||||
- 首次集合查询用 limit=20、offset=0,优先少量对象和短窗。has_more=true 且后页必要时,offset 按本页 limit 推进;超过10000时缩小对象或时间窗。
|
||||
- 普通集合按schema默认值分页。SCADA调查先调用query_scada_readings并省略device_ids,让Server读取当前项目的完整设备属性和窗口内全部授权观测;覆盖压力、流量、水质等全部设备类型。显式device_ids仅用于全量读取后的局部复核。单独读取设备目录时,按每页100个持续翻页到has_more=false,不能自行以代表设备或已标记设备缩小调查输入。
|
||||
- 全量SCADA结果的devices、readings和coverage必须一并核对;缺测、查询失败和冻结范围外设备分别列出。query_complete表示查询已读完,不表示所有设备都有有效观测。当前窗和正常对照保持任务给定的时空边界,最终SCADA报告引用本轮全量读取的evidence_id。
|
||||
- 已有证据按 evidence_read 调用 get_task_evidence;嵌套集合和长文本选择更深 data_path 和小页。RESULT_TOO_LARGE 时调整页或路径,继续遵守数据源整份校验条件。
|
||||
- 用户指定的窗口保持原范围;按真实观测说明覆盖与缺口。模型值另列为模型结果。
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: investigation
|
||||
description: 后台调查的推进、过程展示、人工协作和报告收尾规则。
|
||||
metadata:
|
||||
version: "1.1.6"
|
||||
version: "1.1.8"
|
||||
---
|
||||
|
||||
## 后台调查
|
||||
@@ -29,7 +29,7 @@ synthetic、回放等来源标记本身不构成停止条件。核对工具返
|
||||
|
||||
## 过程展示
|
||||
|
||||
报告、进度、表格和图表统一按Asia/Shanghai(UTC+8)呈现时间,标题、横轴、系列名与采样时刻采用同一阅读时区。sample_times保留真实时间点与日期,使用+08:00偏移;数据源中的Z表示UTC,换算后按UTC+8命名历史日期与窗口。
|
||||
报告、进度、表格和图表统一按Asia/Shanghai(UTC+8)呈现时间,标题、横轴、系列名与采样时刻采用同一阅读时区。sample_times保留真实时间点与日期,使用+08:00偏移;数据源中的Z表示UTC,换算后按UTC+8命名历史日期与窗口。图表标题、横轴和系列名只展示日期与时刻,不写“上海时间”“Asia/Shanghai”或“UTC+8”,横轴用“时间”;结构化sample_times仍保留偏移。
|
||||
|
||||
开始调查、改变路线或取得关键结果时,用 publish_task_progress 更新完整进度;diagram 可选,用于解释真实路线和证据关系。
|
||||
|
||||
@@ -47,7 +47,9 @@ synthetic、回放等来源标记本身不构成停止条件。核对工具返
|
||||
|
||||
同阶段按对象集合发布;数据或方案变化时更新,同内容复用已有请求。人工提问或计算等待前,先发布已取得的关键步骤展示。map_targets和报告链接提供手动入口,过程展示使用上述发布工具。
|
||||
|
||||
SCADA地图定位、等级标记、表格与图表采用同一目标设备集合。先按指标和单位发布覆盖全部目标设备的当前趋势总览,系列名包含device_id;超过8组时分图,各组使用不同且稳定的chart_id。历史对照按设备另图补充,不能以代表测点替代其他设备的当前趋势。缺测保留null,无读数设备明确列入缺测清单并说明窗口;final前核对目标设备、查询覆盖和已发布图表。分页按page.has_more接续,大目录可用limit=100;缩略内容按evidence_read和data_path读取已保存证据。
|
||||
SCADA调查先用query_scada_readings省略device_ids,读取全部设备属性和任务窗口内全部授权观测,核对devices、readings、coverage及缺测、冻结范围外清单;全量读取后才选择局部对象深入复核。设备目录单独读取时持续翻页到has_more=false。最终SCADA报告必须引用本轮全量证据,Server会拒绝仅有局部设备证据的final。
|
||||
|
||||
SCADA地图定位、等级标记、表格与图表采用同一目标设备集合;展示重点可以选择,但调查输入仍须全量。以本轮knowledge_cutoff或异常时刻t为终点,先查询并按指标和单位发布[t-3小时,t]内覆盖全部已标识设备的当前趋势总览,压力、流量分别出图;每条序列保留窗口内全部采样点,15分钟数据正常为13个时刻,不能用局部复核的相邻两点替代。系列名包含device_id;超过8组时分图,各组使用不同且稳定的chart_id。SCADA外围触发任务还须按设备另图发布三小时当前折线和前七天历史散点对照,压力、流量均覆盖;七天每天只取末三个对应时刻,缺测保留null并报告具体限制。图表数据视图沿用完整序列,报告按指标列出测点、单位、窗口、有效点数和缺测情况。不能以代表测点替代其他已标识设备的当前趋势。缺测保留null,无读数设备明确列入缺测清单并说明窗口;final前核对完整读取、缺测清单和已发布图表。
|
||||
|
||||
两个及以上有效时刻用折线图,同指标对象比较用柱状图,单值或缺少可比数据时用文字或指标。后台open_chart的图表放在chart,提供稳定chart_id和非空evidence_refs;标题、序列和坐标轴写明对象、时段、单位与来源。变化量采用同口径基准计算。
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { taskPresentationCommandSchema } from "../../src/product/task-presentati
|
||||
import { taskPublicationCommandSchema } from "./task-publication-schema.js";
|
||||
|
||||
export default tool({
|
||||
description: "Publish the current investigation step as a bounded map, chart or evidence-backed overlay command. Publish as the process advances: zoom to a resolved address, locate candidate assets or proposed valves, show derived node coverage, and chart monitoring trends, candidate scores, comparable plans or returned simulation results. Use line charts for time series and bar charts for comparable objects or plans. For SCADA, first publish current-trend charts covering every device marked on the map or listed in the target table, with device_id in each series name. Group by metric and unit, split more than 8 series into separate stable chart_ids, and explicitly account for devices with missing readings. Add per-device historical comparisons separately; representative devices must not replace the complete current-trend overview. For historical samples over a current trend, use chart_type=line with per-series type=line/scatter; preserve null slots and aligned sample_times for the same real instants, displayed with +08:00 offsets. Use Asia/Shanghai (UTC+8) for chart titles, axis labels and series dates; update calendar dates when converting UTC sources. Open_chart requires chart_id, chart and nonempty evidence_refs; label units, time range and observed/model/assumed origin. Separate incompatible units, do not fill missing data with zero or invent a baseline, and explain any selection or aggregation. Do not wait for the final report or substitute report links or final charts for process commands. The Server records the command for optional live browser following; recorded never means a browser displayed it. No browser connection, capability or receipt is required, and investigation continues independently of display. Chart data must reflect the referenced persisted evidence. Overlay coordinates and values are extracted by the Server from the evidence snapshot; omit data when referencing saved geometry, and do not publish an empty coverage. Any supplied data is validated against the evidence snapshot. Never supply invented geometry or arbitrary code. Use a stable UUID request_id and reuse it when retrying the same command; do not republish an unchanged step merely to create activity.",
|
||||
description: "Publish the current investigation step as a bounded map, chart or evidence-backed overlay command. Publish as the process advances: zoom to a resolved address, locate candidate assets or proposed valves, show derived node coverage, and chart monitoring trends, candidate scores, comparable plans or returned simulation results. Use line charts for time series and bar charts for comparable objects or plans. For SCADA, first publish the full three-hour current trend ending at the task cutoff for every device marked on the map or listed in the target table, with device_id in each series name. Publish pressure and flow separately. Keep every available sample in that window (13 timestamps at a 15-minute interval); a two-point adjacent-sample check must never replace the full trend. Peripheral SCADA tasks also require per-device charts combining that current line with scatter samples from the previous seven days; explain unavailable frozen history or missing readings explicitly. Group by metric and unit, split more than 8 series into separate stable chart_ids, and explicitly account for devices with missing readings. Add per-device historical comparisons separately; representative devices must not replace the complete current-trend overview. For historical samples over a current trend, use chart_type=line with per-series type=line/scatter; preserve null slots and aligned sample_times for the same real instants, displayed with +08:00 offsets. Convert chart titles, axis labels and series dates to the Asia/Shanghai clock, including calendar rollover, but omit timezone wording such as Shanghai time, 上海时间, Asia/Shanghai or UTC+8 from visible labels. Name the time axis 时间. Keep explicit offsets in sample_times. Open_chart requires chart_id, chart and nonempty evidence_refs; label units, time range and observed/model/assumed origin. Separate incompatible units, do not fill missing data with zero or invent a baseline, and explain any selection or aggregation. Do not wait for the final report or substitute report links or final charts for process commands. The Server records the command for optional live browser following; recorded never means a browser displayed it. No browser connection, capability or receipt is required, and investigation continues independently of display. Chart data must reflect the referenced persisted evidence. Overlay coordinates and values are extracted by the Server from the evidence snapshot; omit data when referencing saved geometry, and do not publish an empty coverage. Any supplied data is validated against the evidence snapshot. Never supply invented geometry or arbitrary code. Use a stable UUID request_id and reuse it when retrying the same command; do not republish an unchanged step merely to create activity.",
|
||||
args: {
|
||||
request_id: tool.schema.string().uuid().describe("Stable UUID idempotency key; reuse for retries of this command"),
|
||||
command: taskPublicationCommandSchema,
|
||||
|
||||
+5
-5
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"defaults": {
|
||||
"chat": "waternetwork/gpt-5.6-terra",
|
||||
"task": "waternetwork/gpt-5.6-terra",
|
||||
"learning_gate": "waternetwork/gpt-5.6-terra"
|
||||
"chat": "waternetwork/deepseek-flash",
|
||||
"task": "waternetwork/deepseek-flash",
|
||||
"learning_gate": "waternetwork/deepseek-flash"
|
||||
},
|
||||
"providers": {
|
||||
"waternetwork": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"api_url": "https://llm.waternetwork.cn/v1",
|
||||
"api_key": "{env:WATERNETWORK_API_KEY}",
|
||||
"models": {
|
||||
"gpt-5.6-terra": {
|
||||
"deepseek-flash": {
|
||||
"name": "快速",
|
||||
"description": "快速回答和日常任务处理",
|
||||
"icon": "bolt",
|
||||
@@ -18,7 +18,7 @@
|
||||
"context": 272000
|
||||
}
|
||||
},
|
||||
"gpt-5.6-sol": {
|
||||
"gpt-6.1-sol": {
|
||||
"name": "专家",
|
||||
"description": "深入分析和复杂任务处理",
|
||||
"icon": "sparkle",
|
||||
|
||||
@@ -156,19 +156,21 @@ describe("agent model config", () => {
|
||||
});
|
||||
|
||||
it("exposes only the two configured gateway models with their roles, icons and context limits", () => {
|
||||
expect(supportedModels).toEqual(["waternetwork/gpt-5.6-terra", "waternetwork/gpt-5.6-sol"]);
|
||||
expect(supportedModels).toEqual(["waternetwork/deepseek-flash", "waternetwork/gpt-6.1-sol"]);
|
||||
expect(agentModelOptions.map(({ id, label, icon }) => ({ id, label, icon }))).toEqual([
|
||||
{ id: "waternetwork/gpt-5.6-terra", label: "快速", icon: "bolt" },
|
||||
{ id: "waternetwork/gpt-5.6-sol", label: "专家", icon: "sparkle" },
|
||||
{ id: "waternetwork/deepseek-flash", label: "快速", icon: "bolt" },
|
||||
{ id: "waternetwork/gpt-6.1-sol", label: "专家", icon: "sparkle" },
|
||||
]);
|
||||
expect(isSupportedModel("deepseek/deepseek-flash")).toBe(false);
|
||||
expect(isSupportedModel("waternetwork/deepseek-flash")).toBe(false);
|
||||
expect(isSupportedModel("waternetwork/deepseek-flash")).toBe(true);
|
||||
expect(isSupportedModel("waternetwork/gpt-5.6-terra")).toBe(false);
|
||||
expect(isSupportedModel("waternetwork/gpt-5.6-sol")).toBe(false);
|
||||
expect(isSupportedModel("waternetwork/gpt-image-2.5")).toBe(false);
|
||||
expect(isSupportedModel("waternetwork/codex-auto-review")).toBe(false);
|
||||
const native = serviceOpencodeConfig({});
|
||||
expect(Object.keys(native.providers)).toEqual(["waternetwork"]);
|
||||
expect(native.model).toBe("waternetwork/gpt-5.6-terra");
|
||||
expect(native.providers.waternetwork.models["gpt-5.6-terra"].limit?.context).toBe(272000);
|
||||
expect(native.providers.waternetwork.models["gpt-5.6-sol"].limit?.context).toBe(475000);
|
||||
expect(native.model).toBe("waternetwork/deepseek-flash");
|
||||
expect(native.providers.waternetwork.models["deepseek-flash"].limit?.context).toBe(272000);
|
||||
expect(native.providers.waternetwork.models["gpt-6.1-sol"].limit?.context).toBe(475000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,30 @@ afterEach(async () => {
|
||||
});
|
||||
const productTool: Tool = { name: "get_task_context", description: "Bound task", inputSchema: { type: "object", properties: { report_revision: { type: "integer", minimum: 1 } }, additionalProperties: false } };
|
||||
|
||||
it("delivers complete SCADA metadata and observations through native MCP without narrowing device scope", async () => {
|
||||
const data = {
|
||||
devices: Array.from({ length: 168 }, (_, index) => ({ device_id: `D${index}`, node_id: `J${index}`, description: "x".repeat(100) })),
|
||||
readings: Array.from({ length: 2184 }, (_, index) => ({ device_id: `D${index % 168}`, monitored_value: index, cleaned_value: null })),
|
||||
coverage: { mode: "all_scada", query_complete: true, queried_device_count: 168, reading_count: 2184 },
|
||||
};
|
||||
const upstream = { content: [{ type: "text" as const, text: JSON.stringify(data) }], structuredContent: {
|
||||
source: "query_scada_readings", evidence_id: "mcp:all-scada", data, truncated: false,
|
||||
} };
|
||||
const query = mock(async () => upstream);
|
||||
const tool: Tool = { name: "query_scada_readings", inputSchema: { type: "object", properties: {
|
||||
start: { type: "string" }, end: { type: "string" },
|
||||
device_ids: { type: "array", items: { type: "string" }, maxItems: 20 },
|
||||
}, required: ["start", "end"], additionalProperties: false } };
|
||||
const { call } = await setup({ productTools: [tool], productClient: { query } });
|
||||
setRuntimeSessionContext({ ...owner, purpose: "task_execution", taskId: "scada-task" });
|
||||
const args = { start: "2026-07-16T05:00:00+08:00", end: "2026-07-16T08:00:00+08:00" };
|
||||
const result = await call("query_scada_readings", args);
|
||||
expect(result.isError).not.toBeTrue();
|
||||
expect((query.mock.calls[0] as unknown as unknown[])[3]).toEqual(args);
|
||||
expect(result.structuredContent).toEqual(upstream.structuredContent);
|
||||
expect(JSON.stringify(result.structuredContent).length).toBeGreaterThan(12000);
|
||||
});
|
||||
|
||||
it("hides HTTP budgets from models and fixes the native connection ceiling", async () => {
|
||||
const simulation: Tool = { name: "run_simulation", inputSchema: { type: "object", properties: {
|
||||
timeout_seconds: { type: "integer", minimum: 1, maximum: 240, default: 120 },
|
||||
|
||||
@@ -313,9 +313,9 @@ describe("OpencodeRuntimeAdapter.warmup", () => {
|
||||
} finally { await cleanup(); }
|
||||
});
|
||||
it("rejects an invalid non-default model before readiness and cleans up the session", async () => {
|
||||
const { runtime, calls, cleanup } = await createWarmupRuntime([], "waternetwork/gpt-5.6-sol");
|
||||
const { runtime, calls, cleanup } = await createWarmupRuntime([], "waternetwork/gpt-6.1-sol");
|
||||
try {
|
||||
await expect(runtime.warmup()).rejects.toThrow("waternetwork/gpt-5.6-sol: not_advertised");
|
||||
await expect(runtime.warmup()).rejects.toThrow("waternetwork/gpt-6.1-sol: not_advertised");
|
||||
expect(calls).not.toContain("model.list");
|
||||
expect(calls.at(-1)).toBe("session.remove");
|
||||
} finally { await cleanup(); }
|
||||
|
||||
Reference in New Issue
Block a user