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:
@@ -9,7 +9,10 @@ per-use read, ``app/api/chat.py``'s ``plan_turn`` gate), the shared
|
||||
snapshot, ``app/api/chat.py::get_llm``), and the chat concurrency
|
||||
semaphore (``chat_max_concurrent``). Plus the kill-switch counterpart
|
||||
(``BOR_SETTINGS_DB=0`` with rows present → env values are back) and
|
||||
the ``scripts/``-consumer surface (``import_extension_set``).
|
||||
the ``scripts/``-consumer surface (``import_extension_set``), and the
|
||||
phase-172 thinking level (``llm_thinking_level`` — the value the LLM
|
||||
layer reads per request via ``get_settings()``; the off switch is
|
||||
live-settable, A2).
|
||||
|
||||
The rows are inserted directly through the ``db`` session (the admin
|
||||
API is task 04); the save itself is ``invalidate_settings()`` —
|
||||
@@ -160,6 +163,47 @@ def test_llm_client_repoints_on_the_next_save(db: Session) -> None:
|
||||
assert llm.settings.llm_chat_model == "gpt-second"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# the thinking level: save/reset resolve the live value (phase 172, task 02)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_llm_thinking_level_live_apply_no_restart(
|
||||
db: Session, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Phase 172 (task 02): the thinking level follows the overlay
|
||||
live — a save (the PUT's write, minus the API: ``_save`` +
|
||||
``invalidate_settings()`` is exactly what task 04's PUT/DELETE
|
||||
call after the write) resolves
|
||||
``get_settings().llm_thinking_level`` WITHOUT a restart (the proof
|
||||
the LLM layer — task 03 reads the setting per request via
|
||||
``get_settings()`` — picks the override up live), the EMPTY value
|
||||
resolves live too (the off switch is live-settable, A2/A4), and a
|
||||
reset (the DELETE) returns the env value.
|
||||
"""
|
||||
# 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"
|
||||
_save(db, "llm_thinking_level", "high")
|
||||
invalidate_settings()
|
||||
assert get_settings().llm_thinking_level == "high" # NO restart
|
||||
# The off switch is live-settable too (A2/A4): the empty value
|
||||
# resolves through the overlay, not stripped or coerced.
|
||||
_save(db, "llm_thinking_level", "")
|
||||
invalidate_settings()
|
||||
assert get_settings().llm_thinking_level == ""
|
||||
# The reset returns the env value (no process restart in between —
|
||||
# the LLM layer re-reads per request, task 03).
|
||||
db.execute(
|
||||
text("DELETE FROM app_settings WHERE key = 'llm_thinking_level'")
|
||||
)
|
||||
db.commit()
|
||||
invalidate_settings()
|
||||
assert get_settings().llm_thinking_level == "low"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# the chat concurrency semaphore follows the saved cap
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user