Files
next-tjwater-server/app/domain/schemas/operational_data.py
T
jiang be6317eb48 feat(server): integrate MCP queries and investigation messaging
Add project-bound OAuth MCP queries and controlled analysis with scoped evidence,
limits, timeouts and a nearby-model spatial query using EPSG:4326 inputs.
Default nearby searches to 200 meters and five results.

Integrate investigation messaging/presentation, health/readiness and typed history;
remove duplicate web search and fix online simulation and compressed baseline writes.
Include project migrations 023-025; keep local credentials and demo seeding excluded.

Validation: 319 focused pytest checks; real PostGIS temporary-table regression;
read-only Jinqian bridge radius comparison; cross-language MCP discovery/calls.
2026-10-19 18:46:58 +08:00

84 lines
2.7 KiB
Python

"""Finite read scopes available to operational investigations."""
from datetime import timedelta
from typing import Literal
from pydantic import Field, JsonValue, model_validator
from app.domain.schemas.shared import NonEmptyStr, StrictModel
from app.domain.schemas.workbench_runtime import WorkbenchDateTime
TaskDataSource = Literal[
"workbench_runtime", "scada_devices", "scada_readings", "peripheral_points",
"peripheral_work_orders", "peripheral_observations", "peripheral_test_data",
]
McpSnapshotSource = Literal[
'run_simulation',
'run_contaminant_simulation',
'analyze_valve_closure',
'analyze_flushing',
'analyze_pressure_regulation',
'optimize_sensor_placement',
'run_burst_detection',
'run_burst_location',
'analyze_valve_isolation',
'run_leakage_identification',
'get_element_properties',
'list_elements',
'get_network_options',
'get_network_schema',
'list_scada_devices',
'get_scada_device',
'query_scada_readings',
'query_model_baseline_series',
'get_model_baseline_at_time',
'query_model_baseline_field',
'query_analysis_series',
'query_analysis_values',
'list_analysis_runs',
'get_analysis_run',
'list_analysis_results',
'list_sensor_placement_runs',
'get_sensor_placement_run',
'query_element_history',
'get_element_gis_properties',
'get_source_gis_properties',
'get_workbench_runtime',
'get_task_context',
'query_peripheral_data',
'get_task_evidence',
]
TaskSnapshotSource = TaskDataSource | McpSnapshotSource
class TaskDataQuery(StrictModel):
source: TaskDataSource
device_ids: list[NonEmptyStr] = Field(default_factory=list, max_length=20)
point_id: NonEmptyStr | None = None
start: WorkbenchDateTime | None = None
end: WorkbenchDateTime | None = None
@model_validator(mode="after")
def validate_window(self):
if self.source in {"scada_readings", "peripheral_observations"}:
if self.start is None or self.end is None:
raise ValueError("time series queries require start and end")
if not timedelta(0) < self.end - self.start <= timedelta(days=1):
raise ValueError("query window must be positive and at most 24 hours")
if self.source == "scada_readings" and not self.device_ids:
raise ValueError("SCADA queries require device_ids")
if self.source == "peripheral_observations" and not self.point_id:
raise ValueError("peripheral queries require point_id")
return self
class TaskDataSnapshot(StrictModel):
source: TaskSnapshotSource
source_ref: NonEmptyStr
queried_at: WorkbenchDateTime
origin: Literal["system_data", "synthetic"]
data: JsonValue
truncated: bool