mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Pass model and provider information through chat components to include in quick action messages. This fixes the issue of defaulting to anthropic model.
122 lines
4.6 KiB
TypeScript
122 lines
4.6 KiB
TypeScript
import type { Message } from 'ai';
|
|
import { Fragment } from 'react';
|
|
import { classNames } from '~/utils/classNames';
|
|
import { AssistantMessage } from './AssistantMessage';
|
|
import { UserMessage } from './UserMessage';
|
|
import { useLocation } from '@remix-run/react';
|
|
import { db, chatId } from '~/lib/persistence/useChatHistory';
|
|
import { forkChat } from '~/lib/persistence/db';
|
|
import { toast } from 'react-toastify';
|
|
import { useStore } from '@nanostores/react';
|
|
import { profileStore } from '~/lib/stores/profile';
|
|
import { forwardRef } from 'react';
|
|
import type { ForwardedRef } from 'react';
|
|
import type { ProviderInfo } from '~/types/model';
|
|
|
|
interface MessagesProps {
|
|
id?: string;
|
|
className?: string;
|
|
isStreaming?: boolean;
|
|
messages?: Message[];
|
|
append?: (message: Message) => void;
|
|
chatMode?: 'discuss' | 'build';
|
|
setChatMode?: (mode: 'discuss' | 'build') => void;
|
|
model?: string;
|
|
provider?: ProviderInfo;
|
|
}
|
|
|
|
export const Messages = forwardRef<HTMLDivElement, MessagesProps>(
|
|
(props: MessagesProps, ref: ForwardedRef<HTMLDivElement> | undefined) => {
|
|
const { id, isStreaming = false, messages = [] } = props;
|
|
const location = useLocation();
|
|
const profile = useStore(profileStore);
|
|
|
|
const handleRewind = (messageId: string) => {
|
|
const searchParams = new URLSearchParams(location.search);
|
|
searchParams.set('rewindTo', messageId);
|
|
window.location.search = searchParams.toString();
|
|
};
|
|
|
|
const handleFork = async (messageId: string) => {
|
|
try {
|
|
if (!db || !chatId.get()) {
|
|
toast.error('Chat persistence is not available');
|
|
return;
|
|
}
|
|
|
|
const urlId = await forkChat(db, chatId.get()!, messageId);
|
|
window.location.href = `/chat/${urlId}`;
|
|
} catch (error) {
|
|
toast.error('Failed to fork chat: ' + (error as Error).message);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div id={id} className={props.className} ref={ref}>
|
|
{messages.length > 0
|
|
? messages.map((message, index) => {
|
|
const { role, content, id: messageId, annotations } = message;
|
|
const isUserMessage = role === 'user';
|
|
const isFirst = index === 0;
|
|
const isLast = index === messages.length - 1;
|
|
const isHidden = annotations?.includes('hidden');
|
|
|
|
if (isHidden) {
|
|
return <Fragment key={index} />;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
key={index}
|
|
className={classNames('flex gap-4 p-6 py-5 w-full rounded-[calc(0.75rem-1px)]', {
|
|
'bg-bolt-elements-messages-background': isUserMessage || !isStreaming || (isStreaming && !isLast),
|
|
'bg-gradient-to-b from-bolt-elements-messages-background from-30% to-transparent':
|
|
isStreaming && isLast,
|
|
'mt-4': !isFirst,
|
|
})}
|
|
>
|
|
{isUserMessage && (
|
|
<div className="flex items-center justify-center w-[40px] h-[40px] overflow-hidden bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-500 rounded-full shrink-0 self-start">
|
|
{profile?.avatar ? (
|
|
<img
|
|
src={profile.avatar}
|
|
alt={profile?.username || 'User'}
|
|
className="w-full h-full object-cover"
|
|
loading="eager"
|
|
decoding="sync"
|
|
/>
|
|
) : (
|
|
<div className="i-ph:user-fill text-2xl" />
|
|
)}
|
|
</div>
|
|
)}
|
|
<div className="grid grid-col-1 w-full">
|
|
{isUserMessage ? (
|
|
<UserMessage content={content} />
|
|
) : (
|
|
<AssistantMessage
|
|
content={content}
|
|
annotations={message.annotations}
|
|
messageId={messageId}
|
|
onRewind={handleRewind}
|
|
onFork={handleFork}
|
|
append={props.append}
|
|
chatMode={props.chatMode}
|
|
setChatMode={props.setChatMode}
|
|
model={props.model}
|
|
provider={props.provider}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
})
|
|
: null}
|
|
{isStreaming && (
|
|
<div className="text-center w-full text-bolt-elements-item-contentAccent i-svg-spinners:3-dots-fade text-4xl mt-4"></div>
|
|
)}
|
|
</div>
|
|
);
|
|
},
|
|
);
|