Files
OpenJarvis/tests/learning/test_learning_api.py
05f2c02131 feat: Algolia DocSearch + learning subsystem reorganization (#43)
* chore: create learning subdirectory structure (routing, agents, intelligence)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: extract classify_query to routing/_utils.py

Move the classify_query() function and its regex patterns into a shared
utility module so multiple routing policies can import it without
depending on the full trace_policy module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move routing files to learning/routing/ subdirectory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: create LearnedRouterPolicy merging trace-driven + SFT routing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add conditional Algolia DocSearch integration

Add Algolia DocSearch as an optional search upgrade — native lunr.js
search remains the default until credentials are configured. Includes
CDN assets, Jinja2 conditional config injection, init script with
graceful fallback, light/dark theme CSS, improved search tokenization
for snake_case/dotted identifiers, and search boosts for key pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move agent_evolver and skill_discovery to learning/agents/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move learning/orchestrator to learning/intelligence/orchestrator

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: delete removed learning policies, rewrite __init__.py, clean up api_routes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add SFT/GRPO/DSPy/GEPA config dataclasses, update LearningConfig

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add general-purpose SFT trainer (intelligence/sft_trainer.py)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update stale imports in multi_model_router example

Update imports to use new learning/routing/ paths after the
subdirectory reorganization. Replace BanditRouterPolicy with
LearnedRouterPolicy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add general-purpose GRPO trainer (intelligence/grpo_trainer.py)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add DSPy agent optimizer (agents/dspy_optimizer.py)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add GEPA agent optimizer (agents/gepa_optimizer.py)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add learning-dspy and learning-gepa optional dependency extras

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update integration test to check for learned policy instead of grpo

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: clean up stale APIs and unused params in examples

- deep_research: remove system_prompt and max_turns params not accepted
  by Jarvis.ask(), inline system prompt into the query instead
- doc_qa: remove unused --top-k CLI arg that was never passed to the API
- multi_model_router: fix select_model() call to match single-arg signature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: import SFT/GRPO trainers in intelligence/__init__.py for registry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove .md file changes from PR

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: restore search boost frontmatter for key docs pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 21:34:31 -07:00

82 lines
2.2 KiB
Python

"""Tests for the Learning Dashboard API endpoints."""
from __future__ import annotations
import pytest
fastapi = pytest.importorskip("fastapi")
starlette = pytest.importorskip("starlette")
from fastapi import FastAPI # noqa: E402
from starlette.testclient import TestClient # noqa: E402
from openjarvis.server.api_routes import learning_router # noqa: E402
def _make_app() -> FastAPI:
"""Create a minimal FastAPI app with the learning router included."""
app = FastAPI()
app.include_router(learning_router)
return app
def _client() -> TestClient:
return TestClient(_make_app())
# ---- /v1/learning/stats tests ----
def test_learning_stats_returns_200():
"""GET /v1/learning/stats should return 200."""
client = _client()
resp = client.get("/v1/learning/stats")
assert resp.status_code == 200
def test_learning_stats_has_all_sections():
"""Response must contain skill_discovery section."""
client = _client()
data = client.get("/v1/learning/stats").json()
assert "skill_discovery" in data
assert "available" in data["skill_discovery"]
# ---- /v1/learning/policy tests ----
def test_learning_policy_returns_200():
"""GET /v1/learning/policy should return 200."""
client = _client()
resp = client.get("/v1/learning/policy")
assert resp.status_code == 200
def test_learning_policy_has_expected_keys():
"""Response must include enabled, routing, intelligence, agent, metrics."""
client = _client()
data = client.get("/v1/learning/policy").json()
assert "enabled" in data
assert "routing" in data
assert "intelligence" in data
assert "agent" in data
assert "metrics" in data
def test_learning_policy_routing_structure():
"""The routing section should contain policy name and min_samples."""
client = _client()
data = client.get("/v1/learning/policy").json()
routing = data["routing"]
assert "policy" in routing
assert "min_samples" in routing
assert isinstance(routing["policy"], str)
assert isinstance(routing["min_samples"], int)
def test_learning_policy_enabled_is_bool():
"""The enabled field should be a boolean."""
client = _client()
data = client.get("/v1/learning/policy").json()
assert isinstance(data["enabled"], bool)