Skip to content

Commit

Permalink
Merge branch 'main' into new_bolt2
Browse files Browse the repository at this point in the history
  • Loading branch information
ali00209 authored Nov 12, 2024
2 parents 45df6d6 + a081f8b commit 9181f81
Show file tree
Hide file tree
Showing 17 changed files with 1,012 additions and 143 deletions.
32 changes: 0 additions & 32 deletions .github/workflows/semantic-pr.yaml

This file was deleted.

20 changes: 18 additions & 2 deletions app/components/chat/Artifact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,13 @@ const ActionList = memo(({ actions }: ActionListProps) => {
<div className="flex items-center gap-1.5 text-sm">
<div className={classNames('text-lg', getIconColor(action.status))}>
{status === 'running' ? (
<div className="i-svg-spinners:90-ring-with-bg"></div>
<>
{type !== 'start' ? (
<div className="i-svg-spinners:90-ring-with-bg"></div>
) : (
<div className="i-ph:terminal-window-duotone"></div>
)}
</>
) : status === 'pending' ? (
<div className="i-ph:circle-duotone"></div>
) : status === 'complete' ? (
Expand All @@ -171,9 +177,19 @@ const ActionList = memo(({ actions }: ActionListProps) => {
<div className="flex items-center w-full min-h-[28px]">
<span className="flex-1">Run command</span>
</div>
) : type === 'start' ? (
<a
onClick={(e) => {
e.preventDefault();
workbenchStore.currentView.set('preview');
}}
className="flex items-center w-full min-h-[28px]"
>
<span className="flex-1">Start Application</span>
</a>
) : null}
</div>
{type === 'shell' && (
{(type === 'shell' || type === 'start') && (
<ShellCodeBlock
classsName={classNames('mt-1', {
'mb-3.5': !isLast,
Expand Down
34 changes: 19 additions & 15 deletions app/components/chat/BaseChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ const EXAMPLE_PROMPTS = [
{ text: 'How do I center a div?' },
];

const providerList = [...new Set(MODEL_LIST.map((model) => model.provider))]
const providerList = [...new Set(MODEL_LIST.map((model) => model.provider))];

const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList }) => {
return (
<div className="mb-2 flex gap-2">
<select
<select
value={provider}
onChange={(e) => {
setProvider(e.target.value);
const firstModel = [...modelList].find(m => m.provider == e.target.value);
const firstModel = [...modelList].find((m) => m.provider == e.target.value);
setModel(firstModel ? firstModel.name : '');
}}
className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all"
Expand All @@ -58,11 +58,13 @@ const ModelSelector = ({ model, setModel, provider, setProvider, modelList, prov
onChange={(e) => setModel(e.target.value)}
className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all"
>
{[...modelList].filter(e => e.provider == provider && e.name).map((modelOption) => (
<option key={modelOption.name} value={modelOption.name}>
{modelOption.label}
</option>
))}
{[...modelList]
.filter((e) => e.provider == provider && e.name)
.map((modelOption) => (
<option key={modelOption.name} value={modelOption.name}>
{modelOption.label}
</option>
))}
</select>
</div>
);
Expand All @@ -81,10 +83,10 @@ interface BaseChatProps {
enhancingPrompt?: boolean;
promptEnhanced?: boolean;
input?: string;
model: string;
setModel: (model: string) => void;
provider: string;
setProvider: (provider: string) => void;
model?: string;
setModel?: (model: string) => void;
provider?: string;
setProvider?: (provider: string) => void;
handleStop?: () => void;
sendMessage?: (event: React.UIEvent, messageInput?: string) => void;
handleInputChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
Expand Down Expand Up @@ -144,7 +146,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
expires: 30, // 30 days
secure: true, // Only send over HTTPS
sameSite: 'strict', // Protect against CSRF
path: '/' // Accessible across the site
path: '/', // Accessible across the site
});
} catch (error) {
console.error('Error saving API keys to cookies:', error);
Expand Down Expand Up @@ -281,7 +283,9 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
</div>
{input.length > 3 ? (
<div className="text-xs text-bolt-elements-textTertiary">
Use <kbd className="kdb px-1.5 py-0.5 rounded bg-bolt-elements-background-depth-2">Shift</kbd> + <kbd className="kdb px-1.5 py-0.5 rounded bg-bolt-elements-background-depth-2">Return</kbd> for a new line
Use <kbd className="kdb px-1.5 py-0.5 rounded bg-bolt-elements-background-depth-2">Shift</kbd> +{' '}
<kbd className="kdb px-1.5 py-0.5 rounded bg-bolt-elements-background-depth-2">Return</kbd> for
a new line
</div>
) : null}
</div>
Expand Down Expand Up @@ -315,4 +319,4 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
</div>
);
},
);
);
38 changes: 30 additions & 8 deletions app/components/chat/Chat.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,14 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
const textareaRef = useRef<HTMLTextAreaElement>(null);

const [chatStarted, setChatStarted] = useState(initialMessages.length > 0);
const [model, setModel] = useState(DEFAULT_MODEL);
const [provider, setProvider] = useState(DEFAULT_PROVIDER);
const [model, setModel] = useState(() => {
const savedModel = Cookies.get('selectedModel');
return savedModel || DEFAULT_MODEL;
});
const [provider, setProvider] = useState(() => {
const savedProvider = Cookies.get('selectedProvider');
return savedProvider || DEFAULT_PROVIDER;
});

const { showChat } = useStore(chatStore);

Expand Down Expand Up @@ -216,6 +222,16 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
}
}, []);

const handleModelChange = (newModel: string) => {
setModel(newModel);
Cookies.set('selectedModel', newModel, { expires: 30 });
};

const handleProviderChange = (newProvider: string) => {
setProvider(newProvider);
Cookies.set('selectedProvider', newProvider, { expires: 30 });
};

return (
<BaseChat
ref={animationScope}
Expand All @@ -228,9 +244,9 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
promptEnhanced={promptEnhanced}
sendMessage={sendMessage}
model={model}
setModel={setModel}
setModel={handleModelChange}
provider={provider}
setProvider={setProvider}
setProvider={handleProviderChange}
messageRef={messageRef}
scrollRef={scrollRef}
handleInputChange={handleInputChange}
Expand All @@ -246,10 +262,16 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
};
})}
enhancePrompt={() => {
enhancePrompt(input, (input) => {
setInput(input);
scrollTextArea();
});
enhancePrompt(
input,
(input) => {
setInput(input);
scrollTextArea();
},
model,
provider,
apiKeys
);
}}
/>
);
Expand Down
74 changes: 57 additions & 17 deletions app/components/workbench/EditorPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { themeStore } from '~/lib/stores/theme';
import { workbenchStore } from '~/lib/stores/workbench';
import { classNames } from '~/utils/classNames';
import { WORK_DIR } from '~/utils/constants';
import { renderLogger } from '~/utils/logger';
import { logger, renderLogger } from '~/utils/logger';
import { isMobile } from '~/utils/mobile';
import { FileBreadcrumb } from './FileBreadcrumb';
import { FileTree } from './FileTree';
Expand Down Expand Up @@ -199,25 +199,48 @@ export const EditorPanel = memo(
<div className="h-full">
<div className="bg-bolt-elements-terminals-background h-full flex flex-col">
<div className="flex items-center bg-bolt-elements-background-depth-2 border-y border-bolt-elements-borderColor gap-1.5 min-h-[34px] p-2">
{Array.from({ length: terminalCount }, (_, index) => {
{Array.from({ length: terminalCount + 1 }, (_, index) => {
const isActive = activeTerminal === index;

return (
<button
key={index}
className={classNames(
'flex items-center text-sm cursor-pointer gap-1.5 px-3 py-2 h-full whitespace-nowrap rounded-full',
{
'bg-bolt-elements-terminals-buttonBackground text-bolt-elements-textPrimary': isActive,
'bg-bolt-elements-background-depth-2 text-bolt-elements-textSecondary hover:bg-bolt-elements-terminals-buttonBackground':
!isActive,
},
<>
{index == 0 ? (
<button
key={index}
className={classNames(
'flex items-center text-sm cursor-pointer gap-1.5 px-3 py-2 h-full whitespace-nowrap rounded-full',
{
'bg-bolt-elements-terminals-buttonBackground text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary':
isActive,
'bg-bolt-elements-background-depth-2 text-bolt-elements-textSecondary hover:bg-bolt-elements-terminals-buttonBackground':
!isActive,
},
)}
onClick={() => setActiveTerminal(index)}
>
<div className="i-ph:terminal-window-duotone text-lg" />
Bolt Terminal
</button>
) : (
<>
<button
key={index}
className={classNames(
'flex items-center text-sm cursor-pointer gap-1.5 px-3 py-2 h-full whitespace-nowrap rounded-full',
{
'bg-bolt-elements-terminals-buttonBackground text-bolt-elements-textPrimary': isActive,
'bg-bolt-elements-background-depth-2 text-bolt-elements-textSecondary hover:bg-bolt-elements-terminals-buttonBackground':
!isActive,
},
)}
onClick={() => setActiveTerminal(index)}
>
<div className="i-ph:terminal-window-duotone text-lg" />
Terminal {terminalCount > 1 && index}
</button>
</>
)}
onClick={() => setActiveTerminal(index)}
>
<div className="i-ph:terminal-window-duotone text-lg" />
Terminal {terminalCount > 1 && index + 1}
</button>
</>
);
})}
{terminalCount < MAX_TERMINALS && <IconButton icon="i-ph:plus" size="md" onClick={addTerminal} />}
Expand All @@ -229,9 +252,26 @@ export const EditorPanel = memo(
onClick={() => workbenchStore.toggleTerminal(false)}
/>
</div>
{Array.from({ length: terminalCount }, (_, index) => {
{Array.from({ length: terminalCount + 1 }, (_, index) => {
const isActive = activeTerminal === index;
if (index == 0) {
logger.info('Starting bolt terminal');

return (
<Terminal
key={index}
className={classNames('h-full overflow-hidden', {
hidden: !isActive,
})}
ref={(ref) => {
terminalRefs.current.push(ref);
}}
onTerminalReady={(terminal) => workbenchStore.attachBoltTerminal(terminal)}
onTerminalResize={(cols, rows) => workbenchStore.onTerminalResize(cols, rows)}
theme={theme}
/>
);
}
return (
<Terminal
key={index}
Expand Down
12 changes: 9 additions & 3 deletions app/lib/.server/llm/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,16 @@ You are Bolt, an expert AI assistant and exceptional senior software developer w
- When Using \`npx\`, ALWAYS provide the \`--yes\` flag.
- When running multiple shell commands, use \`&&\` to run them sequentially.
- ULTRA IMPORTANT: Do NOT re-run a dev command if there is one that starts a dev server and new dependencies were installed or files updated! If a dev server has started already, assume that installing dependencies will be executed in a different process and will be picked up by the dev server.
- ULTRA IMPORTANT: Do NOT re-run a dev command with shell action use dev action to run dev commands
- file: For writing new files or updating existing files. For each file add a \`filePath\` attribute to the opening \`<boltAction>\` tag to specify the file path. The content of the file artifact is the file contents. All file paths MUST BE relative to the current working directory.
- start: For starting development server.
- Use to start application if not already started or NEW dependencies added
- Only use this action when you need to run a dev server or start the application
- ULTRA IMORTANT: do NOT re-run a dev server if files updated, existing dev server can autometically detect changes and executes the file changes
9. The order of the actions is VERY IMPORTANT. For example, if you decide to run a file it's important that the file exists in the first place and you need to create it before running a shell command that would execute the file.
10. ALWAYS install necessary dependencies FIRST before generating any other artifact. If that requires a \`package.json\` then you should create that first!
Expand Down Expand Up @@ -265,7 +271,7 @@ Here are some examples of correct usage of artifacts:
...
</boltAction>
<boltAction type="shell">
<boltAction type="start">
npm run dev
</boltAction>
</boltArtifact>
Expand Down Expand Up @@ -322,7 +328,7 @@ Here are some examples of correct usage of artifacts:
...
</boltAction>
<boltAction type="shell">
<boltAction type="start">
npm run dev
</boltAction>
</boltArtifact>
Expand Down
4 changes: 4 additions & 0 deletions app/lib/hooks/useMessageParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const messageParser = new StreamingMessageParser({

workbenchStore.runAction(data);
},
onActionStream: (data) => {
logger.trace('onActionStream', data.action);
workbenchStore.runAction(data, true);
},
},
});

Expand Down
Loading

0 comments on commit 9181f81

Please sign in to comment.