mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-07-09 17:08:29 +00:00
Clarify parallel tool-call batching
- document that parallel accepts full reply-shaped tool call objects and ignores planning-only fields - steer prompt guidance toward one mixed batch for ready independent calls instead of splitting by tool type - add normalization and prompt regression coverage plus matching DOX notes
This commit is contained in:
parent
b704a0e3f5
commit
6eeddf2f04
4 changed files with 37 additions and 4 deletions
|
|
@ -23,6 +23,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.
|
||||
- `call_subordinate` jobs run in isolated child chat contexts tagged with parent-chat metadata; they must not be added to the scheduler task list.
|
||||
- Direct tool jobs run in isolated background contexts and are blocked from recursively invoking `parallel`.
|
||||
- Parent-visible child log items are created for each wrapped call so the WebUI can inspect concurrent children separately while the wrapper result remains model-history-only.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
### parallel
|
||||
run independent tool calls concurrently, or await/cancel background parallel jobs.
|
||||
|
||||
Use only for independent work. Each `tool_calls` item is a normal tool request object: `{ "tool_name": "...", "tool_args": { ... } }`.
|
||||
Use only for independent work. Each `tool_calls` item is a normal tool request object using the same `tool_name` and `tool_args` shape as a top-level reply: `{ "tool_name": "...", "tool_args": { ... } }`.
|
||||
Only `tool_name` and `tool_args` are used; if an item is copied from a full reply object, planning fields like `thoughts` or `headline` are ignored.
|
||||
Batch all independent calls that are ready now into one `tool_calls` list, even when they use different tools. Do not split by tool type.
|
||||
|
||||
Rules:
|
||||
- do not use for one simple call, dependent steps, ordered steps, or shared mutable state
|
||||
- do not use for one simple call, dependent steps, ordered steps, shared mutable state, or state/tool-availability changes that must happen in the parent context
|
||||
- never nest `parallel`
|
||||
- `call_subordinate` inside `parallel` starts an isolated child chat under the parent chat, not a scheduler task
|
||||
- use `wait: false` only when you will collect results later with `job_ids`
|
||||
|
|
@ -18,8 +20,8 @@ Start and wait:
|
|||
"tool_name": "parallel",
|
||||
"tool_args": {
|
||||
"tool_calls": [
|
||||
{"tool_name": "call_subordinate", "tool_args": {"message": "Research option A.", "reset": true}},
|
||||
{"tool_name": "call_subordinate", "tool_args": {"message": "Research option B.", "reset": true}}
|
||||
{"tool_name": "call_subordinate", "tool_args": {"message": "Review option A and return key risks.", "reset": true}},
|
||||
{"tool_name": "search_engine", "tool_args": {"query": "official API changelog release notes"}}
|
||||
],
|
||||
"wait": true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ if str(PROJECT_ROOT) not in sys.path:
|
|||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from helpers.extract_tools import normalize_tool_request
|
||||
from helpers import parallel_tools
|
||||
|
||||
|
||||
def test_normalize_tool_request_accepts_canonical_keys() -> None:
|
||||
|
|
@ -65,3 +66,30 @@ def test_normalize_tool_request_preserves_explicit_action_over_method() -> None:
|
|||
def test_normalize_tool_request_rejects_missing_args() -> None:
|
||||
with pytest.raises(ValueError, match="tool_args"):
|
||||
normalize_tool_request({"tool_name": "response"})
|
||||
|
||||
|
||||
def test_normalize_parallel_tool_calls_accepts_full_agent_reply_shape() -> None:
|
||||
calls = parallel_tools.normalize_parallel_tool_calls(
|
||||
[
|
||||
{
|
||||
"thoughts": ["This is independent and ready to run."],
|
||||
"headline": "Search Python release notes",
|
||||
"tool_name": "search_engine",
|
||||
"tool_args": {"query": "latest Python version changelog"},
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert calls[0].tool_name == "search_engine"
|
||||
assert calls[0].tool_args == {"query": "latest Python version changelog"}
|
||||
|
||||
|
||||
def test_parallel_prompt_encourages_mixed_independent_batches() -> None:
|
||||
prompt = (PROJECT_ROOT / "prompts" / "agent.system.tool.parallel.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
assert "same `tool_name` and `tool_args` shape as a top-level reply" in prompt
|
||||
assert "planning fields like `thoughts` or `headline` are ignored" in prompt
|
||||
assert "even when they use different tools" in prompt
|
||||
assert "Do not split by tool type" in prompt
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
- Tool modules must define `helpers.tool.Tool` subclasses and return `helpers.tool.Response` from `execute(...)`.
|
||||
- Wrapped items use the same schema as normal tool calls: a tool name plus arguments.
|
||||
- The tool is intended for independent calls only; dependent operations remain sequential.
|
||||
- Independent calls should share one batch even when they use different tools; split only for dependencies, ordering, shared mutable state, or parent-context state/tool-availability changes.
|
||||
- `action="start"` starts calls and optionally waits according to `wait`.
|
||||
- `action="await"` waits for requested job IDs.
|
||||
- `action="collect"` returns completed job results without waiting.
|
||||
|
|
@ -31,6 +32,7 @@
|
|||
## Key Concepts
|
||||
|
||||
- `tool_calls`, `calls`, and `items` are accepted aliases for the wrapped call list.
|
||||
- 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.
|
||||
- Visible child rows are emitted by `helpers/parallel_tools.py` before each background job starts.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue