Problem/Motivation

Some AI-initiated work (e.g., image generation via text-to-image models) takes too long to complete within the chat turn's HTTP request. The AI agent needs to commit the entity and respond to the user immediately, while the slow work completes asynchronously and updates the page when finished.

Without a deferred processing system, the options are:

  • Block the chat response until generation completes (unacceptable UX — 10-30s wait with no feedback)
  • Kick off image generation on the back end and require the user to manually refresh after some unknown delay

Proposed resolution

Introduce a first-class deferred operation system with two client-side execution strategies:

Server-side deferred flow

  1. AI tool persists entity; field handler emits DeferredOperation value objects for work it cannot resolve synchronously
  2. Event subscriber stores operations in PrivateTempStore and queues a TriggerDeferredCommand
  3. Client shows a loading indicator (shimmer animation on placeholder), POSTs to DeferredProcessingController::process
  4. Controller dispatches each operation to the matching tagged processor service
  5. On success: returns AJAX commands to re-render affected components with highlighting
  6. On retryable failure (e.g., content moderation rejection): client POSTs to retry endpoint, processor rewrites the prompt via LLM, tries again

Chat-driven followup flow

  1. Server queues a TriggerFollowupChatCommand with an LLM-facing message
  2. Client sends a synthetic chat turn to the DeepChat API (user never sees it)
  3. Loops on should_continue (mirrors the agent polling loop)
  4. On completion, POSTs to RefreshComponentsController to re-render with highlights

Image generation processor

The canonical deferred processor implementation:

  • Calls the configured text_to_image AI provider
  • Creates a media entity from the generated image
  • Updates the element on the entity
  • Implements RetryableProcessorInterface — on content moderation failure, uses an LLM to rewrite the rejected prompt and retries (up to 2x)

Image generation field handler

An entity_blueprint field handler (ImageGenerationHandler) that intercepts entity_reference fields targeting media:

  • When the AI sends {_generate: "description"}, sets a configured placeholder media and emits a DeferredOperation
  • On update: leaves the field unchanged and emits the deferred operation (element is updated and swaped later)
  • Provides guidance text to the AI describing the _generate syntax

User interface changes

  • Placeholder components show a shimmer animation (dashed outline + gradient sweep) while generation is in progress
  • After generation completes, the component re-renders with the real image and receives a highlight animation

Comments

tim bozeman created an issue. See original summary.

  • tim bozeman committed ed9a443d on 1.0.x
    task: #3591602 Add deferred operation processing for async image...
tim bozeman’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.