phase: 182_verbatim_show_text
**Phase 182 — final verification pass (all 8 tasks already complete; this was verification + docs + one defect fix).**
- Verified: `app/rag/verbatim.py` (locator grammar, `splitlines()` slice, line-boundary cap, `resolve_answer_blocks`), `SHOW_TEXT_TOOL` + `shown_texts`, `SHOW_TEXT_CLAUSE`, `done.answer_text` (9 fields, key dropped when empty) + `ChatMessageRecord.answer_text` (≤50, 600 000-char cap counted in the 8 M budget), `verbatim.js` + 4 `{verbatim:true}` renderers, `Containerfile` minify step, `.env.example` 3 vars.
- `uv run python -c "…answer_text, show_text_max_chars, show_text_max_blocks"` → `True 12000 5`; each negative refuses startup naming its field; `0` accepted as inert ✅
- `bash .agents/validate.sh` → **validation OK**: 4320 unit+integration tests green, `TOTAL 6849 17 → 99%` (gate app/ >90% OK), `ruff check .` "All checks passed!", `pyright` 0 errors (re-run after my edits, 08:28).
- E2E, each in isolation `--no-cov`: `test_verbatim_show_text.py` 13 passed (panel bytes == `documents.content`, server caption, clipboard == server string, `/document.html?source=…&path=…`, honest unresolved state, reload+share, `show_image` regression, flag-off app) ✅; green: `test_answer_images` `test_harness_aligned_tools` `test_agent_document_tools` `test_markdown_tables` `test_markdown_inline_links_images` `test_svg_document_preview` `test_smoke` `test_document_viewer` `test_markdown_blockquotes` `test_chat_persistence` `test_thinking_timeline` `test_chat_rag` `test_settings_mobile_value_width`.
- **Defect found & fixed (pre-existing, not phase 182):** `tests/e2e/test_admin_settings_panel.py::test_admin_sees_groups_and_source_badges` failed — its whole-page `assert "reese" not in page.content()` tripped on the shell's onboarding chips, which follow the newest saved chats in the one shared E2E DB (a leftover `reeselink.json` question from a tool suite). Scoped the strict sweep to `.settings-shell` and kept a whole-page `reese:reese` credential needle → 12 passed with the leftovers still present.
- Docs: README fixed 2 inconsistencies — Quick Start omitted the **required** `BOR_ADMIN_PASSWORD`/`BOR_SESSION_SECRET` (the app fail-loud refuses boot) and the broken anchor `#chat--` → `#chat-`; full re-read of README (1816 lines) + AGENTS confirmed the phase-182 feature/settings/log/UI-contract text matches the code, and every `.env.example` var + every `Settings` field is documented.
- Notable: kept `resolve_answer_blocks` synchronous on the SSE terminal path (bounded indexed SELECTs, matching the existing `query_log` precedent and the phase's documented fence-lookup bound); no live-infra changes made.
- Next pending phase: none — `todo/` holds only 182 (its 8 task files are in `complete/`; the harness commits + moves `00_phase.md`).
This commit is contained in:
@@ -123,8 +123,12 @@ def test_agent_tools_off_is_the_three_base_tools() -> None:
|
||||
"""LOCKED A2: toggle off (the default) → exactly the three base
|
||||
tools, element-for-element equal to ``AGENT_TOOLS`` — and a FRESH
|
||||
list (not the constant), so a caller mutating the offer can never
|
||||
mutate the constant."""
|
||||
off = agent_tools(_settings())
|
||||
mutate the constant. Phase 182 (task 03) pin update, deliberate:
|
||||
the flag pin passes ``answer_text=False`` explicitly — with
|
||||
``answer_text`` ON (the shipped default) the offer additionally
|
||||
carries ``show_text`` (pinned in ``tests/unit/test_agent.py``); the
|
||||
``answer_images`` gate itself is unchanged."""
|
||||
off = agent_tools(_settings(answer_text=False))
|
||||
assert [t["function"]["name"] for t in off] == ["ls", "read", "grep"]
|
||||
assert off == AGENT_TOOLS # element-for-element
|
||||
assert off is not AGENT_TOOLS # a fresh list, never the constant itself
|
||||
@@ -136,8 +140,12 @@ def test_agent_tools_on_appends_show_image() -> None:
|
||||
"""Toggle on → the three base tools (byte-identical) plus the 4th
|
||||
tool, ``show_image`` — the offer list the grounded turn passes to
|
||||
the model request (LOCKED A2: ``BOR_ANSWER_IMAGES`` gates ONLY the
|
||||
offer; the base three are unchanged)."""
|
||||
on = agent_tools(_settings(answer_images=True))
|
||||
offer; the base three are unchanged). Phase 182 (task 03) pin
|
||||
update, deliberate: ``answer_text=False`` isolates the
|
||||
``answer_images`` gate — with ``answer_text`` ON (the shipped
|
||||
default) ``show_text`` rides LAST (pinned in
|
||||
``tests/unit/test_agent.py``)."""
|
||||
on = agent_tools(_settings(answer_images=True, answer_text=False))
|
||||
assert [t["function"]["name"] for t in on] == ["ls", "read", "grep", "show_image"]
|
||||
assert on[:3] == AGENT_TOOLS # the base three byte-identical
|
||||
assert on[3] == SHOW_IMAGE_TOOL
|
||||
@@ -166,7 +174,11 @@ def test_run_agent_gates_the_show_image_offer() -> None:
|
||||
"""The wiring pin (completion criteria): a grounded turn's offer
|
||||
(the ``tools`` on the model request, ``max_rounds`` > 0) is the
|
||||
three base tools when the toggle is off — element-for-element the
|
||||
pre-phase-124 list — and gains ``show_image`` only when it is on."""
|
||||
pre-phase-124 list — and gains ``show_image`` only when it is on.
|
||||
Phase 182 (task 03) pin update, deliberate: both apps pass
|
||||
``answer_text=False`` to isolate the ``answer_images`` gate (with
|
||||
the shipped default ON, ``show_text`` additionally rides last —
|
||||
pinned in ``tests/unit/test_agent.py``)."""
|
||||
|
||||
class _ScriptedLLM:
|
||||
"""One canned content-only round; records the ``tools`` every
|
||||
@@ -207,12 +219,12 @@ def test_run_agent_gates_the_show_image_offer() -> None:
|
||||
pass
|
||||
|
||||
llm_off = _ScriptedLLM()
|
||||
asyncio.run(_consume(llm_off, _settings()))
|
||||
asyncio.run(_consume(llm_off, _settings(answer_text=False)))
|
||||
assert len(llm_off.requests) == 1
|
||||
assert llm_off.requests[0][1] == AGENT_TOOLS # off: element-for-element pre-124
|
||||
|
||||
llm_on = _ScriptedLLM()
|
||||
asyncio.run(_consume(llm_on, _settings(answer_images=True)))
|
||||
asyncio.run(_consume(llm_on, _settings(answer_images=True, answer_text=False)))
|
||||
sent = llm_on.requests[0][1]
|
||||
assert sent is not None # the grounded turn (max_rounds > 0) offers tools
|
||||
assert [t["function"]["name"] for t in sent] == [
|
||||
@@ -427,14 +439,24 @@ def test_plan_turn_grounded_carries_clause_exactly_when_toggle_on() -> None:
|
||||
IDENTICAL to the pre-task build when ``answer_images`` is off (the
|
||||
default — the pre-phase pins pass untouched) and gains the clause
|
||||
(inside ``<tools>``) exactly when it is on."""
|
||||
off = _plan3(0.9, _settings())
|
||||
off_settings = _settings()
|
||||
off = _plan3(0.9, off_settings)
|
||||
assert off.deflected is False
|
||||
assert off.system_prompt == build_high_prompt([_P3_DOC])
|
||||
# Phase 182 (task 04): the reconstruction mirrors the OTHER display
|
||||
# clause's flag too (BOR_ANSWER_TEXT, default ON) so this pin stays
|
||||
# about answer_images alone — the show_text clause is pinned in
|
||||
# tests/unit/test_prompts.py.
|
||||
assert off.system_prompt == build_high_prompt(
|
||||
[_P3_DOC], show_text=off_settings.answer_text
|
||||
)
|
||||
assert SHOW_IMAGE_CLAUSE not in off.system_prompt
|
||||
|
||||
on = _plan3(0.9, _settings(answer_images=True))
|
||||
on_settings = _settings(answer_images=True)
|
||||
on = _plan3(0.9, on_settings)
|
||||
assert on.deflected is False
|
||||
assert on.system_prompt == build_high_prompt([_P3_DOC], show_image=True)
|
||||
assert on.system_prompt == build_high_prompt(
|
||||
[_P3_DOC], show_image=True, show_text=on_settings.answer_text
|
||||
)
|
||||
assert SHOW_IMAGE_CLAUSE in on.system_prompt
|
||||
assert on.system_prompt.index("<tools>") < on.system_prompt.index(SHOW_IMAGE_CLAUSE)
|
||||
assert on.system_prompt.index(SHOW_IMAGE_CLAUSE) < on.system_prompt.index("</tools>")
|
||||
|
||||
Reference in New Issue
Block a user