diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 028b4d9a..6f3ce052 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: uses: astral-sh/setup-uv@v8.0.0 - name: Install dependencies - run: uv sync --extra dev --extra framework-comparison + run: uv sync --extra dev --extra framework-comparison --extra server - name: Ruff check run: uv run ruff check src/ tests/ @@ -57,7 +57,7 @@ jobs: uses: astral-sh/setup-uv@v8.0.0 - name: Install dependencies - run: uv sync --extra dev --extra framework-comparison + run: uv sync --extra dev --extra framework-comparison --extra server - name: Build Rust extension run: uv run maturin develop --manifest-path rust/crates/openjarvis-python/Cargo.toml diff --git a/src/openjarvis/server/agent_manager_routes.py b/src/openjarvis/server/agent_manager_routes.py index 3ab4b65a..a0e7e079 100644 --- a/src/openjarvis/server/agent_manager_routes.py +++ b/src/openjarvis/server/agent_manager_routes.py @@ -1303,10 +1303,11 @@ async def _stream_managed_agent( def create_agent_manager_router( manager: AgentManager, -) -> Tuple[APIRouter, APIRouter, APIRouter, APIRouter]: +) -> Tuple[APIRouter, APIRouter, APIRouter, APIRouter, APIRouter]: """Create FastAPI routers with agent management endpoints. - Returns a 4-tuple: (agents_router, templates_router, global_router, tools_router). + Returns a 5-tuple: + ``(agents_router, templates_router, global_router, tools_router, sendblue_router)``. """ agents_router = APIRouter(prefix="/v1/managed-agents", tags=["managed-agents"]) templates_router = APIRouter(prefix="/v1/templates", tags=["templates"]) diff --git a/tests/evals/test_dataset_splits_integration.py b/tests/evals/test_dataset_splits_integration.py index 90034e53..e312ec21 100644 --- a/tests/evals/test_dataset_splits_integration.py +++ b/tests/evals/test_dataset_splits_integration.py @@ -23,10 +23,28 @@ def test_train_and_test_are_disjoint_per_provider(mod_name, cls_name): mod = importlib.import_module(mod_name) ds_cls = getattr(mod, cls_name) - train_ds = ds_cls() - train_ds.load(split="train", seed=42) - test_ds = ds_cls() - test_ds.load(split="test", seed=42) + # Some providers wrap gated HuggingFace datasets (GAIA, + # LiveResearchBench) or optional upstream packages (TauBench needs + # the ``tau2`` package). When the local environment lacks the + # required HF auth token or the optional install, the dataset + # raises rather than returns empty — skip cleanly so a CI runner + # without secrets doesn't fail the suite. The split-disjointness + # invariant under test is still exercised by every provider whose + # data IS available. + try: + train_ds = ds_cls() + train_ds.load(split="train", seed=42) + test_ds = ds_cls() + test_ds.load(split="test", seed=42) + except (ImportError, ModuleNotFoundError) as exc: + pytest.skip(f"{cls_name}: optional upstream not installed ({exc})") + except Exception as exc: # noqa: BLE001 — HF errors live in many modules + msg = str(exc) + if "GatedRepo" in type(exc).__name__ or "gated" in msg.lower(): + pytest.skip(f"{cls_name}: gated dataset, no HF auth ({type(exc).__name__})") + if "DatasetNotFound" in type(exc).__name__: + pytest.skip(f"{cls_name}: dataset not accessible ({type(exc).__name__})") + raise train_ids = {r.record_id for r in train_ds.iter_records()} test_ids = {r.record_id for r in test_ds.iter_records()} diff --git a/tests/server/test_agent_manager_routes.py b/tests/server/test_agent_manager_routes.py index 62373c86..738144db 100644 --- a/tests/server/test_agent_manager_routes.py +++ b/tests/server/test_agent_manager_routes.py @@ -38,11 +38,8 @@ class TestAgentManagerRoutes: app = FastAPI() routers = create_agent_manager_router(manager) - agents_router, templates_router, global_router, tools_router = routers - app.include_router(agents_router) - app.include_router(templates_router) - app.include_router(global_router) - app.include_router(tools_router) + for r in routers: + app.include_router(r) return TestClient(app) def test_list_agents_empty(self, client): @@ -287,11 +284,8 @@ class TestAgentManagerStreaming: app.state.bus = None routers = create_agent_manager_router(manager) - agents_router, templates_router, global_router, tools_router = routers - app.include_router(agents_router) - app.include_router(templates_router) - app.include_router(global_router) - app.include_router(tools_router) + for r in routers: + app.include_router(r) return TestClient(app) def test_send_message_stream(self, manager, stream_client): diff --git a/tests/server/test_connectors_router.py b/tests/server/test_connectors_router.py index 6ff2db3e..d5421d33 100644 --- a/tests/server/test_connectors_router.py +++ b/tests/server/test_connectors_router.py @@ -19,7 +19,11 @@ def app(): _app = FastAPI() router = create_connectors_router() - _app.include_router(router, prefix="/v1") + # The router already carries ``prefix="/v1/connectors"``. The real + # ``server/app.py`` mounts it with ``include_router(router)`` — adding + # a second ``prefix="/v1"`` here would produce ``/v1/v1/connectors`` + # and every request would 404. + _app.include_router(router) return TestClient(_app) @@ -83,7 +87,12 @@ def test_sync_status(app): def test_trigger_sync(app, tmp_path: Path) -> None: - """POST /v1/connectors/obsidian/sync triggers an incremental sync.""" + """POST /v1/connectors/obsidian/sync triggers an incremental sync. + + The endpoint is intentionally fire-and-forget — it starts the sync in + a background thread and returns immediately with ``status=started``. + Sync progress is observable via the separate ``GET .../sync`` endpoint. + """ vault = tmp_path / "vault" vault.mkdir() (vault / "note.md").write_text("# Test note\n\nContent here.") @@ -91,4 +100,5 @@ def test_trigger_sync(app, tmp_path: Path) -> None: resp = app.post("/v1/connectors/obsidian/sync") assert resp.status_code == 200 data = resp.json() - assert data["chunks_indexed"] >= 1 + assert data["connector_id"] == "obsidian" + assert data["status"] in {"started", "already_syncing"}