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]