fix(agent): unambiguous document listing format for LLM parsing
This commit is contained in:
+25
-18
@@ -65,9 +65,10 @@ Implements just enough of the aipi surface:
|
||||
``call_0``, no arguments), ``finish_reason: "tool_calls"``, no
|
||||
content;
|
||||
* request 2 (a ``tool``-role catalog result in the messages):
|
||||
parse the FIRST catalog line (``source/path — title`` → split on
|
||||
``" — "`` → ``rsplit("/", 1)``) and stream a ``tool_calls`` delta
|
||||
calling ``read_document`` on it (id ``call_1``);
|
||||
parse the FIRST catalog line (``source: X | path: Y | title: Z``
|
||||
— the labeled ``source:`` / ``path:`` fields, phase 63) and
|
||||
stream a ``tool_calls`` delta calling ``read_document`` on it
|
||||
(id ``call_1``);
|
||||
* request 3 (a ``tool``-role read result in the messages): a
|
||||
content answer, deterministic: ``Read <source/path>. <first 80
|
||||
chars of the read document's content>`` — so a suite can assert
|
||||
@@ -269,6 +270,14 @@ TABLE_ANSWER = (
|
||||
#: ``_execute_tool``): ``"Document <source/path>:\n<content>"``.
|
||||
_READ_RESULT_PREFIX = "Document "
|
||||
|
||||
#: One line of the agent's ``list_documents`` output (app.rag.agent
|
||||
#: ``_execute_tool``, phase 63): labeled, pipe-delimited fields —
|
||||
#: ``source: X | path: Y | title: Z`` — unambiguous for LLM parsing even
|
||||
#: when the path contains ``/`` characters.
|
||||
_CATALOG_LINE_RE = re.compile(
|
||||
r"^source: (?P<source>.+?) \| path: (?P<path>.+?) \| title: .+$"
|
||||
)
|
||||
|
||||
|
||||
def _read_results(body: dict[str, Any]) -> list[tuple[str, str]]:
|
||||
"""The read results in the messages, in order: ``(source/path, content)``.
|
||||
@@ -291,15 +300,15 @@ def _read_results(body: dict[str, Any]) -> list[tuple[str, str]]:
|
||||
|
||||
|
||||
def _catalog_docs(body: dict[str, Any]) -> list[tuple[str, str]]:
|
||||
"""Every ``source/path`` in the catalog tool result, in listing order.
|
||||
"""Every ``(source, path)`` in the catalog tool result, in listing order.
|
||||
|
||||
Catalog lines are ``source/path — title`` (the agent's
|
||||
``list_documents`` output): split on ``" — "``, keep the head, and
|
||||
recover ``(source, path)`` with ``rsplit("/", 1)`` (``rpartition``)
|
||||
— the same convention the single-read flow's read step uses. The
|
||||
``"N documents:"`` header line carries no ``/`` and is skipped; read-
|
||||
result messages are full documents, not listings, and are skipped
|
||||
too.
|
||||
Catalog lines are ``source: X | path: Y | title: Z`` (the agent's
|
||||
``list_documents`` output — phase 63: labeled, pipe-delimited
|
||||
fields, unambiguous even for paths full of ``/``): the line-level
|
||||
regex recovers the ``source`` and ``path`` fields directly. The
|
||||
``"N documents:"`` header line matches no line and is skipped;
|
||||
read-result messages are full documents, not listings, and are
|
||||
skipped too.
|
||||
"""
|
||||
docs: list[tuple[str, str]] = []
|
||||
for m in _messages(body):
|
||||
@@ -309,11 +318,9 @@ def _catalog_docs(body: dict[str, Any]) -> list[tuple[str, str]]:
|
||||
if content.startswith(_READ_RESULT_PREFIX):
|
||||
continue
|
||||
for line in content.splitlines():
|
||||
head = line.split(" — ", 1)[0].strip()
|
||||
if "/" in head:
|
||||
source, _, path = head.rpartition("/")
|
||||
if source and path:
|
||||
docs.append((source, path))
|
||||
match = _CATALOG_LINE_RE.match(line)
|
||||
if match:
|
||||
docs.append((match.group("source"), match.group("path")))
|
||||
return docs
|
||||
|
||||
|
||||
@@ -327,8 +334,8 @@ def _tool_flow(body: dict[str, Any]) -> tuple[str, ...] | None:
|
||||
are in the messages yet: the model lists the catalog.
|
||||
* ``("read", source, path, "call_1")`` — a ``tool``-role catalog
|
||||
result is in the messages: the model reads its FIRST
|
||||
``source/path — title`` line (split on ``" — "``, then
|
||||
``rsplit("/", 1)``).
|
||||
``source: X | path: Y | title: Z`` line (the labeled
|
||||
``source:`` / ``path:`` fields, phase 63).
|
||||
* ``("answer", "source/path", content)`` — a ``tool``-role read
|
||||
result (``"Document <source/path>:\n<content>"``) is in the
|
||||
messages: the model answers, quoting the read document. Reached
|
||||
|
||||
Reference in New Issue
Block a user