Skip to main content
The Xpert chat API uses the handoff queue to run agent chat work outside the HTTP/SSE process. The HTTP instance only keeps the client stream open and subscribes to realtime results. A Bull handoff worker executes the actual XpertChatCommand and publishes stream events back through Redis Pub/Sub. This architecture is used by:
  • POST /api/xpert/:id/chat
  • POST /api/xpert/:name/chat-app
It replaces the previous process-local callback path for Xpert Chat SSE, where the request process had to wait on in-memory task and pending-result maps.

Goals

  • Support multiple API and worker instances without sticky sessions.
  • Keep the public HTTP API and normal SSE stream payloads unchanged.
  • Avoid Local task not found and Pending result timeout on Xpert Chat SSE requests caused by process-local state.
  • Use Redis Pub/Sub only for live forwarding. The system does not replay missed chat stream events after disconnect.

Runtime Flow

The API instance subscribes before enqueueing the job. This prevents a fast worker from publishing the first token before the SSE process is listening.

Main Components

Message Contract

The controller enqueues a handoff message with type agent.chat_dispatch.v1. The request and options must be serializable because the job can run in another process.
runId is the same value as the handoff message id. The realtime Redis channel is:

Callback Transports

AgentChatCallbackTarget supports two callback transports:
handoff-message is the compatibility mode. It publishes callback messages through the handoff queue and still requires messageType. redis-pubsub is the Xpert Chat SSE mode. It publishes realtime envelopes directly to Redis:

SSE Semantics

  • stream: forwarded as the original MessageEvent payload.
  • complete: completes the SSE observable.
  • error: sends an SSE error event and then completes the observable.
  • Client close: triggers StopHandoffMessageCommand({ messageIds: [runId] }).
  • Keepalive behavior remains unchanged. The controller still applies keepAlive(30000) and takeUntilClose(res).
Redis Pub/Sub is a live transport only. If the browser disconnects, the chat run is canceled and the client must start a new request. There is no DB persistence or event replay for this stream.

Operational Notes

  • Redis is required for both Bull queues and realtime Pub/Sub.
  • API and worker instances can scale independently. The worker that executes XpertChatCommand does not need to be the same process that accepted the HTTP request.
  • If a request stalls, check whether the API instance subscribed to ai:handoff:agent-chat:<runId>, whether the handoff job was enqueued, and whether the worker published stream, complete, or error.
  • Local task not found and Pending result timeout should not appear on this Xpert Chat SSE path. If they do, the request is likely still using an older local handoff path.

Code Map