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:
+402
-2
@@ -662,7 +662,10 @@ Implements just enough of the aipi surface:
|
||||
- user message containing ``show me the picture of``
|
||||
(``SHOW_IMAGE_TRIGGER``, phase 124 task 07 — the image-chips-and-
|
||||
answers suite ``tests/e2e/test_answer_images.py``) **and** the
|
||||
system prompt contains ``show_image`` (the tool clause's presence
|
||||
system prompt carries the show_image clause's marker
|
||||
(:data:`_SHOW_IMAGE_CLAUSE_MARKER` — a sentence only the image
|
||||
clause carries, so the phase-182 ``show_text`` clause's pointer to
|
||||
``show_image`` never trips it; the tool clause's presence
|
||||
— the ``BOR_ANSWER_IMAGES`` toggle's server-side marker: the
|
||||
clause rides inside the HIGH prompt's ``<tools>`` section ONLY
|
||||
when the toggle is on, so on a default-OFF app the trigger NEVER
|
||||
@@ -691,6 +694,62 @@ Implements just enough of the aipi surface:
|
||||
phrase — the phase-71/72/94/118 ordering convention); verified
|
||||
2026-09-26: no existing E2E question or fixture file contains the
|
||||
phrase, so every other suite is unaffected.
|
||||
- user message containing ``show me the exact text of``
|
||||
(``SHOW_TEXT_TRIGGER``, phase 182 task 08 — the verbatim-display suite
|
||||
``tests/e2e/test_verbatim_show_text.py``) **and** the system prompt
|
||||
carries the show_text clause's marker
|
||||
(:data:`_SHOW_TEXT_CLAUSE_MARKER` — a sentence only the TEXT clause
|
||||
carries, the exact mirror of ``_SHOW_IMAGE_CLAUSE_MARKER``, so a
|
||||
``BOR_ANSWER_TEXT=0`` app never fires it) -> the deterministic
|
||||
SHOW_TEXT flow, discriminated statelessly from the tool results
|
||||
(streaming only). The question carries the scripted target — a
|
||||
combined ``source/path`` with an optional ``12-40`` line range and an
|
||||
optional ``describe it without a block`` marker
|
||||
(``SHOW_TEXT_NO_FENCE_MARKER``):
|
||||
* request 1 (``tools`` offered, no tool result yet): stream ONLY
|
||||
``tool_calls`` deltas — ``show_text`` with ``{"path": <target>}``
|
||||
plus ``offset``/``limit`` when the question named a range
|
||||
(synthetic id ``call_show_text``); the target comes from the
|
||||
QUESTION (not the seed), which is what lets one trigger drive a
|
||||
text doc, an image doc (the LOCKED-A6 refusal) and an
|
||||
out-of-range request;
|
||||
* the follow-up request (any ``tool``-role result — a refusal means
|
||||
"stop calling" too): the FINAL answer — prose, one
|
||||
`` ```bor <locator> `` fence whose BODY is a DELIBERATELY
|
||||
CORRUPTED copy of the slice the tool returned (one flipped
|
||||
character + a trailing space via
|
||||
:func:`corrupt_verbatim_line`, plus a line carrying
|
||||
``SHOW_TEXT_MODEL_BODY_MARKER``), then a SECOND standalone
|
||||
`` ```bor `` fence for the OTHER seeded text document when the show
|
||||
SUCCEEDED (the answer-order half of the contract; a refused turn
|
||||
stays a single-fence answer so the honest-state cases are clean), then
|
||||
one ordinary
|
||||
`` ```bash `` block (the model's own, A5's Copy control) — unless
|
||||
the question carried ``SHOW_TEXT_NO_FENCE_MARKER``, which drops
|
||||
every fence so the shown block lands UNLOCATED (the client's
|
||||
append path, above ``.sources``).
|
||||
Checked BEFORE the plain ``TOOLS_TRIGGER`` flow (disjoint trigger
|
||||
phrase — the phase-71/72/94/118 ordering convention); no existing E2E
|
||||
question or fixture file contains the phrase.
|
||||
- user message containing ``put the block inline``
|
||||
(``SHOW_TEXT_INLINE_TRIGGER``, phase 182 task 08, same suite) -> the
|
||||
deterministic answer with ONE `` ```bor `` locator fence and ZERO tool
|
||||
calls — the half of the contract the tool does not cover (a fence that
|
||||
appears in the answer text on its own resolves through the same
|
||||
server-side pass). Its body is the model's own claim (it never saw the
|
||||
bytes), so it carries ``SHOW_TEXT_MODEL_BODY_MARKER`` and the suite
|
||||
asserts none of it painted. NOT clause-gated on purpose: on the
|
||||
``BOR_ANSWER_TEXT=0`` app the same text lands, which is how that suite
|
||||
proves the client never paints the model's bytes even with the tool and
|
||||
the clause gone. Checked BEFORE the ``DEFLECT_MODE`` branch (the marker
|
||||
lives in the user message — the ``TABLE_TRIGGER`` convention).
|
||||
- user message containing ``show me a block i cannot find``
|
||||
(``SHOW_TEXT_MISSING_TRIGGER``, phase 182 task 08, same suite) -> the
|
||||
deterministic answer whose one `` ```bor `` fence names
|
||||
``SHOW_TEXT_MISSING_TARGET`` — a locator the server has NO document
|
||||
for, so the client must land on its honest unresolved state (no badge,
|
||||
no body, none of the model's bytes). Checked BEFORE the
|
||||
``DEFLECT_MODE`` branch, same convention.
|
||||
- user message containing ``which diagram is in your notes``
|
||||
(``DIAGRAM_TRIGGER``, phase 124 task 07 — the BUG-FIX-ONLY
|
||||
trigger, same suite) -> the deterministic ZERO-READ answer: the
|
||||
@@ -2716,6 +2775,20 @@ CONTEXT_LINE_TRIGGER = "quote the image reference"
|
||||
#: the house marker-flow convention).
|
||||
_SHOW_CONFIRM_MARKER = "Image shown to the user"
|
||||
|
||||
#: The SHOW_IMAGE flow's clause gate (phase 124, task 07) — tightened
|
||||
#: 2026-10-15 (phase 182, task 04). The gate's INTENT is "the
|
||||
#: ``show_image`` clause is in the system prompt" (the
|
||||
#: ``BOR_ANSWER_IMAGES`` toggle's server-side marker) and it was written
|
||||
#: as the loose substring check ``"show_image" in system``. Phase 182's
|
||||
#: locked ``SHOW_TEXT_CLAUSE`` ends with "For an image use `show_image`
|
||||
#: instead.", so that approximation now also matches a text-clause-only
|
||||
#: prompt and the image flow fired on the default-OFF app (the phase-124
|
||||
#: toggle-off pin failed). One sentence only the IMAGE clause carries is
|
||||
#: the exact marker: present iff ``show_image=True``, so the ON app fires
|
||||
#: exactly as before and a ``BOR_ANSWER_IMAGES=0`` app stays silent even
|
||||
#: when ``BOR_ANSWER_TEXT`` (default ON) is what mentions the tool.
|
||||
_SHOW_IMAGE_CLAUSE_MARKER = "displays a standalone image document"
|
||||
|
||||
#: The image-doc extension family (``app.rag.summarizer.IMAGE_MIMES``
|
||||
#: — phase 122's ext→mime map, imported so the mock can never drift
|
||||
#: from the app's image family): a seeded ``<documents>`` block is
|
||||
@@ -2800,7 +2873,7 @@ def _show_image_flow(body: dict[str, Any]) -> tuple[str, ...] | None:
|
||||
if SHOW_IMAGE_TRIGGER not in _user(body).lower():
|
||||
return None
|
||||
system = _system(body)
|
||||
if "show_image" not in system:
|
||||
if _SHOW_IMAGE_CLAUSE_MARKER not in system:
|
||||
return None
|
||||
doc = _seeded_image_doc(system)
|
||||
if doc is None:
|
||||
@@ -2812,6 +2885,295 @@ def _show_image_flow(body: dict[str, Any]) -> tuple[str, ...] | None:
|
||||
return ("call", f"{doc[0]}/{doc[1]}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Phase 182 (task 08): the SHOW_TEXT (verbatim display) flows
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
#: A user message containing this substring (case-insensitive) — combined
|
||||
#: with the ``show_text`` clause's marker (:data:`_SHOW_TEXT_CLAUSE_MARKER`,
|
||||
#: the ``BOR_ANSWER_TEXT`` toggle's server-side marker, exactly as
|
||||
#: ``_SHOW_IMAGE_CLAUSE_MARKER`` is phase 124's) — drives the deterministic
|
||||
#: SHOW_TEXT flow described in the module docstring: the scripted tool call
|
||||
#: on the first request, the fence-carrying final answer once a tool result
|
||||
#: exists. The TARGET lives in the question (a combined ``source/path`` +
|
||||
#: an optional ``12-40`` range + an optional :data:`
|
||||
#: SHOW_TEXT_NO_FENCE_MARKER`), which is what lets ONE trigger drive a text
|
||||
#: doc, an image doc (LOCKED A6's refusal) and a wrong-range request.
|
||||
#: Disjoint from every other trigger phrase — the phase-71/72/94/118
|
||||
#: ordering convention; no existing E2E question or fixture file contains
|
||||
#: the phrase, so every other suite is unaffected.
|
||||
SHOW_TEXT_TRIGGER = "show me the exact text of"
|
||||
|
||||
#: In the show-me question: the final answer carries NO locator fence, so
|
||||
#: the block the tool showed is UNLOCATED by the prose — the client's
|
||||
#: append path (below the answer text, above ``.sources``, phase 124's DOM
|
||||
#: order) is what renders it.
|
||||
SHOW_TEXT_NO_FENCE_MARKER = "describe it without a block"
|
||||
|
||||
#: A user message containing this substring (case-insensitive) -> the ONE
|
||||
#: locator fence with NO tool call at all (see the module docstring). Not
|
||||
#: clause-gated: the ``answer_text=False`` app receives the same text, so
|
||||
#: the suite can pin the client's own no-model-bytes rule on the kill-switch
|
||||
#: build too.
|
||||
SHOW_TEXT_INLINE_TRIGGER = "put the block inline"
|
||||
|
||||
#: A user message containing this substring (case-insensitive) -> the ONE
|
||||
#: fence naming :data:`SHOW_TEXT_MISSING_TARGET` (a locator with no row).
|
||||
SHOW_TEXT_MISSING_TRIGGER = "show me a block i cannot find"
|
||||
|
||||
#: The hallucinated locator (never seeded — the fixture's sources are
|
||||
#: ``baselab`` and the suite seeds no file of this name).
|
||||
SHOW_TEXT_MISSING_TARGET = "baselab/notes/the-file-that-is-not-there.md"
|
||||
|
||||
#: A token that exists ONLY in the model's re-typed fence BODY. The suite
|
||||
#: asserts it appears nowhere in the rendered DOM (the body is dropped at
|
||||
#: render, :mod:`app.rag.verbatim` supplies the bytes) while the answer's
|
||||
#: ordinary `` ```bash `` block — legitimately the model's — stays.
|
||||
SHOW_TEXT_MODEL_BODY_MARKER = "MODEL_RETYPED_THIS_LINE"
|
||||
|
||||
#: The ordinary (non-locator) fenced block every phase-182 answer carries —
|
||||
#: LOCKED A5's control: `.code-block` + Copy, NO badge, flag-independent.
|
||||
SHOW_TEXT_PLAIN_LANG = "bash"
|
||||
SHOW_TEXT_PLAIN_BODY = "systemctl --user start gufo.container"
|
||||
|
||||
#: The SHOW_TEXT flow's clause gate (phase 182, task 08) — one sentence
|
||||
#: :data:`app.rag.prompts.SHOW_TEXT_CLAUSE` carries and nothing else does,
|
||||
#: present iff ``answer_text=True`` (the exact mirror of
|
||||
#: :data:`_SHOW_IMAGE_CLAUSE_MARKER`, tightened for the same reason).
|
||||
_SHOW_TEXT_CLAUSE_MARKER = "displays part of a document to the user EXACTLY as stored"
|
||||
|
||||
#: The agent's ``show_text`` SUCCESS result's confirming first line
|
||||
#: (``app.rag.agent``'s ``show_text`` branch — the line ``read``'s result
|
||||
#: never carries). Kept for the wire assertion; the flow itself stops on
|
||||
#: ANY tool result, because a REFUSAL also means "do not call again" (the
|
||||
#: wrong-range and image-doc variants depend on that: the model still
|
||||
#: answers, and the fence it writes is what the client must judge honestly).
|
||||
_SHOW_TEXT_CONFIRM_MARKER = "Text shown to the user"
|
||||
|
||||
#: The target inside the question: a combined ``source/path`` plus an
|
||||
#: optional 1-based ``12-40`` / ``lines 12-40`` range — the model's CLAIM.
|
||||
#: (The server's extent is whatever the resolver returned; the suite pins
|
||||
#: the two apart.)
|
||||
_SHOW_TEXT_TARGET_RE = re.compile(
|
||||
r"(?P<path>[a-z0-9_.\-]+(?:/[a-z0-9_.\-]+)+)"
|
||||
r"(?:\s+(?:lines?\s+)?(?P<start>\d+)\s*[-\u2013]\s*(?P<end>\d+))?"
|
||||
)
|
||||
|
||||
|
||||
def corrupt_verbatim_line(line: str) -> str:
|
||||
"""The model's one-character drift on a real line (phase-182 E2E).
|
||||
|
||||
Flips the first ``a`` to ``4`` (or the last character when the line has
|
||||
no ``a``) and appends a trailing space — exactly the silent drift a
|
||||
retyping model produces, the incident the phase exists for. Exported so
|
||||
the suite can derive the SAME string from the fixture's stored text and
|
||||
assert none of it reached the DOM.
|
||||
"""
|
||||
flipped = line.replace("a", "4", 1)
|
||||
if flipped == line:
|
||||
flipped = line[:-1] + "4" if line else "4"
|
||||
return flipped + " "
|
||||
|
||||
|
||||
def _show_text_request(body: dict[str, Any]) -> tuple[str, int | None, int | None]:
|
||||
"""The scripted target ``(path, claimed_start, claimed_end)``.
|
||||
|
||||
Markdown emphasis/backticks are stripped first: the questions quote the
|
||||
path the way a person types it (``Show me the exact text of
|
||||
`baselab/a/b.md` 2-999?``), and the closing backtick sits between the
|
||||
path and its range.
|
||||
"""
|
||||
text = _user(body).lower().replace("`", "")
|
||||
match = _SHOW_TEXT_TARGET_RE.search(text)
|
||||
if match is None:
|
||||
return "", None, None
|
||||
start, end = match.group("start"), match.group("end")
|
||||
return (
|
||||
match.group("path"),
|
||||
int(start) if start else None,
|
||||
int(end) if end else None,
|
||||
)
|
||||
|
||||
|
||||
def _show_text_locator(path: str, start: int | None, end: int | None) -> str:
|
||||
"""The locator the model writes: ``source/path`` or ``source/path#12-40``."""
|
||||
return f"{path}#{start}-{end}" if start and end else path
|
||||
|
||||
|
||||
def _show_text_slice(result: str) -> str:
|
||||
"""The verbatim slice a ``show_text`` result carried (everything after its
|
||||
``lines: a-b of N`` extent line), or ``""`` when the call was refused."""
|
||||
lines = result.split("\n")
|
||||
for index, line in enumerate(lines):
|
||||
if line.startswith("lines: "):
|
||||
return "\n".join(lines[index + 1 :])
|
||||
return ""
|
||||
|
||||
|
||||
def _show_text_fence_body(slice_text: str) -> str:
|
||||
"""The deliberately corrupted copy of the slice + the sentinel line."""
|
||||
lines = [line for line in slice_text.split("\n") if line.strip()]
|
||||
if not lines:
|
||||
lines = ["the model has nothing to retype after a refusal"]
|
||||
return "\n".join(
|
||||
[corrupt_verbatim_line(lines[0]), *lines[1:], SHOW_TEXT_MODEL_BODY_MARKER]
|
||||
)
|
||||
|
||||
|
||||
def _show_text_plain_block() -> str:
|
||||
"""One ordinary fenced block — the model's own, badged nothing (A5)."""
|
||||
return f"```{SHOW_TEXT_PLAIN_LANG}\n{SHOW_TEXT_PLAIN_BODY}\n```"
|
||||
|
||||
|
||||
def _second_seeded_document(system: str, exclude: str) -> str:
|
||||
"""The OTHER text document in the ``<documents>`` seed (combined path),
|
||||
or ``""`` — the second fence's target (the answer-order half)."""
|
||||
for block in _DOCUMENT_BLOCK_RE.finditer(system):
|
||||
identity = f"{block.group('source')}/{block.group('path')}"
|
||||
if identity == exclude or identity.lower().endswith(_IMAGE_PATH_SUFFIXES):
|
||||
continue
|
||||
return identity
|
||||
return ""
|
||||
|
||||
|
||||
def _show_text_call_arguments(path: str, start: str, end: str) -> dict[str, Any]:
|
||||
"""The scripted ``show_text`` arguments: ``path`` always, ``offset`` +
|
||||
``limit`` only when the question named a range (``limit`` derived from
|
||||
the CLAIMED range — the server clamps it and the caption follows the
|
||||
server)."""
|
||||
arguments: dict[str, Any] = {"path": path}
|
||||
if start:
|
||||
first = int(start)
|
||||
last = int(end) if end else first
|
||||
arguments["offset"] = first
|
||||
arguments["limit"] = max(last - first + 1, 1)
|
||||
return arguments
|
||||
|
||||
|
||||
def _show_text_answer(body: dict[str, Any], result: str) -> str:
|
||||
"""The final answer of the SHOW_TEXT turn (prose + fences + a plain block).
|
||||
|
||||
With :data:`SHOW_TEXT_NO_FENCE_MARKER` in the question the answer carries
|
||||
NO locator fence at all — the block the tool showed then has no home in
|
||||
the prose, which is the client's APPEND path (below the answer text,
|
||||
above ``.sources``). The SECOND (other-file) fence rides only a turn whose
|
||||
show SUCCEEDED (:data:`_SHOW_TEXT_CONFIRM_MARKER`): a refused turn (the
|
||||
image document, a range past the end) is the suite's honest-state case and
|
||||
stays a single-fence answer.
|
||||
"""
|
||||
path, start, end = _show_text_request(body)
|
||||
parts = ["Here is the exact text, straight from the file:"]
|
||||
if SHOW_TEXT_NO_FENCE_MARKER not in _user(body).lower():
|
||||
parts += [
|
||||
"",
|
||||
"```bor " + _show_text_locator(path, start, end),
|
||||
_show_text_fence_body(_show_text_slice(result)),
|
||||
"```",
|
||||
]
|
||||
second = (
|
||||
_second_seeded_document(_system(body), path)
|
||||
if _SHOW_TEXT_CONFIRM_MARKER in result
|
||||
else ""
|
||||
)
|
||||
if second:
|
||||
parts += [
|
||||
"",
|
||||
"And the note file next to it, in full:",
|
||||
"",
|
||||
"```bor " + second,
|
||||
f"The model re-typed this file instead — {SHOW_TEXT_MODEL_BODY_MARKER}.",
|
||||
"```",
|
||||
]
|
||||
else:
|
||||
parts += [
|
||||
"",
|
||||
"It is on screen above — the panel holds it, so it is not repeated here.",
|
||||
]
|
||||
parts += [
|
||||
"",
|
||||
"To start it afterwards:",
|
||||
"",
|
||||
_show_text_plain_block(),
|
||||
"",
|
||||
"(Deterministic mock answer for E2E.)",
|
||||
]
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
def _show_text_flow(body: dict[str, Any]) -> tuple[str, ...] | None:
|
||||
"""Classify a phase-182 SHOW_TEXT request (see the module docstring).
|
||||
|
||||
Stateless over the messages, like the other marker flows:
|
||||
|
||||
* ``("call", path, start, end)`` — the trigger is in the question, the
|
||||
system prompt carries the ``show_text`` clause and no ``tool``-role
|
||||
result exists yet: stream ONLY the ``show_text`` tool-call delta built
|
||||
by :func:`_show_text_call_arguments` from the three strings (``""`` =
|
||||
no range).
|
||||
* ``("answer", text)`` — a ``tool``-role result is in the messages
|
||||
(success or refusal — both mean "stop calling"): the fence-carrying
|
||||
final answer.
|
||||
* ``None`` — the trigger is absent, the clause is absent (a
|
||||
``BOR_ANSWER_TEXT=0`` app: the mock behaves exactly as pre-phase), or
|
||||
the question names no ``source/path`` target.
|
||||
"""
|
||||
if SHOW_TEXT_TRIGGER not in _user(body).lower():
|
||||
return None
|
||||
if _SHOW_TEXT_CLAUSE_MARKER not in _system(body):
|
||||
return None
|
||||
path, start, end = _show_text_request(body)
|
||||
if not path:
|
||||
return None
|
||||
results = _tool_results(body)
|
||||
if results:
|
||||
return ("answer", _show_text_answer(body, results[-1]))
|
||||
return (
|
||||
"call",
|
||||
path,
|
||||
str(start) if start is not None else "",
|
||||
str(end) if end is not None else "",
|
||||
)
|
||||
|
||||
|
||||
def show_text_inline_answer(body: dict[str, Any]) -> str:
|
||||
"""The ``put the block inline`` answer: ONE locator fence, zero tool
|
||||
calls (see the module docstring)."""
|
||||
path, start, end = _show_text_request(body)
|
||||
return "\n".join(
|
||||
[
|
||||
"Sure — the block itself:",
|
||||
"",
|
||||
"```bor " + _show_text_locator(path, start, end),
|
||||
f"Run `podman generate quadlet gufo` and paste the inline block "
|
||||
f"for baselab — {SHOW_TEXT_MODEL_BODY_MARKER}.",
|
||||
"```",
|
||||
"",
|
||||
"To apply it:",
|
||||
"",
|
||||
_show_text_plain_block(),
|
||||
"",
|
||||
"(Deterministic mock answer for E2E.)",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def show_text_missing_answer() -> str:
|
||||
"""The ``show me a block i cannot find`` answer: a locator the server has
|
||||
no document for, so the client must land on its honest state."""
|
||||
return "\n".join(
|
||||
[
|
||||
"Here is the block you asked for:",
|
||||
"",
|
||||
"```bor " + SHOW_TEXT_MISSING_TARGET + "#3-4",
|
||||
f"A file that does not exist, re-typed by the model "
|
||||
f"{SHOW_TEXT_MODEL_BODY_MARKER}.",
|
||||
"```",
|
||||
"",
|
||||
"(Deterministic mock answer for E2E.)",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _summary_seed_read_flow(body: dict[str, Any]) -> tuple[str, ...] | None:
|
||||
"""Classify a phase-118 scripted summary-read request (see the
|
||||
module docstring). The question carries the scripted call (``read
|
||||
@@ -4165,6 +4527,22 @@ def compose_answer(body: dict[str, Any]) -> str:
|
||||
# the user message, so a marker question always gets the inline
|
||||
# answer whatever the gate says.
|
||||
answer = INLINE_ANSWER
|
||||
elif SHOW_TEXT_INLINE_TRIGGER in user.lower():
|
||||
# Phase 182 (task 08, the verbatim-display suite): ONE locator fence
|
||||
# and ZERO tool calls — the standalone-fence half of the contract
|
||||
# (the server resolves the bytes from the row; the model's body is
|
||||
# dropped at render). Checked BEFORE the DEFLECT_MODE branch, like
|
||||
# TABLE_TRIGGER: the marker lives in the user message, so a marker
|
||||
# question always gets the fenced answer whatever the gate says.
|
||||
# NOT gated on the show_text clause (unlike the SHOW_TEXT_TRIGGER
|
||||
# flow): on a BOR_ANSWER_TEXT=0 app the same text lands with no
|
||||
# answer_text on the wire, which is the suite's witness that the
|
||||
# client never paints the model's bytes.
|
||||
answer = show_text_inline_answer(body)
|
||||
elif SHOW_TEXT_MISSING_TRIGGER in user.lower():
|
||||
# Phase 182 (task 08): the unresolvable locator — the client's honest
|
||||
# unresolved state is the subject. Same branch convention as above.
|
||||
answer = show_text_missing_answer()
|
||||
elif HISTORY_TRIGGER in user.lower():
|
||||
# Phase 74 (TODO L4, chat history): the deterministic history
|
||||
# echo — proves on the wire that the client's prior turns (and
|
||||
@@ -5310,6 +5688,28 @@ def chat_completions(body: dict[str, Any]) -> Any:
|
||||
# TOOLS_TRIGGER flow (disjoint trigger phrases — the
|
||||
# phase-71/72/94 ordering convention; the trigger needs the
|
||||
# ``<tools>`` section, so deflected turns never hit it).
|
||||
# Phase 182 (task 08): the deterministic SHOW_TEXT marker flow —
|
||||
# checked BEFORE the plain TOOLS_TRIGGER flow (disjoint trigger
|
||||
# phrase — the phase-71/72/94/118 ordering convention; the trigger
|
||||
# needs the show_text clause, so deflected turns and a
|
||||
# BOR_ANSWER_TEXT=0 app never hit it).
|
||||
show_text = _show_text_flow(body)
|
||||
if show_text is not None:
|
||||
if show_text[0] == "call":
|
||||
stream = _tool_call_stream(
|
||||
"show_text",
|
||||
_show_text_call_arguments(show_text[1], show_text[2], show_text[3]),
|
||||
"call_show_text",
|
||||
)
|
||||
else: # "answer" — the fence-carrying final answer
|
||||
stream = _sse_stream(
|
||||
_apply_max_tokens(show_text[1], body.get("max_tokens")), 0.0
|
||||
)
|
||||
return StreamingResponse(
|
||||
stream,
|
||||
media_type="text/event-stream",
|
||||
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
|
||||
)
|
||||
turn_progress = _turn_progress_flow(body)
|
||||
if turn_progress is not None:
|
||||
stream = _turn_progress_stream(turn_progress)
|
||||
|
||||
Reference in New Issue
Block a user