phase: 95_read_truncation_cap
All gates are green. Final verification is complete — no fixes were needed; the phase is fully implemented and passing. **Phase 95 final verification report** - Verified all 3 tasks already implemented (task files in `complete/`): read cap + notice + `ToolResultPiece` (task 01), `tool_result` SSE + live/saved/shared marker (task 02), E2E suite (task 03). - Code checks passed: `BOR_READ_MAX_CHARS` (default 128 000, validator), pinned `READ_TRUNCATION_NOTICE` + `TRUNCATION_MARKER`, byte-identical at/under-cap read, holder `read_truncations` (no `tool_calls` impact), piece order (after `tool`, before next round), `ChatToolResultEvent`, `ToolCall` back-compat fields, `app.js` live/restore handlers, `shared.js`, `.truncated-note` CSS, `.env.example` entry, mock-LLM echo script. - **Tests:** `uv run pytest` → 1966 passed; `uv run pytest --cov=app --cov-report=term-missing` → all green, TOTAL **99%** (>90% gate). - **E2E:** `uv run pytest tests/e2e/test_read_truncation_cap.py -v --no-cov` → **3 passed** (frame order + live marker + LLM notice via echo; save→shared fidelity; short-read control). - **Regression (isolated):** `test_agent_document_tools` 4 ✓, `test_chat_history` 5 ✓, `test_share_chat` 4 ✓, `test_big_read_progress` 4 ✓, `test_stop_generation` 3 ✓. - **Lint/types:** `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors, 0 warnings. **Completion criteria:** ① over-cap read → first-cap-chars + marker + pinned notice — ✓ (unit-pinned: at-cap/cap+1/notice tests); ② user marker live/saved/shared — ✓ (E2E + frontend tests); ③ at/under cap byte-identical, no frame — ✓ (unit + control E2E); ④ top-2 `<documents>` retrieval untouched — ✓ (`app/rag/retriever.py` unmodified vs HEAD); ⑤ suite green, >90% coverage, ruff+pyright clean — ✓; ⑥ no completed-phase behavior change — ✓ (all gates green; commit left to harness per pass rules). - No defects found; no changes made this pass. Next pending phase: none in `todo/` (96 is the next free number).
This commit is contained in:
@@ -89,6 +89,36 @@ class ToolCallPiece:
|
||||
arguments: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ToolResultPiece:
|
||||
"""One executed tool call whose result was truncated (phase 95).
|
||||
|
||||
A15 extension (owner permission 2026-09-10, ``TODO.md`` L5 — recorded
|
||||
in the phase 95 overview ``00_phase.md``; PLAN.md is being redone by
|
||||
the owner): the ``read`` tool caps its result at
|
||||
``settings.read_max_chars`` (``BOR_READ_MAX_CHARS``, default 128 000
|
||||
chars ≈ 32k tokens). When a document is longer than the cap, the agent
|
||||
loop appends the shared ``[…truncated…]`` marker + the grep-pointer
|
||||
notice to the result the model sees AND yields one of these pieces so
|
||||
the API layer can surface the truncation to the user (an SSE
|
||||
``tool_result`` frame, task 02). It is the ONLY piece the agent loop
|
||||
yields that does not come from the model stream — it is derived from
|
||||
the executed call. ``argument`` is the combined ``source/path`` the
|
||||
model passed (the same value the matching ``tool`` frame carries),
|
||||
``chars_shown`` is the cap (``settings.read_max_chars``) and
|
||||
``chars_total`` is the document's true length — so the UI can render
|
||||
"(truncated — showing N of M chars)". ``truncated`` is always ``True``
|
||||
on a yielded piece (a non-truncated read yields nothing). Frozen like
|
||||
its siblings: an immutable wire value.
|
||||
"""
|
||||
|
||||
name: str # the tool that was executed (always "read" today)
|
||||
argument: str | None # the model's argument (the combined source/path)
|
||||
truncated: bool # always True on a yielded piece
|
||||
chars_shown: int # the cap actually kept (settings.read_max_chars)
|
||||
chars_total: int # the document's true length
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RetryPiece:
|
||||
"""One LLM request retry that is about to start (phase 67, locked A2).
|
||||
|
||||
Reference in New Issue
Block a user