unbridled-41 opened a new issue, #4736:
URL: https://github.com/apache/rocketmq-dashboard/issues/4736

   ### Studio Version
   
   branch: rocketmq-studio
   git commit id: 7ce9a68215c4cd1c7025013d02135b43b6aa6ba1
   
   ### Problem
   
   The manual tool playground keeps an in-flight execution alive across a tool 
or scope change, so its response lands in the output pane of whatever tool is 
selected afterwards. The pane never names the tool that produced the output, so 
tool A's result is presented as tool B's.
   
   Chain: `handleExecuteTool` 
(`web/src/pages/ai/components/ToolPlaygroundModal.tsx:200-225`) awaits 
`executeTool(selectedToolName, parsedInput, selectedClusterId)` and assigns the 
response to `toolResult` with no generation check. Neither invalidation path 
touches that call:
   
   - `selectTool` (`:127-135`) clears the panel (`setToolResult(undefined)`) 
but does not invalidate the running request, and the tool `Select` (`:267-281`) 
stays enabled while `toolExecuting` is true (only the Run button goes into 
`loading`, `:247-250`).
   - `loadTools` (`:137-161`, reached by a cluster-scope change, `:191-198`) 
clears the panel the same way.
   - `handleClose` (`:227-233`) bumps only `toolLoadRequestRef` — the catalog 
guard — so a response can also arrive after the modal was closed and reopened 
(the modal has no `destroyOnHidden`, so its state survives).
   
   Trigger (deterministic): open 工具 on the AI page, run any tool that takes a 
few seconds (the RocketMQ tools do), then switch the tool in the selector 
before it returns. The panel was cleared by the switch; when the response 
arrives it is repopulated, the success toast fires, and the output is shown 
under the newly selected tool's name and risk/permission tags (`:283-302`).
   
   ### Evidence
   
   - `web/src/pages/ai/components/ToolPlaygroundModal.tsx:200-225` — 
`setToolResult(await executeTool(...))` with no request-generation check; the 
only guard is `if (!selectedToolName || toolExecuting) return` at the top, 
which prevents a second *start*, not a late *landing*.
   - `web/src/pages/ai/components/ToolPlaygroundModal.tsx:127-135` and 
`:137-161` — the two paths that clear `toolResult` without invalidating the 
execute.
   - `web/src/pages/ai/components/ToolPlaygroundModal.tsx:227-233` — 
`handleClose` bumps `toolLoadRequestRef` only.
   - `web/src/pages/ai/components/ToolPlaygroundModal.tsx:318-342` — the output 
pane is labelled with the generic `ai.tool.output` and renders 
`formatToolResult(toolResult)`; nothing ties the text to the tool that produced 
it.
   - The same file documents and implements the analogous guard for the catalog 
load ("Stale catalog guard", `:40-43`), so the pattern is established in this 
component; the execute path is the one call that never got it.
   - Regression test added with this report (fails on 7ce9a682): two tools in 
the catalog, `executeTool` returns a deferred promise, run the first, switch to 
the second in the selector, then resolve — `queryByTestId('tool-result')` must 
be absent, but the stale output is rendered.
   
   ### Impact
   
   An operator who uses the playground to confirm what a transcript's tool call 
actually returns can read a different tool's output under the selected tool's 
name and risk level. Because the pane is the "human-driven escape hatch" for 
exactly that comparison, a misattributed result is worse than a missing one: it 
looks like a successful manual reproduction of a call that was never made.
   
   ### Expected behavior
   
   A response for a tool or cluster scope that is no longer the one on screen 
is discarded — no result and no success toast — while the Run button's loading 
state still clears. Output that does land must belong to the tool currently 
selected, in every path that changes the selection or closes the modal.
   
   ### Related work
   
   - #4609 (PR #4615) and #4612 (PR #4618) — a request's failure and a stale 
response respectively, rendered as if they were the current state: same 
"response outlives its context" family.
   - #4585 (PR #4586) — a superseded comparison overwriting a newer result.
   - #4606 (merged, 5b761df8) — introduced this component.
   
   #
   
   ## PR
   
   Fix: TBD.
   


-- 
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