Reuse native parallel child logs

Pass each parent-visible child log into direct parallel worker execution so tool before_execution reuses it instead of creating a second generic tool log.

This keeps native badge types such as wait/progress (HDL) intact through execution, updates the parallel helper DOX contract, and adds a regression test for log reuse.
This commit is contained in:
Alessandro 2026-07-09 17:42:41 +02:00
parent 8d79f556c6
commit fa05710da7
3 changed files with 82 additions and 2 deletions

View file

@ -487,13 +487,24 @@ async def _run_direct_tool_job(parent_context_id: str, job: ParallelJob) -> str:
worker_agent = worker_context.agent0
worker_agent.loop_data = LoopData()
return await execute_tool_call(worker_agent, job.tool_name, job.tool_args)
return await execute_tool_call(
worker_agent,
job.tool_name,
job.tool_args,
log_item=job.log_item,
)
finally:
if worker_context:
await _remove_context(worker_context.id)
async def execute_tool_call(agent: "Agent", tool_name: str, tool_args: dict[str, Any]) -> str:
async def execute_tool_call(
agent: "Agent",
tool_name: str,
tool_args: dict[str, Any],
*,
log_item: "LogItem | None" = None,
) -> str:
if tool_name == "parallel":
raise ValueError("`parallel` cannot be nested inside a parallel worker.")
@ -501,6 +512,11 @@ async def execute_tool_call(agent: "Agent", tool_name: str, tool_args: dict[str,
if not tool:
raise ValueError(f"Tool '{tool_name}' not found or could not be initialized.")
original_get_log_object = None
if log_item is not None:
original_get_log_object = tool.get_log_object
tool.get_log_object = lambda: log_item
agent.loop_data.current_tool = tool
try:
await agent.handle_intervention()
@ -524,6 +540,8 @@ async def execute_tool_call(agent: "Agent", tool_name: str, tool_args: dict[str,
await agent.handle_intervention()
return response.message
finally:
if original_get_log_object is not None:
tool.get_log_object = original_get_log_object
agent.loop_data.current_tool = None

View file

@ -32,6 +32,7 @@
- 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.
- Child tool logs mirror normal tool-call visible args; job ids remain available through wrapper results and prompt extras rather than visible process-step args.
- Wrapped tool child logs use each tool's native `get_log_object()` output when available, preserving special log rendering (for example: `code_execution_tool` uses `code_exe`, `wait` uses `progress`, MCP tools use `mcp`, and regular tools use `tool`).
- Direct parallel worker execution reuses the parent-visible child log item so tool `before_execution()` cannot create a second generic worker log or lose the native badge type.
- Job IDs are stable handles for later await, collect, or cancel operations.
- Prompt extras must stay bounded and expose only job IDs, tool names, status, and compact result/error summaries.