diff --git a/web/src/app/chat/ChatPage.tsx b/web/src/app/chat/ChatPage.tsx
index 927b21b58..b60d3a5d2 100644
--- a/web/src/app/chat/ChatPage.tsx
+++ b/web/src/app/chat/ChatPage.tsx
@@ -132,18 +132,16 @@ import {
import { getSourceMetadata } from "@/lib/sources";
import { UserSettingsModal } from "./modal/UserSettingsModal";
-import { AlignStartVertical } from "lucide-react";
import { AgenticMessage } from "./message/AgenticMessage";
import AssistantModal from "../assistants/mine/AssistantModal";
-import {
- OperatingSystem,
- useOperatingSystem,
- useSidebarShortcut,
-} from "@/lib/browserUtilities";
-import { Button } from "@/components/ui/button";
+import { useSidebarShortcut } from "@/lib/browserUtilities";
import { ConfirmEntityModal } from "@/components/modals/ConfirmEntityModal";
+<<<<<<< HEAD
import { MessageChannel } from "node:worker_threads";
import { ChatSearchModal } from "./chat_search/ChatSearchModal";
+=======
+import { ErrorBanner } from "./message/Resubmit";
+>>>>>>> db242d0b3 (add error handling)
const TEMP_USER_MESSAGE_ID = -1;
const TEMP_ASSISTANT_MESSAGE_ID = -2;
@@ -1169,6 +1167,7 @@ export function ChatPage({
navigatingAway.current = false;
let frozenSessionId = currentSessionId();
updateCanContinue(false, frozenSessionId);
+ setUncaughtError(null);
// Mark that we've sent a message for this session in the current page load
markSessionMessageSent(frozenSessionId);
@@ -1319,6 +1318,7 @@ export function ChatPage({
let isStreamingQuestions = true;
let includeAgentic = false;
let secondLevelMessageId: number | null = null;
+ let isAgentic: boolean = false;
let initialFetchDetails: null | {
user_message_id: number;
@@ -1481,6 +1481,9 @@ export function ChatPage({
second_level_generating = true;
}
}
+ if (Object.hasOwn(packet, "is_agentic")) {
+ isAgentic = (packet as any).is_agentic;
+ }
if (Object.hasOwn(packet, "refined_answer_improvement")) {
isImprovement = (packet as RefinedAnswerImprovement)
@@ -1514,6 +1517,7 @@ export function ChatPage({
);
} else if (Object.hasOwn(packet, "sub_question")) {
updateChatState("toolBuilding", frozenSessionId);
+ isAgentic = true;
is_generating = true;
sub_questions = constructSubQuestions(
sub_questions,
@@ -1714,6 +1718,7 @@ export function ChatPage({
sub_questions: sub_questions,
second_level_generating: second_level_generating,
agentic_docs: agenticDocs,
+ is_agentic: isAgentic,
},
...(includeAgentic
? [
@@ -2062,6 +2067,26 @@ export function ChatPage({
const [sharedChatSession, setSharedChatSession] =
useState();
+ const handleResubmitLastMessage = () => {
+ // Grab the last user-type message
+ const lastUserMsg = messageHistory
+ .slice()
+ .reverse()
+ .find((m) => m.type === "user");
+ if (!lastUserMsg) {
+ setPopup({
+ message: "No previously-submitted user message found.",
+ type: "error",
+ });
+ return;
+ }
+ // We call onSubmit, passing a `messageOverride`
+ onSubmit({
+ messageIdToResend: lastUserMsg.messageId,
+ messageOverride: lastUserMsg.message,
+ });
+ };
+
const showShareModal = (chatSession: ChatSession) => {
setSharedChatSession(chatSession);
};
@@ -2644,9 +2669,9 @@ export function ChatPage({
: null
}
>
- {message.sub_questions &&
- message.sub_questions.length > 0 ? (
+ {message.is_agentic ? (
- {message.message}
- {message.stackTrace && (
-
- setStackTraceModalContent(
- message.stackTrace!
- )
- }
- className="ml-2 cursor-pointer underline"
- >
- Show stack trace.
-
- )}
-
+
+ setStackTraceModalContent(
+ message.stackTrace!
+ )
+ : undefined
+ }
+ />
}
/>
diff --git a/web/src/app/chat/interfaces.ts b/web/src/app/chat/interfaces.ts
index aa4970e25..6f614c7d2 100644
--- a/web/src/app/chat/interfaces.ts
+++ b/web/src/app/chat/interfaces.ts
@@ -103,6 +103,7 @@ export interface Message {
overridden_model?: string;
stopReason?: StreamStopReason | null;
sub_questions?: SubQuestionDetail[] | null;
+ is_agentic?: boolean | null;
// Streaming only
second_level_generating?: boolean;
@@ -148,6 +149,7 @@ export interface BackendMessage {
comments: any;
parentMessageId: number | null;
refined_answer_improvement: boolean | null;
+ is_agentic: boolean | null;
}
export interface MessageResponseIDInfo {
diff --git a/web/src/app/chat/message/AgenticMessage.tsx b/web/src/app/chat/message/AgenticMessage.tsx
index 6bc114960..b206d8a96 100644
--- a/web/src/app/chat/message/AgenticMessage.tsx
+++ b/web/src/app/chat/message/AgenticMessage.tsx
@@ -50,6 +50,9 @@ import "katex/dist/katex.min.css";
import SubQuestionsDisplay from "./SubQuestionsDisplay";
import { StatusRefinement } from "../Refinement";
import { copyAll, handleCopy } from "./copyingUtils";
+import { Button } from "@/components/ui/button";
+import { RefreshCw } from "lucide-react";
+import { ErrorBanner, Resubmit } from "./Resubmit";
export const AgenticMessage = ({
isStreamingQuestions,
@@ -84,7 +87,9 @@ export const AgenticMessage = ({
secondLevelSubquestions,
toggleDocDisplay,
error,
+ resubmit,
}: {
+ resubmit?: () => void;
isStreamingQuestions: boolean;
isGenerating: boolean;
docSidebarToggled?: boolean;
@@ -268,8 +273,8 @@ export const AgenticMessage = ({
? docs
: agenticDocs
: agenticDocs && agenticDocs.length > 0
- ? agenticDocs
- : docs
+ ? agenticDocs
+ : docs
}
subQuestions={[
...(subQuestions || []),
@@ -437,8 +442,8 @@ export const AgenticMessage = ({
!allowDocuments
? []
: isViewingInitialAnswer
- ? docs!
- : agenticDocs!
+ ? docs!
+ : agenticDocs!
}
toggleDocumentSelection={() => {
toggleDocumentSelection!(!isViewingInitialAnswer);
@@ -503,9 +508,7 @@ export const AgenticMessage = ({
content
)}
{error && (
-
- {error}
-
+
)}
@@ -513,15 +516,13 @@ export const AgenticMessage = ({
) : isComplete ? (
error && (
- {error}
+
)
) : (
<>
{error && (
-
- {error}
-
+
)}
>
)}
diff --git a/web/src/app/chat/message/Resubmit.tsx b/web/src/app/chat/message/Resubmit.tsx
new file mode 100644
index 000000000..c8febd55a
--- /dev/null
+++ b/web/src/app/chat/message/Resubmit.tsx
@@ -0,0 +1,58 @@
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { AlertCircle } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { RefreshCw } from "lucide-react";
+
+interface ResubmitProps {
+ resubmit: () => void;
+}
+
+export const Resubmit: React.FC = ({ resubmit }) => {
+ return (
+
+
+ There was an error with the response.
+
+
+
+ );
+};
+
+export const ErrorBanner = ({
+ error,
+ showStackTrace,
+ resubmit,
+}: {
+ error: string;
+ showStackTrace?: () => void;
+ resubmit?: () => void;
+}) => {
+ return (
+
+
+
+ Error
+
+ {error}
+ {showStackTrace && (
+
+ Show stack trace
+
+ )}
+
+
+ {resubmit &&
}
+
+ );
+};
diff --git a/web/src/components/ui/alert.tsx b/web/src/components/ui/alert.tsx
index 74b63b270..ee668e2f4 100644
--- a/web/src/components/ui/alert.tsx
+++ b/web/src/components/ui/alert.tsx
@@ -8,8 +8,10 @@ const alertVariants = cva(
{
variants: {
variant: {
+ broken:
+ "border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-100 dark:dark:border-red-900 dark:[&>svg]:text-red-700 bg-red-50 dark:bg-red-950",
+ ark: "border-amber-500/50 text-amber-500 dark:border-amber-500 [&>svg]:text-amber-500 dark:border-amber-900/50 dark:text-amber-900 dark:dark:border-amber-900 dark:[&>svg]:text-amber-900 bg-amber-50 dark:bg-amber-950",
info: "border-black/50 dark:border-black dark:border-black/50 dark:dark:border-black",
-
default:
"bg-neutral-50 text-neutral-darker dark:bg-neutral-950 dark:text-text",
destructive:
diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx
index fa8fd9d6f..3a8b69083 100644
--- a/web/src/components/ui/button.tsx
+++ b/web/src/components/ui/button.tsx
@@ -9,6 +9,8 @@ const buttonVariants = cva(
{
variants: {
variant: {
+ agent:
+ "bg-agent text-white hover:bg-agent-hovered dark:bg-agent dark:text-white dark:hover:bg-agent/90",
success:
"bg-green-100 text-green-600 hover:bg-green-500/90 dark:bg-green-700 dark:text-green-100 dark:hover:bg-green-600/90",
"success-reverse":