From e34af4434b63003c60d5ed498ff7476702ec131c Mon Sep 17 00:00:00 2001 From: Waleed Alzarooni Date: Mon, 8 Sep 2025 16:43:11 +0100 Subject: [PATCH 01/31] fixed closing notification functionality --- src/components/Dialog/CloseNotice.tsx | 39 +++++++++++++++++++++++++++ src/components/Layout/index.tsx | 27 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/components/Dialog/CloseNotice.tsx diff --git a/src/components/Dialog/CloseNotice.tsx b/src/components/Dialog/CloseNotice.tsx new file mode 100644 index 000000000..2e19ef298 --- /dev/null +++ b/src/components/Dialog/CloseNotice.tsx @@ -0,0 +1,39 @@ +import { useCallback } from "react"; +import { Button } from "../ui/button"; +import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog"; + +interface Props { + open: boolean; + onOpenChange: (open: boolean) => void; + trigger?: React.ReactNode; +} +export default function CloseNoticeDialog({open, onOpenChange, trigger}: Props) { + + const onSubmit = useCallback(() => { + window.electronAPI.closeWindow(true) + }, []) + + return + {trigger && {trigger}} + + + + Close notice + + +
+ A task is currently running. Exiting will terminate it. Are you sure you want to exit? +
+ + + + + + +
+
+} \ No newline at end of file diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 260b72ce5..685531bfe 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -6,10 +6,32 @@ import { useAuthStore } from "@/store/authStore"; import { useEffect, useState } from "react"; import { AnimationJson } from "@/components/AnimationJson"; import animationData from "@/assets/animation/onboarding_success.json"; +import CloseNoticeDialog from "../Dialog/CloseNotice"; +import { useChatStore } from "@/store/chatStore"; const Layout = () => { const { initState, setInitState, isFirstLaunch, setIsFirstLaunch } = useAuthStore(); const [isInstalling, setIsInstalling] = useState(false); + const [noticeOpen, setNoticeOpen] = useState(false); + const chatStore = useChatStore(); + + useEffect(() => { + const handleBeforeClose = () => { + const currentStatus = chatStore.tasks[chatStore.activeTaskId as string]?.status; + if(["pending", "running", "pause"].includes(currentStatus)) { + setNoticeOpen(true); + } else { + window.electronAPI.closeWindow(true); + } + }; + + window.ipcRenderer.on("before-close", handleBeforeClose); + + return () => { + window.ipcRenderer.removeAllListeners("before-close"); + }; + }, [chatStore.tasks, chatStore.activeTaskId]); + useEffect(() => { const checkToolInstalled = async () => { // in render process @@ -25,6 +47,7 @@ const Layout = () => { }; checkToolInstalled(); }, []); + return (
@@ -46,6 +69,10 @@ const Layout = () => { )} +
); From ea4755005dbc0ffe107b346a553f7adb5df9d1aa Mon Sep 17 00:00:00 2001 From: sw3205933776 <3205933776@qq.com> Date: Tue, 9 Sep 2025 18:25:26 +0800 Subject: [PATCH 02/31] ix: resolve issue where tasks from previous account kept running after switching accounts --- electron/main/index.ts | 7 +++++++ src/pages/Setting/Models.tsx | 3 --- src/store/chatStore.ts | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/electron/main/index.ts b/electron/main/index.ts index af7152835..e39e1e5e4 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -312,6 +312,13 @@ function registerIpcHandlers() { }); ipcMain.handle('get-app-version', () => app.getVersion()); ipcMain.handle('get-backend-port', () => backendPort); + ipcMain.handle('restart-backend', () => { + if (backendPort) { + cleanupPythonProcess(); + checkAndStartBackend(); + } + return { success: true }; + }); ipcMain.handle('get-system-language', getSystemLanguage); ipcMain.handle('is-fullscreen', () => win?.isFullScreen() || false); ipcMain.handle('get-home-dir', () => { diff --git a/src/pages/Setting/Models.tsx b/src/pages/Setting/Models.tsx index 5bb082586..577119b80 100644 --- a/src/pages/Setting/Models.tsx +++ b/src/pages/Setting/Models.tsx @@ -682,9 +682,6 @@ export default function SettingModels() { GPT-5 GPT-5 mini GPT-5 nano - - Claude Opus 4.1 - Claude Sonnet 4 diff --git a/src/store/chatStore.ts b/src/store/chatStore.ts index 7069fa406..ef7268ecc 100644 --- a/src/store/chatStore.ts +++ b/src/store/chatStore.ts @@ -1639,6 +1639,7 @@ const chatStore = create()( const { create } = get() console.log('clearTasks') fetchDelete('/task/stop-all') + window.ipcRenderer.invoke('restart-backend') const newTaskId = create() set((state) => ({ ...state, From bf42d595cd6eb02426aa65ac6ea175e745345fb9 Mon Sep 17 00:00:00 2001 From: sw3205933776 <3205933776@qq.com> Date: Thu, 11 Sep 2025 18:19:57 +0800 Subject: [PATCH 03/31] update --- electron/main/index.ts | 6 +++--- src/store/chatStore.ts | 27 +++++++++++++++------------ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/electron/main/index.ts b/electron/main/index.ts index e39e1e5e4..f3022c8ff 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -312,10 +312,10 @@ function registerIpcHandlers() { }); ipcMain.handle('get-app-version', () => app.getVersion()); ipcMain.handle('get-backend-port', () => backendPort); - ipcMain.handle('restart-backend', () => { + ipcMain.handle('restart-backend', async () => { if (backendPort) { - cleanupPythonProcess(); - checkAndStartBackend(); + await cleanupPythonProcess(); + await checkAndStartBackend(); } return { success: true }; }); diff --git a/src/store/chatStore.ts b/src/store/chatStore.ts index ef7268ecc..198322048 100644 --- a/src/store/chatStore.ts +++ b/src/store/chatStore.ts @@ -497,7 +497,7 @@ const chatStore = create()( setTaskAssigning(taskId, taskAssigning) return; } - + // Activate agent if (agentMessages.step === "activate_agent" || agentMessages.step === "deactivate_agent") { let taskAssigning = [...tasks[taskId].taskAssigning] @@ -607,7 +607,7 @@ const chatStore = create()( if (taskAssigning && taskAssigning[assigneeAgentIndex]) { // Check if task already exists in the agent's task list const existingTaskIndex = taskAssigning[assigneeAgentIndex].tasks.findIndex(item => item.id === task_id); - + if (existingTaskIndex !== -1) { // Task already exists, update its status taskAssigning[assigneeAgentIndex].tasks[existingTaskIndex].status = "running"; @@ -624,7 +624,7 @@ const chatStore = create()( taskAssigning[assigneeAgentIndex].tasks.push(taskTemp ?? { id: task_id, content, status: "running", }); } } - + // Only update or add to taskRunning, never duplicate if (taskRunningIndex === -1) { // Task not in taskRunning, add it @@ -1639,16 +1639,19 @@ const chatStore = create()( const { create } = get() console.log('clearTasks') fetchDelete('/task/stop-all') - window.ipcRenderer.invoke('restart-backend') - const newTaskId = create() - set((state) => ({ - ...state, - tasks: { - [newTaskId]: { - ...state.tasks[newTaskId], + window.ipcRenderer.invoke('restart-backend').then((res) => { + console.log('restart-backend', res) + const newTaskId = create() + set((state) => ({ + ...state, + tasks: { + [newTaskId]: { + ...state.tasks[newTaskId], + }, }, - }, - })) + })) + }) + }, }) ); From 1788465fe11afad5b61cb9b07763d56e35561376 Mon Sep 17 00:00:00 2001 From: sw3205933776 <3205933776@qq.com> Date: Thu, 11 Sep 2025 18:37:55 +0800 Subject: [PATCH 04/31] fix: browser not working due to no active page available (#328) --- electron/main/webview.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/electron/main/webview.ts b/electron/main/webview.ts index 20816fd1b..4ac0a7738 100644 --- a/electron/main/webview.ts +++ b/electron/main/webview.ts @@ -120,10 +120,12 @@ export class WebViewManager { const activeSize = this.getActiveWebview().length const allSize = Array.from(this.webViews.values()).length if (allSize - activeSize <= 3) { - const newId = Array.from(this.webViews.keys()).length + 2 + const newId = (Math.max(0, ...Array.from(this.webViews.keys()).map(Number)) || 0) + 2 this.createWebview(newId.toString(), 'about:blank?use=0') this.createWebview((newId + 1).toString(), 'about:blank?use=0') this.createWebview((newId + 2).toString(), 'about:blank?use=0') + this.createWebview((newId + 3).toString(), 'about:blank?use=0') + this.createWebview((newId + 4).toString(), 'about:blank?use=0') } // setTimeout(() => { From aa1291352942efa8e40a83afae1aa8e5488ac304 Mon Sep 17 00:00:00 2001 From: sw3205933776 <3205933776@qq.com> Date: Fri, 12 Sep 2025 11:37:50 +0800 Subject: [PATCH 05/31] fix: reset keyword when selecting mcp in toolselect component --- src/components/AddWorker/ToolSelect.tsx | 4 +++- src/store/chatStore.ts | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/AddWorker/ToolSelect.tsx b/src/components/AddWorker/ToolSelect.tsx index 489c28554..5dfc4f9ad 100644 --- a/src/components/AddWorker/ToolSelect.tsx +++ b/src/components/AddWorker/ToolSelect.tsx @@ -230,6 +230,7 @@ const ToolSelect = forwardRef< // select management const addOption = (item: McpItem, isLocal?: boolean) => { + setKeyword(""); const currentSelected = initialSelectedTools || []; console.log(currentSelected.find((i) => i.id === item.id)); if (isLocal) { @@ -244,6 +245,7 @@ const ToolSelect = forwardRef< const newSelected = [...currentSelected, { ...item, isLocal }]; onSelectedToolsChange?.(newSelected); } + }; const removeOption = (item: McpItem) => { @@ -471,7 +473,7 @@ const ToolSelect = forwardRef< onChange={(e) => setKeyword(e.target.value)} onFocus={() => setIsOpen(true)} ref={inputRef} - className="bg-transparent border-none !shadow-none text-sm leading-normal !ring-0 !ring-offset-0 w-10 !h-[20px] p-0" + className="bg-transparent border-none !shadow-none text-sm leading-normal !ring-0 !ring-offset-0 w-auto !h-[20px] p-0" /> diff --git a/src/store/chatStore.ts b/src/store/chatStore.ts index 7069fa406..54d7b017a 100644 --- a/src/store/chatStore.ts +++ b/src/store/chatStore.ts @@ -580,11 +580,12 @@ const chatStore = create()( if (agentMessages.step === "assign_task") { if (!agentMessages.data?.assignee_id || !agentMessages.data?.task_id) return; - const { assignee_id, task_id, content = "", state: taskState } = agentMessages.data as any; + const { assignee_id, task_id, content = "", state: taskState ,failure_count} = agentMessages.data as any; let taskAssigning = [...tasks[taskId].taskAssigning] let taskRunning = [...tasks[taskId].taskRunning] let taskInfo = [...tasks[taskId].taskInfo] + // Find the index of the agent corresponding to assignee_id const assigneeAgentIndex = taskAssigning!.findIndex((agent: Agent) => agent.agent_id === assignee_id); // Find task corresponding to task_id const task = taskInfo!.find((task: TaskInfo) => task.id === task_id); @@ -602,7 +603,7 @@ const chatStore = create()( setTaskAssigning(taskId, [...taskAssigning]); return; // Return early, do not add to the running queue } - + // The following logic is for when the task actually starts executing (running) if (taskAssigning && taskAssigning[assigneeAgentIndex]) { // Check if task already exists in the agent's task list @@ -611,6 +612,9 @@ const chatStore = create()( if (existingTaskIndex !== -1) { // Task already exists, update its status taskAssigning[assigneeAgentIndex].tasks[existingTaskIndex].status = "running"; + if (failure_count!==0) { + taskAssigning[assigneeAgentIndex].tasks[existingTaskIndex].failure_count = failure_count; + } } else { // Task doesn't exist, add it let taskTemp = null From fabd223253b99ca21d70ee4245a76fc285dd6ba7 Mon Sep 17 00:00:00 2001 From: Sun Tao <2605127667@qq.com> Date: Fri, 12 Sep 2025 14:15:18 +0800 Subject: [PATCH 06/31] Update slack_toolkit.py --- backend/app/utils/toolkit/slack_toolkit.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/backend/app/utils/toolkit/slack_toolkit.py b/backend/app/utils/toolkit/slack_toolkit.py index 89987b1ff..dac33d357 100644 --- a/backend/app/utils/toolkit/slack_toolkit.py +++ b/backend/app/utils/toolkit/slack_toolkit.py @@ -51,13 +51,10 @@ class SlackToolkit(BaseSlackToolkit, AbstractToolkit): @listen_toolkit( BaseSlackToolkit.send_slack_message, - lambda _, - message, - channel_id, - user=None: f"send Slack message: {message} to channel id: {channel_id} for user: {user}", + lambda _, message, channel_id, file_path, user: f"send Slack message: {message} to channel id: {channel_id}, file: {file_path}, user: {user}", ) - def send_slack_message(self, message: str, channel_id: str, user: str | None = None) -> str: - return super().send_slack_message(message, channel_id, user) + def send_slack_message(self, message: str, channel_id: str, file_path: str, user: str) -> str: + return super().send_slack_message(message, channel_id, file_path, user) @listen_toolkit( BaseSlackToolkit.delete_slack_message, From a1e38898594e929255de41461ff654b246945d0b Mon Sep 17 00:00:00 2001 From: Sun Tao <2605127667@qq.com> Date: Fri, 12 Sep 2025 14:21:42 +0800 Subject: [PATCH 07/31] Update slack_toolkit.py --- backend/app/utils/toolkit/slack_toolkit.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/app/utils/toolkit/slack_toolkit.py b/backend/app/utils/toolkit/slack_toolkit.py index dac33d357..3c681ed89 100644 --- a/backend/app/utils/toolkit/slack_toolkit.py +++ b/backend/app/utils/toolkit/slack_toolkit.py @@ -51,9 +51,9 @@ class SlackToolkit(BaseSlackToolkit, AbstractToolkit): @listen_toolkit( BaseSlackToolkit.send_slack_message, - lambda _, message, channel_id, file_path, user: f"send Slack message: {message} to channel id: {channel_id}, file: {file_path}, user: {user}", + lambda _, message, channel_id, file_path=None, user=None: f"send Slack message: {message} to channel id: {channel_id}, file: {file_path}, user: {user}", ) - def send_slack_message(self, message: str, channel_id: str, file_path: str, user: str) -> str: + def send_slack_message(self, message: str, channel_id: str, file_path: str | None = None, user: str | None = None) -> str: return super().send_slack_message(message, channel_id, file_path, user) @listen_toolkit( @@ -64,6 +64,20 @@ class SlackToolkit(BaseSlackToolkit, AbstractToolkit): ) def delete_slack_message(self, time_stamp: str, channel_id: str) -> str: return super().delete_slack_message(time_stamp, channel_id) + + @listen_toolkit( + BaseSlackToolkit.get_slack_user_list, + lambda _: "get Slack user list", + ) + def get_slack_user_list(self) -> list[dict]: + return super().get_slack_user_list() + + @listen_toolkit( + BaseSlackToolkit.get_slack_user_info, + lambda _, user_id: f"get Slack user info with user id: {user_id}", + ) + def get_slack_user_info(self, user_id: str) -> dict: + return super().get_slack_user_info(user_id) @classmethod def get_can_use_tools(cls, api_task_id: str) -> list[FunctionTool]: From 8ab8e6d591cf02e41386bd782f2985260ea8af32 Mon Sep 17 00:00:00 2001 From: Sun Tao <2605127667@qq.com> Date: Fri, 12 Sep 2025 15:31:05 +0800 Subject: [PATCH 08/31] update --- backend/app/component/environment.py | 44 +++++++++++++++++++++-- backend/app/controller/chat_controller.py | 4 +++ backend/app/controller/task_controller.py | 3 ++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/backend/app/component/environment.py b/backend/app/component/environment.py index 3096d84c6..514ff9590 100644 --- a/backend/app/component/environment.py +++ b/backend/app/component/environment.py @@ -5,10 +5,36 @@ from fastapi import APIRouter, FastAPI from dotenv import load_dotenv import importlib from typing import Any, overload +import threading + +# Thread-local storage for user-specific environment +_thread_local = threading.local() + +# Default global environment path +default_env_path = os.path.join(os.path.expanduser("~"), ".eigent", ".env") +load_dotenv(dotenv_path=default_env_path) -env_path = os.path.join(os.path.expanduser("~"), ".eigent", ".env") -load_dotenv(dotenv_path=env_path) +def set_user_env_path(env_path: str | None = None): + """ + Set user-specific environment path for current thread. + If env_path is None, uses default global environment. + """ + if env_path and os.path.exists(env_path): + _thread_local.env_path = env_path + # Load user-specific environment variables + load_dotenv(dotenv_path=env_path, override=True) + else: + # Clear thread-local env_path to fall back to global + if hasattr(_thread_local, 'env_path'): + delattr(_thread_local, 'env_path') + + +def get_current_env_path() -> str: + """ + Get current environment path (either user-specific or default). + """ + return getattr(_thread_local, 'env_path', default_env_path) @overload @@ -24,6 +50,20 @@ def env(key: str, default: Any) -> Any: ... def env(key: str, default=None): + """ + Get environment variable. + First checks thread-local user-specific environment, + then falls back to global environment. + """ + # If we have a user-specific environment path, try to reload it to get latest values + if hasattr(_thread_local, 'env_path') and os.path.exists(_thread_local.env_path): + # Temporarily load user-specific env to get the latest value + from dotenv import dotenv_values + user_env_values = dotenv_values(_thread_local.env_path) + if key in user_env_values: + return user_env_values[key] or default + + # Fall back to global environment return os.getenv(key, default) diff --git a/backend/app/controller/chat_controller.py b/backend/app/controller/chat_controller.py index e5c248198..45bafd41e 100644 --- a/backend/app/controller/chat_controller.py +++ b/backend/app/controller/chat_controller.py @@ -20,6 +20,7 @@ from app.service.task import ( create_task_lock, get_task_lock, ) +from app.component.environment import set_user_env_path router = APIRouter(tags=["chat"]) @@ -33,6 +34,9 @@ chat_logger = traceroot.get_logger('chat_controller') async def post(data: Chat, request: Request): chat_logger.info(f"Starting new chat session for task_id: {data.task_id}, user: {data.email}") task_lock = create_task_lock(data.task_id) + + # Set user-specific environment path for this thread + set_user_env_path(data.env_path) load_dotenv(dotenv_path=data.env_path) # logger.debug(f"start chat: {data.model_dump_json()}") diff --git a/backend/app/controller/task_controller.py b/backend/app/controller/task_controller.py index 7a8a034b0..f8f104f1b 100644 --- a/backend/app/controller/task_controller.py +++ b/backend/app/controller/task_controller.py @@ -15,6 +15,7 @@ from app.service.task import ( task_locks, ) import asyncio +from app.component.environment import set_user_env_path router = APIRouter(tags=["task"]) @@ -49,6 +50,8 @@ def take_control(id: str, data: TakeControl): @router.post("/task/{id}/add-agent", name="add new agent") def add_agent(id: str, data: NewAgent): + # Set user-specific environment path for this thread + set_user_env_path(data.env_path) load_dotenv(dotenv_path=data.env_path) asyncio.run(get_task_lock(id).put_queue(ActionNewAgent(**data.model_dump()))) return Response(status_code=204) From c0b6f11fd1d50db2ab756371ac6750c24c8c4d5c Mon Sep 17 00:00:00 2001 From: Sun Tao <2605127667@qq.com> Date: Fri, 12 Sep 2025 15:52:17 +0800 Subject: [PATCH 09/31] Update agent.py --- backend/app/utils/agent.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/app/utils/agent.py b/backend/app/utils/agent.py index 5d542b2b6..5dc1f4a5a 100644 --- a/backend/app/utils/agent.py +++ b/backend/app/utils/agent.py @@ -1,5 +1,6 @@ import asyncio import json +import os import platform from threading import Event import traceback @@ -1438,7 +1439,17 @@ async def get_mcp_tools(mcp_server: McpServers): traceroot_logger.info(f"Getting MCP tools for {len(mcp_server['mcpServers'])} servers") if len(mcp_server["mcpServers"]) == 0: return [] - mcp_toolkit = MCPToolkit(config_dict={**mcp_server}, timeout=180) + + # Ensure unified auth directory for all mcp-remote servers to avoid re-authentication on each task + config_dict = {**mcp_server} + for server_config in config_dict["mcpServers"].values(): + if "env" not in server_config: + server_config["env"] = {} + # Set global auth directory to persist authentication across tasks + if "MCP_REMOTE_CONFIG_DIR" not in server_config["env"]: + server_config["env"]["MCP_REMOTE_CONFIG_DIR"] = env("MCP_REMOTE_CONFIG_DIR", os.path.expanduser("~/.mcp-auth")) + + mcp_toolkit = MCPToolkit(config_dict=config_dict, timeout=20) try: await mcp_toolkit.connect() traceroot_logger.info(f"Successfully connected to MCP toolkit with {len(mcp_server['mcpServers'])} servers") From 031289b3acd5056786233e52f1dea3a81f90f721 Mon Sep 17 00:00:00 2001 From: sw3205933776 <3205933776@qq.com> Date: Fri, 12 Sep 2025 18:23:59 +0800 Subject: [PATCH 10/31] chore: update task reassignment logic and styles --- src/components/ChatBox/TaskCard.tsx | 11 +- src/components/HistorySidebar/index.tsx | 6 +- src/components/SearchAgentWrokSpace/index.tsx | 7 +- src/components/TaskState/index.tsx | 114 +++++++++---- src/components/WorkFlow/index.tsx | 10 +- src/components/WorkFlow/node.tsx | 150 +++++++++++------- src/pages/History.tsx | 6 +- src/store/chatStore.ts | 32 +++- src/types/chatbox.d.ts | 1 + 9 files changed, 232 insertions(+), 105 deletions(-) diff --git a/src/components/ChatBox/TaskCard.tsx b/src/components/ChatBox/TaskCard.tsx index 6b00f5079..78c12e96b 100644 --- a/src/components/ChatBox/TaskCard.tsx +++ b/src/components/ChatBox/TaskCard.tsx @@ -141,6 +141,8 @@ export function TaskCard({
{taskType === 1 && ( task.content !== "").length || 0 @@ -150,23 +152,28 @@ export function TaskCard({ )} {taskType !== 1 && ( task.status === "completed" || task.status === "failed" ).length || 0 } + reAssignTo={ + taskRunning?.filter((task) => task.reAssignTo).length || 0 + } progress={ taskRunning?.filter( (task) => task.status !== "completed" && task.status !== "failed" && task.status !== "skipped" && + task.status !== "waiting" && task.content !== "" ).length || 0 } skipped={ - taskRunning?.filter((task) => task.status === "skipped") + taskRunning?.filter((task) => task.status === "skipped"||task.status==="waiting") .length || 0 } /> @@ -316,7 +323,7 @@ export function TaskCard({
{taskAssigning.name} diff --git a/src/components/SearchAgentWrokSpace/index.tsx b/src/components/SearchAgentWrokSpace/index.tsx index e9d65110d..59cc9d89f 100644 --- a/src/components/SearchAgentWrokSpace/index.tsx +++ b/src/components/SearchAgentWrokSpace/index.tsx @@ -202,6 +202,8 @@ export default function Home() { {agentMap[activeAgent?.type as keyof typeof agentMap]?.name}
task.reAssignTo).length || 0} done={ activeAgent?.tasks?.filter( (task) => @@ -213,11 +215,12 @@ export default function Home() { (task) => task.status !== "failed" && task.status !== "completed" && - task.status !== "skipped" + task.status !== "skipped"&& + task.status !== "waiting" ).length || 0 } skipped={ - activeAgent?.tasks?.filter((task) => task.status === "skipped") + activeAgent?.tasks?.filter((task) => task.status === "skipped"||task.status==="waiting") .length || 0 } /> diff --git a/src/components/TaskState/index.tsx b/src/components/TaskState/index.tsx index 36a5f33a0..a4299389a 100644 --- a/src/components/TaskState/index.tsx +++ b/src/components/TaskState/index.tsx @@ -1,47 +1,103 @@ -import { CircleCheckBig, LoaderCircle } from "lucide-react"; +import { CircleCheckBig, CircleSlash2, LoaderCircle } from "lucide-react"; import { useChatStore } from "@/store/chatStore"; export const TaskState = ({ + all, done, + reAssignTo, progress, skipped, }: { + all: number; done: number; progress: number; skipped: number; + reAssignTo: number; }) => { const chatStore = useChatStore(); return (
-
-
- - - {done} done +
+ {/* All */} +
+ + All {all} + +
+ + {/* Done */} +
0 ? "bg-tag-surface" : "bg-transparent" + }`} + > + 0 ? "text-icon-success" : "text-icon-secondary" + }`} + /> + 0 ? "text-text-success" : "text-text-label" + }`} + > + Done {done>0 ? done : ""} + +
+ + {/* Reassigned */} +
0 ? "bg-tag-surface" : "bg-transparent" + }`} + > + 0 ? "text-icon-warning" : "text-icon-secondary" + }`} + /> + 0 ? "text-text-warning" : "text-text-label" + }`} + > + Reassigned {reAssignTo>0 ? reAssignTo : ""} + +
+ + {/* Ongoing */} +
0 ? "bg-tag-surface" : "bg-transparent" + }`} + > + 0 ? "text-icon-information" : "text-icon-secondary" + } ${ + chatStore.tasks[chatStore.activeTaskId as string].status === + "running" && "animate-spin" + }`} + /> + 0 ? "text-text-information" : "text-text-label" + }`} + > + Ongoing {progress>0 ? progress : ""} + +
+ + {/* Pending */} +
0 ? "bg-tag-surface" : "bg-transparent" + }`} + > + + + Pending {skipped>0 ? skipped : ""}
- {progress !== 0 && ( -
- - - {progress} in progress - -
- )} - {skipped !== 0 && ( -
- - - {skipped} Unfinished - -
- )}
); diff --git a/src/components/WorkFlow/index.tsx b/src/components/WorkFlow/index.tsx index e1f59ea15..201830f29 100644 --- a/src/components/WorkFlow/index.tsx +++ b/src/components/WorkFlow/index.tsx @@ -131,7 +131,7 @@ export default function Workflow({ return prev.map((node) => { // calculate node width and position based on expansion state - const nodeWidth = node.data.isExpanded ? 560 : 280; + const nodeWidth = node.data.isExpanded ? 684 : 342; const newPosition = { x: currentX, y: node.position.y }; currentX += nodeWidth + 20; // 20 is the spacing between nodes @@ -203,7 +203,7 @@ export default function Workflow({ }; // calculate node width and position based on expansion state - const nodeWidth = updatedNode.data.isExpanded ? 560 : 280; + const nodeWidth = updatedNode.data.isExpanded ? 684 : 342; const newPosition = { x: currentX, y: node.position.y }; currentX += nodeWidth + 20; // 20 is the spacing between nodes @@ -243,7 +243,7 @@ export default function Workflow({ }, position: isEditMode ? node.position - : { x: index * 300 + 8, y: 16 }, + : { x: index * (342+20) + 8, y: 16 }, }; } else { return { @@ -257,7 +257,7 @@ export default function Workflow({ isEditMode: isEditMode, workerInfo: agent?.workerInfo, }, - position: { x: index * 300 + 8, y: 16 }, + position: { x: index * (342+20) + 8, y: 16 }, type: "node", }; } @@ -301,7 +301,7 @@ export default function Workflow({
Your AI Workforce
-
+
{/*