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:
2026-10-19 18:46:58 +08:00
parent 2b6fc5aa52
commit be6317eb48
117 changed files with 12703 additions and 638 deletions
+38
View File
@@ -2,9 +2,16 @@ import asyncio
from contextlib import asynccontextmanager, contextmanager
from datetime import datetime, timezone
import pytest
from pydantic import ValidationError
from app.core.config import Settings, settings
from app.infra.db.timescaledb.repositories.realtime import RealtimeRepository
SNAPSHOT_BUDGET_SQL = "SELECT set_config('timescaledb.max_tuples_decompressed_per_dml_transaction', %s, true)"
class _FakeCursor:
def __init__(self):
self.calls: list[tuple[str, tuple]] = []
@@ -113,10 +120,12 @@ def test_realtime_node_and_link_replacement_share_outer_transaction(monkeypatch)
assert conn.transactions == 1
assert calls == ["nodes", "links"]
assert [query for query, _params in conn.calls] == [
SNAPSHOT_BUDGET_SQL,
"SELECT pg_advisory_xact_lock(hashtextextended(%s::text, 1))",
"DELETE FROM realtime.node_results WHERE time = %s",
"DELETE FROM realtime.link_results WHERE time = %s",
]
assert conn.calls[0][1] == (str(settings.TIMESCALEDB_REALTIME_MAX_DECOMPRESSED_TUPLES),)
def test_realtime_batch_rejects_multiple_timestamps_before_writing():
@@ -170,7 +179,36 @@ def test_empty_realtime_side_is_deleted_as_part_of_snapshot_replacement():
)
assert [query for query, _params in conn.calls] == [
SNAPSHOT_BUDGET_SQL,
"SELECT pg_advisory_xact_lock(hashtextextended(%s::text, 1))",
"DELETE FROM realtime.node_results WHERE time = %s",
"DELETE FROM realtime.link_results WHERE time = %s",
]
@pytest.mark.parametrize("side", ["nodes", "links"])
@pytest.mark.parametrize("asynchronous", [False, True])
def test_all_snapshot_batch_writers_use_configured_local_budget(monkeypatch, side, asynchronous):
monkeypatch.setattr(settings, "TIMESCALEDB_REALTIME_MAX_DECOMPRESSED_TUPLES", 1_200_000)
conn = _AsyncEmptySnapshotConnection() if asynchronous else _SyncTransactionConnection()
if asynchronous:
async def copy(*_):
pass
monkeypatch.setattr(RealtimeRepository, f"_copy_{side}", copy)
else:
monkeypatch.setattr(RealtimeRepository, f"_copy_{side}_sync", lambda *_: None)
method = getattr(RealtimeRepository, f"insert_{side}_batch" + ("" if asynchronous else "_sync"))
rows = [{"time": "2026-10-08T04:00:00Z", "id": "fixture"}]
if asynchronous:
asyncio.run(method(conn, rows))
else:
method(conn, rows)
assert conn.calls[0] == (SNAPSHOT_BUDGET_SQL, ("1200000",))
assert "pg_advisory_xact_lock" in conn.calls[1][0]
assert conn.calls[2][0].startswith("DELETE FROM realtime.")
@pytest.mark.parametrize("value", [0, -1, 2_147_483_648])
def test_snapshot_budget_must_remain_a_finite_positive_postgres_limit(value):
with pytest.raises(ValidationError):
Settings(TIMESCALEDB_REALTIME_MAX_DECOMPRESSED_TUPLES=value, _env_file=None)