Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dist/components/Bot.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ export type MessageType = {
id?: string;
followUpPrompts?: string;
dateTime?: string;
thinking?: string;
thinkingDuration?: number;
isThinking?: boolean;
};
type observerConfigType = (accessor: string | boolean | object | MessageType[]) => void;
export type observersConfigType = Record<'observeUserInput' | 'observeLoading' | 'observeMessages', observerConfigType>;
Expand Down
2 changes: 1 addition & 1 deletion dist/components/Bot.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/components/bubbles/BotBubble.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions dist/components/bubbles/ThinkingBubble.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type Props = {
thinking?: string;
thinkingDuration?: number;
isThinking?: boolean;
backgroundColor?: string;
textColor?: string;
};
export declare const ThinkingCard: (props: Props) => import("solid-js").JSX.Element;
export {};
//# sourceMappingURL=ThinkingBubble.d.ts.map
1 change: 1 addition & 0 deletions dist/components/bubbles/ThinkingBubble.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions dist/components/treeview/AgentflowIcons.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { JSXElement } from 'solid-js';
type IconProps = {
size?: number;
color?: string;
};
export declare const MaximizeIcon: (props: IconProps) => import("solid-js").JSX.Element;
type AgentflowIconEntry = {
name: string;
icon: (props: IconProps) => JSXElement;
color: string;
};
export declare const AGENTFLOW_ICONS: AgentflowIconEntry[];
export declare function getAgentflowIcon(name: string): AgentflowIconEntry | null;
export {};
//# sourceMappingURL=AgentflowIcons.d.ts.map
1 change: 1 addition & 0 deletions dist/components/treeview/AgentflowIcons.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions dist/components/treeview/NodeDetailsDialog.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
type NodeDetailsDialogProps = {
isOpen: boolean;
onClose: () => void;
node: {
label: string;
name: string;
status: string;
data: any;
} | null;
backgroundColor?: string;
textColor?: string;
apiHost?: string;
chatflowid?: string;
chatId?: string;
};
export declare const NodeDetailsDialog: (props: NodeDetailsDialogProps) => import("solid-js").JSX.Element;
export {};
//# sourceMappingURL=NodeDetailsDialog.d.ts.map
1 change: 1 addition & 0 deletions dist/components/treeview/NodeDetailsDialog.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/web.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/web.umd.js

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions src/components/Bot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ export type MessageType = {
id?: string;
followUpPrompts?: string;
dateTime?: string;
thinking?: string;
thinkingDuration?: number;
isThinking?: boolean;
};

type IUploads = {
Expand Down Expand Up @@ -495,6 +498,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
const [isLeadSaved, setIsLeadSaved] = createSignal(false);
const [leadEmail, setLeadEmail] = createSignal('');
const [disclaimerPopupOpen, setDisclaimerPopupOpen] = createSignal(false);
const [isThinking, setIsThinking] = createSignal(false);

const [openFeedbackDialog, setOpenFeedbackDialog] = createSignal(false);
const [feedback, setFeedback] = createSignal('');
Expand Down Expand Up @@ -788,6 +792,41 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
});
};

const handleThinkingEvent = (data: string, duration?: number) => {
if (data && duration === undefined) {
setIsThinking(true);
setMessages((prevMessages) => {
const lastMsg = prevMessages[prevMessages.length - 1];
if (lastMsg.type === 'userMessage') return prevMessages;
const allMessages = [...prevMessages.slice(0, -1), { ...lastMsg, thinking: (lastMsg.thinking || '') + data, isThinking: true }];
addChatMessage(allMessages);
return allMessages;
});
} else if (data === '' && duration !== undefined) {
setIsThinking(false);
setMessages((prevMessages) => {
const lastMsg = prevMessages[prevMessages.length - 1];
if (lastMsg.type === 'userMessage') return prevMessages;
const allMessages = [...prevMessages.slice(0, -1), { ...lastMsg, thinkingDuration: duration, isThinking: false }];
addChatMessage(allMessages);
return allMessages;
});
}
};
Comment on lines +795 to +815

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The logic in handleThinkingEvent seems a bit brittle. It relies on a strict contract where either data is provided for streaming, or an empty data string and a duration are provided for completion. If the backend sends a payload that doesn't match these exact conditions (e.g., data is undefined but duration is present), the event might be ignored. Consider making the logic more robust by prioritizing the duration check to signify the final event, which makes the handler more resilient to variations in the event payload.

  const handleThinkingEvent = (data: string, duration?: number) => {
    if (duration !== undefined) {
      // This is the final thinking event, which includes the duration.
      setIsThinking(false);
      setMessages((prevMessages) => {
        const lastMsg = prevMessages[prevMessages.length - 1];
        if (lastMsg.type === 'userMessage') return prevMessages;
        const thinkingText = data ? (lastMsg.thinking || '') + data : lastMsg.thinking;
        const allMessages = [...prevMessages.slice(0, -1), { ...lastMsg, thinking: thinkingText, thinkingDuration: duration, isThinking: false }];
        addChatMessage(allMessages);
        return allMessages;
      });
    } else if (data) {
      // This is a streaming thinking event.
      setIsThinking(true);
      setMessages((prevMessages) => {
        const lastMsg = prevMessages[prevMessages.length - 1];
        if (lastMsg.type === 'userMessage') return prevMessages;
        const allMessages = [...prevMessages.slice(0, -1), { ...lastMsg, thinking: (lastMsg.thinking || '') + data, isThinking: true }];
        addChatMessage(allMessages);
        return allMessages;
      });
    }
  };


const finalizeThinking = () => {
if (isThinking()) {
setIsThinking(false);
setMessages((prevMessages) => {
const lastMsg = prevMessages[prevMessages.length - 1];
if (lastMsg.type === 'userMessage') return prevMessages;
const allMessages = [...prevMessages.slice(0, -1), { ...lastMsg, isThinking: false }];
addChatMessage(allMessages);
return allMessages;
});
}
};

const clearPreviews = () => {
// Revoke the data uris to avoid memory leaks
previews().forEach((file) => URL.revokeObjectURL(file.preview));
Expand Down Expand Up @@ -918,6 +957,9 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
case 'agentReasoning':
updateLastMessageAgentReasoning(payload.data);
break;
case 'thinking':
handleThinkingEvent(payload.data, payload.duration);
break;
case 'agentFlowEvent':
updateAgentFlowEvent(payload.data);
break;
Expand All @@ -941,6 +983,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
closeResponse();
break;
case 'end':
finalizeThinking();
setLocalStorageChatflow(chatflowid, chatId);
closeResponse();
break;
Expand Down Expand Up @@ -1193,6 +1236,8 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
agentFlowExecutedData: data?.agentFlowExecutedData,
action: data?.action,
artifacts: data?.artifacts,
thinking: data?.reasonContent?.thinking,
thinkingDuration: data?.reasonContent?.thinkingDuration,
type: 'apiMessage' as messageType,
feedback: null,
dateTime: new Date().toISOString(),
Expand Down Expand Up @@ -1314,6 +1359,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
messages.push({ message: '', type: 'leadCaptureMessage' });
}
setMessages(messages);
setShowScrollButton(false);
} catch (error: any) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`;
console.error(`error: ${errorData}`);
Expand Down Expand Up @@ -1397,6 +1443,12 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
if (message.fileAnnotations) chatHistory.fileAnnotations = message.fileAnnotations;
if (message.fileUploads) chatHistory.fileUploads = message.fileUploads;
if (message.agentReasoning) chatHistory.agentReasoning = message.agentReasoning;
if ((message as any).reasonContent && typeof (message as any).reasonContent === 'object') {
chatHistory.thinking = (message as any).reasonContent.thinking;
chatHistory.thinkingDuration = (message as any).reasonContent.thinkingDuration;
}
if (message.thinking) chatHistory.thinking = message.thinking;
if (message.thinkingDuration !== undefined) chatHistory.thinkingDuration = message.thinkingDuration;
Comment on lines +1446 to +1451

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic for populating thinking and thinkingDuration from local storage is verbose and relies on casting to any, which reduces type safety. It appears to handle two different structures for the same data (reasonContent object vs. top-level properties), with the top-level properties taking precedence. This can be simplified for better readability and maintainability.

              const reasonContent = (message as any).reasonContent;
              chatHistory.thinking = message.thinking ?? reasonContent?.thinking;
              if (message.thinkingDuration !== undefined) {
                chatHistory.thinkingDuration = message.thinkingDuration;
              } else {
                chatHistory.thinkingDuration = reasonContent?.thinkingDuration;
              }

if (message.action) chatHistory.action = message.action;
if (message.artifacts) chatHistory.artifacts = message.artifacts;
if (message.followUpPrompts) chatHistory.followUpPrompts = message.followUpPrompts;
Expand Down
Loading