feat(agent): align the document tools with the harness-trained shape — ls, read(path), grep(pattern, path?)
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user