mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-04 20:08:40 +00:00
* fix(frontend): hide stale follow-up chips while a turn is streaming (#3395) Follow-up suggestion chips are generated when a turn finishes streaming, but `showFollowups` did not exclude the streaming state. If a user sent a new message before the previous response finished, the old chips (and the lone close button) stayed mounted and overlapped the To-dos panel and the input box. Gate `showFollowups` on `status !== "streaming"` so stale chips are never shown while a response is in progress. * fix(frontend): suppress follow-up suggestions for user-interrupted turns (#3395) Gating showFollowups on status alone was not enough: stopping a streaming turn (or sending a new message mid-stream, which also stops it) flips status back to a non-streaming state and triggers the follow-up generation effect on that streaming->ready transition, producing chips for a half-finished, interrupted response. Track user interruption with a ref set in the stop path, and have the generation effect skip that transition (and clear/hide any pending chips), so follow-ups are only generated for turns that finished on their own.
This commit is contained in:
parent
4795452102
commit
c0f1cfef69
@ -417,6 +417,9 @@ export function InputBox({
|
||||
useState<string | null>(null);
|
||||
const lastGeneratedForAiIdRef = useRef<string | null>(null);
|
||||
const wasStreamingRef = useRef(false);
|
||||
// Set when the user stops a streaming turn. Such a turn ends on a
|
||||
// half-finished response, so we must NOT generate follow-up suggestions for it.
|
||||
const stoppedByUserRef = useRef(false);
|
||||
const messagesRef = useRef(thread.messages);
|
||||
|
||||
const clearVoiceRestartTimer = useCallback(() => {
|
||||
@ -1148,6 +1151,16 @@ export function InputBox({
|
||||
],
|
||||
);
|
||||
|
||||
const handleStopStreaming = useCallback(() => {
|
||||
// Mark the in-progress turn as user-interrupted so the next
|
||||
// streaming->ready transition does not suggest follow-ups for it.
|
||||
stoppedByUserRef.current = true;
|
||||
setFollowups([]);
|
||||
setFollowupsHidden(true);
|
||||
setFollowupsLoading(false);
|
||||
onStop?.();
|
||||
}, [onStop]);
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
async (message: PromptInputMessage) => {
|
||||
if (status === "streaming") {
|
||||
@ -1200,7 +1213,7 @@ export function InputBox({
|
||||
return handleCompactCommand();
|
||||
}
|
||||
if (submitAction.kind === "stop") {
|
||||
onStop?.();
|
||||
handleStopStreaming();
|
||||
return;
|
||||
}
|
||||
if (submitAction.kind === "empty") {
|
||||
@ -1215,7 +1228,7 @@ export function InputBox({
|
||||
abortVoiceInput,
|
||||
handleCompactCommand,
|
||||
handleGoalCommand,
|
||||
onStop,
|
||||
handleStopStreaming,
|
||||
selectedSlashSkill,
|
||||
status,
|
||||
submitThreadMessage,
|
||||
@ -1923,6 +1936,10 @@ export function InputBox({
|
||||
!showSkillSuggestions &&
|
||||
!selectedSlashSkill &&
|
||||
!followupsHidden &&
|
||||
// Never show stale follow-up chips while a turn is streaming: a message
|
||||
// sent before the previous response finished would otherwise leave the
|
||||
// old chips (and the lone close button) overlapping the input box.
|
||||
status !== "streaming" &&
|
||||
(followupsLoading || followups.length > 0);
|
||||
|
||||
useEffect(() => {
|
||||
@ -1945,6 +1962,13 @@ export function InputBox({
|
||||
return;
|
||||
}
|
||||
|
||||
// The turn was interrupted by the user, so skip generating follow-ups for
|
||||
// this half-finished response.
|
||||
if (stoppedByUserRef.current) {
|
||||
stoppedByUserRef.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (disabled || isMock) {
|
||||
return;
|
||||
}
|
||||
@ -2666,7 +2690,7 @@ export function InputBox({
|
||||
onClick={(e) => {
|
||||
if (status === "streaming") {
|
||||
e.preventDefault();
|
||||
onStop?.();
|
||||
handleStopStreaming();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user