Skip to content

Commit 712c2a4

Browse files
authored
Merge branch 'main' into fix/preserve-login-after-install
2 parents 0430366 + a75af4c commit 712c2a4

6 files changed

Lines changed: 665 additions & 96 deletions

File tree

src/components/ChatBox/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ export default function ChatBox(): JSX.Element {
102102
const task = chatStore.tasks[_taskId];
103103
const isTaskBusy = (
104104
// running or paused counts as busy
105-
// TODO: Bug where when replay end hasMessages = false & status = running
106105
(task.status === 'running' && !task.hasMessages) || task.status === 'pause' ||
107106
// splitting phase: has to_sub_tasks not confirmed OR skeleton computing
108107
task.messages.some(m => m.step === 'to_sub_tasks' && !m.isConfirm) ||
@@ -111,6 +110,10 @@ export default function ChatBox(): JSX.Element {
111110
(!!task.messages.find(m => m.step === 'to_sub_tasks' && !m.isConfirm) && task.status === 'pending')
112111
);
113112

113+
//Fixes bug where doesn't matter the SSE order or final state of the chatStore
114+
const isReplayChatStore = chatStore.tasks[_taskId as string]?.type === "replay";
115+
const queueTask = isTaskBusy && !isReplayChatStore;
116+
114117
console.log(`Current task is ${isTaskBusy} with ${task}`);
115118

116119
if (textareaRef.current) textareaRef.current.style.height = "60px";
@@ -152,7 +155,7 @@ export default function ChatBox(): JSX.Element {
152155
}
153156
} else {
154157
// If current task is busy (splitting/confirm/running), queue the new message instead of sending immediately
155-
if (isTaskBusy) {
158+
if (queueTask) {
156159
const project_id = projectStore.activeProjectId;
157160
// Queue the message locally; do not send to backend yet.
158161
const currentAttaches = JSON.parse(JSON.stringify(task.attaches)) || [];

src/lib/replay.ts

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ChatStore } from "@/store/chatStore";
2+
import { ProjectStore } from "@/store/projectStore";
13
import { NavigateFunction } from "react-router-dom";
24

35
/**
@@ -11,7 +13,7 @@ import { NavigateFunction } from "react-router-dom";
1113
* @param historyId - The history ID for the replay
1214
*/
1315
export const replayProject = async (
14-
projectStore: any,
16+
projectStore: ProjectStore,
1517
navigate: NavigateFunction,
1618
projectId: string,
1719
question: string,
@@ -36,8 +38,8 @@ export const replayProject = async (
3638
* @param navigate - The navigate function from useNavigate hook
3739
*/
3840
export const replayActiveTask = async (
39-
chatStore: any,
40-
projectStore: any,
41+
chatStore: ChatStore,
42+
projectStore: ProjectStore,
4143
navigate: NavigateFunction
4244
) => {
4345
const taskId = chatStore.activeTaskId as string;
@@ -57,9 +59,10 @@ export const replayActiveTask = async (
5759
if (project && project.chatStores) {
5860
Object.entries(project.chatStores).forEach(([chatStoreId, chatStoreData]: [string, any]) => {
5961
const timestamp = project.chatStoreTimestamps[chatStoreId] || 0;
60-
61-
if (chatStoreData.tasks) {
62-
Object.values(chatStoreData.tasks).forEach((task: any) => {
62+
const chatState = chatStoreData.getState();
63+
64+
if (chatState.tasks) {
65+
Object.values(chatState.tasks).forEach((task: any) => {
6366
// Check messages for user content
6467
if (task.messages && task.messages.length > 0) {
6568
const userMessage = task.messages.find((msg: any) => msg.role === 'user');
@@ -68,33 +71,6 @@ export const replayActiveTask = async (
6871
earliestTimestamp = timestamp;
6972
}
7073
}
71-
72-
// Check task info for original questions
73-
if (task.taskInfo && task.taskInfo.length > 0) {
74-
task.taskInfo.forEach((info: any) => {
75-
if (info.content && timestamp < earliestTimestamp) {
76-
question = info.content;
77-
earliestTimestamp = timestamp;
78-
}
79-
});
80-
}
81-
82-
// Check agent logs for original task content
83-
if (task.taskAssigning) {
84-
task.taskAssigning.forEach((agent: any) => {
85-
if (agent.log) {
86-
agent.log.forEach((logEntry: any) => {
87-
if (logEntry.data && logEntry.data.message) {
88-
const match = logEntry.data.message.match(/==============================\n(.*?)\n==============================/s);
89-
if (match && match[1] && timestamp < earliestTimestamp) {
90-
question = match[1].trim();
91-
earliestTimestamp = timestamp;
92-
}
93-
}
94-
});
95-
}
96-
});
97-
}
9874
});
9975
}
10076
});
@@ -103,6 +79,7 @@ export const replayActiveTask = async (
10379
// Fallback to current task's first message if no question found
10480
if (!question && chatStore.tasks[taskId] && chatStore.tasks[taskId].messages[0]) {
10581
question = chatStore.tasks[taskId].messages[0].content;
82+
console.log("[REPLAY] question fall back to ", question);
10683
}
10784

10885
const historyId = projectStore.getHistoryId(projectId);

src/store/projectStore.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ const projectStore = create<ProjectStore>()((set, get) => ({
196196
queuedMessages: [], // Initialize empty queued messages array
197197
metadata: {
198198
status: 'active',
199-
historyId: historyId
199+
historyId: historyId,
200+
tags: type === ProjectType.REPLAY ? ["replay"] : []
200201
}
201202
};
202203

@@ -472,27 +473,34 @@ const projectStore = create<ProjectStore>()((set, get) => ({
472473
}
473474

474475
console.log(`[ProjectStore] Created replay project ${replayProjectId} for ${taskIds.length} tasks`);
475-
476+
476477
// For each taskId, create a chat store within the project and call replay
477-
taskIds.forEach(async (taskId, index) => {
478-
console.log(`[ProjectStore] Creating replay for task ${index + 1}/${taskIds.length}: ${taskId}`);
479-
480-
// Create a new chat store for this task
481-
const chatId = createChatStore(replayProjectId, `Task ${taskId}`);
482-
483-
if (chatId) {
484-
const project = get().projects[replayProjectId];
485-
const chatStore = project.chatStores[chatId];
486-
487-
if (chatStore) {
488-
// Call replay on the chat store with the taskId, question, and 0 delay
489-
await chatStore.getState().replay(taskId, question, 0.2);
490-
console.log(`[ProjectStore] Started replay for task ${taskId}`);
478+
(async () => {
479+
for (let index = 0; index < taskIds.length; index++) {
480+
const taskId = taskIds[index];
481+
console.log(`[ProjectStore] Creating replay for task ${index + 1}/${taskIds.length}: ${taskId}`);
482+
483+
// Create a new chat store for this task
484+
const chatId = createChatStore(replayProjectId, `Task ${taskId}`);
485+
486+
if (chatId) {
487+
const project = get().projects[replayProjectId];
488+
const chatStore = project.chatStores[chatId];
489+
490+
if (chatStore) {
491+
// Call replay on the chat store with the taskId, question, and 0 delay
492+
try {
493+
await chatStore.getState().replay(taskId, question, 0.2);
494+
console.log(`[ProjectStore] Started replay for task ${taskId}`);
495+
} catch (error) {
496+
console.error(`[ProjectStore] Failed to replay task ${taskId}:`, error);
497+
}
498+
}
491499
}
492500
}
493-
});
494-
495-
console.log(`[ProjectStore] Completed replay setup for ${taskIds.length} tasks`);
501+
console.log(`[ProjectStore] Completed replay setup for ${taskIds.length} tasks`);
502+
})();
503+
496504
return replayProjectId;
497505
},
498506

test/integration/chatStore/activeQueue.test.tsx

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,7 @@ import '../../../src/store/chatStore'
1313

1414
import { useProjectStore } from '../../../src/store/projectStore'
1515
import useChatStoreAdapter from '../../../src/hooks/useChatStoreAdapter'
16-
import { mockFetchEventSource } from '../../mocks/sse.mock'
17-
18-
// Helper function for sequential SSE events
19-
const createSSESequence = (events: Array<{ event: any; delay: number }>) => {
20-
return async (onMessage: (data: any) => void) => {
21-
for (let i = 0; i < events.length; i++) {
22-
const { event, delay } = events[i]
23-
24-
await new Promise<void>((resolve) => {
25-
setTimeout(() => {
26-
console.log(`Sending SSE Event ${i + 1}:`, event.step);
27-
onMessage({
28-
data: JSON.stringify(event)
29-
})
30-
resolve()
31-
}, delay)
32-
})
33-
}
34-
}
35-
}
16+
import { mockFetchEventSource, createSSESequence } from '../../mocks/sse.mock'
3617

3718
// Mock electron IPC
3819
(global as any).ipcRenderer = {

0 commit comments

Comments
 (0)