Skip to content

Commit e40264e

Browse files
authored
Merge pull request #1735 from xKevIsDev/main
feat: add discuss mode and quick actions
2 parents 05d7ef0 + f79bf06 commit e40264e

File tree

13 files changed

+974
-415
lines changed

13 files changed

+974
-415
lines changed

app/components/chat/Artifact.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ const actionVariants = {
184184
visible: { opacity: 1, y: 0 },
185185
};
186186

187-
function openArtifactInWorkbench(filePath: any) {
187+
export function openArtifactInWorkbench(filePath: any) {
188188
if (workbenchStore.currentView.get() !== 'code') {
189189
workbenchStore.currentView.set('code');
190190
}

app/components/chat/AssistantMessage.tsx

Lines changed: 112 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@ import Popover from '~/components/ui/Popover';
55
import { workbenchStore } from '~/lib/stores/workbench';
66
import { WORK_DIR } from '~/utils/constants';
77
import WithTooltip from '~/components/ui/Tooltip';
8+
import type { Message } from 'ai';
9+
import type { ProviderInfo } from '~/types/model';
810

911
interface AssistantMessageProps {
1012
content: string;
1113
annotations?: JSONValue[];
1214
messageId?: string;
1315
onRewind?: (messageId: string) => void;
1416
onFork?: (messageId: string) => void;
17+
append?: (message: Message) => void;
18+
chatMode?: 'discuss' | 'build';
19+
setChatMode?: (mode: 'discuss' | 'build') => void;
20+
model?: string;
21+
provider?: ProviderInfo;
1522
}
1623

1724
function openArtifactInWorkbench(filePath: string) {
@@ -38,104 +45,120 @@ function normalizedFilePath(path: string) {
3845
return normalizedPath;
3946
}
4047

41-
export const AssistantMessage = memo(({ content, annotations, messageId, onRewind, onFork }: AssistantMessageProps) => {
42-
const filteredAnnotations = (annotations?.filter(
43-
(annotation: JSONValue) => annotation && typeof annotation === 'object' && Object.keys(annotation).includes('type'),
44-
) || []) as { type: string; value: any } & { [key: string]: any }[];
48+
export const AssistantMessage = memo(
49+
({
50+
content,
51+
annotations,
52+
messageId,
53+
onRewind,
54+
onFork,
55+
append,
56+
chatMode,
57+
setChatMode,
58+
model,
59+
provider,
60+
}: AssistantMessageProps) => {
61+
const filteredAnnotations = (annotations?.filter(
62+
(annotation: JSONValue) =>
63+
annotation && typeof annotation === 'object' && Object.keys(annotation).includes('type'),
64+
) || []) as { type: string; value: any } & { [key: string]: any }[];
4565

46-
let chatSummary: string | undefined = undefined;
66+
let chatSummary: string | undefined = undefined;
4767

48-
if (filteredAnnotations.find((annotation) => annotation.type === 'chatSummary')) {
49-
chatSummary = filteredAnnotations.find((annotation) => annotation.type === 'chatSummary')?.summary;
50-
}
68+
if (filteredAnnotations.find((annotation) => annotation.type === 'chatSummary')) {
69+
chatSummary = filteredAnnotations.find((annotation) => annotation.type === 'chatSummary')?.summary;
70+
}
5171

52-
let codeContext: string[] | undefined = undefined;
72+
let codeContext: string[] | undefined = undefined;
5373

54-
if (filteredAnnotations.find((annotation) => annotation.type === 'codeContext')) {
55-
codeContext = filteredAnnotations.find((annotation) => annotation.type === 'codeContext')?.files;
56-
}
74+
if (filteredAnnotations.find((annotation) => annotation.type === 'codeContext')) {
75+
codeContext = filteredAnnotations.find((annotation) => annotation.type === 'codeContext')?.files;
76+
}
5777

58-
const usage: {
59-
completionTokens: number;
60-
promptTokens: number;
61-
totalTokens: number;
62-
} = filteredAnnotations.find((annotation) => annotation.type === 'usage')?.value;
78+
const usage: {
79+
completionTokens: number;
80+
promptTokens: number;
81+
totalTokens: number;
82+
} = filteredAnnotations.find((annotation) => annotation.type === 'usage')?.value;
6383

64-
return (
65-
<div className="overflow-hidden w-full">
66-
<>
67-
<div className=" flex gap-2 items-center text-sm text-bolt-elements-textSecondary mb-2">
68-
{(codeContext || chatSummary) && (
69-
<Popover side="right" align="start" trigger={<div className="i-ph:info" />}>
70-
{chatSummary && (
71-
<div className="max-w-chat">
72-
<div className="summary max-h-96 flex flex-col">
73-
<h2 className="border border-bolt-elements-borderColor rounded-md p4">Summary</h2>
74-
<div style={{ zoom: 0.7 }} className="overflow-y-auto m4">
75-
<Markdown>{chatSummary}</Markdown>
76-
</div>
77-
</div>
78-
{codeContext && (
79-
<div className="code-context flex flex-col p4 border border-bolt-elements-borderColor rounded-md">
80-
<h2>Context</h2>
81-
<div className="flex gap-4 mt-4 bolt" style={{ zoom: 0.6 }}>
82-
{codeContext.map((x) => {
83-
const normalized = normalizedFilePath(x);
84-
return (
85-
<Fragment key={normalized}>
86-
<code
87-
className="bg-bolt-elements-artifacts-inlineCode-background text-bolt-elements-artifacts-inlineCode-text px-1.5 py-1 rounded-md text-bolt-elements-item-contentAccent hover:underline cursor-pointer"
88-
onClick={(e) => {
89-
e.preventDefault();
90-
e.stopPropagation();
91-
openArtifactInWorkbench(normalized);
92-
}}
93-
>
94-
{normalized}
95-
</code>
96-
</Fragment>
97-
);
98-
})}
84+
return (
85+
<div className="overflow-hidden w-full">
86+
<>
87+
<div className=" flex gap-2 items-center text-sm text-bolt-elements-textSecondary mb-2">
88+
{(codeContext || chatSummary) && (
89+
<Popover side="right" align="start" trigger={<div className="i-ph:info" />}>
90+
{chatSummary && (
91+
<div className="max-w-chat">
92+
<div className="summary max-h-96 flex flex-col">
93+
<h2 className="border border-bolt-elements-borderColor rounded-md p4">Summary</h2>
94+
<div style={{ zoom: 0.7 }} className="overflow-y-auto m4">
95+
<Markdown>{chatSummary}</Markdown>
9996
</div>
10097
</div>
98+
{codeContext && (
99+
<div className="code-context flex flex-col p4 border border-bolt-elements-borderColor rounded-md">
100+
<h2>Context</h2>
101+
<div className="flex gap-4 mt-4 bolt" style={{ zoom: 0.6 }}>
102+
{codeContext.map((x) => {
103+
const normalized = normalizedFilePath(x);
104+
return (
105+
<Fragment key={normalized}>
106+
<code
107+
className="bg-bolt-elements-artifacts-inlineCode-background text-bolt-elements-artifacts-inlineCode-text px-1.5 py-1 rounded-md text-bolt-elements-item-contentAccent hover:underline cursor-pointer"
108+
onClick={(e) => {
109+
e.preventDefault();
110+
e.stopPropagation();
111+
openArtifactInWorkbench(normalized);
112+
}}
113+
>
114+
{normalized}
115+
</code>
116+
</Fragment>
117+
);
118+
})}
119+
</div>
120+
</div>
121+
)}
122+
</div>
123+
)}
124+
<div className="context"></div>
125+
</Popover>
126+
)}
127+
<div className="flex w-full items-center justify-between">
128+
{usage && (
129+
<div>
130+
Tokens: {usage.totalTokens} (prompt: {usage.promptTokens}, completion: {usage.completionTokens})
131+
</div>
132+
)}
133+
{(onRewind || onFork) && messageId && (
134+
<div className="flex gap-2 flex-col lg:flex-row ml-auto">
135+
{onRewind && (
136+
<WithTooltip tooltip="Revert to this message">
137+
<button
138+
onClick={() => onRewind(messageId)}
139+
key="i-ph:arrow-u-up-left"
140+
className="i-ph:arrow-u-up-left text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors"
141+
/>
142+
</WithTooltip>
143+
)}
144+
{onFork && (
145+
<WithTooltip tooltip="Fork chat from this message">
146+
<button
147+
onClick={() => onFork(messageId)}
148+
key="i-ph:git-fork"
149+
className="i-ph:git-fork text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors"
150+
/>
151+
</WithTooltip>
101152
)}
102153
</div>
103154
)}
104-
<div className="context"></div>
105-
</Popover>
106-
)}
107-
<div className="flex w-full items-center justify-between">
108-
{usage && (
109-
<div>
110-
Tokens: {usage.totalTokens} (prompt: {usage.promptTokens}, completion: {usage.completionTokens})
111-
</div>
112-
)}
113-
{(onRewind || onFork) && messageId && (
114-
<div className="flex gap-2 flex-col lg:flex-row ml-auto">
115-
{onRewind && (
116-
<WithTooltip tooltip="Revert to this message">
117-
<button
118-
onClick={() => onRewind(messageId)}
119-
key="i-ph:arrow-u-up-left"
120-
className="i-ph:arrow-u-up-left text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors"
121-
/>
122-
</WithTooltip>
123-
)}
124-
{onFork && (
125-
<WithTooltip tooltip="Fork chat from this message">
126-
<button
127-
onClick={() => onFork(messageId)}
128-
key="i-ph:git-fork"
129-
className="i-ph:git-fork text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors"
130-
/>
131-
</WithTooltip>
132-
)}
133-
</div>
134-
)}
155+
</div>
135156
</div>
136-
</div>
137-
</>
138-
<Markdown html>{content}</Markdown>
139-
</div>
140-
);
141-
});
157+
</>
158+
<Markdown append={append} chatMode={chatMode} setChatMode={setChatMode} model={model} provider={provider} html>
159+
{content}
160+
</Markdown>
161+
</div>
162+
);
163+
},
164+
);

0 commit comments

Comments
 (0)