Skip to content

feat(api): append mode for recalled reference images (+ fix recall socket double-emit) - #9288

Merged
lstein merged 7 commits into
mainfrom
lstein/feat/recall-append-ref-images
Jun 28, 2026
Merged

feat(api): append mode for recalled reference images (+ fix recall socket double-emit)#9288
lstein merged 7 commits into
mainfrom
lstein/feat/recall-append-ref-images

Conversation

@lstein

@lstein lstein commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an append mode to the recall API for reference images, and fixes a latent double-delivery in the recall socket event that the new mode exposed.

feat(api): append mode for recalled reference images. POST /api/v1/recall/{queue_id} previously always replaced the frontend's reference-image list — the recall_parameters_updated handler dispatched refImagesRecalled with a hard-coded replace: true. This adds an append query parameter; when append=true, the recalled ip_adapters / reference_images are added to the existing list (replace: false) instead of replacing it. The flag rides inside the event's parameters dict so the generated client schema needs no regeneration, and it's injected after the persistence loop so it is never stored as a recall parameter. strict and append are mutually exclusive (400). The frontend skips the dispatch entirely when nothing resolved, so a failed append can never clear the user's current reference images.

fix(sockets): emit the recall event once to the owner+admin room union. RecallParametersUpdatedEvent was emitted in two separate socket.io calls — one to user:{user_id}, one to admin. A socket belonging to both rooms (the system user in single-user mode is also an admin, so it joins both) received the event twice. That was invisible for the idempotent scalar/replace recall fields, but the new append mode pushes rather than replaces, so each append showed up as two copies of the same reference image. Fixed by emitting once to the room union [user_room, "admin"] — python-socketio deduplicates recipients across a room list, so a socket in both rooms is delivered to exactly once while genuinely distinct owner/admin sockets each still receive it. Scoped to the recall event only; the other private events are idempotent UI updates where a double delivery is harmless.

QA Instructions

  1. Single-user mode, a model that uses reference images (FLUX.2 Klein / FLUX Kontext / Qwen Image Edit). Add one reference image.
  2. POST /api/v1/recall/default?append=true with {"reference_images": [{"image_name": "<an output image>"}]}.
  3. Expect exactly one new reference image added (the existing one preserved) — not two, and the prior entry not cleared.
  4. Repeat with ?append=false (or omitted) → the list is replaced, as before.
  5. ?strict=true&append=true → 400.

Automated: tests/app/routers/test_recall_parameters.py (append flag plumbing, strict/append mutual exclusion, not-persisted) and tests/app/routers/test_multiuser_authorization.py::TestWebSocketAuth::test_recall_parameters_emitted_once_to_owner_and_admin_rooms (single emit to the room union). Full recall + multiuser-auth suites pass (153 tests).

Merge Plan

Standard merge. The frontend change is a single dispatch in setEventListeners.tsx (no redux-slice schema change, no migration). Recommend a frontend rebuild on deploy so the append branch takes effect in the served UI.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Tests added / updated (if applicable)
  • ❗Changes to a redux slice have a corresponding migration — N/A, no slice shape change (uses existing refImagesRecalled with replace: false)
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

🤖 Generated with Claude Code

lstein and others added 2 commits June 13, 2026 09:33
POST /api/v1/recall/{queue_id}?append=true now asks the frontend to add
the recalled reference images (ip_adapters and model-free
reference_images) to its existing list instead of replacing it. The flag
rides inside the event's parameters dict so the generated client schema
needs no regeneration, and is injected after the persistence loop so it
is never stored as a recall parameter. Mutually exclusive with strict.

The frontend dispatches refImagesRecalled with replace:false in append
mode, and skips the dispatch entirely when nothing resolved so a failed
append can never clear the user's current reference images.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RecallParametersUpdatedEvent was emitted in two separate socket.io
calls — one to the owner's user room, one to the admin room. A socket
that belongs to both (the "system" user in single-user mode is also an
admin, so it joins user:system AND admin) received the event twice.

That double delivery was invisible for the scalar/replace recall fields,
which are idempotent, but the append-mode reference-image recall pushes
rather than replaces — so each append showed up as two copies of the
same reference image in the InvokeAI canvas.

Emit once to the room union [user_room, "admin"] instead. python-socketio
deduplicates recipients across a room list, so a socket in both rooms is
delivered to exactly once, while genuinely distinct owner/admin sockets
still each receive it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added api python PRs that change python files frontend PRs that change frontend files python-tests PRs that change python tests labels Jun 13, 2026
Rebuilds the committed OpenAPI schema and generated TypeScript types so the
update_recall_parameters operation advertises the new append query
parameter. Generated via 'make frontend-openapi' / 'frontend-typegen'
equivalent; the only change is the added append param + its docstring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lstein lstein added the 6.13.5 Library Updates label Jun 13, 2026
@lstein lstein moved this to 6.13.5 LIBRARY UPDATES in Invoke - Community Roadmap Jun 13, 2026

@JPPhoto JPPhoto 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.

Code looks good! Docs need updating for this PR.

This adds a public append query parameter to POST /api/v1/recall/{queue_id}, and the repo already has a dedicated Recall Parameters API guide at docs/src/content/docs/development/Guides/recall-api.mdx.

I think it'd be nice to document:

  • append=true appends recalled ip_adapters / reference_images to the existing frontend reference-image list.
  • The default behavior (append=false or omitted) still replaces the list.
  • strict=true&append=true is invalid and returns 400.
  • A short cURL example for append mode.

This is API-consumer-facing behavior, so it should not only live in the generated OpenAPI/schema output.

Documents the new append=true query parameter on POST /api/v1/recall/{queue_id}:
- new Query parameters subsection covering strict and append
- mutual exclusivity (strict+append -> 400) with error body
- append-mode cURL example
- updated WebSocket Events + frontend log sample for the merged reference-image list

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the docs PRs that change docs label Jun 28, 2026
@lstein

lstein commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator Author

Documentation fix and curl example are in.

@lstein
lstein requested a review from JPPhoto June 28, 2026 00:03

@JPPhoto JPPhoto 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.

LGTM!

@lstein
lstein merged commit c7d37c7 into main Jun 28, 2026
17 of 18 checks passed
@lstein
lstein deleted the lstein/feat/recall-append-ref-images branch June 28, 2026 00:30
dunkeroni pushed a commit to dunkeroni/InvokeAI that referenced this pull request Jun 29, 2026
…cket double-emit) (invoke-ai#9288)

* feat(api): add append mode to recall reference images

POST /api/v1/recall/{queue_id}?append=true now asks the frontend to add
the recalled reference images (ip_adapters and model-free
reference_images) to its existing list instead of replacing it. The flag
rides inside the event's parameters dict so the generated client schema
needs no regeneration, and is injected after the persistence loop so it
is never stored as a recall parameter. Mutually exclusive with strict.

The frontend dispatches refImagesRecalled with replace:false in append
mode, and skips the dispatch entirely when nothing resolved so a failed
append can never clear the user's current reference images.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sockets): emit recall event once to owner+admin room union

RecallParametersUpdatedEvent was emitted in two separate socket.io
calls — one to the owner's user room, one to the admin room. A socket
that belongs to both (the "system" user in single-user mode is also an
admin, so it joins user:system AND admin) received the event twice.

That double delivery was invisible for the scalar/replace recall fields,
which are idempotent, but the append-mode reference-image recall pushes
rather than replaces — so each append showed up as two copies of the
same reference image in the InvokeAI canvas.

Emit once to the room union [user_room, "admin"] instead. python-socketio
deduplicates recipients across a room list, so a socket in both rooms is
delivered to exactly once, while genuinely distinct owner/admin sockets
still each receive it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(api): regenerate openapi.json + schema.ts for recall append param

Rebuilds the committed OpenAPI schema and generated TypeScript types so the
update_recall_parameters operation advertises the new append query
parameter. Generated via 'make frontend-openapi' / 'frontend-typegen'
equivalent; the only change is the added append param + its docstring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: document append query parameter for recall API

Documents the new append=true query parameter on POST /api/v1/recall/{queue_id}:
- new Query parameters subsection covering strict and append
- mutual exclusivity (strict+append -> 400) with error body
- append-mode cURL example
- updated WebSocket Events + frontend log sample for the merged reference-image list

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.13.5 Library Updates api docs PRs that change docs frontend PRs that change frontend files python PRs that change python files python-tests PRs that change python tests

Projects

Status: 6.13.5 LIBRARY UPDATES

Development

Successfully merging this pull request may close these issues.

2 participants