updated + functional

This commit is contained in:
pablodanswer 2025-01-23 13:31:01 -08:00 committed by Evan Lohn
parent d32d1c6079
commit 28ba01b361
5 changed files with 451 additions and 133 deletions

View File

@ -250,25 +250,21 @@ export const constructSubQuestions = (
console.log("STOP REASON");
console.log(newDetail);
const { level, level_question_nr } = newDetail;
const actual_level_question_nr = level_question_nr ?? 0;
let subQuestion = updatedSubQuestions.find(
(sq) =>
sq.level === level && sq.level_question_nr === actual_level_question_nr
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
);
if (subQuestion) {
subQuestion.is_complete = true;
}
} else if ("top_documents" in newDetail) {
const { level, level_question_nr, top_documents } = newDetail;
const actual_level_question_nr = level_question_nr ?? 0;
let subQuestion = updatedSubQuestions.find(
(sq) =>
sq.level === level && sq.level_question_nr === actual_level_question_nr
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
);
if (!subQuestion) {
subQuestion = {
level: level ?? 0,
level_question_nr: actual_level_question_nr,
level_question_nr: level_question_nr ?? 0,
question: "",
answer: "",
sub_queries: [],
@ -280,17 +276,15 @@ export const constructSubQuestions = (
} else if ("answer_piece" in newDetail) {
// Handle AgentAnswerPiece
const { level, level_question_nr, answer_piece } = newDetail;
const actual_level_question_nr = level_question_nr;
// Find or create the relevant SubQuestionDetail
let subQuestion = updatedSubQuestions.find(
(sq) =>
sq.level === level && sq.level_question_nr === actual_level_question_nr
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
);
if (!subQuestion) {
subQuestion = {
level,
level_question_nr: actual_level_question_nr,
level_question_nr,
question: "",
answer: "",
sub_queries: [],
@ -327,19 +321,17 @@ export const constructSubQuestions = (
} else if ("sub_query" in newDetail) {
// Handle SubQueryPiece
const { level, level_question_nr, query_id, sub_query } = newDetail;
const actual_level_question_nr = level_question_nr;
// Find the relevant SubQuestionDetail
let subQuestion = updatedSubQuestions.find(
(sq) =>
sq.level === level && sq.level_question_nr === actual_level_question_nr
(sq) => sq.level === level && sq.level_question_nr === level_question_nr
);
if (!subQuestion) {
// If we receive a sub_query before its parent question, create a placeholder
subQuestion = {
level,
level_question_nr: actual_level_question_nr,
level_question_nr: level_question_nr,
question: "",
answer: "",
sub_queries: [],

View File

@ -67,18 +67,9 @@ import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import "katex/dist/katex.min.css";
import SubQuestionsDisplay from "./SubQuestionsDisplay";
import SubQuestionProgress from "./SubQuestionProgress";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/Spinner";
import { LoadingAnimation } from "@/components/Loading";
import { LoadingIndicator } from "react-select/dist/declarations/src/components/indicators";
import {
StreamingPhase,
StreamingPhaseText,
useStreamingMessages,
} from "./StreamingMessages";
import { Badge } from "@/components/ui/badge";
import RefinemenetBadge from "../refinmentBadge";
import SubQuestionProgress from "./SubQuestionProgress";
export const AgenticMessage = ({
secondLevelAssistantMessage,
@ -466,7 +457,7 @@ export const AgenticMessage = ({
{/* For debugging purposes */}
{/* <SubQuestionProgress subQuestions={subQuestions || []} /> */}
{/* */}
{(allowStreaming &&
finalContent &&
finalContent.length > 8) ||
@ -479,8 +470,13 @@ export const AgenticMessage = ({
Answer
</div>
{true ? (
{!secondLevelAssistantMessage &&
// !isGenerating &&
subQuestions &&
subQuestions.length > 0 ? (
<RefinemenetBadge
finished={!secondLevelGenerating}
overallAnswer={secondLevelAssistantMessage || ""}
secondLevelSubquestions={secondLevelSubquestions}
toggleInitialAnswerVieinwg={() => {
setIsViewingInitialAnswer(

View File

@ -25,6 +25,41 @@ import { CheckIcon, ChevronDown } from "lucide-react";
import { PHASE_MIN_MS, useStreamingMessages } from "./StreamingMessages";
import { CirclingArrowIcon } from "@/components/icons/icons";
export const StatusIndicator = ({ status }: { status: ToggleState }) => {
return (
<>
{" "}
{status != ToggleState.InProgress ? (
<div
className={` h-full w-full rounded-full z-10
bg-background border-3 border-background-900 "
${
status === ToggleState.Todo
? "!border-4 border border-background-900 bg-background"
: false
? "bg-background border-3 border border-background-900 rotating-border"
: "bg-background-900 flex items-center justify-center"
}
`}
>
{status === ToggleState.Done && (
<CheckIcon className="m-auto text-white" size={8} />
)}
</div>
) : (
<div className="relative h-full w-full">
<div className="absolute top-0 left-0 z-[100] h-full w-full rounded-full bg-background" />
<CirclingArrowIcon
size={12}
className="absolute top-0 left-0 z-[2000] h-full w-full animate-spin"
/>
</div>
)}
</>
);
};
export interface TemporaryDisplay {
question: string;
tinyQuestion: string;
@ -43,7 +78,7 @@ interface SubQuestionsDisplayProps {
overallAnswerGenerating?: boolean;
}
enum ToggleState {
export enum ToggleState {
Todo,
InProgress,
Done,
@ -300,34 +335,9 @@ const SubQuestionDisplay: React.FC<{
ref={questionRef}
className={`flex items-start ${!isLast ? "pb-2" : ""}`}
>
{status != ToggleState.InProgress ? (
<div
className={`absolute left-0 w-3 h-3 rounded-full mt-[12px] z-10
bg-background border-3 border-background-900 "
${
status === ToggleState.Todo
? "!border-4 border border-background-900 bg-background"
: false
? "bg-background border-3 border border-background-900 rotating-border"
: "bg-background-900 flex items-center justify-center"
}
`}
>
{status === ToggleState.Done && (
<CheckIcon className="m-auto text-white" size={8} />
)}
</div>
) : (
<>
<div className="absolute z-[100] left-0 mt-[12px] w-3 h-3 rounded-full bg-background" />
<CirclingArrowIcon
size={12}
className="absolute z-[2000] left-0 mt-[12px] w-3 h-3 animate-spin"
/>
</>
)}
<div className="absolute left-0 w-3 h-3 rounded-full mt-[12px] z-10">
<StatusIndicator status={status} />
</div>
<div className="ml-8 w-full">
<div
className="flex -mx-2 rounded-md px-2 hover:bg-[#F5F3ED] items-start py-1.5 my-.5 cursor-pointer"

View File

@ -1,4 +1,5 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import {
Tooltip,
TooltipTrigger,
@ -6,69 +7,109 @@ import {
TooltipContent,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { FiChevronRight, FiGlobe } from "react-icons/fi";
import {
StreamingPhase,
StreamingPhaseText,
} from "./message/StreamingMessages";
import { SubQuestionDetail } from "./interfaces";
import { useEffect, useRef, useState } from "react";
import { FiChevronRight, FiChevronDown, FiGlobe } from "react-icons/fi";
import { CheckIcon } from "lucide-react";
import { CirclingArrowIcon } from "@/components/icons/icons";
import { StatusIndicator, ToggleState } from "./message/SubQuestionsDisplay";
// Replace with your actual icons/components
// import { CheckIcon, CirclingArrowIcon } from "@/your-icons-or-components";
/** --------------------------------------------------------------------------------
* 1. StreamingPhase + Display Text
* We add a pseudo "COMPARE" phase before COMPLETE to show "Comparing results"
* for at least 0.5 seconds.
* -------------------------------------------------------------------------------- */
export enum StreamingPhase {
WAITING = "WAITING",
SUB_QUERIES = "SUB_QUERIES",
CONTEXT_DOCS = "CONTEXT_DOCS",
ANSWER = "ANSWER",
COMPARE = "COMPARE",
COMPLETE = "COMPLETE",
EVALUATE = "EVALUATE",
}
export const StreamingPhaseText: Record<StreamingPhase, string> = {
[StreamingPhase.WAITING]: "Extracting key concepts",
[StreamingPhase.SUB_QUERIES]: "Identifying additional questions",
[StreamingPhase.CONTEXT_DOCS]: "Reading more documents",
[StreamingPhase.ANSWER]: "Generating refined answer",
[StreamingPhase.EVALUATE]: "Evaluating new context",
[StreamingPhase.COMPARE]: "Comparing results",
[StreamingPhase.COMPLETE]: "Finished",
};
/** --------------------------------------------------------------------------------
* 2. Ordered Phases: Ensure the COMPARE phase is inserted before COMPLETE
* -------------------------------------------------------------------------------- */
const PHASES_ORDER: StreamingPhase[] = [
StreamingPhase.WAITING,
StreamingPhase.SUB_QUERIES,
StreamingPhase.CONTEXT_DOCS,
StreamingPhase.ANSWER,
StreamingPhase.COMPARE,
StreamingPhase.COMPLETE,
];
/** --------------------------------------------------------------------------------
* 3. Hook to queue up phases in order, each with a minimum visible time of 0.5s
* -------------------------------------------------------------------------------- */
export function useOrderedPhases(externalPhase: StreamingPhase) {
const [phaseQueue, setPhaseQueue] = useState<StreamingPhase[]>([]);
const [displayedPhase, setDisplayedPhase] = useState<StreamingPhase>(
StreamingPhase.WAITING
);
const lastDisplayTimestampRef = useRef<number>(Date.now());
const [displayedPhases, setDisplayedPhases] = useState<StreamingPhase[]>([]);
const lastDisplayTimeRef = useRef<number>(Date.now());
const MIN_DELAY = 1000; // 0.5 seconds
const getPhaseIndex = (phase: StreamingPhase) => {
return PHASES_ORDER.indexOf(phase);
};
const getPhaseIndex = (phase: StreamingPhase) => PHASES_ORDER.indexOf(phase);
// Whenever externalPhase changes, add any missing steps into the queue
useEffect(() => {
setPhaseQueue((prevQueue) => {
const lastQueuedPhase =
prevQueue.length > 0 ? prevQueue[prevQueue.length - 1] : displayedPhase;
const lastDisplayed = displayedPhases[displayedPhases.length - 1];
const lastIndex = lastDisplayed
? getPhaseIndex(lastDisplayed)
: getPhaseIndex(StreamingPhase.WAITING);
const lastQueuedIndex = getPhaseIndex(lastQueuedPhase);
const externalIndex = getPhaseIndex(externalPhase);
let targetPhase = externalPhase;
let targetIndex = getPhaseIndex(targetPhase);
if (externalIndex <= lastQueuedIndex) {
// If externalPhase is COMPLETE, show "COMPARE" first (unless we've shown it already)
if (externalPhase === StreamingPhase.COMPLETE) {
if (!displayedPhases.includes(StreamingPhase.COMPARE)) {
targetPhase = StreamingPhase.COMPARE;
targetIndex = getPhaseIndex(targetPhase);
}
}
// If the new target is before or at the last displayed, do nothing
if (targetIndex <= lastIndex) {
return prevQueue;
}
// Otherwise, collect all missing phases from lastDisplayed+1 up to targetIndex
const missingPhases: StreamingPhase[] = [];
for (let i = lastQueuedIndex + 1; i <= externalIndex; i++) {
for (let i = lastIndex + 1; i <= targetIndex; i++) {
missingPhases.push(PHASES_ORDER[i]);
}
return [...prevQueue, ...missingPhases];
});
}, [externalPhase, displayedPhase]);
}, [externalPhase, displayedPhases]);
// Process the queue, displaying each queued phase for at least MIN_DELAY (0.5s)
useEffect(() => {
if (phaseQueue.length === 0) return;
let rafId: number;
let rafId: number;
const processQueue = () => {
const now = Date.now();
const elapsed = now - lastDisplayTimestampRef.current;
// Keep this at 1000ms from the original example (unchanged),
// but you can adjust if you want a different visible time in *this* component.
if (elapsed >= 1000) {
if (now - lastDisplayTimeRef.current >= MIN_DELAY) {
setPhaseQueue((prevQueue) => {
if (prevQueue.length > 0) {
const [next, ...rest] = prevQueue;
setDisplayedPhase(next);
lastDisplayTimestampRef.current = Date.now();
const [nextPhase, ...rest] = prevQueue;
setDisplayedPhases((prev) => [...prev, nextPhase]);
lastDisplayTimeRef.current = Date.now();
return rest;
}
return prevQueue;
@ -78,75 +119,348 @@ export function useOrderedPhases(externalPhase: StreamingPhase) {
};
rafId = requestAnimationFrame(processQueue);
return () => {
if (rafId) {
cancelAnimationFrame(rafId);
}
};
return () => cancelAnimationFrame(rafId);
}, [phaseQueue]);
return StreamingPhaseText[displayedPhase];
// displayedPhases are the ones currently shown, in the order they appeared
return displayedPhases;
}
/** --------------------------------------------------------------------------------
* 4. StatusIndicator: shows "running" (spinner) or "finished" (check)
* -------------------------------------------------------------------------------- */
/** --------------------------------------------------------------------------------
* 5. Example SubQuestionDetail interface (from your snippet)
* -------------------------------------------------------------------------------- */
export interface SubQuestionDetail {
question: string;
answer: string;
sub_queries?: { query: string }[] | null;
context_docs?: { top_documents: any[] } | null;
is_complete?: boolean;
}
/** --------------------------------------------------------------------------------
* 6. Final "RefinemenetBadge" component
* - Renders a "Refining" box with phases shown in order
* - Disappears once COMPLETE is reached, unless hovered
* - Preserves any states already shown
* -------------------------------------------------------------------------------- */
export default function RefinemenetBadge({
overallAnswer,
secondLevelSubquestions,
toggleInitialAnswerVieinwg,
isViewingInitialAnswer,
finished,
}: {
finished: boolean;
overallAnswer: string;
secondLevelSubquestions?: SubQuestionDetail[] | null;
toggleInitialAnswerVieinwg: () => void;
isViewingInitialAnswer: boolean;
}) {
const currentState = secondLevelSubquestions?.[0]
? secondLevelSubquestions[0].answer
? secondLevelSubquestions[0].is_complete
// Derive the 'externalPhase' from your existing logic:
const currentState =
overallAnswer.length > 0
? finished
? StreamingPhase.COMPLETE
: StreamingPhase.ANSWER
: secondLevelSubquestions[0].context_docs
? StreamingPhase.CONTEXT_DOCS
: secondLevelSubquestions[0].sub_queries
? StreamingPhase.SUB_QUERIES
: secondLevelSubquestions[0].question
? StreamingPhase.WAITING
: StreamingPhase.WAITING
: StreamingPhase.WAITING;
: secondLevelSubquestions?.[0]
? secondLevelSubquestions.every((q) => q.answer && q.answer.length > 0)
? StreamingPhase.EVALUATE
: secondLevelSubquestions?.[0].context_docs
? StreamingPhase.CONTEXT_DOCS
: secondLevelSubquestions?.[0].sub_queries
? StreamingPhase.SUB_QUERIES
: StreamingPhase.WAITING
: StreamingPhase.WAITING;
const message = useOrderedPhases(currentState);
// secondLevelSubquestions?.[0]
// : secondLevelSubquestions[0].context_docs
// ? StreamingPhase.CONTEXT_DOCS
// : secondLevelSubquestions[0].sub_queries
// ? StreamingPhase.SUB_QUERIES
// : secondLevelSubquestions[0].question
// ? StreamingPhase.WAITING
// : StreamingPhase.WAITING
// : StreamingPhase.WAITING;
// Once the first query token comes through, it should be in the sub queries
// Once the first set of documents come through it should be in context docs
// Once all of the analysis have started generating, it should say evaluate
// Once the refined answer starts generating, it should say Answer
// Once the refined answer finishes generating, show COMPARE (we don't have this yet)
// export const StreamingPhaseText: Record<StreamingPhase, string> = {
// [StreamingPhase.WAITING]: "Extracting key concepts",
// [StreamingPhase.SUB_QUERIES]: "Identifying additional questions",
// [StreamingPhase.CONTEXT_DOCS]: "Reading more documents",
// [StreamingPhase.ANSWER]: "Generating refined answer",
// [StreamingPhase.EVALUATE]: "Evaluating new context",
// [StreamingPhase.COMPARE]: "Comparing results",
// [StreamingPhase.COMPLETE]: "Finished",
// };
// Get the array of displayed phases
const displayedPhases = useOrderedPhases(currentState);
const isDone = displayedPhases.includes(StreamingPhase.COMPLETE);
// Expand/collapse, hover states
const [expanded, setExpanded] = useState(true);
const [isHovered, setIsHovered] = useState(false);
const [shouldShow, setShouldShow] = useState(true);
// Once "done", hide after a short delay if not hovered
useEffect(() => {
if (isDone) {
const timer = setTimeout(() => {
if (!isHovered) {
setShouldShow(false);
}
}, 800); // e.g. 0.8s
return () => clearTimeout(timer);
}
}, [isDone, isHovered]);
if (!shouldShow) {
return null; // entire box disappears
}
return (
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<div className="flex loading-text items-center gap-x-2 text-black text-sm font-medium cursor-pointer hover:text-blue-600 transition-colors duration-200">
Refining answer...
<FiChevronRight
className="inline-block text-text-darker"
size={16}
/>
</div>
</TooltipTrigger>
<TooltipContent className="w-80 p-4 bg-white shadow-lg rounded-md">
<div className="space-y-4">
<p className="text-lg leading-none font-semibold text-gray-800">
{message}
</p>
<p className="text-sm text-gray-600">
The answer is being refined based on additional context and
analysis.
</p>
<Button
onClick={() => toggleInitialAnswerVieinwg()}
size="sm"
className="w-full"
<div
className="relative w-full max-w-sm"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{/* Original snippet's tooltip usage */}
<TooltipTrigger asChild>
<div
className="flex loading-text items-center gap-x-2 text-black text-sm
font-medium cursor-pointer hover:text-blue-600
transition-colors duration-200"
>
{isViewingInitialAnswer
? "See Live Updates"
: "Hide Live Updates"}
<FiGlobe className="inline-block mr-2" />
</Button>
</div>
</TooltipContent>
Refining Answer
<FiChevronRight
className={`inline-block transition-transform duration-200 text-text-darker ${
isHovered ? "rotate-90" : ""
}`}
size={16}
/>
</div>
</TooltipTrigger>
<TooltipContent
side="bottom"
align="start"
className="w-80 p-4 bg-white shadow-lg rounded-md"
>
{/* If not done, show the "Refining" box + a chevron */}
{/* Expanded area: each displayed phase in order */}
{expanded && (
<div className="items-start flex flex-col gap-y-2">
{currentState !== StreamingPhase.WAITING ? (
Array.from(new Set(displayedPhases)).map((phase, index) => {
const phaseIndex = displayedPhases.indexOf(phase);
// The last displayed item is "running" if not COMPLETE
let status = ToggleState.Done;
if (
index ===
Array.from(new Set(displayedPhases)).length - 1
) {
status = ToggleState.InProgress;
}
if (phase === StreamingPhase.COMPLETE) {
status = ToggleState.Done;
}
return (
<div
key={phase}
className="text-text flex items-center justify-start gap-x-2"
>
<div className="w-3 h-3">
<StatusIndicator status={status} />
</div>
<span className="text-sm font-medium">
{StreamingPhaseText[phase]}
</span>
</div>
);
})
) : (
<div
key={currentState}
className="text-text flex items-center justify-start gap-x-2"
>
<div className="w-3 h-3">
<StatusIndicator status={ToggleState.InProgress} />
</div>
<span className="text-sm font-medium">
{StreamingPhaseText[StreamingPhase.SUB_QUERIES]}
</span>
</div>
)}
</div>
)}
</TooltipContent>
</div>
</Tooltip>
</TooltipProvider>
);
}
// "use client";
// import {
// Tooltip,
// TooltipTrigger,
// TooltipProvider,
// TooltipContent,
// } from "@/components/ui/tooltip";
// import { Button } from "@/components/ui/button";
// import { FiChevronRight, FiGlobe } from "react-icons/fi";
// import {
// StreamingPhase,
// StreamingPhaseText,
// } from "./message/StreamingMessages";
// import { SubQuestionDetail } from "./interfaces";
// import { useEffect, useRef, useState } from "react";
// const PHASES_ORDER: StreamingPhase[] = [
// StreamingPhase.WAITING,
// StreamingPhase.SUB_QUERIES,
// StreamingPhase.CONTEXT_DOCS,
// StreamingPhase.ANSWER,
// StreamingPhase.COMPLETE,
// ];
// export function useOrderedPhases(externalPhase: StreamingPhase) {
// const [phaseQueue, setPhaseQueue] = useState<StreamingPhase[]>([]);
// const [displayedPhase, setDisplayedPhase] = useState<StreamingPhase>(
// StreamingPhase.WAITING
// );
// const lastDisplayTimestampRef = useRef<number>(Date.now());
// const getPhaseIndex = (phase: StreamingPhase) => {
// return PHASES_ORDER.indexOf(phase);
// };
// useEffect(() => {
// setPhaseQueue((prevQueue) => {
// const lastQueuedPhase =
// prevQueue.length > 0 ? prevQueue[prevQueue.length - 1] : displayedPhase;
// const lastQueuedIndex = getPhaseIndex(lastQueuedPhase);
// const externalIndex = getPhaseIndex(externalPhase);
// if (externalIndex <= lastQueuedIndex) {
// return prevQueue;
// }
// const missingPhases: StreamingPhase[] = [];
// for (let i = lastQueuedIndex + 1; i <= externalIndex; i++) {
// missingPhases.push(PHASES_ORDER[i]);
// }
// return [...prevQueue, ...missingPhases];
// });
// }, [externalPhase, displayedPhase]);
// useEffect(() => {
// if (phaseQueue.length === 0) return;
// let rafId: number;
// const processQueue = () => {
// const now = Date.now();
// const elapsed = now - lastDisplayTimestampRef.current;
// // Keep this at 1000ms from the original example (unchanged),
// // but you can adjust if you want a different visible time in *this* component.
// if (elapsed >= 1000) {
// setPhaseQueue((prevQueue) => {
// if (prevQueue.length > 0) {
// const [next, ...rest] = prevQueue;
// setDisplayedPhase(next);
// lastDisplayTimestampRef.current = Date.now();
// return rest;
// }
// return prevQueue;
// });
// }
// rafId = requestAnimationFrame(processQueue);
// };
// rafId = requestAnimationFrame(processQueue);
// return () => {
// if (rafId) {
// cancelAnimationFrame(rafId);
// }
// };
// }, [phaseQueue]);
// return StreamingPhaseText[displayedPhase];
// }
// export default function RefinemenetBadge({
// secondLevelSubquestions,
// toggleInitialAnswerVieinwg,
// isViewingInitialAnswer,
// }: {
// secondLevelSubquestions?: SubQuestionDetail[] | null;
// toggleInitialAnswerVieinwg: () => void;
// isViewingInitialAnswer: boolean;
// }) {
// const currentState = secondLevelSubquestions?.[0]
// ? secondLevelSubquestions[0].answer
// ? secondLevelSubquestions[0].is_complete
// ? StreamingPhase.COMPLETE
// : StreamingPhase.ANSWER
// : secondLevelSubquestions[0].context_docs
// ? StreamingPhase.CONTEXT_DOCS
// : secondLevelSubquestions[0].sub_queries
// ? StreamingPhase.SUB_QUERIES
// : secondLevelSubquestions[0].question
// ? StreamingPhase.WAITING
// : StreamingPhase.WAITING
// : StreamingPhase.WAITING;
// const message = useOrderedPhases(currentState);
// return (
// <TooltipProvider delayDuration={0}>
// <Tooltip>
// <TooltipTrigger asChild>
// <div className="flex loading-text items-center gap-x-2 text-black text-sm font-medium cursor-pointer hover:text-blue-600 transition-colors duration-200">
// Refining answer...
// <FiChevronRight
// className="inline-block text-text-darker"
// size={16}
// />
// </div>
// </TooltipTrigger>
// <TooltipContent className="w-80 p-4 bg-white shadow-lg rounded-md">
// <div className="space-y-4">
// <p className="text-lg leading-none font-semibold text-gray-800">
// {message}
// </p>
// <p className="text-sm text-gray-600">
// The answer is being refined based on additional context and
// analysis.
// </p>
// <Button
// onClick={() => toggleInitialAnswerVieinwg()}
// size="sm"
// className="w-full"
// >
// {isViewingInitialAnswer
// ? "See Live Updates"
// : "Hide Live Updates"}
// <FiGlobe className="inline-block mr-2" />
// </Button>
// </div>
// </TooltipContent>
// </Tooltip>
// </TooltipProvider>
// );
// }

View File

@ -13,7 +13,13 @@ export function WebResultIcon({
size?: number;
}) {
const [error, setError] = useState(false);
const hostname = new URL(url).hostname;
let hostname;
try {
hostname = new URL(url).hostname;
} catch (e) {
console.log(e);
hostname = "docs.onyx.app";
}
return (
<>
{hostname == "docs.onyx.app" ? (