mirror of
https://github.com/coleam00/bolt.new-any-llm
synced 2024-12-28 06:42:56 +00:00
Merge branch 'main' into github-import
This commit is contained in:
commit
b0743e00b1
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -56,6 +56,16 @@ body:
|
||||
- OS: [e.g. macOS, Windows, Linux]
|
||||
- Browser: [e.g. Chrome, Safari, Firefox]
|
||||
- Version: [e.g. 91.1]
|
||||
- type: input
|
||||
id: provider
|
||||
attributes:
|
||||
label: Provider Used
|
||||
description: Tell us the provider you are using.
|
||||
- type: input
|
||||
id: model
|
||||
attributes:
|
||||
label: Model Used
|
||||
description: Tell us the model you are using.
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
|
6
.github/workflows/stale.yml
vendored
6
.github/workflows/stale.yml
vendored
@ -16,10 +16,10 @@ jobs:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "This issue has been marked as stale due to inactivity. If no further activity occurs, it will be closed in 7 days."
|
||||
stale-pr-message: "This pull request has been marked as stale due to inactivity. If no further activity occurs, it will be closed in 7 days."
|
||||
days-before-stale: 14 # Number of days before marking an issue or PR as stale
|
||||
days-before-close: 7 # Number of days after being marked stale before closing
|
||||
days-before-stale: 10 # Number of days before marking an issue or PR as stale
|
||||
days-before-close: 4 # Number of days after being marked stale before closing
|
||||
stale-issue-label: "stale" # Label to apply to stale issues
|
||||
stale-pr-label: "stale" # Label to apply to stale pull requests
|
||||
exempt-issue-labels: "pinned,important" # Issues with these labels won't be marked stale
|
||||
exempt-pr-labels: "pinned,important" # PRs with these labels won't be marked stale
|
||||
operations-per-run: 90 # Limits the number of actions per run to avoid API rate limits
|
||||
operations-per-run: 75 # Limits the number of actions per run to avoid API rate limits
|
||||
|
@ -17,7 +17,7 @@ fi
|
||||
|
||||
echo "Running lint..."
|
||||
if ! pnpm lint; then
|
||||
echo "❌ Linting failed! 'pnpm lint:check' will help you fix the easy ones."
|
||||
echo "❌ Linting failed! 'pnpm lint:fix' will help you fix the easy ones."
|
||||
echo "Once you're done, don't forget to add your beautification to the commit! 🤩"
|
||||
echo "lint exit code: $?"
|
||||
exit 1
|
||||
|
@ -4,10 +4,13 @@
|
||||
|
||||
This fork of Bolt.new (oTToDev) allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models.
|
||||
|
||||
Check the [oTToDev Docs](https://coleam00.github.io/bolt.new-any-llm/) for more information.
|
||||
|
||||
## Join the community for oTToDev!
|
||||
|
||||
https://thinktank.ottomator.ai
|
||||
|
||||
|
||||
## Requested Additions - Feel Free to Contribute!
|
||||
|
||||
- ✅ OpenRouter Integration (@coleam00)
|
||||
@ -31,6 +34,7 @@ https://thinktank.ottomator.ai
|
||||
- ✅ Ability to revert code to earlier version (@wonderwhy-er)
|
||||
- ✅ Cohere Integration (@hasanraiyan)
|
||||
- ✅ Dynamic model max token length (@hasanraiyan)
|
||||
- ✅ Better prompt enhancing (@SujalXplores)
|
||||
- ✅ Prompt caching (@SujalXplores)
|
||||
- ✅ Load local projects into the app (@wonderwhy-er)
|
||||
- ✅ Together Integration (@mouimet-infinisoft)
|
||||
|
@ -255,6 +255,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
|
||||
<span>Model Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={isModelSettingsCollapsed ? 'hidden' : ''}>
|
||||
<ModelSelector
|
||||
key={provider?.name + ':' + modelList.length}
|
||||
|
@ -24,17 +24,19 @@ export function Header() {
|
||||
<span className="i-bolt:logo-text?mask w-[46px] inline-block" />
|
||||
</a>
|
||||
</div>
|
||||
<span className="flex-1 px-4 truncate text-center text-bolt-elements-textPrimary">
|
||||
<ClientOnly>{() => <ChatDescription />}</ClientOnly>
|
||||
</span>
|
||||
{chat.started && (
|
||||
<ClientOnly>
|
||||
{() => (
|
||||
<div className="mr-1">
|
||||
<HeaderActionButtons />
|
||||
</div>
|
||||
)}
|
||||
</ClientOnly>
|
||||
{chat.started && ( // Display ChatDescription and HeaderActionButtons only when the chat has started.
|
||||
<>
|
||||
<span className="flex-1 px-4 truncate text-center text-bolt-elements-textPrimary">
|
||||
<ClientOnly>{() => <ChatDescription />}</ClientOnly>
|
||||
</span>
|
||||
<ClientOnly>
|
||||
{() => (
|
||||
<div className="mr-1">
|
||||
<HeaderActionButtons />
|
||||
</div>
|
||||
)}
|
||||
</ClientOnly>
|
||||
</>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
|
@ -19,7 +19,7 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
|
||||
<div className="flex border border-bolt-elements-borderColor rounded-md overflow-hidden">
|
||||
<Button
|
||||
active={showChat}
|
||||
disabled={!canHideChat || isSmallViewport} // expand button is disabled on mobile as it's needed
|
||||
disabled={!canHideChat || isSmallViewport} // expand button is disabled on mobile as it's not needed
|
||||
onClick={() => {
|
||||
if (canHideChat) {
|
||||
chatStore.setKey('showChat', !showChat);
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { useParams } from '@remix-run/react';
|
||||
import { classNames } from '~/utils/classNames';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { type ChatHistoryItem } from '~/lib/persistence';
|
||||
import WithTooltip from '~/components/ui/Tooltip';
|
||||
import { useEditChatDescription } from '~/lib/hooks';
|
||||
|
||||
interface HistoryItemProps {
|
||||
item: ChatHistoryItem;
|
||||
@ -10,48 +13,115 @@ interface HistoryItemProps {
|
||||
}
|
||||
|
||||
export function HistoryItem({ item, onDelete, onDuplicate, exportChat }: HistoryItemProps) {
|
||||
const { id: urlId } = useParams();
|
||||
const isActiveChat = urlId === item.urlId;
|
||||
|
||||
const { editing, handleChange, handleBlur, handleSubmit, handleKeyDown, currentDescription, toggleEditMode } =
|
||||
useEditChatDescription({
|
||||
initialDescription: item.description,
|
||||
customChatId: item.id,
|
||||
syncWithGlobalStore: isActiveChat,
|
||||
});
|
||||
|
||||
const renderDescriptionForm = (
|
||||
<form onSubmit={handleSubmit} className="flex-1 flex items-center">
|
||||
<input
|
||||
type="text"
|
||||
className="flex-1 bg-bolt-elements-background-depth-1 text-bolt-elements-textPrimary rounded px-2 mr-2"
|
||||
autoFocus
|
||||
value={currentDescription}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="i-ph:check scale-110 hover:text-bolt-elements-item-contentAccent"
|
||||
onMouseDown={handleSubmit}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="group rounded-md text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 overflow-hidden flex justify-between items-center px-2 py-1">
|
||||
<a href={`/chat/${item.urlId}`} className="flex w-full relative truncate block">
|
||||
{item.description}
|
||||
<div className="absolute right-0 z-1 top-0 bottom-0 bg-gradient-to-l from-bolt-elements-background-depth-2 group-hover:from-bolt-elements-background-depth-3 box-content pl-3 to-transparent w-10 flex justify-end group-hover:w-15 group-hover:from-99%">
|
||||
<div className="flex items-center p-1 text-bolt-elements-textSecondary opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<WithTooltip tooltip="Export chat">
|
||||
<button
|
||||
type="button"
|
||||
className="i-ph:download-simple scale-110 mr-2 hover:text-bolt-elements-item-contentAccent"
|
||||
<div
|
||||
className={classNames(
|
||||
'group rounded-md text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 overflow-hidden flex justify-between items-center px-2 py-1',
|
||||
{ '[&&]:text-bolt-elements-textPrimary bg-bolt-elements-background-depth-3': isActiveChat },
|
||||
)}
|
||||
>
|
||||
{editing ? (
|
||||
renderDescriptionForm
|
||||
) : (
|
||||
<a href={`/chat/${item.urlId}`} className="flex w-full relative truncate block">
|
||||
{currentDescription}
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute right-0 z-1 top-0 bottom-0 bg-gradient-to-l from-bolt-elements-background-depth-2 group-hover:from-bolt-elements-background-depth-3 box-content pl-3 to-transparent w-10 flex justify-end group-hover:w-22 group-hover:from-99%',
|
||||
{ 'from-bolt-elements-background-depth-3 w-10 ': isActiveChat },
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center p-1 text-bolt-elements-textSecondary opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<ChatActionButton
|
||||
toolTipContent="Export chat"
|
||||
icon="i-ph:download-simple"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
exportChat(item.id);
|
||||
}}
|
||||
title="Export chat"
|
||||
/>
|
||||
</WithTooltip>
|
||||
{onDuplicate && (
|
||||
<WithTooltip tooltip="Duplicate chat">
|
||||
<button
|
||||
type="button"
|
||||
className="i-ph:copy scale-110 mr-2 hover:text-bolt-elements-item-contentAccent"
|
||||
{onDuplicate && (
|
||||
<ChatActionButton
|
||||
toolTipContent="Duplicate chat"
|
||||
icon="i-ph:copy"
|
||||
onClick={() => onDuplicate?.(item.id)}
|
||||
title="Duplicate chat"
|
||||
/>
|
||||
</WithTooltip>
|
||||
)}
|
||||
<Dialog.Trigger asChild>
|
||||
<WithTooltip tooltip="Delete chat">
|
||||
<button
|
||||
type="button"
|
||||
className="i-ph:trash scale-110 hover:text-bolt-elements-button-danger-text"
|
||||
)}
|
||||
<ChatActionButton
|
||||
toolTipContent="Rename chat"
|
||||
icon="i-ph:pencil-fill"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
toggleEditMode();
|
||||
}}
|
||||
/>
|
||||
<Dialog.Trigger asChild>
|
||||
<ChatActionButton
|
||||
toolTipContent="Delete chat"
|
||||
icon="i-ph:trash"
|
||||
className="[&&]:hover:text-bolt-elements-button-danger-text"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
onDelete?.(event);
|
||||
}}
|
||||
/>
|
||||
</WithTooltip>
|
||||
</Dialog.Trigger>
|
||||
</Dialog.Trigger>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const ChatActionButton = ({
|
||||
toolTipContent,
|
||||
icon,
|
||||
className,
|
||||
onClick,
|
||||
}: {
|
||||
toolTipContent: string;
|
||||
icon: string;
|
||||
className?: string;
|
||||
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
btnTitle?: string;
|
||||
}) => {
|
||||
return (
|
||||
<WithTooltip tooltip={toolTipContent}>
|
||||
<button
|
||||
type="button"
|
||||
className={`scale-110 mr-2 hover:text-bolt-elements-item-contentAccent ${icon} ${className ? className : ''}`}
|
||||
onClick={onClick}
|
||||
/>
|
||||
</WithTooltip>
|
||||
);
|
||||
};
|
||||
|
@ -2,4 +2,5 @@ export * from './useMessageParser';
|
||||
export * from './usePromptEnhancer';
|
||||
export * from './useShortcuts';
|
||||
export * from './useSnapScroll';
|
||||
export * from './useEditChatDescription';
|
||||
export { default } from './useViewport';
|
||||
|
163
app/lib/hooks/useEditChatDescription.ts
Normal file
163
app/lib/hooks/useEditChatDescription.ts
Normal file
@ -0,0 +1,163 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import {
|
||||
chatId as chatIdStore,
|
||||
description as descriptionStore,
|
||||
db,
|
||||
updateChatDescription,
|
||||
getMessages,
|
||||
} from '~/lib/persistence';
|
||||
|
||||
interface EditChatDescriptionOptions {
|
||||
initialDescription?: string;
|
||||
customChatId?: string;
|
||||
syncWithGlobalStore?: boolean;
|
||||
}
|
||||
|
||||
type EditChatDescriptionHook = {
|
||||
editing: boolean;
|
||||
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
handleBlur: () => Promise<void>;
|
||||
handleSubmit: (event: React.FormEvent) => Promise<void>;
|
||||
handleKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => Promise<void>;
|
||||
currentDescription: string;
|
||||
toggleEditMode: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to manage the state and behavior for editing chat descriptions.
|
||||
*
|
||||
* Offers functions to:
|
||||
* - Switch between edit and view modes.
|
||||
* - Manage input changes, blur, and form submission events.
|
||||
* - Save updates to IndexedDB and optionally to the global application state.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {string} options.initialDescription - The current chat description.
|
||||
* @param {string} options.customChatId - Optional ID for updating the description via the sidebar.
|
||||
* @param {boolean} options.syncWithGlobalStore - Flag to indicate global description store synchronization.
|
||||
* @returns {EditChatDescriptionHook} Methods and state for managing description edits.
|
||||
*/
|
||||
export function useEditChatDescription({
|
||||
initialDescription = descriptionStore.get()!,
|
||||
customChatId,
|
||||
syncWithGlobalStore,
|
||||
}: EditChatDescriptionOptions): EditChatDescriptionHook {
|
||||
const chatIdFromStore = useStore(chatIdStore);
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [currentDescription, setCurrentDescription] = useState(initialDescription);
|
||||
|
||||
const [chatId, setChatId] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
setChatId(customChatId || chatIdFromStore);
|
||||
}, [customChatId, chatIdFromStore]);
|
||||
useEffect(() => {
|
||||
setCurrentDescription(initialDescription);
|
||||
}, [initialDescription]);
|
||||
|
||||
const toggleEditMode = useCallback(() => setEditing((prev) => !prev), []);
|
||||
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setCurrentDescription(e.target.value);
|
||||
}, []);
|
||||
|
||||
const fetchLatestDescription = useCallback(async () => {
|
||||
if (!db || !chatId) {
|
||||
return initialDescription;
|
||||
}
|
||||
|
||||
try {
|
||||
const chat = await getMessages(db, chatId);
|
||||
return chat?.description || initialDescription;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch latest description:', error);
|
||||
return initialDescription;
|
||||
}
|
||||
}, [db, chatId, initialDescription]);
|
||||
|
||||
const handleBlur = useCallback(async () => {
|
||||
const latestDescription = await fetchLatestDescription();
|
||||
setCurrentDescription(latestDescription);
|
||||
toggleEditMode();
|
||||
}, [fetchLatestDescription, toggleEditMode]);
|
||||
|
||||
const isValidDescription = useCallback((desc: string): boolean => {
|
||||
const trimmedDesc = desc.trim();
|
||||
|
||||
if (trimmedDesc === initialDescription) {
|
||||
toggleEditMode();
|
||||
return false; // No change, skip validation
|
||||
}
|
||||
|
||||
const lengthValid = trimmedDesc.length > 0 && trimmedDesc.length <= 100;
|
||||
const characterValid = /^[a-zA-Z0-9\s]+$/.test(trimmedDesc);
|
||||
|
||||
if (!lengthValid) {
|
||||
toast.error('Description must be between 1 and 100 characters.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!characterValid) {
|
||||
toast.error('Description can only contain alphanumeric characters and spaces.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}, []);
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!isValidDescription(currentDescription)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!db) {
|
||||
toast.error('Chat persistence is not available');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chatId) {
|
||||
toast.error('Chat Id is not available');
|
||||
return;
|
||||
}
|
||||
|
||||
await updateChatDescription(db, chatId, currentDescription);
|
||||
|
||||
if (syncWithGlobalStore) {
|
||||
descriptionStore.set(currentDescription);
|
||||
}
|
||||
|
||||
toast.success('Chat description updated successfully');
|
||||
} catch (error) {
|
||||
toast.error('Failed to update chat description: ' + (error as Error).message);
|
||||
}
|
||||
|
||||
toggleEditMode();
|
||||
},
|
||||
[currentDescription, db, chatId, initialDescription, customChatId],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
async (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Escape') {
|
||||
await handleBlur();
|
||||
}
|
||||
},
|
||||
[handleBlur],
|
||||
);
|
||||
|
||||
return {
|
||||
editing,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
handleSubmit,
|
||||
handleKeyDown,
|
||||
currentDescription,
|
||||
toggleEditMode,
|
||||
};
|
||||
}
|
@ -1,6 +1,68 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { description } from './useChatHistory';
|
||||
import { TooltipProvider } from '@radix-ui/react-tooltip';
|
||||
import WithTooltip from '~/components/ui/Tooltip';
|
||||
import { useEditChatDescription } from '~/lib/hooks';
|
||||
import { description as descriptionStore } from '~/lib/persistence';
|
||||
|
||||
export function ChatDescription() {
|
||||
return useStore(description);
|
||||
const initialDescription = useStore(descriptionStore)!;
|
||||
|
||||
const { editing, handleChange, handleBlur, handleSubmit, handleKeyDown, currentDescription, toggleEditMode } =
|
||||
useEditChatDescription({
|
||||
initialDescription,
|
||||
syncWithGlobalStore: true,
|
||||
});
|
||||
|
||||
if (!initialDescription) {
|
||||
// doing this to prevent showing edit button until chat description is set
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
{editing ? (
|
||||
<form onSubmit={handleSubmit} className="flex items-center justify-center">
|
||||
<input
|
||||
type="text"
|
||||
className="bg-bolt-elements-background-depth-1 text-bolt-elements-textPrimary rounded px-2 mr-2 w-fit"
|
||||
autoFocus
|
||||
value={currentDescription}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
style={{ width: `${Math.max(currentDescription.length * 8, 100)}px` }}
|
||||
/>
|
||||
<TooltipProvider>
|
||||
<WithTooltip tooltip="Save title">
|
||||
<div className="flex justify-between items-center p-2 rounded-md bg-bolt-elements-item-backgroundAccent">
|
||||
<button
|
||||
type="submit"
|
||||
className="i-ph:check-bold scale-110 hover:text-bolt-elements-item-contentAccent"
|
||||
onMouseDown={handleSubmit}
|
||||
/>
|
||||
</div>
|
||||
</WithTooltip>
|
||||
</TooltipProvider>
|
||||
</form>
|
||||
) : (
|
||||
<>
|
||||
{currentDescription}
|
||||
<TooltipProvider>
|
||||
<WithTooltip tooltip="Rename chat">
|
||||
<div className="flex justify-between items-center p-2 rounded-md bg-bolt-elements-item-backgroundAccent ml-2">
|
||||
<button
|
||||
type="button"
|
||||
className="i-ph:pencil-fill scale-110 hover:text-bolt-elements-item-contentAccent"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
toggleEditMode();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</WithTooltip>
|
||||
</TooltipProvider>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -52,17 +52,23 @@ export async function setMessages(
|
||||
messages: Message[],
|
||||
urlId?: string,
|
||||
description?: string,
|
||||
timestamp?: string,
|
||||
): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction('chats', 'readwrite');
|
||||
const store = transaction.objectStore('chats');
|
||||
|
||||
if (timestamp && isNaN(Date.parse(timestamp))) {
|
||||
reject(new Error('Invalid timestamp'));
|
||||
return;
|
||||
}
|
||||
|
||||
const request = store.put({
|
||||
id,
|
||||
messages,
|
||||
urlId,
|
||||
description,
|
||||
timestamp: new Date().toISOString(),
|
||||
timestamp: timestamp ?? new Date().toISOString(),
|
||||
});
|
||||
|
||||
request.onsuccess = () => resolve();
|
||||
@ -212,3 +218,17 @@ export async function createChatFromMessages(
|
||||
|
||||
return newUrlId; // Return the urlId instead of id for navigation
|
||||
}
|
||||
|
||||
export async function updateChatDescription(db: IDBDatabase, id: string, description: string): Promise<void> {
|
||||
const chat = await getMessages(db, id);
|
||||
|
||||
if (!chat) {
|
||||
throw new Error('Chat not found');
|
||||
}
|
||||
|
||||
if (!description.trim()) {
|
||||
throw new Error('Description cannot be empty');
|
||||
}
|
||||
|
||||
await setMessages(db, id, chat.messages, chat.urlId, description, chat.timestamp);
|
||||
}
|
||||
|
@ -100,6 +100,10 @@ export class ActionRunner {
|
||||
.catch((error) => {
|
||||
console.error('Action failed:', error);
|
||||
});
|
||||
|
||||
await this.#currentExecutionPromise;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async #executeAction(actionId: string, isStreaming: boolean = false) {
|
||||
|
@ -44,8 +44,9 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
||||
content:
|
||||
`[Model: ${model}]\n\n[Provider: ${providerName}]\n\n` +
|
||||
stripIndents`
|
||||
You are a professional prompt engineer specializing in crafting precise, effective prompts.
|
||||
You are a professional prompt engineer specializing in crafting precise, effective prompts.
|
||||
Your task is to enhance prompts by making them more specific, actionable, and effective.
|
||||
|
||||
I want you to improve the user prompt that is wrapped in \`<original_prompt>\` tags.
|
||||
|
||||
For valid prompts:
|
||||
@ -55,12 +56,14 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
||||
- Maintain the core intent
|
||||
- Ensure the prompt is self-contained
|
||||
- Use professional language
|
||||
|
||||
For invalid or unclear prompts:
|
||||
- Respond with a clear, professional guidance message
|
||||
- Keep responses concise and actionable
|
||||
- Maintain a helpful, constructive tone
|
||||
- Focus on what the user should provide
|
||||
- Use a standard template for consistency
|
||||
|
||||
IMPORTANT: Your response must ONLY contain the enhanced prompt text.
|
||||
Do not include any explanations, metadata, or wrapper tags.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user