Skip to content

Commit 7f79afe

Browse files
committed
feat: add plain regenerate response action
add a regenerate control to feedback actions andrerun the latest prompt without duplicating the user message - coupled with chatflow config
1 parent 029ad04 commit 7f79afe

File tree

10 files changed

+168515
-13
lines changed

10 files changed

+168515
-13
lines changed

dist/components/Bot.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/components/bubbles/BotBubble.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type Props = {
2121
renderHTML?: boolean;
2222
handleActionClick: (elem: any, action: IAction | undefined | null) => void;
2323
handleSourceDocumentsClick: (src: any) => void;
24+
onRegenerateResponse?: () => void;
2425
isTTSEnabled?: boolean;
2526
isTTSLoading?: Record<string, boolean>;
2627
isTTSPlaying?: Record<string, boolean>;

dist/components/bubbles/BotBubble.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/components/buttons/FeedbackButtons.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ type RatingButtonProps = {
99
export declare const CopyToClipboardButton: (props: RatingButtonProps) => JSX.Element;
1010
export declare const ThumbsUpButton: (props: RatingButtonProps) => JSX.Element;
1111
export declare const ThumbsDownButton: (props: RatingButtonProps) => JSX.Element;
12+
export declare const RegenerateResponseButton: (props: RatingButtonProps) => JSX.Element;
1213
export {};
1314
//# sourceMappingURL=FeedbackButtons.d.ts.map

dist/components/buttons/FeedbackButtons.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/web.js

Lines changed: 84221 additions & 1 deletion
Large diffs are not rendered by default.

dist/web.umd.js

Lines changed: 84229 additions & 1 deletion
Large diffs are not rendered by default.

src/components/Bot.tsx

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,28 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
865865
handleSubmit(prompt);
866866
};
867867

868+
const handleRegenerateResponse = async (messageIndex: number) => {
869+
if (loading()) return;
870+
if (previews().length) return;
871+
if (startInputType() === 'formInput') return;
872+
873+
const currentMessages = messages();
874+
const targetMessage = currentMessages[messageIndex];
875+
if (!targetMessage || targetMessage.type !== 'apiMessage') return;
876+
877+
const previousMessage = currentMessages[messageIndex - 1];
878+
if (!previousMessage || previousMessage.type !== 'userMessage' || previousMessage.fileUploads?.length) return;
879+
880+
setFollowUpPrompts([]);
881+
const updatedMessages = currentMessages.slice(0, messageIndex);
882+
addChatMessage(updatedMessages);
883+
setMessages(updatedMessages);
884+
885+
// Note: chatId is kept so the server retains conversation context up to this point.
886+
// The server's history will still include messages that were removed client-side
887+
await handleSubmit(previousMessage.message, undefined, undefined, { skipAddUserMessage: true });
888+
};
889+
868890
const updateMetadata = (data: any, input: string) => {
869891
if (data.chatId) {
870892
setChatId(data.chatId);
@@ -1141,7 +1163,12 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
11411163
};
11421164

11431165
// Handle form submission
1144-
const handleSubmit = async (value: string | object, action?: IAction | undefined | null, humanInput?: any) => {
1166+
const handleSubmit = async (
1167+
value: string | object,
1168+
action?: IAction | undefined | null,
1169+
humanInput?: any,
1170+
options?: { skipAddUserMessage?: boolean },
1171+
) => {
11451172
if (typeof value === 'string' && value.trim() === '') {
11461173
const containsFile = previews().filter((item) => !item.mime.startsWith('image') && item.type !== 'audio').length > 0;
11471174
if (!previews().length || (previews().length && containsFile)) {
@@ -1178,11 +1205,13 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
11781205

11791206
clearPreviews();
11801207

1181-
setMessages((prevMessages) => {
1182-
const messages: MessageType[] = [...prevMessages, { message: value as string, type: 'userMessage', fileUploads: uploads }];
1183-
addChatMessage(messages);
1184-
return messages;
1185-
});
1208+
if (!options?.skipAddUserMessage) {
1209+
setMessages((prevMessages) => {
1210+
const messages: MessageType[] = [...prevMessages, { message: value as string, type: 'userMessage', fileUploads: uploads }];
1211+
addChatMessage(messages);
1212+
return messages;
1213+
});
1214+
}
11861215

11871216
const body: IncomingInput = {
11881217
question: value,
@@ -2581,6 +2610,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
25812610
showAvatar={props.botMessage?.showAvatar}
25822611
avatarSrc={props.botMessage?.avatarSrc}
25832612
chatFeedbackStatus={chatFeedbackStatus()}
2613+
onRegenerateResponse={() => handleRegenerateResponse(index())}
25842614
fontSize={props.fontSize}
25852615
isLoading={loading() && index() === messages().length - 1}
25862616
showAgentMessages={props.showAgentMessages}

src/components/bubbles/BotBubble.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Marked } from '@ts-stack/markdown';
44
import DOMPurify from 'dompurify';
55
import { FeedbackRatingType, sendFeedbackQuery, sendFileDownloadQuery, updateFeedbackQuery } from '@/queries/sendMessageQuery';
66
import { FileUpload, IAction, MessageType } from '../Bot';
7-
import { CopyToClipboardButton, ThumbsDownButton, ThumbsUpButton } from '../buttons/FeedbackButtons';
7+
import { CopyToClipboardButton, RegenerateResponseButton, ThumbsDownButton, ThumbsUpButton } from '../buttons/FeedbackButtons';
88
import { TTSButton } from '../buttons/TTSButton';
99
import FeedbackContentDialog from '../FeedbackContentDialog';
1010
import { AgentReasoningBubble } from './AgentReasoningBubble';
@@ -35,6 +35,7 @@ type Props = {
3535
renderHTML?: boolean;
3636
handleActionClick: (elem: any, action: IAction | undefined | null) => void;
3737
handleSourceDocumentsClick: (src: any) => void;
38+
onRegenerateResponse?: () => void;
3839
// TTS props
3940
isTTSEnabled?: boolean;
4041
isTTSLoading?: Record<string, boolean>;
@@ -577,6 +578,7 @@ export const BotBubble = (props: Props) => {
577578
</Show>
578579
{props.chatFeedbackStatus && props.message.messageId && (
579580
<>
581+
<RegenerateResponseButton feedbackColor={props.feedbackColor} onClick={() => props.onRegenerateResponse?.()} />
580582
<CopyToClipboardButton feedbackColor={props.feedbackColor} onClick={() => copyMessageToClipboard()} />
581583
<Show when={copiedMessage()}>
582584
<div class="copied-message" style={{ color: props.feedbackColor ?? defaultFeedbackColor }}>

src/components/buttons/FeedbackButtons.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { JSX, Show } from 'solid-js';
22
import { Spinner } from './SendButton';
3-
import { ClipboardIcon, ThumbsDownIcon, ThumbsUpIcon } from '../icons';
3+
import { ClipboardIcon, DeleteIcon as RefreshIcon, ThumbsDownIcon, ThumbsUpIcon } from '../icons';
44

55
type RatingButtonProps = {
66
feedbackColor?: string;
@@ -70,3 +70,23 @@ export const ThumbsDownButton = (props: RatingButtonProps) => {
7070
</button>
7171
);
7272
};
73+
74+
export const RegenerateResponseButton = (props: RatingButtonProps) => {
75+
return (
76+
<button
77+
type="button"
78+
disabled={props.isDisabled || props.isLoading}
79+
{...props}
80+
class={
81+
'w-4 h-4 p-0 justify-center font-semibold text-white focus:outline-none inline-flex items-center disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100 transition-all filter hover:brightness-90 active:brightness-75 chatbot-button ' +
82+
props.class
83+
}
84+
style={{ background: 'transparent', border: 'none' }}
85+
title="Regenerate response"
86+
>
87+
<Show when={!props.isLoading} fallback={<Spinner class="text-white" />}>
88+
<RefreshIcon color={props.feedbackColor ?? defaultFeedbackColor} class={'send-icon flex ' + (props.disableIcon ? 'hidden' : '')} />
89+
</Show>
90+
</button>
91+
);
92+
};

0 commit comments

Comments
 (0)