phase: 172_thinking_level
All verification complete. Final report: **Phase 172 final verification pass — all tasks (01–05) were already complete; verified the whole phase, no code fixes needed.** - **Verified implementation:** `Settings.llm_thinking_level: str = "low"` + `CATALOG` row (`LLM (aipi)` / "Thinking level", plain: not secret/restart/overridable-exempt) + `.env.example` line under `BOR_LLM_CHAT_MODEL` + README table row; `_thinking_extra_body()` → `reasoning_effort` via `extra_body` on `chat()` + `chat_stream()` when trimmed-non-empty, key absent (byte-identical) when empty, embeddings untouched; per-turn line gains `thinking=<value>` (`-` when empty) before `thinking_chars`. - **Tests/lint/coverage (all green):** `uv run pytest` → 4084 passed · `uv run pytest --cov=app --cov-report=term-missing` → 4084 passed, `app/` **99%** (>90%) · `uv run ruff check .` → All checks passed · `uv run pyright` → 0 errors, 0 warnings. - **Completion criteria:** (1) `pytest -k "config and thinking"` 4 passed + `.env.example` grep ✓ (2) live `GET /api/admin/settings` curl shows the row (str, `low`, `default`) + integration PUT/DELETE round-trip ✓ (3) 9 mocked-client unit tests assert `extra_body` present/absent ✓ (4) log-line tests assert `low`/`high`/`-`/whitespace ✓ (5) suite + coverage + lint ✓ (6) `test_thinking_level.py` 3/3 in isolation; `test_admin_settings_panel.py` 12/12; `test_admin_settings_layout.py` 5/5 ✓ (7) atomic commit + phase move = the harness's job (task files already in `complete/`; I ran no git index/history commands). - **Documentation:** README.md reviewed in full — verified consistent (env table complete vs `.env.example`, catalog restart/non-overridable claims re-verified at runtime); AGENTS.md reviewed in full — verified consistent (no rule affected, A5 = no UI change). No changes needed. **Flag (not fixable here):** PLAN.md §9's per-turn-line spec predates the phase-172 `thinking=` field; PLAN.md is off-limits per protocol. - **Next pending phase:** none — `todo/` contains only phase 172 (the harness moves it on this pass's success).
This commit is contained in:
@@ -516,3 +516,89 @@ def test_catalog_covers_every_settings_field(admin_client) -> None:
|
||||
assert r.status_code == 200
|
||||
assert {item["key"] for item in r.json()["items"]} == set(Settings.model_fields)
|
||||
assert set(CATALOG) == set(Settings.model_fields)
|
||||
|
||||
|
||||
def test_llm_thinking_level_row_contract(
|
||||
admin_client: TestClient, db: Session, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Phase 172 (task 02): the new ``llm_thinking_level`` row behaves
|
||||
exactly like ``llm_chat_model`` — the machinery is generic over
|
||||
the catalogue (D4 / A5), so the per-key contract is: (a) present in
|
||||
the GET body (group ``LLM (aipi)``, ``str``, effective ``low``
|
||||
with no row in ``app_settings``, ``env_var`` named); (b) PUT stores
|
||||
the RAW string in ``app_settings`` (the overlay's env-native
|
||||
string form) and the response reports the new effective value;
|
||||
(c) the EMPTY value is storable (the off switch, A2/A4 — the API
|
||||
stores as-is, no allowlist); (d) DELETE resets to the env value;
|
||||
(e) the non-admin 403 gate applies (asserted once here; the full
|
||||
four-route matrix is ``test_auth_matrix_all_four_routes``).
|
||||
``test_catalogue_shape_and_sources_on_empty_table`` +
|
||||
``test_catalog_covers_every_settings_field`` already pin the row's
|
||||
PRESENCE generically — these cases pin the per-key behavior.
|
||||
"""
|
||||
# A deterministic base (machine-independent, the kill-switch test's
|
||||
# idiom): the code default, no row in the table.
|
||||
monkeypatch.delenv("BOR_LLM_THINKING_LEVEL", raising=False)
|
||||
invalidate_settings()
|
||||
assert get_settings().llm_thinking_level == "low"
|
||||
|
||||
# (a) the row: group, type, env var, effective ``low`` with NO row
|
||||
# in app_settings, not secret, not restart-required (the LLM layer
|
||||
# reads the setting per request — live).
|
||||
r = admin_client.get(API)
|
||||
assert r.status_code == 200, r.text
|
||||
item = _item(r.json(), "llm_thinking_level")
|
||||
assert item["group"] == "LLM (aipi)"
|
||||
assert item["label"] == "Thinking level"
|
||||
assert item["type"] == "str"
|
||||
assert item["env_var"] == "BOR_LLM_THINKING_LEVEL"
|
||||
assert item["secret"] is False
|
||||
assert item["restart_required"] is False
|
||||
assert item["value"] == "low"
|
||||
assert item["source"] in ("default", "env") # no row in app_settings
|
||||
assert item["has_override"] is False
|
||||
assert item["db_value"] is None
|
||||
assert item["default"] == "low"
|
||||
|
||||
# (b) PUT stores the RAW string (the overlay's D1 — env-native
|
||||
# string form) and the response reports the new effective value.
|
||||
r = admin_client.put(f"{API}/llm_thinking_level", json={"value": "high"})
|
||||
assert r.status_code == 200, r.text
|
||||
assert r.json()["value"] == "high"
|
||||
assert r.json()["source"] == "db"
|
||||
assert r.json()["has_override"] is True
|
||||
assert r.json()["db_value"] == "high"
|
||||
assert db.execute(
|
||||
text("SELECT value FROM app_settings WHERE key = 'llm_thinking_level'")
|
||||
).scalar() == "high" # stored raw, exactly as sent
|
||||
assert get_settings().llm_thinking_level == "high" # live, no restart
|
||||
|
||||
# (c) the EMPTY value is storable (the off switch, A2/A4 — the
|
||||
# API stores as-is; no allowlist, no value validation): the row
|
||||
# holds the empty string and the effective value is ``""``.
|
||||
r = admin_client.put(f"{API}/llm_thinking_level", json={"value": ""})
|
||||
assert r.status_code == 200, r.text
|
||||
assert r.json()["value"] == ""
|
||||
assert r.json()["has_value"] is False # the effective value is empty
|
||||
assert db.execute(
|
||||
text("SELECT value FROM app_settings WHERE key = 'llm_thinking_level'")
|
||||
).scalar() == "" # stored as-is (the off switch)
|
||||
assert get_settings().llm_thinking_level == ""
|
||||
|
||||
# (d) DELETE: the row is gone and the effective value is back to
|
||||
# the env value (``low`` — the base pinned above).
|
||||
r = admin_client.delete(f"{API}/llm_thinking_level")
|
||||
assert r.status_code == 200, r.text
|
||||
assert r.json()["value"] == "low"
|
||||
assert r.json()["has_override"] is False
|
||||
assert db.execute(
|
||||
text("SELECT count(*) FROM app_settings WHERE key = 'llm_thinking_level'")
|
||||
).scalar() == 0 # the row is gone
|
||||
assert get_settings().llm_thinking_level == "low"
|
||||
|
||||
# (e) the non-admin 403 gate still applies (asserted once for this
|
||||
# key — the router-wide dependency is pinned on ALL four routes in
|
||||
# ``test_auth_matrix_all_four_routes``).
|
||||
anon = TestClient(fastapi_app)
|
||||
r = anon.put(f"{API}/llm_thinking_level", json={"value": "high"})
|
||||
assert r.status_code == 403 and r.json() == {"detail": "admin only"}
|
||||
|
||||
Reference in New Issue
Block a user