"""One finite query catalog; names, schemas and permissions come from this registry.""" from dataclasses import dataclass from pydantic import BaseModel from mcp import types from app.mcp import models as m from app.mcp import extended_models as e from app.mcp.analysis_models import BurstDetectionInput, BurstLocationInput, ValveIsolationInput, LeakageIdentificationInput from app.mcp.analysis_models import ScenarioInput, ContaminantSimulationInput, ValveClosureInput, FlushingInput, PressureRegulationInput, SensorPlacementInput @dataclass(frozen=True) class QueryTool: name: str description: str model: type[BaseModel] permission: str semantics: str task_only: bool = False computation: bool = False mutating: bool = False def protocol_tool(self) -> types.Tool: if self.mutating: suffix = "。默认dry_run只预览;执行必须携带预览摘要、相同request_id并通过宿主原生许可。仅项目普通聊天可用,后台调查和reader禁止;失败或超时先核实状态,不自动重试。" elif self.name == "run_simulation": suffix = "。任务调用复用证据留存。" elif self.computation: suffix = "。仅计算建议,不保存方案、不控制设备;任务调用复用证据留存。" elif self.name == "query_nearby_elements": suffix = "。仅查询当前已授权项目的模型管网,按距离和元素ID稳定排序;按需分页,不自动遍历全量;空间邻近不代表管网连通或供水关系。" else: suffix = ( "。先限定对象和时间范围,再读取明细;集合默认20条,按需逐页扩大," "不要自动遍历全量;截断或非零offset不能证明完整范围无异常。" ) return types.Tool( name=self.name, description=self.description + suffix, inputSchema=self.model.model_json_schema(), outputSchema=m.QueryResult.model_json_schema(), annotations=types.ToolAnnotations( readOnlyHint=not (self.computation or self.mutating), destructiveHint=self.mutating or self.name == "run_simulation", openWorldHint=self.name in {"search_project_places", "reverse_geocode"} ), ) _specs = [ ("run_simulation", "按水力步长在在线业务模型上执行指定时间段的实时模拟,不复制数据库;更新该时段的模型条件及实时基线,返回指定节点和管段结果;duration单位为秒,不创建方案或正式分析运行,结果不是实测", ScenarioInput, "simulation.run", "analysis", False, True), ("run_contaminant_simulation", "在隔离模型中模拟假设污染源的浓度传播;返回指定节点/管段结果,不反演污染源,不代表实测污染范围", ContaminantSimulationInput, "simulation.run", "analysis", False, True), ("analyze_valve_closure", "在隔离模型中模拟关阀的水力影响,返回指定节点/管段结果;不操作真实阀门", ValveClosureInput, "simulation.run", "analysis", False, True), ("analyze_flushing", "在隔离模型中评估指定排放节点、冲洗流量和关阀组合的水力结果;不是现场冲洗或消毒合格证明", FlushingInput, "simulation.run", "analysis", False, True), ("analyze_pressure_regulation", "在隔离模型中评估给定调泵序列和水箱初始水位的压力影响;不自动优化调度,不实际控制泵", PressureRegulationInput, "simulation.run", "analysis", False, True), ("optimize_sensor_placement", "使用灵敏度或K-means算法推荐压力监测点;仅返回候选节点,不保存正式方案,不保证污染溯源可观测性", SensorPlacementInput, "optimization.run", "analysis", False, True), ("run_leakage_identification", "基于SCADA压力与模型进行DMA漏损分配识别,需有依据的总漏损流量和时间对齐;返回区域估计,不是已确认漏点。内部执行遗传算法与水力计算", LeakageIdentificationInput, "burst.run", "analysis", False, True), ("run_burst_detection", "爆管异常侦测:使用至少5个完整压力传感器此前15天数据;只提示压力异常,不定位、不证明爆管", BurstDetectionInput, "burst.run", "analysis", False, True), ("run_burst_location", "爆管候选定位:对比异常与正常压力,可辅助流量;需有依据的漏水量假设。压力节点可省略,自动读取项目SCADA压力测点;monitoring正常窗可成对省略,默认前一天同时间段,须说明该对照假设。simulation须有已有分析运行UUID并读取同窗模型基线,不是实测;定位内部会执行水力计算,不创建新的事件方案", BurstLocationInput, "burst.run", "analysis", False, True), ("analyze_valve_isolation", "按事故候选要素分析拓扑隔离边界、建议关闭阀门和受影响节点;不是污染扩散或水力影响范围,不执行关阀,须现场核实", ValveIsolationInput, "simulation.run", "analysis", False, True), ( "get_element_properties", "读取当前项目的单个管网元素属性", m.ElementInput, "webgis.view", "asset", ), ( "list_elements", "分页读取管网元素,不自动读取全网", m.ElementPageInput, "webgis.view", "asset", ), ( "query_nearby_elements", "查询坐标附近的模型元素,默认pipe;center为EPSG:4326 [经度,纬度],可直接使用geocode.center;radius_m默认200米、最大10000米,limit默认5、最大100,支持offset。按点到完整几何的WGS84椭球最短距离筛选并排序,返回element_id、distance_m和属性;不查询原始GIS管线、不自动扩大半径、不解析道路交叉点", m.NearbyElementsInput, "webgis.view", "asset", ), ( "get_network_options", "读取模型时间、能源或网络选项", m.OptionsInput, "webgis.view", "asset", ), ( "get_network_schema", "读取当前支持的元素、SCADA和选项结构", m.SchemaInput, "webgis.view", "asset", ), ( "list_scada_devices", "分页读取SCADA设备和物理单位", m.PageInput, "scada.view", "asset", ), ("get_scada_device", "读取一个SCADA设备", m.DeviceInput, "scada.view", "asset"), ( "query_scada_readings", "查询带时区且最多24小时的原始或清洗监测数据", m.ScadaInput, "scada.view", "observed", ), ( "query_model_baseline_series", "读取最多20个元素的模型基线,不能称为实测", m.BaselineSeriesInput, "simulation.view", "model_baseline", ), ( "get_model_baseline_at_time", "读取单个元素指定时刻的模型基线", m.BaselineAtTimeInput, "simulation.view", "model_baseline", ), ( "query_model_baseline_field", "分页读取指定时刻的模型字段", m.BaselineFieldInput, "simulation.view", "model_baseline", ), ( "query_analysis_series", "读取指定分析运行和元素字段时序", m.AnalysisSeriesInput, "simulation.view", "analysis", ), ( "query_analysis_values", "分页读取指定分析运行某时刻的元素字段", m.AnalysisValuesInput, "simulation.view", "analysis", ), ( "list_analysis_runs", "分页读取持久分析运行", m.RunsInput, "webgis.view", "analysis", ), ("get_analysis_run", "读取单个持久分析运行", m.RunInput, "webgis.view", "analysis"), ( "list_analysis_results", "分页读取分析成果,可筛选result_type", m.ResultsInput, "webgis.view", "analysis", ), ( "list_sensor_placement_runs", "分页读取已有监测点选址运行", m.PageInput, "optimization.run", "analysis", ), ( "get_sensor_placement_run", "读取已有监测点选址成果", m.RunInput, "optimization.run", "analysis", ), ( "query_element_history", "比较实测与模型基线或分析结果;analysis_comparison要求run_id;limit/offset按序列、时间排序的数据点分页", m.HistoryInput, "scada.view", "observed", ), ( "get_element_gis_properties", "读取元素关联GIS台账", m.ElementInput, "webgis.view", "asset", ), ( "get_source_gis_properties", "读取指定图层源要素台账", m.SourceGisInput, "webgis.view", "asset", ), ( "get_workbench_runtime", "读取工作台已有运行态", m.StrictInput, "simulation.view", "task", ), ( "get_task_context", "读取绑定任务的有界摘要及handling_skill元数据;section=skill读取Server按任务workflow分发的业务处置Skill正文与版本,属于流程指引而非事件证据;其他section选择task/report/evidence/actions/progress/access_requests/plan/run,data_path按返回路径读取嵌套字段,limit/offset分页;report_revision保留选定报告版本", m.TaskContextInput, "operational_task.view", "task", True, ), ( "query_peripheral_data", "查询有限外围数据源;synthetic是合成证据", m.PeripheralInput, "simulation.view", "peripheral", ), ( "get_task_evidence", "读取当前绑定任务已保存的证据快照", m.EvidenceInput, "operational_task.view", "task", True, ), ] _specs += [ ("list_regions", "分页查询当前项目区域/DMA列表", m.PageInput, "webgis.view", "asset"), ("get_region", "查询当前项目区域边界,返回EPSG:4326;不等于供水拓扑", e.RegionInput, "webgis.view", "asset"), ("get_region_nodes", "分页查询区域配置的成员节点,未配置时使用区域几何筛选", e.RegionInput, "webgis.view", "asset"), ("get_node_connections", "分页查询节点直接连接的管线,不自动遍历全网", e.NodeConnectionsInput, "webgis.view", "asset"), ("query_network_extent", "按EPSG:4326矩形范围分页查询当前项目模型几何;无GIS配置不跨项目回退", e.ExtentInput, "webgis.view", "asset"), ("list_major_nodes", "按关联管道最小管径查询骨干节点,经纬度EPSG:4326", e.MajorNodesInput, "webgis.view", "asset"), ("get_model_configuration", "读取模式、曲线、控制规则、需水量、水质及反应等模型配置;集合按页返回", e.ModelConfigurationInput, "webgis.view", "asset"), ("list_model_configurations", "分页读取模式或曲线ID", e.ConfigurationListInput, "webgis.view", "asset"), ("search_project_places", "按项目配置的行政区搜索地名,最多10个候选,依赖天地图配置", e.PlaceSearchInput, "webgis.view", "asset"), ("reverse_geocode", "把EPSG:4326地图取点转为项目范围内地名,保留输入坐标", e.ReverseGeocodeInput, "webgis.view", "asset"), ("get_project_info", "读取当前项目概况与地图范围,不返回数据库路由或凭据", m.StrictInput, "webgis.view", "asset"), ("export_project_model", "从当前项目数据库导出INP或ChangeSet压缩文件,由宿主保存到会话文件", e.ProjectExportInput, "webgis.view", "asset"), ("get_sensor_placement_candidate", "读取监测点候选节点工程属性", e.SensorCandidateInput, "optimization.run", "asset"), ("export_sensor_placement", "导出已有监测点方案的Excel工程清单,由宿主保存到会话文件", e.SensorExportInput, "optimization.run", "analysis"), ("list_task_schedules", "分页读取当前项目定时任务配置,不启动调度", m.PageInput, "operational_task.view", "task"), ("get_task_run_history", "分页读取指定项目任务的运行历史", e.TaskHistoryInput, "operational_task.view", "task"), ("get_mutation_status", "读取当前身份和会话内的写入执行状态;started只表示已启动,超时后须核实目标数据,不自动重试", e.MutationStatusInput, "webgis.view", "task"), ("calculate_demand_allocation", "按管长权重分配总需水量到节点、区域或全网,只计算不修改模型,按页返回", e.DemandAllocationInput, "webgis.view", "analysis", False, True), ("run_burst_simulation", "在隔离模型中模拟假设管道破口面积的水力影响;不是爆管侦测或定位,不保存正式方案", e.BurstSimulationInput, "simulation.run", "analysis", False, True), ("edit_model_element", "预览或增删改模型节点、管段、泵阀、水池和区域;仅修改模型,不控制现场设备", e.ModelElementMutationInput, "webgis.edit", "asset", False, False, True), ("edit_model_configuration", "预览或修改模型需水量、模式、曲线、控制规则、水质及模拟选项", e.ConfigurationMutationInput, "webgis.edit", "asset", False, False, True), ("clean_scada_readings", "预览或清洗明确设备与24小时内时间窗的数据,写入cleaned_value", e.ScadaCleaningInput, "scada.clean", "observed", False, False, True), ("write_scada_readings", "预览或补录/修正SCADA数据,要求真实来源依据;不把模拟当实测", e.ScadaWriteInput, "scada.clean", "observed", False, False, True), ("delete_scada_readings", "预览或删除明确设备与24小时内时间窗的SCADA记录", e.ScadaDeleteInput, "scada.clean", "observed", False, False, True), ("save_simulation_scenario", "预览或重新计算并保存正式隔离场景成果;有真实计算开销,不保存模型生成的观测数组", e.SavedScenarioInput, "simulation.run", "analysis", False, False, True), ("create_sensor_placement", "预览或计算并保存正式压力监测点选址方案", e.SensorCreateInput, "optimization.run", "analysis", False, False, True), ("update_sensor_placement", "预览或修改本人有权编辑的监测点方案,保留旧点位乐观校验", e.SensorUpdateInput, "optimization.run", "analysis", False, False, True), ("create_operational_task", "预览或创建项目任务,不伪造Agent运行完成", e.TaskCreateInput, "operational_task.write", "task", False, False, True), ("create_task_schedule", "预览或创建定时任务配置", e.ScheduleCreateInput, "operational_task.write", "task", False, False, True), ("update_task_schedule", "预览或启停定时任务配置,校验版本", e.ScheduleUpdateInput, "operational_task.write", "task", False, False, True), ("retry_operational_task", "预览或重新入队已终止任务;不自动启动新Agent会话", e.TaskRetryInput, "operational_task.write", "task", False, False, True), ("cancel_task_run", "预览或取消指定任务运行,校验运行版本", e.TaskCancelInput, "operational_task.write", "task", False, False, True), ] TOOLS = {row[0]: QueryTool(*row) for row in _specs}