Files
multica/apps/desktop
Naiyuan Qing 736fbc8a5f MUL-5685: fix agent builder composer clearing and conversation routing (#6339)
* fix(agents): clear the builder composer as soon as the send is accepted

Sending a message in the Agent Builder left the user's text in the box
while the message was already on screen.

The composer is on the shared MUL-5181 contract, which clears the draft
when the owner's send resolves. This owner resolved late: it awaited
three cache invalidations (messages, pendingTask, drafts list) after the
POST had already been accepted and the caches primed, so the clear was
gated behind that many extra round-trips. Typing during that window also
tripped ChatInput's stale-submit guard, which then declines to clear at
all and strands the sent text in the box.

`send` now takes ChatInput's `commitInput` and runs it the moment the
server accepts and the caches render the message; the invalidations
reconcile in the background. Same ordering as use-chat-controller's
handleSend. The empty-state prompt buttons call `send` with no composer
to clear, which is why the parameter is optional.

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

* refactor(agents): give a builder conversation its own route

The AI creation studio served two unrelated screens from one route,
switched on `?session=`: absent rendered the runtime picker, present
rendered the conversation. That inverted what each one is. The runtime
pick is a step — consumed the instant the session exists, since the
runtime is frozen onto the hidden carrier agent and cannot be revisited.
The conversation is a durable object: leaving the studio no longer
deletes it (#6307), so it is left and resumed, and it is the thing that
needs an address. It had the address of a modifier on the step.

Split into one route per screen:

    /{ws}/agents/new/ai              start one
    /{ws}/agents/new/ai/{sessionId}  one conversation

Behavior is deliberately unchanged: starting still REPLACES the picker
entry so a back cannot land on a consumed step, back still leaves to the
chooser, and a discarded conversation still replaces its own entry
rather than leaving a dead address on the stack.

One latent bug goes with it. The runtime a just-started conversation
runs on lived in React state on the shared page, because a conversation
joins the sessions list only once it holds a message or a saved
configuration — so for the first turn there was nothing to read it back
from. A refresh on that first turn dropped it and locked the runtime
picker. It now rides in `?runtime=` on the conversation URL, which is a
seed for exactly that gap and absent on every later visit.

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

* fix(core): register the builder conversation route for diagnostics

diagnostic-context.ts keeps a route-mask table that every path builder
must match, so a diagnostic report names the route instead of a
wildcard. The new conversation path fell through to `/:slug/agents/*`,
which its coverage test rejects.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 10:34:27 +08:00
..