diff --git a/studio/frontend/src/components/assistant-ui/thread.tsx b/studio/frontend/src/components/assistant-ui/thread.tsx
index 4b9b83319f..9cbb0fb397 100644
--- a/studio/frontend/src/components/assistant-ui/thread.tsx
+++ b/studio/frontend/src/components/assistant-ui/thread.tsx
@@ -125,8 +125,15 @@ export const Thread: FC<{
hideComposer?: boolean;
hideWelcome?: boolean;
targetThreadId?: string;
+ canCompare?: boolean;
onEnterCompare?: () => void;
-}> = ({ hideComposer, hideWelcome, targetThreadId, onEnterCompare }) => {
+}> = ({
+ hideComposer,
+ hideWelcome,
+ targetThreadId,
+ canCompare = true,
+ onEnterCompare,
+}) => {
// Intent-aware autoscroll: replaces assistant-ui's built-in autoscroll
// to prevent the streaming-mutation race that makes the viewport snap
// back to the bottom while the user is scrolling up (see the hook for
@@ -172,6 +179,7 @@ export const Thread: FC<{
@@ -216,6 +224,7 @@ export const Thread: FC<{
@@ -321,8 +330,9 @@ const GeneratedImageViewportOverlay: FC<{ hideComposer?: boolean }> = ({
const ThreadComposerDock: FC<{
disabled?: boolean;
threadId?: string | null;
+ canCompare?: boolean;
onEnterCompare?: () => void;
-}> = ({ disabled, threadId, onEnterCompare }) => {
+}> = ({ disabled, threadId, canCompare = true, onEnterCompare }) => {
const { overlay } = useGeneratedImageOverlay();
return (
@@ -342,6 +352,7 @@ const ThreadComposerDock: FC<{
disabled={disabled}
threadId={threadId}
menuSide="top"
+ canCompare={canCompare}
onEnterCompare={onEnterCompare}
/>
@@ -388,8 +399,9 @@ function getWelcomeEmoji(): string {
const ThreadWelcome: FC<{
hideComposer?: boolean;
threadId?: string | null;
+ canCompare?: boolean;
onEnterCompare?: () => void;
-}> = ({ hideComposer, threadId, onEnterCompare }) => {
+}> = ({ hideComposer, threadId, canCompare = true, onEnterCompare }) => {
const [currentEmoji] = useState(getWelcomeEmoji);
const currentEmojiSrc =
@@ -410,6 +422,7 @@ const ThreadWelcome: FC<{
{!hideComposer && (
)}
@@ -423,8 +436,9 @@ const ComposerAnimated: FC<{
disabled?: boolean;
threadId?: string | null;
menuSide?: "top" | "bottom";
+ canCompare?: boolean;
onEnterCompare?: () => void;
-}> = ({ disabled, threadId, menuSide, onEnterCompare }) => {
+}> = ({ disabled, threadId, menuSide, canCompare = true, onEnterCompare }) => {
return (
@@ -432,6 +446,7 @@ const ComposerAnimated: FC<{
disabled={disabled}
threadId={threadId}
menuSide={menuSide}
+ canCompare={canCompare}
onEnterCompare={onEnterCompare}
/>
@@ -467,8 +482,9 @@ const Composer: FC<{
disabled?: boolean;
threadId?: string | null;
menuSide?: "top" | "bottom";
+ canCompare?: boolean;
onEnterCompare?: () => void;
-}> = ({ disabled, threadId, menuSide, onEnterCompare }) => {
+}> = ({ disabled, threadId, menuSide, canCompare = true, onEnterCompare }) => {
const aui = useAui();
const { overlay, closeOverlay } = useGeneratedImageOverlay();
const setImageToolsEnabled = useChatRuntimeStore(
@@ -654,6 +670,7 @@ const Composer: FC<{
{composerExpanded ? (
@@ -1477,8 +1494,9 @@ const PROJECTS_PR_URL = "https://github.com/unslothai/unsloth/pull/5725";
// welcome composer; the docked composer passes side="top" to open upward.
const ComposerToolsMenu: FC<{
side?: "top" | "bottom";
+ canCompare?: boolean;
onEnterCompare?: () => void;
-}> = ({ side = "bottom", onEnterCompare }) => {
+}> = ({ side = "bottom", canCompare = true, onEnterCompare }) => {
const navigate = useNavigate();
const setSettingsPanelOpen = useChatRuntimeStore(
(s) => s.setSettingsPanelOpen,
@@ -1559,6 +1577,9 @@ const ComposerToolsMenu: FC<{
}, [codeMenuDisabled, codeToolsEnabled, setCodeToolsEnabled]);
const startCompare = useCallback(() => {
+ if (!canCompare) {
+ return;
+ }
if (onEnterCompare) {
onEnterCompare();
return;
@@ -1567,7 +1588,7 @@ const ComposerToolsMenu: FC<{
store.setActiveThreadId(null);
store.setContextUsage(null);
navigate({ to: "/chat", search: { compare: createCompareId() } });
- }, [navigate, onEnterCompare]);
+ }, [canCompare, navigate, onEnterCompare]);
return (
@@ -1672,7 +1693,7 @@ const ComposerToolsMenu: FC<{
Canvas (coming soon)
- startCompare()}>
+
Compare chat
diff --git a/studio/frontend/src/features/chat/chat-page.tsx b/studio/frontend/src/features/chat/chat-page.tsx
index fb7a2eaeb1..3148e4978c 100644
--- a/studio/frontend/src/features/chat/chat-page.tsx
+++ b/studio/frontend/src/features/chat/chat-page.tsx
@@ -159,10 +159,12 @@ function messageHasImage(message: MessageRecord): boolean {
const SingleContent = memo(function SingleContent({
threadId,
newThreadNonce,
+ canCompare,
onEnterCompare,
}: {
threadId?: string;
newThreadNonce?: string;
+ canCompare?: boolean;
onEnterCompare?: () => void;
}): ReactElement {
return (
@@ -175,6 +177,7 @@ const SingleContent = memo(function SingleContent({
@@ -1634,6 +1637,7 @@ export function ChatPage(): ReactElement {
key={view.threadId ?? "single"}
threadId={view.threadId}
newThreadNonce={view.newThreadNonce}
+ canCompare={canCompare}
onEnterCompare={enterCompare}
/>
) : (