Prefill messages in main process and ensure loading state is always shown (incl. new chat) (#35)
This commit is contained in:
@@ -62,44 +62,18 @@ export function useStreamChat({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
setMessages((currentMessages: Message[]) => {
|
|
||||||
if (redo) {
|
|
||||||
let remainingMessages = currentMessages.slice();
|
|
||||||
if (
|
|
||||||
currentMessages[currentMessages.length - 1].role === "assistant"
|
|
||||||
) {
|
|
||||||
remainingMessages = currentMessages.slice(0, -1);
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
...remainingMessages,
|
|
||||||
{
|
|
||||||
id: getRandomNumberId(),
|
|
||||||
role: "assistant",
|
|
||||||
content: "",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
...currentMessages,
|
|
||||||
{
|
|
||||||
id: getRandomNumberId(),
|
|
||||||
role: "user",
|
|
||||||
content: prompt,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: getRandomNumberId(),
|
|
||||||
role: "assistant",
|
|
||||||
content: "",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
setIsStreaming(true);
|
setIsStreaming(true);
|
||||||
setStreamCount((streamCount) => streamCount + 1);
|
let hasIncrementedStreamCount = false;
|
||||||
try {
|
try {
|
||||||
IpcClient.getInstance().streamMessage(prompt, {
|
IpcClient.getInstance().streamMessage(prompt, {
|
||||||
chatId,
|
chatId,
|
||||||
redo,
|
redo,
|
||||||
onUpdate: (updatedMessages: Message[]) => {
|
onUpdate: (updatedMessages: Message[]) => {
|
||||||
|
if (!hasIncrementedStreamCount) {
|
||||||
|
setStreamCount((streamCount) => streamCount + 1);
|
||||||
|
hasIncrementedStreamCount = true;
|
||||||
|
}
|
||||||
|
|
||||||
setMessages(updatedMessages);
|
setMessages(updatedMessages);
|
||||||
},
|
},
|
||||||
onEnd: (response: ChatResponseEnd) => {
|
onEnd: (response: ChatResponseEnd) => {
|
||||||
|
|||||||
@@ -97,6 +97,16 @@ export function registerChatStreamHandlers() {
|
|||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
// Add a placeholder assistant message immediately
|
||||||
|
const [placeholderAssistantMessage] = await db
|
||||||
|
.insert(messages)
|
||||||
|
.values({
|
||||||
|
chatId: req.chatId,
|
||||||
|
role: "assistant",
|
||||||
|
content: "", // Start with empty content
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
// Fetch updated chat data after possible deletions and additions
|
// Fetch updated chat data after possible deletions and additions
|
||||||
const updatedChat = await db.query.chats.findFirst({
|
const updatedChat = await db.query.chats.findFirst({
|
||||||
where: eq(chats.id, req.chatId),
|
where: eq(chats.id, req.chatId),
|
||||||
@@ -112,6 +122,12 @@ export function registerChatStreamHandlers() {
|
|||||||
throw new Error(`Chat not found: ${req.chatId}`);
|
throw new Error(`Chat not found: ${req.chatId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send the messages right away so that the loading state is shown for the message.
|
||||||
|
event.sender.send("chat:response:chunk", {
|
||||||
|
chatId: req.chatId,
|
||||||
|
messages: updatedChat.messages,
|
||||||
|
});
|
||||||
|
|
||||||
let fullResponse = "";
|
let fullResponse = "";
|
||||||
|
|
||||||
// Check if this is a test prompt
|
// Check if this is a test prompt
|
||||||
@@ -206,7 +222,7 @@ export function registerChatStreamHandlers() {
|
|||||||
temperature: 0,
|
temperature: 0,
|
||||||
model: modelClient,
|
model: modelClient,
|
||||||
system: systemPrompt,
|
system: systemPrompt,
|
||||||
messages: chatMessages,
|
messages: chatMessages.filter((m) => m.content),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
logger.error("Error streaming text:", error);
|
logger.error("Error streaming text:", error);
|
||||||
const message =
|
const message =
|
||||||
@@ -240,16 +256,20 @@ export function registerChatStreamHandlers() {
|
|||||||
// Store the current partial response
|
// Store the current partial response
|
||||||
partialResponses.set(req.chatId, fullResponse);
|
partialResponses.set(req.chatId, fullResponse);
|
||||||
|
|
||||||
|
// Update the placeholder assistant message content in the messages array
|
||||||
|
const currentMessages = [...updatedChat.messages];
|
||||||
|
if (
|
||||||
|
currentMessages.length > 0 &&
|
||||||
|
currentMessages[currentMessages.length - 1].role === "assistant"
|
||||||
|
) {
|
||||||
|
currentMessages[currentMessages.length - 1].content =
|
||||||
|
fullResponse;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the assistant message in the database
|
// Update the assistant message in the database
|
||||||
event.sender.send("chat:response:chunk", {
|
event.sender.send("chat:response:chunk", {
|
||||||
chatId: req.chatId,
|
chatId: req.chatId,
|
||||||
messages: [
|
messages: currentMessages,
|
||||||
...updatedChat.messages,
|
|
||||||
{
|
|
||||||
role: "assistant",
|
|
||||||
content: fullResponse,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the stream was aborted, exit early
|
// If the stream was aborted, exit early
|
||||||
@@ -266,14 +286,20 @@ export function registerChatStreamHandlers() {
|
|||||||
// If we have a partial response, save it to the database
|
// If we have a partial response, save it to the database
|
||||||
if (partialResponse) {
|
if (partialResponse) {
|
||||||
try {
|
try {
|
||||||
// Insert a new assistant message with the partial content
|
// Update the placeholder assistant message with the partial content and cancellation note
|
||||||
await db.insert(messages).values({
|
await db
|
||||||
chatId,
|
.update(messages)
|
||||||
role: "assistant",
|
.set({
|
||||||
content: `${partialResponse}\n\n[Response cancelled by user]`,
|
content: `${partialResponse}
|
||||||
});
|
|
||||||
logger.log(`Saved partial response for chat ${chatId}`);
|
[Response cancelled by user]`,
|
||||||
partialResponses.delete(chatId);
|
})
|
||||||
|
.where(eq(messages.id, placeholderAssistantMessage.id));
|
||||||
|
|
||||||
|
logger.log(
|
||||||
|
`Updated cancelled response for placeholder message ${placeholderAssistantMessage.id} in chat ${chatId}`
|
||||||
|
);
|
||||||
|
partialResponses.delete(req.chatId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Error saving partial response for chat ${chatId}:`,
|
`Error saving partial response for chat ${chatId}:`,
|
||||||
@@ -301,21 +327,17 @@ export function registerChatStreamHandlers() {
|
|||||||
}
|
}
|
||||||
const chatSummary = chatTitle?.[1];
|
const chatSummary = chatTitle?.[1];
|
||||||
|
|
||||||
// Create initial assistant message
|
// Update the placeholder assistant message with the full response
|
||||||
const [assistantMessage] = await db
|
await db
|
||||||
.insert(messages)
|
.update(messages)
|
||||||
.values({
|
.set({ content: fullResponse })
|
||||||
chatId: req.chatId,
|
.where(eq(messages.id, placeholderAssistantMessage.id));
|
||||||
role: "assistant",
|
|
||||||
content: fullResponse,
|
|
||||||
})
|
|
||||||
.returning();
|
|
||||||
|
|
||||||
if (readSettings().autoApproveChanges) {
|
if (readSettings().autoApproveChanges) {
|
||||||
const status = await processFullResponseActions(
|
const status = await processFullResponseActions(
|
||||||
fullResponse,
|
fullResponse,
|
||||||
req.chatId,
|
req.chatId,
|
||||||
{ chatSummary, messageId: assistantMessage.id }
|
{ chatSummary, messageId: placeholderAssistantMessage.id } // Use placeholder ID
|
||||||
);
|
);
|
||||||
|
|
||||||
const chat = await db.query.chats.findFirst({
|
const chat = await db.query.chats.findFirst({
|
||||||
|
|||||||
Reference in New Issue
Block a user