feat(scada): add project monitoring replay
This commit is contained in:
@@ -66,8 +66,23 @@ def page_result(rows, args):
|
||||
async def authorize_query(
|
||||
scope: QueryScope, binding: BoundContext, tool: QueryTool, args: BaseModel
|
||||
) -> None:
|
||||
replay_context = getattr(binding, "replay_context", None)
|
||||
if tool.name not in binding.tool_cap:
|
||||
raise HTTPException(403, "Query is outside the captured tool catalog")
|
||||
if replay_context:
|
||||
from app.services.scada_replay_queries import check_replay_window
|
||||
allowed = {"get_task_context", "get_task_evidence", "list_scada_devices", "get_scada_device",
|
||||
"query_scada_readings", "get_network_schema", "run_burst_location",
|
||||
"get_calculation_job", "get_calculation_result", "list_calculation_jobs"}
|
||||
if tool.name not in allowed:
|
||||
raise HTTPException(403, "回放调查当前仅开放冻结 SCADA 证据与模型目录查询;请使用 query_scada_readings")
|
||||
if tool.name == "query_scada_readings":
|
||||
check_replay_window(replay_context, args.start, args.end)
|
||||
if tool.name == "run_burst_location":
|
||||
if args.data_source != "monitoring" or args.scada_normal_start is None or args.scada_normal_end is None:
|
||||
raise HTTPException(422, "回放定位只支持显式异常窗和正常对照窗的 monitoring 输入")
|
||||
check_replay_window(replay_context, args.scada_burst_start, args.scada_burst_end)
|
||||
check_replay_window(replay_context, args.scada_normal_start, args.scada_normal_end)
|
||||
permissions = permissions_for_context(scope.project)
|
||||
if tool.mutating:
|
||||
if binding.purpose != "ordinary_chat" or binding.task_id is not None or scope.project.project_role != "member":
|
||||
@@ -149,7 +164,37 @@ async def execute_query(
|
||||
gaps = []
|
||||
source_ref = "mcp:" + str(uuid4())
|
||||
evidence_id = None
|
||||
if tool.computation:
|
||||
replay_context = getattr(binding, "replay_context", None)
|
||||
if name == "query_scada_readings" and replay_context:
|
||||
from app.services.scada_replay_queries import replay_snapshot_rows
|
||||
rows = await replay_snapshot_rows(conn, scope.project.project_id, replay_context,
|
||||
args.device_ids, args.start, args.end, args.limit + 1, args.offset)
|
||||
data, page, truncated = page_result(rows, args)
|
||||
origin = "synthetic"
|
||||
gaps.append("历史数据回放证据,仅覆盖该轮调查已提交的批次,不表示现场实时观测。")
|
||||
elif name == "run_burst_location" and replay_context:
|
||||
from app.mcp.analysis_service import calculate_replay_burst_location
|
||||
from app.services.scada_replay_queries import replay_burst_location_inputs
|
||||
|
||||
parameters = await replay_burst_location_inputs(
|
||||
conn, scope.project.project_id, replay_context, args,
|
||||
)
|
||||
await conn.commit()
|
||||
async with scope.simulation_routing():
|
||||
result = await calculate_replay_burst_location(
|
||||
parameters,
|
||||
network=scope.project.project_code,
|
||||
username=scope.user.username,
|
||||
)
|
||||
data = {
|
||||
"parameters": args.model_dump(mode="json", exclude={"context_handle"}),
|
||||
"result": result,
|
||||
}
|
||||
origin = "synthetic"
|
||||
gaps = [
|
||||
"定位只使用任务知识截止前已固化的回放清洗输出;候选排序依赖漏量假设、模型和测点覆盖,仍需现场核实。"
|
||||
]
|
||||
elif tool.computation:
|
||||
from app.mcp.analysis_service import TIMESCALE_CALCULATIONS, calculate
|
||||
|
||||
# Context/receipt reads may have started an implicit transaction. Release
|
||||
|
||||
Reference in New Issue
Block a user