mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-07-09 17:08:29 +00:00
Accept JSON-string parallel tool calls
Restore parallel normalization tolerance for provider/model outputs that stringify the tool_calls array inside tool_args. The wrapper still expects normal tool-call objects after decoding, so nested parallel and document_query guards continue to run through the same validation path.
This commit is contained in:
parent
5c914bc49e
commit
b11818bfff
4 changed files with 44 additions and 1 deletions
|
|
@ -78,6 +78,13 @@ def extract_tool_calls(args: dict[str, Any]) -> Any:
|
|||
|
||||
|
||||
def normalize_parallel_tool_calls(raw_calls: Any) -> list[NormalizedToolCall]:
|
||||
if isinstance(raw_calls, str):
|
||||
try:
|
||||
raw_calls = json.loads(raw_calls)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise ValueError(
|
||||
"`tool_calls` must be an array of normal tool-call objects."
|
||||
) from exc
|
||||
if not isinstance(raw_calls, list):
|
||||
raise ValueError("`tool_calls` must be an array of normal tool-call objects.")
|
||||
if not raw_calls:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
- Helper modules own reusable framework APIs and must preserve public callers unless all callers, tests, and docs are updated together.
|
||||
- Wrapped tool-call items must use the same shape as normal tool calls: a tool name plus arguments.
|
||||
- Normalization accepts full agent-reply-shaped objects when `tool_name` and `tool_args` are present; non-contract planning fields such as `thoughts` or `headline` are ignored.
|
||||
- `tool_calls` should be an array, but normalization also accepts a valid JSON string encoding of that array to recover provider/model stringification.
|
||||
- Normalization rejects `document_query` inside `parallel` because document parsing and Q&A fan out into heavier worker/model paths that must run sequentially.
|
||||
- `call_subordinate` jobs run in isolated child chat contexts tagged with parent-chat metadata; they must not be added to the scheduler task list and may use normal child-chat tools, including `parallel`.
|
||||
- Direct tool jobs run in isolated background contexts and are blocked from recursively invoking `parallel`.
|
||||
|
|
|
|||
|
|
@ -103,6 +103,41 @@ def test_normalize_parallel_tool_calls_accepts_normal_tool_request_shapes() -> N
|
|||
assert calls[1].tool_args == {"method": "list_tasks", "action": "list_tasks"}
|
||||
|
||||
|
||||
def test_normalize_parallel_tool_calls_accepts_json_string_array() -> None:
|
||||
calls = parallel_tools.normalize_parallel_tool_calls(
|
||||
json.dumps(
|
||||
[
|
||||
{
|
||||
"tool_name": "call_subordinate",
|
||||
"tool_args": {
|
||||
"profile": "researcher",
|
||||
"reset": True,
|
||||
"message": "Research nuclear fusion news in French.",
|
||||
},
|
||||
"headline": "Researching nuclear fusion news in French",
|
||||
},
|
||||
{
|
||||
"tool_name": "call_subordinate",
|
||||
"tool_args": {
|
||||
"profile": "researcher",
|
||||
"reset": True,
|
||||
"message": "Research nuclear fusion news in Italian.",
|
||||
},
|
||||
"headline": "Researching nuclear fusion news in Italian",
|
||||
},
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
assert [call.tool_name for call in calls] == [
|
||||
"call_subordinate",
|
||||
"call_subordinate",
|
||||
]
|
||||
assert calls[0].tool_args["profile"] == "researcher"
|
||||
assert calls[0].tool_args["reset"] is True
|
||||
assert calls[1].tool_args["message"] == "Research nuclear fusion news in Italian."
|
||||
|
||||
|
||||
def test_normalize_parallel_tool_calls_rejects_nested_parallel() -> None:
|
||||
with pytest.raises(ValueError, match="cannot be nested"):
|
||||
parallel_tools.normalize_parallel_tool_calls(
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
## Key Concepts
|
||||
|
||||
- `tool_calls`, `calls`, and `items` are accepted aliases for the wrapped call list.
|
||||
- `tool_calls`, `calls`, and `items` are accepted aliases for the wrapped call list; a valid JSON string encoding of the list is tolerated for provider/model recovery.
|
||||
- Wrapped call items can use the same `tool_name`/`tool_args` shape as top-level agent replies; extra planning fields are ignored by normalization.
|
||||
- `job_ids` can be supplied as a string or list when awaiting, collecting, or canceling existing jobs.
|
||||
- The response is compact JSON intended for the model to read and continue with.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue