Skip to content

Commit c6098d2

Browse files
committed
Added queue for the user message with limit of 5
1 parent f05a464 commit c6098d2

File tree

3 files changed

+103
-7
lines changed

3 files changed

+103
-7
lines changed

apps/studio/src/lib/editor/engine/chat/index.ts

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ import {
55
ChatMessageRole,
66
StreamRequestType,
77
type AssistantChatMessage,
8+
type ChatMessageContext,
89
type CompletedStreamResponse,
910
type ErrorStreamResponse,
11+
type QueuedMessage,
1012
type RateLimitedStreamResponse,
1113
} from '@onlook/models/chat';
1214
import { MainChannels } from '@onlook/models/constants';
1315
import type { ParsedError } from '@onlook/utility';
1416
import type { CoreMessage } from 'ai';
15-
import { makeAutoObservable } from 'mobx';
17+
import { makeAutoObservable, runInAction } from 'mobx';
1618
import { nanoid } from 'nanoid/non-secure';
1719
import type { EditorEngine } from '..';
1820
import { ChatCodeManager } from './code';
@@ -31,13 +33,17 @@ export class ChatManager {
3133
context: ChatContext;
3234
stream: StreamResolver;
3335
suggestions: SuggestionManager;
36+
messageQueue: QueuedMessage[] = [];
37+
private maxQueueSize = 5;
3438

3539
constructor(
3640
private editorEngine: EditorEngine,
3741
private projectsManager: ProjectsManager,
3842
private userManager: UserManager,
3943
) {
40-
makeAutoObservable(this);
44+
makeAutoObservable(this, {
45+
messageQueue: true,
46+
});
4147
this.context = new ChatContext(this.editorEngine, this.projectsManager);
4248
this.conversation = new ConversationManager(this.editorEngine, this.projectsManager);
4349
this.stream = new StreamResolver();
@@ -49,14 +55,38 @@ export class ChatManager {
4955
window.dispatchEvent(new Event(FOCUS_CHAT_INPUT_EVENT));
5056
}
5157

52-
async sendNewMessage(content: string): Promise<void> {
58+
get queueSize(): number {
59+
return this.messageQueue.length;
60+
}
61+
62+
async processMessageQueue() {
63+
if (this.messageQueue.length === 0 || this.isWaiting) {
64+
return;
65+
}
66+
const nextMessage = this.messageQueue.shift()!;
67+
await this.processMessage(nextMessage.content, nextMessage.context);
68+
69+
if (this.messageQueue.length > 0) {
70+
await this.processMessageQueue();
71+
}
72+
}
73+
74+
private async processMessage(content: string, context?: ChatMessageContext[]) {
5375
if (!this.conversation.current) {
5476
console.error('No conversation found');
5577
return;
5678
}
5779

58-
const context = await this.context.getChatContext();
59-
const userMessage = this.conversation.addUserMessage(content, context);
80+
if (this.isWaiting) {
81+
this.messageQueue.push({ content, context });
82+
if (this.messageQueue.length > this.maxQueueSize) {
83+
this.messageQueue.shift();
84+
}
85+
return;
86+
}
87+
88+
const messageContext = context ?? (await this.context.getChatContext());
89+
const userMessage = this.conversation.addUserMessage(content, messageContext);
6090
this.conversation.current.updateName(content);
6191
if (!userMessage) {
6292
console.error('Failed to add user message');
@@ -68,6 +98,29 @@ export class ChatManager {
6898
await this.sendChatToAi(StreamRequestType.CHAT, content);
6999
}
70100

101+
async sendNewMessage(content: string): Promise<void> {
102+
if (!this.conversation.current) {
103+
console.error('No conversation found');
104+
return;
105+
}
106+
107+
if (this.isWaiting) {
108+
if (this.messageQueue.length >= this.maxQueueSize) {
109+
console.warn('Message queue is full');
110+
return;
111+
}
112+
runInAction(() => {
113+
this.messageQueue.push({ content });
114+
});
115+
116+
console.log(`Message queued. Queue size: ${this.messageQueue.length}`);
117+
return;
118+
}
119+
120+
await this.processMessage(content);
121+
this.processMessageQueue();
122+
}
123+
71124
async sendFixErrorToAi(errors: ParsedError[]): Promise<boolean> {
72125
if (!this.conversation.current) {
73126
console.error('No conversation found');
@@ -77,6 +130,22 @@ export class ChatManager {
77130
const prompt = `How can I resolve these errors? If you propose a fix, please make it concise.`;
78131
const errorContexts = this.context.getMessageContext(errors);
79132
const projectContexts = this.context.getProjectContext();
133+
134+
if (this.isWaiting) {
135+
if (this.messageQueue.length >= this.maxQueueSize) {
136+
console.warn('Message queue is full');
137+
return false;
138+
}
139+
runInAction(() => {
140+
this.messageQueue.push({
141+
content: prompt,
142+
context: [...errorContexts, ...projectContexts],
143+
});
144+
});
145+
console.log(`Error-fix message queued. Queue size: ${this.messageQueue.length}`);
146+
return true;
147+
}
148+
80149
const userMessage = this.conversation.addUserMessage(prompt, [
81150
...errorContexts,
82151
...projectContexts,
@@ -139,6 +208,10 @@ export class ChatManager {
139208
invokeMainChannel(MainChannels.SEND_STOP_STREAM_REQUEST, {
140209
requestId,
141210
});
211+
212+
runInAction(() => {
213+
this.messageQueue = [];
214+
});
142215
sendAnalytics('stop chat stream');
143216
}
144217

@@ -204,6 +277,8 @@ export class ChatManager {
204277
}
205278

206279
this.context.clearAttachments();
280+
281+
await this.processMessageQueue();
207282
}
208283

209284
handleNewCoreMessages(messages: CoreMessage[]) {

apps/studio/src/routes/editor/EditPanel/ChatTab/ChatInput.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export const ChatInput = observer(() => {
2929
const [actionTooltipOpen, setActionTooltipOpen] = useState(false);
3030
const [isDragging, setIsDragging] = useState(false);
3131

32+
const queueSize = editorEngine.chat.queueSize;
33+
const MAX_QUEUE_SIZE = 5;
34+
3235
const focusInput = () => {
3336
requestAnimationFrame(() => {
3437
textareaRef.current?.focus();
@@ -428,6 +431,11 @@ export const ChatInput = observer(() => {
428431
<span className="text-smallPlus">File Reference</span>
429432
</Button>
430433
</div>
434+
{queueSize > 0 && (
435+
<span className="text-micro text-foreground-secondary">
436+
{queueSize} message{queueSize > 1 ? 's' : ''} queued
437+
</span>
438+
)}
431439
{editorEngine.chat.isWaiting ? (
432440
<Tooltip open={actionTooltipOpen} onOpenChange={setActionTooltipOpen}>
433441
<TooltipTrigger asChild>
@@ -450,7 +458,10 @@ export const ChatInput = observer(() => {
450458
size={'icon'}
451459
variant={'secondary'}
452460
className="text-smallPlus w-fit h-full py-0.5 px-2.5 text-primary"
453-
disabled={inputEmpty || editorEngine.chat.isWaiting}
461+
disabled={
462+
inputEmpty ||
463+
(editorEngine.chat.isWaiting && queueSize >= MAX_QUEUE_SIZE)
464+
}
454465
onClick={sendMessage}
455466
>
456467
<Icons.ArrowRight />

packages/models/src/chat/conversation/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import type { AssistantChatMessage, ChatMessage, TokenUsage } from '../message/index.ts';
1+
import type {
2+
AssistantChatMessage,
3+
ChatMessage,
4+
ChatMessageContext,
5+
TokenUsage,
6+
} from '../message/index.ts';
27

38
export type ChatConversation = {
49
id: string;
@@ -10,3 +15,8 @@ export type ChatConversation = {
1015
summaryMessage?: AssistantChatMessage | null;
1116
tokenUsage?: TokenUsage;
1217
};
18+
19+
export type QueuedMessage = {
20+
content: string;
21+
context?: ChatMessageContext[];
22+
};

0 commit comments

Comments
 (0)