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.
This commit is contained in:
@@ -38,10 +38,10 @@ def test_valve_close_analysis_uses_normalized_scheme_type(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
simulation_scenarios.simulation,
|
||||
"run_simulation",
|
||||
lambda **kwargs: captured.update(kwargs),
|
||||
lambda **kwargs: (captured.update(kwargs), {"node_results": []})[1],
|
||||
)
|
||||
|
||||
simulation_scenarios.valve_close_analysis.__wrapped__(
|
||||
saved_result = simulation_scenarios.valve_close_analysis.__wrapped__(
|
||||
name="demo",
|
||||
modify_pattern_start_time="2026-01-01T00:00:00+08:00",
|
||||
modify_valve_opening={"V1": 0.0},
|
||||
@@ -51,6 +51,13 @@ def test_valve_close_analysis_uses_normalized_scheme_type(monkeypatch):
|
||||
|
||||
assert captured["scheme_type"] == "valve_close_analysis"
|
||||
assert captured["result_db_name"] == "demo"
|
||||
assert saved_result is None # Preserve the existing REST "success" response.
|
||||
preview = simulation_scenarios.valve_close_analysis.__wrapped__(
|
||||
name="demo", modify_pattern_start_time="2026-01-01T00:00:00+08:00",
|
||||
_temporary_project="tjw_tmp_demo", persist_results=False,
|
||||
)
|
||||
assert preview == {"node_results": []}
|
||||
assert captured["persist_results"] is False
|
||||
|
||||
|
||||
def test_apply_valve_control_matches_runner_semantics(monkeypatch):
|
||||
@@ -208,6 +215,32 @@ def test_extended_simulation_stores_results_by_run_id(monkeypatch):
|
||||
assert transaction_calls == [("begin", "demo"), ("end", "demo")]
|
||||
refresh_mock.assert_called_once_with("demo")
|
||||
|
||||
preview = simulation.run_simulation(
|
||||
name="tjw_tmp_preview_test", simulation_type="extended",
|
||||
modify_pattern_start_time="2026-07-16T00:00:00+08:00",
|
||||
modify_total_duration=900, persist_results=False,
|
||||
scada_mappings=_empty_scada_mappings(simulation),
|
||||
)
|
||||
assert preview["node_results"][0]["node"] == "J1"
|
||||
assert len(storage_calls) == len(create_calls) == 1
|
||||
assert len(lifecycle_calls) == 1
|
||||
with pytest.raises(ValueError, match="isolated temporary model"):
|
||||
simulation.run_simulation(name="demo", simulation_type="extended",
|
||||
modify_pattern_start_time="2026-07-16T00:00:00+08:00", persist_results=False)
|
||||
|
||||
realtime_storage = Mock()
|
||||
monkeypatch.setattr(simulation.TimescaleInternalStorage, "store_realtime_simulation", realtime_storage)
|
||||
realtime = simulation.run_simulation(
|
||||
name="demo", simulation_type="realtime",
|
||||
modify_pattern_start_time="2026-07-16T00:00:00+08:00",
|
||||
scada_mappings=_empty_scada_mappings(simulation),
|
||||
)
|
||||
realtime_storage.assert_called_once_with(
|
||||
realtime["node_results"], realtime["link_results"],
|
||||
"2026-07-16T00:00:00+08:00", db_name="demo",
|
||||
)
|
||||
assert len(storage_calls) == len(create_calls) == len(lifecycle_calls) == 1
|
||||
|
||||
|
||||
def test_extended_simulation_marks_run_failed_when_result_storage_fails(monkeypatch):
|
||||
from app.services import simulation
|
||||
|
||||
Reference in New Issue
Block a user