Skip to content

Persist assistant messages server-side so answers survive page navigation #204

Description

@nlundee

Summary

Assistant responses are currently persisted by the frontend: the browser receives the assistant_message event over SignalR and POSTs it to the chat API. If the user leaves the page while the agent is working, the workflow completes server-side but the answer is never persisted — the user returns to an empty thread and assumes the agent failed.

Move persistence of assistant messages to the server so a completed workflow always produces a stored message, regardless of whether a browser tab is listening.

Context

Observed in practice (trace b8e945bf47898d9392df41bffece9f29): the user navigated away mid-run, the workflow completed successfully in ~26s with a full answer, success=true — but nothing appeared in the thread, because nobody was there to persist it.

Current flow:

  1. Agents service emits assistant_message → Designer backend (AltinityWebSocketService) forwards it to the SignalR group → frontend useAltinityWorkflow.handleAssistantMessagecreateMessage POST to the chat API.
  2. Every step after SignalR forwarding requires a live, connected tab. The agents service keeps its own conversation history for model context, but the Designer chat database — which the UI renders from — is only written by the client.

This also means a network blip at the wrong moment, a laptop lid close, or a tab crash silently discards completed work.

Goal

Ensure the assistant's final message (including filesChanged, sources, and trace ID) is persisted to the chat store server-side when the workflow completes, with the frontend reduced to rendering — so the user can leave, come back, and find the answer waiting.

In scope

  • Persist assistant_message events server-side — natural candidate: the Designer backend at the point it already receives every agent event (AltinityWebSocketService), which knows the developer/thread from session registration
  • Persist the message with full metadata: content, filesChanged, sources, trace ID
  • Remove (or dedupe against) the frontend's createMessage call for assistant messages so the transition doesn't double-persist
  • Verify the returning user sees the persisted answer on thread reload
  • Decide handling for rejection/error messages the frontend currently synthesizes client-side (formatRejectionMessage, workflow-error fallback)

Out of scope

  • Changes to the agent workflow, events, or the agents service's own conversation history
  • Live-reconnect/resume of an in-progress activity trail (the user returning mid-run sees the trail from scratch; separate concern)
  • Persistence of user messages (already persisted before the workflow starts)
  • Chat storage schema changes beyond what the message metadata requires

Acceptance criteria

  • A workflow that completes with no connected browser still results in a persisted assistant message in the thread
  • The persisted message carries filesChanged, sources, and trace ID (feedback buttons still work)
  • No duplicate messages when the user stays on the page during the whole run
  • Post-workflow branch operations (session-branch checkout) still behave correctly when the user returns later
  • Existing chat rendering, feedback, and thread behavior unaffected

Relationship to other work

This contributes to beta readiness: silent loss of completed work is a trust-breaking failure mode for real users. It was surfaced by the evaluation work on the unified-agent branch (the "lost" run was fully visible in Langfuse, proving the backend succeeded while the product dropped the result).

Metadata

Metadata

Assignees

Type

Projects

Status
In review

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions