perf(image): parallelize image_generate batches - #33971
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating a real image-batch bottleneck. The current main dispatcher still routes multi-image batches sequentially because image_generate is not in agent/tool_dispatch_helpers.py:46-58.
Problems
agent/tool_dispatch_helpers.py:48classifiesimage_generateas parallel-safe, buttools/image_generation_tool.py:806-834force-syncs remote artifacts through the task's shared environment.FileSyncManager.sync()mutates_synced_files,_pushed_hashes, and_last_sync_timewithout a lock (tools/environments/file_sync.py:151-160,162-235), so concurrent image results can race on SSH/Daytona/Modal-style backends.
Suggested changes
- Preserve parallel provider requests, but serialize that shared artifact-sync path (or prove and gate a backend path that is safe). Add a regression test for two concurrent image results using a shared remote sync manager.
- Document the new
image_gen.max_parallel_requestsknob alongside the existing configuration example inwebsite/docs/user-guide/features/image-generation.md:61-67.
This is an automated hermes-sweeper review.
| @@ -45,6 +45,7 @@ | |||
| "ha_get_state", | |||
| "ha_list_entities", | |||
| "ha_list_services", | |||
| "image_generate", | |||
There was a problem hiding this comment.
image_generate is not universally free of shared state: successful remote-backend results call sync_manager.sync(force=True) in tools/image_generation_tool.py:801, and FileSyncManager.sync() mutates shared sync state without a lock. Please serialize that artifact-sync path or gate this parallel classification to a proven-safe backend path before enabling concurrent image calls.
There was a problem hiding this comment.
Addressed in ddf0cea after rebasing the PR onto current main.
Provider calls remain concurrent, while each FileSyncManager now owns a per-instance transaction lock covering complete sync() and sync_back() cycles. This prevents overlapping transport/state commits for a shared SSH/Daytona/Modal environment without serializing independent environments.
Regression coverage now includes:
- two concurrent image results using the same real FileSyncManager, proving both artifact paths remain committed;
- sync_back waiting for an active forward-sync transaction rather than observing partial manager state.
Also documented image_gen.max_parallel_requests (default 4, bounded by the global worker cap).
Verification on current main:
- 108 focused sync/backend/artifact/dispatch tests passed;
- 458 PR validation tests passed;
- Ruff and git diff --check passed.
7aedf8b to
ddf0cea
Compare
Summary
Small patch, large user-visible speedup:
image_generatetool calls run concurrentlyThis PR lets
image_generatetool batches run through Hermes' existing concurrent tool executor instead of forcing image requests to execute one by one.The change is intentionally small:
image_generateas parallel-safe in the tool dispatch gateProblem
When the model emits multiple
image_generatecalls in one assistant tool batch, Hermes currently treats image generation as a stateful/non-parallel tool and sends the calls through the sequential path. For creative workflows, that makes multi-variant generation feel much slower than necessary: each image waits for the previous image request even though the calls are independent.Image generation is a good candidate for bounded parallelism because each request is independent, slow, and usually dominated by provider-side generation latency.
What changed
image_generateis added to the parallel-safe tool set.For mixed or image-only concurrent batches,
agent.tool_executornow uses a dedicated image cap:Behavior:
image_gen.max_parallel_requests_MAX_TOOL_WORKERScapPerformance evidence
These are real-world GPT Image 2 / Codex image-generation runs from an image-heavy creative workflow. They are not synthetic microbenchmarks; the intent is to show user-visible wall-clock behavior.
Observed behavior is roughly 4-slot rolling parallelism:
Practical result:
The main bottleneck moves from "Hermes queues every image one by one" to "provider image latency plus occasional failed/rerun requests."
Related work and duplicate check
I did not find an open or merged PR that directly parallelizes
image_generatebatches.Nearby but not duplicate:
image_generatecalls much more usable.No issues are closed by this PR.
Scope and non-goals
Included:
image_generateNot included:
Those are intentionally left out so this PR stays reviewable.
Validation
Result: