mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-05-31 04:56:02 +00:00
initial fix
This commit is contained in:
parent
e8a7e779fa
commit
a23f5c5778
3 changed files with 112 additions and 26 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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...');
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue