initial fix

This commit is contained in:
puzhen 2026-01-21 19:35:31 +00:00
parent e8a7e779fa
commit a23f5c5778
3 changed files with 112 additions and 26 deletions

View file

@ -517,7 +517,10 @@ async def step_solve(options: Chat, request: Request, task_lock: TaskLock):
if not sub_tasks:
sub_tasks = getattr(task_lock, "decompose_sub_tasks", [])
sub_tasks = update_sub_tasks(sub_tasks, update_tasks)
add_sub_tasks(camel_task, item.data.task)
# Add new tasks (with empty id) to both camel_task and sub_tasks
new_tasks = add_sub_tasks(camel_task, item.data.task)
# Also add new tasks to sub_tasks so workforce.eigent_start uses correct list
sub_tasks.extend(new_tasks)
summary_task_content_local = getattr(task_lock, "summary_task_content", summary_task_content)
yield to_sub_tasks(camel_task, summary_task_content_local)
elif item.action == Action.add_task:
@ -1086,6 +1089,10 @@ def tree_sub_tasks(sub_tasks: list[Task], depth: int = 0):
def update_sub_tasks(sub_tasks: list[Task], update_tasks: dict[str, TaskContent], depth: int = 0):
logger.info(f"[update_sub_tasks] Called with {len(sub_tasks)} sub_tasks, {len(update_tasks)} update_tasks, depth={depth}")
logger.info(f"[update_sub_tasks] sub_tasks ids: {[t.id for t in sub_tasks]}")
logger.info(f"[update_sub_tasks] update_tasks keys: {list(update_tasks.keys())}")
if depth > 5: # limit the depth of the recursion
return []
@ -1093,23 +1100,33 @@ def update_sub_tasks(sub_tasks: list[Task], update_tasks: dict[str, TaskContent]
while i < len(sub_tasks):
item = sub_tasks[i]
if item.id in update_tasks:
logger.info(f"[update_sub_tasks] Updating task {item.id}: {item.content[:30]}... -> {update_tasks[item.id].content[:30]}...")
item.content = update_tasks[item.id].content
update_sub_tasks(item.subtasks, update_tasks, depth + 1)
i += 1
else:
logger.info(f"[update_sub_tasks] Removing task {item.id}: {item.content[:30]}... (not in update_tasks)")
sub_tasks.pop(i)
logger.info(f"[update_sub_tasks] After update: {len(sub_tasks)} tasks remain")
return sub_tasks
def add_sub_tasks(camel_task: Task, update_tasks: list[TaskContent]):
for item in update_tasks:
def add_sub_tasks(camel_task: Task, update_tasks: list[TaskContent]) -> list[Task]:
"""Add new tasks (with empty id) to camel_task and return the list of added tasks."""
logger.info(f"[add_sub_tasks] Called with {len(update_tasks)} update_tasks")
added_tasks = []
for i, item in enumerate(update_tasks):
logger.info(f"[add_sub_tasks] Task {i}: id='{item.id}', content='{item.content[:30]}...'")
if item.id == "": #
camel_task.add_subtask(
Task(
content=item.content,
id=f"{camel_task.id}.{len(camel_task.subtasks) + 1}",
)
logger.info(f"[add_sub_tasks] Adding new task: {item.content[:30]}...")
new_task = Task(
content=item.content,
id=f"{camel_task.id}.{len(camel_task.subtasks) + 1}",
)
camel_task.add_subtask(new_task)
added_tasks.append(new_task)
logger.info(f"[add_sub_tasks] Added {len(added_tasks)} new tasks")
return added_tasks
async def question_confirm(agent: ListenChatAgent, prompt: str, task_lock: TaskLock | None = None) -> bool:

View file

@ -1275,8 +1275,9 @@ async function createWindow() {
minWidth: 1050,
minHeight: 650,
frame: false,
transparent: true,
backgroundColor: '#00000000',
show: false, // Don't show until content is ready
transparent: process.platform === 'darwin', // Only transparent on macOS for vibrancy effects
backgroundColor: process.platform === 'darwin' ? '#00000000' : '#1a1a2e', // Visible fallback on non-macOS
titleBarStyle: isMac ? 'hidden' : undefined,
trafficLightPosition: isMac ? { x: 10, y: 10 } : undefined,
icon: path.join(VITE_PUBLIC, 'favicon.ico'),
@ -1316,6 +1317,41 @@ async function createWindow() {
});
}
// ==================== Handle renderer crashes and failed loads ====================
win.webContents.on('render-process-gone', (event, details) => {
log.error('[RENDERER] Process gone:', details.reason, details.exitCode);
if (win && !win.isDestroyed()) {
// Reload the window after a brief delay
setTimeout(() => {
if (win && !win.isDestroyed()) {
log.info('[RENDERER] Attempting to reload after crash...');
if (VITE_DEV_SERVER_URL) {
win.loadURL(VITE_DEV_SERVER_URL);
} else {
win.loadFile(indexHtml);
}
}
}, 1000);
}
});
win.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
log.error(`[RENDERER] Failed to load: ${errorCode} - ${errorDescription} - ${validatedURL}`);
// Retry loading after a delay
if (errorCode !== -3) { // -3 is USER_CANCELLED, don't retry
setTimeout(() => {
if (win && !win.isDestroyed()) {
log.info('[RENDERER] Retrying load after failure...');
if (VITE_DEV_SERVER_URL) {
win.loadURL(VITE_DEV_SERVER_URL);
} else {
win.loadFile(indexHtml);
}
}
}, 2000);
}
});
// Main window now uses default userData directly with partition 'persist:main_window'
// No migration needed - data is already persistent
@ -1563,9 +1599,15 @@ async function createWindow() {
win.loadFile(indexHtml);
}
// Wait for window to be ready
// Wait for window to be ready with timeout
await new Promise<void>((resolve) => {
const loadTimeout = setTimeout(() => {
log.warn('Window content load timeout (10s), showing window anyway...');
resolve();
}, 10000);
win!.webContents.once('did-finish-load', () => {
clearTimeout(loadTimeout);
log.info(
'Window content loaded, starting dependency check immediately...'
);
@ -1573,6 +1615,12 @@ async function createWindow() {
});
});
// Show window now that content is loaded (or timeout reached)
if (win && !win.isDestroyed()) {
win.show();
log.info('Window shown after content loaded');
}
// Mark window as ready and process any queued protocol URLs
isWindowReady = true;
log.info('Window is ready, processing queued protocol URLs...');

View file

@ -845,6 +845,13 @@ const chatStore = (initial?: Partial<ChatStore>) => createStore<ChatStore>()(
clearStreamingDecomposeText(currentTaskId);
// Clean up TTFT tracking
delete ttftTracking[currentTaskId];
// Check if task is already confirmed - don't overwrite user edits
const existingToSubTasksMessage = tasks[currentTaskId].messages.findLast((m: Message) => m.step === 'to_sub_tasks');
if (existingToSubTasksMessage?.isConfirm) {
return;
}
// Check if this is a multi-turn scenario after task completion
const isMultiTurnAfterCompletion = tasks[currentTaskId].status === 'finished';
@ -2146,20 +2153,16 @@ const chatStore = (initial?: Partial<ChatStore>) => createStore<ChatStore>()(
// record task start time
setTaskTime(taskId, Date.now());
// Filter out empty tasks from the user-edited taskInfo
const taskInfo = tasks[taskId].taskInfo.filter((task) => task.content !== '')
console.log('[handleConfirmTask] Original taskInfo from store:', tasks[taskId].taskInfo.map((t, i) => `${i}: ${t.content?.slice(0, 40)}`));
console.log('[handleConfirmTask] Filtered taskInfo to send:', taskInfo.map((t, i) => `${i}: ${t.content?.slice(0, 40)}`));
setTaskInfo(taskId, taskInfo)
// Also update taskRunning with the filtered tasks to keep counts consistent
const taskRunning = tasks[taskId].taskRunning.filter((task) => task.content !== '')
setTaskRunning(taskId, taskRunning)
if (!type) {
await fetchPut(`/task/${project_id}`, {
task: taskInfo,
});
await fetchPost(`/task/${project_id}/start`, {});
// Sync taskRunning with the filtered taskInfo (user edits should be reflected in execution)
setTaskRunning(taskId, taskInfo)
setActiveWorkSpace(taskId, 'workflow')
setStatus(taskId, 'running')
}
// IMPORTANT: Set isConfirm BEFORE sending API requests to prevent race condition
// where backend sends to_sub_tasks SSE event before we mark task as confirmed
let messages = [...tasks[taskId].messages]
const cardTaskIndex = messages.findLastIndex((message) => message.step === 'to_sub_tasks')
if (cardTaskIndex !== -1) {
@ -2171,11 +2174,23 @@ const chatStore = (initial?: Partial<ChatStore>) => createStore<ChatStore>()(
setMessages(taskId, messages)
}
if (!type) {
console.log('[handleConfirmTask] Sending to backend PUT /task:', taskInfo.map((t, i) => `${i}: ${t.content?.slice(0, 40)}`));
await fetchPut(`/task/${project_id}`, {
task: taskInfo,
});
await fetchPost(`/task/${project_id}/start`, {});
setActiveWorkSpace(taskId, 'workflow')
setStatus(taskId, 'running')
}
// Reset editing state after manual confirmation so next round can auto-start
setIsTaskEdit(taskId, false);
},
addTaskInfo() {
const { tasks, activeTaskId, setTaskInfo } = get()
console.log('[addTaskInfo] Called, activeTaskId:', activeTaskId);
if (!activeTaskId) return
let targetTaskInfo = [...tasks[activeTaskId].taskInfo]
const newTaskInfo = {
@ -2183,6 +2198,7 @@ const chatStore = (initial?: Partial<ChatStore>) => createStore<ChatStore>()(
content: "",
};
targetTaskInfo.push(newTaskInfo)
console.log('[addTaskInfo] New taskInfo length:', targetTaskInfo.length);
setTaskInfo(activeTaskId, targetTaskInfo)
},
addTerminal(taskId, processTaskId, terminal) {
@ -2322,21 +2338,26 @@ const chatStore = (initial?: Partial<ChatStore>) => createStore<ChatStore>()(
},
updateTaskInfo(index: number, content: string) {
const { tasks, activeTaskId, setTaskInfo } = get()
console.log('[updateTaskInfo] Called, activeTaskId:', activeTaskId, 'index:', index, 'content:', content?.slice(0, 30));
if (!activeTaskId) return
let targetTaskInfo = [...tasks[activeTaskId].taskInfo]
if (targetTaskInfo) {
targetTaskInfo[index].content = content
}
// Deep copy the array with updated item to ensure React detects the change
const targetTaskInfo = tasks[activeTaskId].taskInfo.map((item, i) =>
i === index ? { ...item, content } : item
)
console.log('[updateTaskInfo] Updated taskInfo:', targetTaskInfo.map((t, i) => `${i}: ${t.content?.slice(0, 30)}`));
setTaskInfo(activeTaskId, targetTaskInfo)
},
deleteTaskInfo(index: number) {
const { tasks, activeTaskId, setTaskInfo } = get()
console.log('[deleteTaskInfo] Called, activeTaskId:', activeTaskId, 'index:', index);
if (!activeTaskId) return
console.log('[deleteTaskInfo] Before delete:', tasks[activeTaskId].taskInfo.map((t, i) => `${i}: ${t.content?.slice(0, 30)}`));
let targetTaskInfo = [...tasks[activeTaskId].taskInfo]
if (targetTaskInfo) {
targetTaskInfo.splice(index, 1)
}
console.log('[deleteTaskInfo] After delete:', targetTaskInfo.map((t, i) => `${i}: ${t.content?.slice(0, 30)}`));
setTaskInfo(activeTaskId, targetTaskInfo)
},