feat: prompt caching
Browse files
app/components/chat/Chat.client.tsx
CHANGED
@@ -6,19 +6,20 @@ import { useStore } from '@nanostores/react';
|
|
6 |
import type { Message } from 'ai';
|
7 |
import { useChat } from 'ai/react';
|
8 |
import { useAnimate } from 'framer-motion';
|
9 |
-
import { memo, useEffect, useRef, useState } from 'react';
|
10 |
import { cssTransition, toast, ToastContainer } from 'react-toastify';
|
11 |
import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
|
12 |
import { description, useChatHistory } from '~/lib/persistence';
|
13 |
import { chatStore } from '~/lib/stores/chat';
|
14 |
import { workbenchStore } from '~/lib/stores/workbench';
|
15 |
import { fileModificationsToHTML } from '~/utils/diff';
|
16 |
-
import { DEFAULT_MODEL, DEFAULT_PROVIDER, PROVIDER_LIST } from '~/utils/constants';
|
17 |
import { cubicEasingFn } from '~/utils/easings';
|
18 |
import { createScopedLogger, renderLogger } from '~/utils/logger';
|
19 |
import { BaseChat } from './BaseChat';
|
20 |
import Cookies from 'js-cookie';
|
21 |
import type { ProviderInfo } from '~/utils/types';
|
|
|
22 |
|
23 |
const toastAnimation = cssTransition({
|
24 |
enter: 'animated fadeInRight',
|
@@ -120,6 +121,7 @@ export const ChatImpl = memo(
|
|
120 |
logger.debug('Finished streaming');
|
121 |
},
|
122 |
initialMessages,
|
|
|
123 |
});
|
124 |
|
125 |
const { enhancingPrompt, promptEnhanced, enhancePrompt, resetEnhancer } = usePromptEnhancer();
|
@@ -225,12 +227,33 @@ export const ChatImpl = memo(
|
|
225 |
}
|
226 |
|
227 |
setInput('');
|
|
|
228 |
|
229 |
resetEnhancer();
|
230 |
|
231 |
textareaRef.current?.blur();
|
232 |
};
|
233 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
const [messageRef, scrollRef] = useSnapScroll();
|
235 |
|
236 |
useEffect(() => {
|
@@ -268,7 +291,10 @@ export const ChatImpl = memo(
|
|
268 |
setProvider={handleProviderChange}
|
269 |
messageRef={messageRef}
|
270 |
scrollRef={scrollRef}
|
271 |
-
handleInputChange={
|
|
|
|
|
|
|
272 |
handleStop={abort}
|
273 |
description={description}
|
274 |
importChat={importChat}
|
|
|
6 |
import type { Message } from 'ai';
|
7 |
import { useChat } from 'ai/react';
|
8 |
import { useAnimate } from 'framer-motion';
|
9 |
+
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
10 |
import { cssTransition, toast, ToastContainer } from 'react-toastify';
|
11 |
import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
|
12 |
import { description, useChatHistory } from '~/lib/persistence';
|
13 |
import { chatStore } from '~/lib/stores/chat';
|
14 |
import { workbenchStore } from '~/lib/stores/workbench';
|
15 |
import { fileModificationsToHTML } from '~/utils/diff';
|
16 |
+
import { DEFAULT_MODEL, DEFAULT_PROVIDER, PROMPT_COOKIE_KEY, PROVIDER_LIST } from '~/utils/constants';
|
17 |
import { cubicEasingFn } from '~/utils/easings';
|
18 |
import { createScopedLogger, renderLogger } from '~/utils/logger';
|
19 |
import { BaseChat } from './BaseChat';
|
20 |
import Cookies from 'js-cookie';
|
21 |
import type { ProviderInfo } from '~/utils/types';
|
22 |
+
import { debounce } from '~/utils/debounce';
|
23 |
|
24 |
const toastAnimation = cssTransition({
|
25 |
enter: 'animated fadeInRight',
|
|
|
121 |
logger.debug('Finished streaming');
|
122 |
},
|
123 |
initialMessages,
|
124 |
+
initialInput: Cookies.get(PROMPT_COOKIE_KEY) || '',
|
125 |
});
|
126 |
|
127 |
const { enhancingPrompt, promptEnhanced, enhancePrompt, resetEnhancer } = usePromptEnhancer();
|
|
|
227 |
}
|
228 |
|
229 |
setInput('');
|
230 |
+
Cookies.remove(PROMPT_COOKIE_KEY);
|
231 |
|
232 |
resetEnhancer();
|
233 |
|
234 |
textareaRef.current?.blur();
|
235 |
};
|
236 |
|
237 |
+
/**
|
238 |
+
* Handles the change event for the textarea and updates the input state.
|
239 |
+
* @param event - The change event from the textarea.
|
240 |
+
*/
|
241 |
+
const onTextareaChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
242 |
+
handleInputChange(event);
|
243 |
+
};
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Debounced function to cache the prompt in cookies.
|
247 |
+
* Caches the trimmed value of the textarea input after a delay to optimize performance.
|
248 |
+
*/
|
249 |
+
const debouncedCachePrompt = useCallback(
|
250 |
+
debounce((event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
251 |
+
const trimmedValue = event.target.value.trim();
|
252 |
+
Cookies.set(PROMPT_COOKIE_KEY, trimmedValue, { expires: 30 });
|
253 |
+
}, 1000),
|
254 |
+
[],
|
255 |
+
);
|
256 |
+
|
257 |
const [messageRef, scrollRef] = useSnapScroll();
|
258 |
|
259 |
useEffect(() => {
|
|
|
291 |
setProvider={handleProviderChange}
|
292 |
messageRef={messageRef}
|
293 |
scrollRef={scrollRef}
|
294 |
+
handleInputChange={(e) => {
|
295 |
+
onTextareaChange(e);
|
296 |
+
debouncedCachePrompt(e);
|
297 |
+
}}
|
298 |
handleStop={abort}
|
299 |
description={description}
|
300 |
importChat={importChat}
|
app/utils/constants.ts
CHANGED
@@ -7,6 +7,7 @@ export const MODIFICATIONS_TAG_NAME = 'bolt_file_modifications';
|
|
7 |
export const MODEL_REGEX = /^\[Model: (.*?)\]\n\n/;
|
8 |
export const PROVIDER_REGEX = /\[Provider: (.*?)\]\n\n/;
|
9 |
export const DEFAULT_MODEL = 'claude-3-5-sonnet-latest';
|
|
|
10 |
|
11 |
const PROVIDER_LIST: ProviderInfo[] = [
|
12 |
{
|
|
|
7 |
export const MODEL_REGEX = /^\[Model: (.*?)\]\n\n/;
|
8 |
export const PROVIDER_REGEX = /\[Provider: (.*?)\]\n\n/;
|
9 |
export const DEFAULT_MODEL = 'claude-3-5-sonnet-latest';
|
10 |
+
export const PROMPT_COOKIE_KEY = 'cachedPrompt';
|
11 |
|
12 |
const PROVIDER_LIST: ProviderInfo[] = [
|
13 |
{
|