((resolve) => {
const reader = new FileReader();
reader.onloadend = () => {
resolve({
name: file.name,
contentType: file.type,
url: reader.result as string,
});
};
reader.readAsDataURL(file);
}),
),
);
return attachments;
};
const sendMessage = async (_event: React.UIEvent, messageInput?: string) => {
const messageContent = messageInput || input;
if (!messageContent?.trim()) {
return;
}
if (isLoading) {
abort();
return;
}
let finalMessageContent = messageContent;
if (selectedElement) {
console.log('Selected Element:', selectedElement);
const elementInfo = `${JSON.stringify(`${selectedElement.displayText}`)}
`;
finalMessageContent = messageContent + elementInfo;
}
runAnimation();
if (!chatStarted) {
setFakeLoading(true);
if (autoSelectTemplate) {
const { template, title } = await selectStarterTemplate({
message: finalMessageContent,
model,
provider,
});
if (template !== 'blank') {
const temResp = await getTemplates(template, title).catch((e) => {
if (e.message.includes('rate limit')) {
toast.warning('Rate limit exceeded. Skipping starter template\n Continuing with blank template');
} else {
toast.warning('Failed to import starter template\n Continuing with blank template');
}
return null;
});
if (temResp) {
const { assistantMessage, userMessage } = temResp;
const userMessageText = `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${finalMessageContent}`;
setMessages([
{
id: `1-${new Date().getTime()}`,
role: 'user',
content: userMessageText,
parts: createMessageParts(userMessageText, imageDataList),
},
{
id: `2-${new Date().getTime()}`,
role: 'assistant',
content: assistantMessage,
},
{
id: `3-${new Date().getTime()}`,
role: 'user',
content: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${userMessage}`,
annotations: ['hidden'],
},
]);
const reloadOptions =
uploadedFiles.length > 0
? { experimental_attachments: await filesToAttachments(uploadedFiles) }
: undefined;
reload(reloadOptions);
setInput('');
Cookies.remove(PROMPT_COOKIE_KEY);
setUploadedFiles([]);
setImageDataList([]);
resetEnhancer();
textareaRef.current?.blur();
setFakeLoading(false);
return;
}
}
}
// If autoSelectTemplate is disabled or template selection failed, proceed with normal message
const userMessageText = `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${finalMessageContent}`;
const attachments = uploadedFiles.length > 0 ? await filesToAttachments(uploadedFiles) : undefined;
setMessages([
{
id: `${new Date().getTime()}`,
role: 'user',
content: userMessageText,
parts: createMessageParts(userMessageText, imageDataList),
experimental_attachments: attachments,
},
]);
reload(attachments ? { experimental_attachments: attachments } : undefined);
setFakeLoading(false);
setInput('');
Cookies.remove(PROMPT_COOKIE_KEY);
setUploadedFiles([]);
setImageDataList([]);
resetEnhancer();
textareaRef.current?.blur();
return;
}
if (error != null) {
setMessages(messages.slice(0, -1));
}
const modifiedFiles = workbenchStore.getModifiedFiles();
chatStore.setKey('aborted', false);
if (modifiedFiles !== undefined) {
const userUpdateArtifact = filesToArtifacts(modifiedFiles, `${Date.now()}`);
const messageText = `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${userUpdateArtifact}${finalMessageContent}`;
const attachmentOptions =
uploadedFiles.length > 0 ? { experimental_attachments: await filesToAttachments(uploadedFiles) } : undefined;
append(
{
role: 'user',
content: messageText,
parts: createMessageParts(messageText, imageDataList),
},
attachmentOptions,
);
workbenchStore.resetAllFileModifications();
} else {
const messageText = `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${finalMessageContent}`;
const attachmentOptions =
uploadedFiles.length > 0 ? { experimental_attachments: await filesToAttachments(uploadedFiles) } : undefined;
append(
{
role: 'user',
content: messageText,
parts: createMessageParts(messageText, imageDataList),
},
attachmentOptions,
);
}
setInput('');
Cookies.remove(PROMPT_COOKIE_KEY);
setUploadedFiles([]);
setImageDataList([]);
resetEnhancer();
textareaRef.current?.blur();
};
/**
* Handles the change event for the textarea and updates the input state.
* @param event - The change event from the textarea.
*/
const onTextareaChange = (event: React.ChangeEvent) => {
handleInputChange(event);
};
/**
* Debounced function to cache the prompt in cookies.
* Caches the trimmed value of the textarea input after a delay to optimize performance.
*/
const debouncedCachePrompt = useCallback(
debounce((event: React.ChangeEvent) => {
const trimmedValue = event.target.value.trim();
Cookies.set(PROMPT_COOKIE_KEY, trimmedValue, { expires: 30 });
}, 1000),
[],
);
useEffect(() => {
const storedApiKeys = Cookies.get('apiKeys');
if (storedApiKeys) {
setApiKeys(JSON.parse(storedApiKeys));
}
}, []);
const handleModelChange = (newModel: string) => {
setModel(newModel);
Cookies.set('selectedModel', newModel, { expires: 30 });
};
const handleProviderChange = (newProvider: ProviderInfo) => {
setProvider(newProvider);
Cookies.set('selectedProvider', newProvider.name, { expires: 30 });
};
return (
{
streamingState.set(streaming);
}}
enhancingPrompt={enhancingPrompt}
promptEnhanced={promptEnhanced}
sendMessage={sendMessage}
model={model}
setModel={handleModelChange}
provider={provider}
setProvider={handleProviderChange}
providerList={activeProviders}
handleInputChange={(e) => {
onTextareaChange(e);
debouncedCachePrompt(e);
}}
handleStop={abort}
description={description}
importChat={importChat}
exportChat={exportChat}
messages={messages.map((message, i) => {
if (message.role === 'user') {
return message;
}
return {
...message,
content: parsedMessages[i] || '',
};
})}
enhancePrompt={() => {
enhancePrompt(
input,
(input) => {
setInput(input);
scrollTextArea();
},
model,
provider,
apiKeys,
);
}}
uploadedFiles={uploadedFiles}
setUploadedFiles={setUploadedFiles}
imageDataList={imageDataList}
setImageDataList={setImageDataList}
actionAlert={actionAlert}
clearAlert={() => workbenchStore.clearAlert()}
supabaseAlert={supabaseAlert}
clearSupabaseAlert={() => workbenchStore.clearSupabaseAlert()}
deployAlert={deployAlert}
clearDeployAlert={() => workbenchStore.clearDeployAlert()}
llmErrorAlert={llmErrorAlert}
clearLlmErrorAlert={clearApiErrorAlert}
data={chatData}
chatMode={chatMode}
setChatMode={setChatMode}
append={append}
designScheme={designScheme}
setDesignScheme={setDesignScheme}
selectedElement={selectedElement}
setSelectedElement={setSelectedElement}
addToolResult={addToolResult}
/>
);
},
);