Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added Automatic Code Template Detection And Import #867

Merged
merged 6 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 109 additions & 3 deletions app/components/chat/Chat.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { useSettings } from '~/lib/hooks/useSettings';
import type { ProviderInfo } from '~/types/model';
import { useSearchParams } from '@remix-run/react';
import { createSampler } from '~/utils/sampler';
import { getTemplates, selectStarterTemplate } from '~/utils/selectStarterTemplate';

const toastAnimation = cssTransition({
enter: 'animated fadeInRight',
Expand Down Expand Up @@ -116,9 +117,10 @@ export const ChatImpl = memo(
const [uploadedFiles, setUploadedFiles] = useState<File[]>([]); // Move here
const [imageDataList, setImageDataList] = useState<string[]>([]); // Move here
const [searchParams, setSearchParams] = useSearchParams();
const [fakeLoading, setFakeLoading] = useState(false);
const files = useStore(workbenchStore.files);
const actionAlert = useStore(workbenchStore.alert);
const { activeProviders, promptId, contextOptimizationEnabled } = useSettings();
const { activeProviders, promptId, autoSelectTemplate, contextOptimizationEnabled } = useSettings();

const [model, setModel] = useState(() => {
const savedModel = Cookies.get('selectedModel');
Expand All @@ -135,7 +137,7 @@ export const ChatImpl = memo(

const [apiKeys, setApiKeys] = useState<Record<string, string>>({});

const { messages, isLoading, input, handleInputChange, setInput, stop, append } = useChat({
const { messages, isLoading, input, handleInputChange, setInput, stop, append, setMessages, reload } = useChat({
api: '/api/chat',
body: {
apiKeys,
Expand Down Expand Up @@ -266,6 +268,110 @@ export const ChatImpl = memo(

runAnimation();

if (!chatStarted && messageInput && autoSelectTemplate) {
setFakeLoading(true);
setMessages([
{
id: `${new Date().getTime()}`,
role: 'user',
content: [
{
type: 'text',
text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${_input}`,
},
...imageDataList.map((imageData) => ({
type: 'image',
image: imageData,
})),
] as any, // Type assertion to bypass compiler check
},
]);

// reload();

const template = await selectStarterTemplate({
message: messageInput,
model,
provider,
});

if (template !== 'blank') {
const temResp = await getTemplates(template);

if (temResp) {
const { assistantMessage, userMessage } = temResp;

setMessages([
{
id: `${new Date().getTime()}`,
role: 'user',
content: messageInput,

// annotations: ['hidden'],
},
{
id: `${new Date().getTime()}`,
role: 'assistant',
content: assistantMessage,
},
{
id: `${new Date().getTime()}`,
role: 'user',
content: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${userMessage}`,
annotations: ['hidden'],
},
]);

reload();
setFakeLoading(false);

return;
} else {
setMessages([
{
id: `${new Date().getTime()}`,
role: 'user',
content: [
{
type: 'text',
text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${_input}`,
},
...imageDataList.map((imageData) => ({
type: 'image',
image: imageData,
})),
] as any, // Type assertion to bypass compiler check
},
]);
reload();
setFakeLoading(false);

return;
}
} else {
setMessages([
{
id: `${new Date().getTime()}`,
role: 'user',
content: [
{
type: 'text',
text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${_input}`,
},
...imageDataList.map((imageData) => ({
type: 'image',
image: imageData,
})),
] as any, // Type assertion to bypass compiler check
},
]);
reload();
setFakeLoading(false);

return;
}
}

if (fileModifications !== undefined) {
/**
* If we have file modifications we append a new user message manually since we have to prefix
Expand Down Expand Up @@ -368,7 +474,7 @@ export const ChatImpl = memo(
input={input}
showChat={showChat}
chatStarted={chatStarted}
isStreaming={isLoading}
isStreaming={isLoading || fakeLoading}
enhancingPrompt={enhancingPrompt}
promptEnhanced={promptEnhanced}
sendMessage={sendMessage}
Expand Down
9 changes: 7 additions & 2 deletions app/components/chat/Messages.client.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Message } from 'ai';
import React from 'react';
import React, { Fragment } from 'react';
import { classNames } from '~/utils/classNames';
import { AssistantMessage } from './AssistantMessage';
import { UserMessage } from './UserMessage';
Expand Down Expand Up @@ -44,10 +44,15 @@ export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props:
<div id={id} ref={ref} className={props.className}>
{messages.length > 0
? messages.map((message, index) => {
const { role, content, id: messageId } = message;
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
Expand Down
29 changes: 22 additions & 7 deletions app/components/settings/features/FeaturesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default function FeaturesTab() {
enableLatestBranch,
promptId,
setPromptId,
autoSelectTemplate,
setAutoSelectTemplate,
enableContextOptimization,
contextOptimizationEnabled,
} = useSettings();
Expand All @@ -35,12 +37,21 @@ export default function FeaturesTab() {
<div className="flex items-center justify-between">
<div>
<span className="text-bolt-elements-textPrimary">Use Main Branch</span>
<p className="text-sm text-bolt-elements-textSecondary">
<p className="text-xs text-bolt-elements-textTertiary">
Check for updates against the main branch instead of stable
</p>
</div>
<Switch className="ml-auto" checked={isLatestBranch} onCheckedChange={enableLatestBranch} />
</div>
<div className="flex items-center justify-between">
<div>
<span className="text-bolt-elements-textPrimary">Auto Select Code Template</span>
<p className="text-xs text-bolt-elements-textTertiary">
Let Bolt select the best starter template for your project.
</p>
</div>
<Switch className="ml-auto" checked={autoSelectTemplate} onCheckedChange={setAutoSelectTemplate} />
</div>
<div className="flex items-center justify-between">
<div>
<span className="text-bolt-elements-textPrimary">Use Context Optimization</span>
Expand All @@ -59,18 +70,22 @@ export default function FeaturesTab() {

<div className="mb-6 border-t border-bolt-elements-borderColor pt-4">
<h3 className="text-lg font-medium text-bolt-elements-textPrimary mb-4">Experimental Features</h3>
<p className="text-sm text-bolt-elements-textSecondary mb-4">
<p className="text-sm text-bolt-elements-textSecondary mb-10">
Disclaimer: Experimental features may be unstable and are subject to change.
</p>

<div className="flex items-center justify-between mb-2">
<span className="text-bolt-elements-textPrimary">Experimental Providers</span>
<Switch className="ml-auto" checked={isLocalModel} onCheckedChange={enableLocalModels} />
<div className="flex flex-col">
<div className="flex items-center justify-between mb-2">
<span className="text-bolt-elements-textPrimary">Experimental Providers</span>
<Switch className="ml-auto" checked={isLocalModel} onCheckedChange={enableLocalModels} />
</div>
<p className="text-xs text-bolt-elements-textTertiary mb-4">
Enable experimental providers such as Ollama, LMStudio, and OpenAILike.
</p>
</div>
<div className="flex items-start justify-between pt-4 mb-2 gap-2">
<div className="flex-1 max-w-[200px]">
<span className="text-bolt-elements-textPrimary">Prompt Library</span>
<p className="text-sm text-bolt-elements-textSecondary mb-4">
<p className="text-xs text-bolt-elements-textTertiary mb-4">
Choose a prompt from the library to use as the system prompt.
</p>
</div>
Expand Down
16 changes: 16 additions & 0 deletions app/lib/hooks/useSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
promptStore,
providersStore,
latestBranchStore,
autoSelectStarterTemplate,
enableContextOptimizationStore,
} from '~/lib/stores/settings';
import { useCallback, useEffect, useState } from 'react';
Expand All @@ -31,6 +32,7 @@ export function useSettings() {
const promptId = useStore(promptStore);
const isLocalModel = useStore(isLocalModelsEnabled);
const isLatestBranch = useStore(latestBranchStore);
const autoSelectTemplate = useStore(autoSelectStarterTemplate);
const [activeProviders, setActiveProviders] = useState<ProviderInfo[]>([]);
const contextOptimizationEnabled = useStore(enableContextOptimizationStore);

Expand Down Expand Up @@ -121,6 +123,12 @@ export function useSettings() {
latestBranchStore.set(savedLatestBranch === 'true');
}

const autoSelectTemplate = Cookies.get('autoSelectTemplate');

if (autoSelectTemplate) {
autoSelectStarterTemplate.set(autoSelectTemplate === 'true');
}

const savedContextOptimizationEnabled = Cookies.get('contextOptimizationEnabled');

if (savedContextOptimizationEnabled) {
Expand Down Expand Up @@ -187,6 +195,12 @@ export function useSettings() {
Cookies.set('isLatestBranch', String(enabled));
}, []);

const setAutoSelectTemplate = useCallback((enabled: boolean) => {
autoSelectStarterTemplate.set(enabled);
logStore.logSystem(`Auto select template ${enabled ? 'enabled' : 'disabled'}`);
Cookies.set('autoSelectTemplate', String(enabled));
}, []);

const enableContextOptimization = useCallback((enabled: boolean) => {
enableContextOptimizationStore.set(enabled);
logStore.logSystem(`Context optimization ${enabled ? 'enabled' : 'disabled'}`);
Expand All @@ -207,6 +221,8 @@ export function useSettings() {
setPromptId,
isLatestBranch,
enableLatestBranch,
autoSelectTemplate,
setAutoSelectTemplate,
contextOptimizationEnabled,
enableContextOptimization,
};
Expand Down
1 change: 0 additions & 1 deletion app/lib/runtime/message-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export class StreamingMessageParser {
// Remove markdown code block syntax if present and file is not markdown
if (!currentAction.filePath.endsWith('.md')) {
content = cleanoutMarkdownSyntax(content);
console.log('content after cleanup', content);
}

content += '\n';
Expand Down
1 change: 1 addition & 0 deletions app/lib/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ export const promptStore = atom<string>('default');

export const latestBranchStore = atom(false);

export const autoSelectStarterTemplate = atom(true);
export const enableContextOptimizationStore = atom(false);
Loading
Loading