Skip to content

feat(image_gen): support array prompt for parallel multi-image generation - #71345

Open
LAN-TINA-WS wants to merge 5 commits into
NousResearch:mainfrom
LAN-TINA-WS:main
Open

LAN-TINA-WS wants to merge 5 commits into
NousResearch:mainfrom
LAN-TINA-WS:main

Conversation

@LAN-TINA-WS

Copy link
Copy Markdown

Summary

image_generate now accepts prompt as either a string (unchanged) or an array of strings. Array prompts dispatch parallel generation via ThreadPoolExecutor, with concurrency controlled by image_gen.max_parallel (default 5).

Changes

Backend (tools/image_generation_tool.py):

  • prompt schema: "string"["string", "array"]
  • Array mode uses ThreadPoolExecutor with _read_max_parallel()
  • Backward compatible: single string prompt path untouched
  • Configurable via image_gen.max_parallel in config.yaml (default 5, max 20)

Frontend (apps/desktop/):

  • generatedImageFromResult() returns string[] scanning images array
  • GeneratedImage component maps over array, renders each image
  • generatedImageEchoSources also reads images for dedup

Tests: 5 new tests covering schema, empty array rejection, parallel dispatch (monkeypatched), and partial failure handling. 69/69 pass.

Usage

# Single (unchanged)
image_generate(prompt="a cat")

# Parallel (new)
image_generate(prompt=["a cat on windowsill", "a dog in park", "a bird on branch"])
# → 3 images generated in parallel, ~2s total vs ~6s serial

LAN-TINA-WS and others added 4 commits July 25, 2026 19:00
…tion

- prompt schema: string → [string, array] with items
- _handle_image_generate: array mode uses ThreadPoolExecutor
- _read_max_parallel() reads image_gen.max_parallel config (default 5)
- re-register with override=True to bump registry _generation
- backward compatible: single string prompt unchanged
- generatedImageFromResult returns string[] (was string|null)
- GeneratedImage maps over array, renders each as SingleImage
- generatedImageEchoSources also reads images array for dedup
- backward compatible: single image returns [singlePath]
- schema accepts [string, array] type
- empty array rejects with prompt required
- array dispatches via thread pool (3 items → 3 calls)
- partial failures preserve successful images
- backward compatible: single string unchanged
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/tools Tool registry, model_tools, toolsets comp/plugins Plugin system and bundled plugins comp/desktop Electron desktop app (apps/desktop/*) tool/vision Vision analysis and image generation provider/openai OpenAI / Codex Responses API labels Jul 25, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related: #33971 parallelizes separate image_generate calls in the agent executor; this PR adds an array-prompt batch contract and Desktop rendering. They use distinct mechanisms.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding a concrete batch contract and Desktop rendering path. The feature is still absent from current main (tools/image_generation_tool.py:1181-1188, :1501-1540), but the batch result contract needs a few corrections.

Problems

  • apps/desktop/src/lib/generated-images.ts:64-66 discards the images array when top-level success is false. The new backend intentionally emits success: false with successful child entries for a partial failure (tools/image_generation_tool.py:1599-1613 in the PR), so those images render as an indefinite placeholder.
  • tools/image_generation_tool.py:1568-1598 silently skips blank/non-string elements. An all-invalid non-empty array consequently returns success: true with no image.
  • The new nested images shape is not wired into gateway delivery. Current gateway/run.py:1473-1480 reads top-level image fields and stops after the first path, so messaging surfaces would deliver only one batch image.

Suggested changes

  • Add partial-success rendering/deduplication coverage, strict per-item validation, and gateway delivery/history coverage for every nested image.
  • Keep the unrelated API_MODEL rename in plugins/image_gen/openai/__init__.py:52 out of this feature PR unless separately validated.

Automated hermes-sweeper review.


if (!record || record.success === false) {
return null
return []

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The batch handler returns success: false while retaining successful entries in images on a partial failure. Returning here prevents the new batch scan below, so Desktop shows a pending placeholder instead of the successful images. Handle successful child entries before treating the whole result as unusable, and add a partial-success renderer test.

with ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_idx = {}
for idx, p in enumerate(prompt):
if not isinstance(p, str) or not p.strip():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping invalid entries leaves all_ok true. For example, [""] submits no futures and returns {"success": true, "image": null, "images": []}. Validate every item up front and reject a blank or non-string entry (with coverage for an all-invalid non-empty array).

return json.dumps({
"success": all_ok,
"image": first_img,
"images": images_list,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nested result shape also needs gateway delivery support. Current gateway/run.py:1473-1480 only reads top-level image fields and breaks after the first path, so messaging platforms will automatically receive only image, not the remaining entries here. Traverse images in auto-append and history-dedup paths with gateway coverage.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have provider/openai OpenAI / Codex Responses API sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages tool/vision Vision analysis and image generation type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants