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
+30 -32
View File
@@ -500,29 +500,27 @@ def test_chat_stream_llm_error_passes_through_unwrapped() -> None:
# ---------- tool-call streaming (phase 37, task 02) ----------
#: The agent's tool list (phase 37) — the exact wire shape AGENT_TOOLS will
#: pass through (the names are whatever the caller's tools list names).
#: The agent's tool list (phase 70: the harness-aligned surface) — the
#: exact wire shape AGENT_TOOLS passes through (the names are whatever
#: the caller's tools list names).
_AGENT_TOOLS: list[dict[str, Any]] = [
{
"type": "function",
"function": {
"name": "list_documents",
"name": "ls",
"description": "List the indexed documents.",
"parameters": {"type": "object", "properties": {}},
"parameters": {"type": "object", "properties": {}, "required": []},
},
},
{
"type": "function",
"function": {
"name": "read_document",
"name": "read",
"description": "Add one indexed document's full text to the context.",
"parameters": {
"type": "object",
"properties": {
"source": {"type": "string"},
"path": {"type": "string"},
},
"required": ["source", "path"],
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
},
@@ -557,12 +555,12 @@ def test_chat_stream_accumulates_tool_call_across_chunk_partials() -> None:
_tool_call(
0,
id="call_abc",
name="read_document",
arguments='{"source": "Homelab", "pa',
name="read",
arguments='{"path": "Homelab/ku',
)
],
),
_chunk(None, tool_calls=[_tool_call(0, arguments='th": "kubernetes.md"}')]),
_chunk(None, tool_calls=[_tool_call(0, arguments='bernetes.md"}')]),
_chunk(None, finish_reason="tool_calls"),
]
)
@@ -572,8 +570,8 @@ def test_chat_stream_accumulates_tool_call_across_chunk_partials() -> None:
assert pieces == [
ToolCallPiece(
id="call_abc",
name="read_document",
arguments={"source": "Homelab", "path": "kubernetes.md"},
name="read",
arguments={"path": "Homelab/kubernetes.md"},
)
]
@@ -586,14 +584,14 @@ def test_chat_stream_two_tool_calls_yielded_in_index_order() -> None:
_chunk(
None,
tool_calls=[
_tool_call(1, id="call_b", name="read_document", arguments='{"sou')
_tool_call(1, id="call_b", name="read", arguments='{"pa')
],
),
_chunk(
None,
tool_calls=[
_tool_call(0, id="call_a", name="list_documents"),
_tool_call(1, arguments='rce": "Homelab", "path": "a.md"}')
_tool_call(0, id="call_a", name="ls"),
_tool_call(1, arguments='th": "Homelab/a.md"}')
],
),
_chunk(None, finish_reason="tool_calls"),
@@ -603,11 +601,11 @@ def test_chat_stream_two_tool_calls_yielded_in_index_order() -> None:
llm, [{"role": "user", "content": "q"}], _AGENT_TOOLS
)
assert pieces == [
ToolCallPiece(id="call_a", name="list_documents", arguments={}),
ToolCallPiece(id="call_a", name="ls", arguments={}),
ToolCallPiece(
id="call_b",
name="read_document",
arguments={"source": "Homelab", "path": "a.md"},
name="read",
arguments={"path": "Homelab/a.md"},
),
]
@@ -619,21 +617,21 @@ def test_chat_stream_tool_calls_yielded_at_stream_end_without_finish_reason() ->
[
_chunk(
None,
tool_calls=[_tool_call(0, id="call_z", name="list_documents")],
tool_calls=[_tool_call(0, id="call_z", name="ls")],
)
]
)
pieces = _collect_with_tools(
llm, [{"role": "user", "content": "q"}], _AGENT_TOOLS
)
assert pieces == [ToolCallPiece(id="call_z", name="list_documents", arguments={})]
assert pieces == [ToolCallPiece(id="call_z", name="ls", arguments={})]
def test_chat_stream_synthesizes_call_id_when_absent() -> None:
"""Wire never carried the call id ⇒ synthesized "call_<index>"."""
llm, _ = _make_stream_client(
[
_chunk(None, tool_calls=[_tool_call(2, name="read_document", arguments="{}")]),
_chunk(None, tool_calls=[_tool_call(2, name="read", arguments="{}")]),
_chunk(None, finish_reason="tool_calls"),
]
)
@@ -643,7 +641,7 @@ def test_chat_stream_synthesizes_call_id_when_absent() -> None:
assert pieces == [
ToolCallPiece(
id="call_2",
name="read_document",
name="read",
arguments={},
)
]
@@ -656,7 +654,7 @@ def test_chat_stream_null_arguments_become_empty_dict() -> None:
_chunk(
None,
tool_calls=[
_tool_call(0, id="call_n", name="list_documents", arguments="null")
_tool_call(0, id="call_n", name="ls", arguments="null")
],
),
_chunk(None, finish_reason="tool_calls"),
@@ -665,7 +663,7 @@ def test_chat_stream_null_arguments_become_empty_dict() -> None:
pieces = _collect_with_tools(
llm, [{"role": "user", "content": "q"}], _AGENT_TOOLS
)
assert pieces == [ToolCallPiece(id="call_n", name="list_documents", arguments={})]
assert pieces == [ToolCallPiece(id="call_n", name="ls", arguments={})]
def test_chat_stream_malformed_tool_arguments_raise_llm_error() -> None:
@@ -679,8 +677,8 @@ def test_chat_stream_malformed_tool_arguments_raise_llm_error() -> None:
_tool_call(
0,
id="call_x",
name="read_document",
arguments='{"source": "Homelab",',
name="read",
arguments='{"path": "Homelab",',
)
],
),
@@ -706,7 +704,7 @@ def test_chat_stream_non_object_tool_arguments_raise_llm_error() -> None:
_chunk(
None,
tool_calls=[
_tool_call(0, id="call_y", name="read_document", arguments='[1, 2]')
_tool_call(0, id="call_y", name="grep", arguments='[1, 2]')
],
),
_chunk(None, finish_reason="tool_calls"),
@@ -987,7 +985,7 @@ def test_retried_healthy_stream_is_untouched(
a healthy turn is byte-identical to the plain chat_stream."""
answer = [
StreamPiece("thinking", "hmm"),
ToolCallPiece(id="call_1", name="list_documents", arguments={}),
ToolCallPiece(id="call_1", name="ls", arguments={}),
StreamPiece("content", "Talos."),
]
client = _ScriptedClient([(answer, None)])
@@ -995,7 +993,7 @@ def test_retried_healthy_stream_is_untouched(
tools = [
{
"type": "function",
"function": {"name": "list_documents", "parameters": {}},
"function": {"name": "ls", "parameters": {}},
}
]
pieces = _collect_retried(