feat(agent): align the document tools with the harness-trained shape — ls, read(path), grep(pattern, path?)

This commit is contained in:
2026-09-03 11:17:47 -04:00
parent 16f1cfbcaf
commit 801639efcc
55 changed files with 4031 additions and 1466 deletions
+23 -18
View File
@@ -71,24 +71,26 @@ class ChatThinkingEvent(BaseModel):
class ChatToolEvent(BaseModel):
"""SSE frame for one agent tool call (phase 37, PLAN §4 extension).
A15 extension (owner permission 2026-08-26; ``search_documents``
added in phase 68): a grounded turn may call the server-side
document tools (``list_documents`` / ``read_document`` /
``search_documents``, see :mod:`app.rag.agent`); each model-requested
A15 extension (owner permission 2026-08-26; the grep added in phase
68; phase 70 aligned the surface to the harness-trained
``ls`` / ``read`` / ``grep`` — owner permission 2026-09-03): a
grounded turn may call the server-side document tools (``ls`` /
``read`` / ``grep``, see :mod:`app.rag.agent`); each model-requested
call streams as ``{type: "tool", name: str, argument: str | null}``
ahead of the answer's ``delta`` frames. ``argument`` is the read
document's ``"source/path"`` for ``read_document``, the search
pattern for ``search_documents``, and null otherwise (a non-string
pattern — a model error the backend refuses — is null). The client
renders each frame as a "calling tool" line/state (phase 37 task 05);
the ``delta`` / ``done`` shapes are unchanged — the read document is
reflected in ``done.sources`` instead (a search adds no source: it is
a locator, locked A5).
ahead of the answer's ``delta`` frames. ``argument`` is the single
string argument the model passed — ``read``'s ``path`` (the combined
``source/path``), ``grep``'s ``pattern``, ``ls``'s ``path`` — or
null (a non-string value, a model error the backend refuses, and an
omitted argument both yield null). The client renders each frame as
a "calling tool" line/state (phase 37 task 05); the ``delta`` /
``done`` shapes are unchanged — the read document is reflected in
``done.sources`` instead (a grep adds no source: it is a locator,
locked A5).
"""
type: Literal["tool"] = "tool"
name: str # "list_documents" | "read_document" | "search_documents"
argument: str | None = None # "source/path" for read_document, pattern for search_documents
name: str # "ls" | "read" | "grep" (whatever AGENT_TOOLS names)
argument: str | None = None # the single string argument passed, or null
class ChatDoneEvent(BaseModel):
@@ -375,10 +377,13 @@ class ToolCall(BaseModel):
"""One agent tool-call record (the phase-37 ``tools`` record shape).
Mirrors the ``{name, argument}`` pair the SSE ``tool`` frames carry
(PLAN §4 extension): ``argument`` is the read document's
``"source/path"`` for ``read_document`` and null otherwise. Stored
inside :class:`ChatMessage.tools` so a saved chat restores the
"calling tool" lines pixel-identical (phase 50).
(PLAN §4 extension; phase 70): ``argument`` is the single string
argument the model passed (``read``'s combined ``source/path``,
``grep``'s pattern, ``ls``'s scope) or null. Stored inside
:class:`ChatMessage.tools` so a saved chat restores the "calling
tool" lines pixel-identical (phase 50). Saved chats persisting the
pre-phase-70 tool names still validate — ``name`` is opaque
(no migration, locked).
"""
name: str