tju-yxq opened a new issue, #5411:
URL: https://github.com/apache/rocketmq-dashboard/issues/5411

   ## Problem
   
   A send on the bare `/ai` route has to create the conversation first, and 
**that creation window has no double-submit guard**. The stream-start path does 
— `useAgentRun.startStream` opens with the maintainers' own comment, 
"Double-submit guard: Enter twice in one tick must not admit two runs (the 
server would reject the second with 409 anyway, but the UI should not even 
try)" — but a send on `/ai` enters `useAiSend.startRun`'s creation path, which 
checks nothing. The window is wide: `createConversation` **plus** a sequential 
`listInstances()` default-instance lookup must both resolve before the 
navigation installs the new id, and during all of it no run is in flight so the 
composer stays enabled.
   
   The armed `pendingSendRef` is a single slot, so a second send in the window 
breaks one of two ways:
   
   - the second create resolves last and **overwrites the armed entry** — the 
first prompt is never sent, its input was already cleared by the composer, and 
an orphaned empty conversation is left in history; or
   - both creates resolve and both prompts fire into **two different 
conversations**, while the replace-navigation lands the user on only one of 
them.
   
   Either way the user's first question silently disappears.
   
   ## What did you do (steps to reproduce)?
   
   1. Open `/ai` (no conversation yet) and wait for the provider to be ready.
   2. Type a question and press Enter; before the conversation loads (a slow 
backend makes the window seconds wide), type a second question and press Enter 
again.
   3. Two `POST /api/ai/conversations` fire. The first question either vanishes 
entirely (empty conversation in history, no answer) or lands in a conversation 
the navigation never shows.
   
   ## What did you expect to see?
   
   The second Enter is suppressed like it is on an existing conversation: one 
conversation, both prompts preserved (the suppressed one returns to the 
composer).
   
   ## What did you see instead?
   
   A second conversation is created and the first prompt is lost or stranded.
   
   ## Root cause
   
   `web/src/pages/ai/hooks/useAiSend.ts`, the returned `startRun` callback 
(around lines 106-123):
   
   ```ts
   const current = conversationIdRef.current;
   if (current !== null) {
     void optionsRef.current.send(current, request);   // inherits 
startStream's guard
     return current;
   }
   let createdId: number;
   const created = await createConversation(await 
withDefaultInstance(createBody));  // ← no guard
   ...
   pendingSendRef.current = { conversationId: createdId, request };   // single 
slot, blindly overwritten
   ```
   
   Contrast the sibling guard in `web/src/pages/ai/hooks/useAgentRun.ts` (lines 
305-316), whose comment states the intent for the stream path; the creation 
path was simply never given the same treatment.
   
   ## Expected behavior
   
   - A second send while the bare-route creation is in flight resolves `null` — 
the caller's existing null handling restores the prompt into the composer, 
exactly like a failed create.
   - The guard covers the whole creation window: the create request, the 
default-instance lookup, and the navigation settling (it is released when the 
route param becomes a conversation id, or when the create fails).
   - The existing-conversation send path, the home-page draft handoff, and the 
auto-send effect are unchanged.
   
   ## Acceptance criteria
   
   - [ ] Regression proof: on the current code, two rapid Enters on `/ai` call 
`createConversation` twice; with the fix, once.
   - [ ] The suppressed second prompt reappears in the composer.
   - [ ] The home-draft handoff (single send) still creates exactly one 
conversation.
   - [ ] A failed create still reports through `onError` and re-arms the 
composer for the next send.
   
   ## Environment
   
   Branch `rocketmq-studio` at `6a68042f`; file: 
`web/src/pages/ai/hooks/useAiSend.ts`.
   
   ## Duplicate check
   
   Searched open and closed issues for `conversation create send` and `double 
send`: the adjacent items are the in-flight stream rejection (#367-family, the 
server-side 409) and the open Loyal-Young issues on other AI flows (#5371 key 
save). Nothing covers the bare-route creation window.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to