eigent/src/store/chatStore.ts
2025-10-15 18:58:34 +01:00

1730 lines
55 KiB
TypeScript

import { fetchPost, fetchPut, getBaseURL, proxyFetchPost, proxyFetchPut, proxyFetchGet, uploadFile, fetchDelete } from '@/api/http';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { create } from 'zustand';
import { generateUniqueId, uploadLog } from "@/lib";
import { FileText } from 'lucide-react';
import { getAuthStore, useWorkerList } from './authStore';
import { showCreditsToast } from '@/components/Toast/creditsToast';
import { showStorageToast } from '@/components/Toast/storageToast';
interface Task {
messages: Message[];
type: string;
summaryTask: string;
taskInfo: TaskInfo[];
attaches: File[];
taskRunning: TaskInfo[];
taskAssigning: Agent[];
fileList: FileInfo[];
webViewUrls: { url: string, processTaskId: string }[]
activeAsk: string
askList: Message[]
progressValue: number
isPending: boolean
activeWorkSpace: string | null;
hasMessages: boolean;
activeAgent: string;
status: 'running' | 'finished' | 'pending' | 'pause';
taskTime: number;
elapsed: number;
tokens: number;
hasWaitComfirm: boolean;
cotList: string[];
hasAddWorker: boolean
nuwFileNum: number
delayTime: number
selectedFile: FileInfo | null;
snapshots: any[];
snapshotsTemp: any[];
isTakeControl: boolean;
isTaskEdit: boolean;
}
interface ChatStore {
updateCount: number;
activeTaskId: string | null;
tasks: { [key: string]: Task };
create: (id?: string, type?: any) => string;
removeTask: (taskId: string) => void;
setStatus: (taskId: string, status: 'running' | 'finished' | 'pending' | 'pause') => void;
setActiveTaskId: (taskId: string) => void;
replay: (taskId: string, question: string, time: number) => Promise<void>;
startTask: (taskId: string, type?: string, shareToken?: string, delayTime?: number) => Promise<void>;
handleConfirmTask: (taskId: string, type?: string) => void;
addMessages: (taskId: string, messages: Message) => void;
setMessages: (taskId: string, messages: Message[]) => void;
setAttaches: (taskId: string, attaches: File[]) => void;
setSummaryTask: (taskId: string, summaryTask: string) => void;
setHasWaitComfirm: (taskId: string, hasWaitComfirm: boolean) => void;
setTaskAssigning: (taskId: string, taskAssigning: Agent[]) => void;
setTaskInfo: (taskId: string, taskInfo: TaskInfo[]) => void;
setTaskRunning: (taskId: string, taskRunning: TaskInfo[]) => void;
setActiveAsk: (taskId: string, agentName: string) => void;
setActiveAskList: (taskId: string, message: Message[]) => void;
addWebViewUrl: (taskId: string, webViewUrl: string, processTaskId: string) => void;
setWebViewUrls: (taskId: string, webViewUrls: { url: string, processTaskId: string }[]) => void;
setProgressValue: (taskId: string, progressValue: number) => void;
computedProgressValue: (taskId: string) => void;
setIsPending: (taskId: string, isPending: boolean) => void;
addTerminal: (taskId: string, processTaskId: string, terminal: string) => void;
addFileList: (taskId: string, processTaskId: string, fileInfo: FileInfo) => void;
setFileList: (taskId: string, processTaskId: string, fileList: FileInfo[]) => void;
setActiveWorkSpace: (taskId: string, activeWorkSpace: string) => void;
setActiveAgent: (taskId: string, agentName: string) => void;
setHasMessages: (taskId: string, hasMessages: boolean) => void;
getLastUserMessage: () => Message | null;
addTaskInfo: () => void;
updateTaskInfo: (index: number, content: string) => void;
deleteTaskInfo: (index: number) => void;
setTaskTime: (taskId: string, taskTime: number) => void;
setElapsed: (taskId: string, taskTime: number) => void;
getFormattedTaskTime: (taskId: string) => string;
addTokens: (taskId: string, tokens: number) => void;
getTokens: (taskId: string) => void;
setUpdateCount: () => void;
setCotList: (taskId: string, cotList: string[]) => void;
setHasAddWorker: (taskId: string, hasAddWorker: boolean) => void;
setNuwFileNum: (taskId: string, nuwFileNum: number) => void;
setDelayTime: (taskId: string, delayTime: number) => void;
setType: (taskId: string, type: string) => void;
setSelectedFile: (taskId: string, selectedFile: FileInfo | null) => void;
setSnapshots: (taskId: string, snapshots: any[]) => void,
setIsTakeControl: (taskId: string, isTakeControl: boolean) => void,
setSnapshotsTemp: (taskId: string, snapshot: any) => void,
setIsTaskEdit: (taskId: string, isTaskEdit: boolean) => void,
clearTasks: () => void,
}
const chatStore = create<ChatStore>()(
(set, get) => ({
activeTaskId: null,
tasks: {},
updateCount: 0,
create(id?: string, type?: any) {
const taskId = id ? id : generateUniqueId();
console.log("Create Task", taskId)
set((state) => ({
activeTaskId: taskId,
tasks: {
...state.tasks,
[taskId]: {
type: type,
messages: [],
summaryTask: "",
taskInfo: [],
attaches: [],
taskRunning: [],
taskAssigning: [],
fileList: [],
webViewUrls: [],
activeAsk: '',
askList: [],
progressValue: 0,
isPending: false,
activeWorkSpace: 'workflow',
hasMessages: false,
activeAgent: '',
status: 'pending',
taskTime: 0,
tokens: 0,
elapsed: 0,
hasWaitComfirm: false,
cotList: [],
hasAddWorker: false,
nuwFileNum: 0,
delayTime: 0,
selectedFile: null,
snapshots: [],
snapshotsTemp: [],
isTakeControl: false,
isTaskEdit: false
},
}
}))
return taskId
},
computedProgressValue(taskId: string) {
const { tasks, setProgressValue, activeTaskId } = get()
const taskRunning = [...tasks[taskId].taskRunning]
const finshedTask = taskRunning?.filter(
(task) => task.status === "completed" || task.status === "failed"
).length;
const taskProgress = (
((finshedTask || 0) / (taskRunning?.length || 0)) *
100
).toFixed(2);
setProgressValue(
activeTaskId as string,
Number(taskProgress)
);
},
removeTask(taskId: string) {
set((state) => {
delete state.tasks[taskId];
return ({
tasks: {
...state.tasks,
},
})
})
},
startTask: async (taskId: string, type?: string, shareToken?: string, delayTime?: number) => {
const { token, language, modelType, cloud_model_type, email } = getAuthStore()
const workerList = useWorkerList();
const { getLastUserMessage, setDelayTime, setType } = get();
const baseURL = await getBaseURL();
let systemLanguage = language
if (language === 'system') {
systemLanguage = await window.ipcRenderer.invoke('get-system-language');
}
if (type === 'replay') {
setDelayTime(taskId, delayTime as number)
setType(taskId, type)
}
const base_Url = import.meta.env.DEV ? import.meta.env.VITE_PROXY_URL : import.meta.env.VITE_BASE_URL
const api = type == 'share' ? `${base_Url}/api/chat/share/playback/${shareToken}?delay_time=${delayTime}` : type == 'replay' ? `${base_Url}/api/chat/steps/playback/${taskId}?delay_time=${delayTime}` : `${baseURL}/chat`
const { tasks } = get()
let historyId: string | null = null;
let snapshots: any = [];
// replay or share request
if (type) {
await proxyFetchGet(`/api/chat/snapshots`, {
api_task_id: taskId
}).then(res => {
if (res) {
snapshots = [...new Map(res.map((item: any) => [item.camel_task_id, item])).values()];
}
})
}
// get current model
let apiModel = {
api_key: '',
model_type: '',
model_platform: '',
api_url: '',
extra_params: {}
}
if (modelType === 'custom' || modelType === 'local') {
const res = await proxyFetchGet('/api/providers', {
prefer: true
});
const providerList = res.items || []
console.log('providerList', providerList)
const provider = providerList[0]
apiModel = {
api_key: provider.api_key,
model_type: provider.model_type,
model_platform: provider.provider_name,
api_url: provider.endpoint_url || provider.api_url,
extra_params: provider.encrypted_config
}
} else if (modelType === 'cloud') {
// get current model
const res = await proxyFetchGet('/api/user/key');
if (res.warning_code && res.warning_code === '21') {
showStorageToast()
}
apiModel = {
api_key: res.value,
model_type: cloud_model_type,
model_platform: cloud_model_type.includes('gpt') ? 'openai' : 'gemini',
api_url: res.api_url,
extra_params: {}
}
}
let mcpLocal = {}
if (window.ipcRenderer) {
mcpLocal = await window.ipcRenderer.invoke("mcp-list");
}
console.log('mcpLocal', mcpLocal)
const addWorkers = workerList.map((worker) => {
return {
name: worker.workerInfo?.name,
description: worker.workerInfo?.description,
tools: worker.workerInfo?.tools,
mcp_tools: worker.workerInfo?.mcp_tools,
}
});
// get env path
let envPath = ''
try {
envPath = await window.ipcRenderer.invoke('get-env-path', email);
} catch (error) {
console.log('get-env-path error', error)
}
// create history
if (!type) {
const authStore = getAuthStore();
const obj = {
"task_id": taskId,
"user_id": authStore.user_id,
"question": tasks[taskId]?.messages[0]?.content ?? '',
"language": systemLanguage,
"model_platform": apiModel.model_platform,
"model_type": apiModel.model_type,
"api_url": modelType === 'cloud' ? "cloud" : apiModel.api_url,
"max_retries": 3,
"file_save_path": "string",
"installed_mcp": "string",
"status": 1,
"tokens": 0
}
await proxyFetchPost(`/api/chat/history`, obj).then(res => {
historyId = res.id;
})
}
const browser_port = await window.ipcRenderer.invoke('get-browser-port');
fetchEventSource(api, {
method: !type ? "POST" : "GET",
openWhenHidden: true,
headers: { "Content-Type": "application/json", "Authorization": type == 'replay' ? `Bearer ${token}` : undefined as unknown as string },
body: !type ? JSON.stringify({
task_id: taskId,
question: getLastUserMessage()?.content,
model_platform: apiModel.model_platform,
email,
model_type: apiModel.model_type,
api_key: apiModel.api_key,
api_url: apiModel.api_url,
extra_params: apiModel.extra_params,
installed_mcp: mcpLocal,
language: systemLanguage,
allow_local_system: true,
attaches: tasks[taskId].attaches.map(f => f.filePath),
bun_mirror: systemLanguage === 'zh-cn' ? 'https://registry.npmmirror.com' : '',
uvx_mirror: systemLanguage === 'zh-cn' ? 'http://mirrors.aliyun.com/pypi/simple/' : '',
summary_prompt: ``,
new_agents: [...addWorkers],
browser_port: browser_port,
env_path: envPath
}) : undefined,
async onmessage(event: any) {
const agentMessages: AgentMessage = JSON.parse(event.data);
console.log("agentMessages", agentMessages);
const agentNameMap = {
developer_agent: "Developer Agent",
search_agent: "Search Agent",
document_agent: "Document Agent",
multi_modal_agent: "Multi Modal Agent",
social_medium_agent: "Social Media Agent",
};
const { setNuwFileNum, setCotList, getTokens, setUpdateCount, addTokens, setStatus, addWebViewUrl, setIsPending, addMessages, setHasWaitComfirm, setSummaryTask, setTaskAssigning, setTaskInfo, setTaskRunning, addTerminal, addFileList, setActiveAsk, setActiveAskList, tasks, create, setActiveTaskId } = get()
// if (tasks[taskId].status === 'finished') return
if (agentMessages.step === "to_sub_tasks") {
const messages = [...tasks[taskId].messages]
const toSubTaskIndex = messages.findLastIndex((message: Message) => message.step === 'to_sub_tasks')
if (toSubTaskIndex === -1) {
// 30 seconds auto confirm
setTimeout(() => {
const { tasks, handleConfirmTask, setIsTaskEdit } = get();
const message = tasks[taskId].messages.findLast((item) => item.step === "to_sub_tasks");
const isConfirm = message?.isConfirm || false;
const isTakeControl =
tasks[taskId].isTakeControl;
if (!isConfirm && !isTakeControl && !tasks[taskId].isTaskEdit) {
handleConfirmTask(taskId);
}
setIsTaskEdit(taskId, false);
}, 30000);
const newNoticeMessage: Message = {
id: generateUniqueId(),
role: "agent",
content: "",
step: 'notice_card',
};
addMessages(taskId, newNoticeMessage)
const newMessage: Message = {
id: generateUniqueId(),
role: "agent",
content: "",
step: agentMessages.step,
taskType: type ? 2 : 1,
showType: "list",
isConfirm: type ? true : false // share and replay, skip to_sub_tasks
};
addMessages(taskId, newMessage)
const newTaskInfo = {
id: "",
content: "",
};
type !== 'replay' && agentMessages.data.sub_tasks?.push(newTaskInfo)
}
agentMessages.data.sub_tasks = agentMessages.data.sub_tasks?.map(item => {
item.status = ''
return item
})
if (!type && historyId) {
const obj = {
"project_name": agentMessages.data!.summary_task?.split('|')[0] || '',
"summary": agentMessages.data!.summary_task?.split('|')[1] || '',
"status": 1,
"tokens": getTokens(taskId)
}
proxyFetchPut(`/api/chat/history/${historyId}`, obj)
}
setSummaryTask(taskId, agentMessages.data.summary_task as string)
setTaskInfo(taskId, agentMessages.data.sub_tasks as TaskInfo[])
setTaskRunning(taskId, agentMessages.data.sub_tasks as TaskInfo[])
return;
}
// Create agent
if (agentMessages.step === "create_agent") {
const { agent_name, agent_id } = agentMessages.data;
if (!agent_name || !agent_id) return;
// Add agent to taskAssigning
if (!['mcp_agent', 'new_worker_agent', 'task_agent', 'task_summary_agent', "coordinator_agent"].includes(agent_name)) {
// if (agentNameMap[agent_name as keyof typeof agentNameMap]) {
const hasAgent = tasks[taskId].taskAssigning.find((agent) => agent.agent_id === agent_id)
if (!hasAgent) {
let activeWebviewIds: any = [];
if (agent_name == 'search_agent') {
snapshots.forEach((item: any) => {
const imgurl = !item.image_path.includes('/public') ? item.image_path : (import.meta.env.DEV ? import.meta.env.VITE_PROXY_URL : import.meta.env.VITE_BASE_URL) + item.image_path
activeWebviewIds.push({
id: item.id,
img: imgurl,
processTaskId: item.camel_task_id,
url: item.browser_url
})
})
}
setTaskAssigning(taskId, [...tasks[taskId].taskAssigning, {
agent_id,
name: agentNameMap[agent_name as keyof typeof agentNameMap] || agent_name,
type: agent_name as AgentNameType,
tasks: [],
log: [],
img: [],
tools: agentMessages.data.tools,
activeWebviewIds: activeWebviewIds,
}])
}
}
return;
}
if (agentMessages.step === "wait_confirm") {
setHasWaitComfirm(taskId, true)
setIsPending(taskId, false)
addMessages(taskId, {
id: generateUniqueId(),
role: "agent",
content: agentMessages.data!.content as string,
step: "wait_confirm",
isConfirm: false,
})
return;
}
if (agentMessages.step === "confirmed") {
setHasWaitComfirm(taskId, false)
return
}
// Task State
if (agentMessages.step === "task_state") {
const { state, task_id, result, failure_count } = agentMessages.data;
if (!state && !task_id) return
let taskRunning = [...tasks[taskId].taskRunning]
let taskAssigning = [...tasks[taskId].taskAssigning]
const targetTaskIndex = taskRunning.findIndex((task) => task.id === task_id)
const targetTaskAssigningIndex = taskAssigning.findIndex((agent) => agent.tasks.find((task: TaskInfo) => task.id === task_id && !task.reAssignTo))
if (targetTaskAssigningIndex !== -1) {
const taskIndex = taskAssigning[targetTaskAssigningIndex].tasks.findIndex((task: TaskInfo) => task.id === task_id)
taskAssigning[targetTaskAssigningIndex].tasks[taskIndex].status = state === "DONE" ? "completed" : "failed";
taskAssigning[targetTaskAssigningIndex].tasks[taskIndex].failure_count = failure_count || 0
// destroy webview
tasks[taskId].taskAssigning = tasks[taskId].taskAssigning.map((item) => {
if (item.type === "search_agent" && item.activeWebviewIds?.length && item.activeWebviewIds?.length > 0) {
let removeList: number[] = []
item.activeWebviewIds.map((webview, index) => {
if (webview.processTaskId === task_id) {
window.electronAPI.webviewDestroy(webview.id);
removeList.push(index)
}
});
removeList.forEach((webviewIndex) => {
item.activeWebviewIds?.splice(webviewIndex, 1);
});
}
return item
})
if (result && result !== '') {
let targetResult = result.replace(taskAssigning[targetTaskAssigningIndex].agent_id, taskAssigning[targetTaskAssigningIndex].name)
taskAssigning[targetTaskAssigningIndex].tasks[taskIndex].report = targetResult
if (state === "FAILED" && failure_count && failure_count >= 3) {
addMessages(taskId, {
id: generateUniqueId(),
role: "agent",
content: targetResult,
step: "failed",
})
}
}
}
if (targetTaskIndex !== -1) {
console.log("targetTaskIndex", targetTaskIndex, state)
taskRunning[targetTaskIndex].status = state === "DONE" ? "completed" : "failed";
}
setTaskRunning(taskId, taskRunning)
setTaskAssigning(taskId, taskAssigning)
return;
}
// Activate agent
if (agentMessages.step === "activate_agent" || agentMessages.step === "deactivate_agent") {
let taskAssigning = [...tasks[taskId].taskAssigning]
let taskRunning = [...tasks[taskId].taskRunning]
if (agentMessages.data.tokens) {
addTokens(taskId, agentMessages.data.tokens)
}
const { state, agent_id, process_task_id } = agentMessages.data;
if (!state && !agent_id && !process_task_id) return
const agentIndex = taskAssigning.findIndex((agent) => agent.agent_id === agent_id)
if (agentIndex === -1) return;
// // add log
// const message = filterMessage(agentMessages.data.message || '', agentMessages.data.method_name)
// if (message) {
// taskAssigning[agentIndex].log.push(agentMessages);
// }
const message = filterMessage(agentMessages)
if (agentMessages.step === "activate_agent") {
taskAssigning[agentIndex].status = "running";
if (message) {
taskAssigning[agentIndex].log.push({
...agentMessages,
status: "running",
});
}
const taskIndex = taskRunning.findIndex((task) => task.id === process_task_id);
if (taskIndex !== -1 && taskRunning![taskIndex].status) {
taskRunning![taskIndex].agent!.status = "running";
taskRunning![taskIndex]!.status = "running";
const task = taskAssigning[agentIndex].tasks.find((task: TaskInfo) => task.id === process_task_id);
if (task) {
task.status = "running";
}
}
setTaskRunning(taskId, [...taskRunning]);
setTaskAssigning(taskId, [...taskAssigning]);
}
if (agentMessages.step === "deactivate_agent") {
if (message) {
const index = taskAssigning[agentIndex].log.findLastIndex((log) => log.data.method_name === agentMessages.data.method_name && log.data.toolkit_name === agentMessages.data.toolkit_name)
if (index != -1) {
taskAssigning[agentIndex].log[index].status = "completed";
setTaskAssigning(taskId, [...taskAssigning]);
}
}
// const taskIndex = taskRunning.findIndex((task) => task.id === process_task_id);
// if (taskIndex !== -1) {
// taskRunning![taskIndex].agent!.status = "completed";
// taskRunning![taskIndex]!.status = "completed";
// }
if (!type && historyId) {
const obj = {
"project_name": tasks[taskId].summaryTask.split('|')[0],
"summary": tasks[taskId].summaryTask.split('|')[1],
"status": 1,
"tokens": getTokens(taskId)
}
proxyFetchPut(`/api/chat/history/${historyId}`, obj)
}
setTaskRunning(taskId, [...taskRunning]);
setTaskAssigning(taskId, [...taskAssigning]);
}
return;
}
// Assign task
if (agentMessages.step === "assign_task") {
if (!agentMessages.data?.assignee_id || !agentMessages.data?.task_id) return;
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);
const taskRunningIndex = taskRunning!.findIndex((task: TaskInfo) => task.id === task_id);
// Skip tasks with empty content only if the task doesn't exist in taskInfo
// If task exists in taskInfo, we should still process status updates
if ((!content || content.trim() === "") && !task) {
console.warn(`Skipping task ${task_id} with empty content and not found in taskInfo`);
return;
}
if (assigneeAgentIndex === -1) return;
const taskAgent = taskAssigning![assigneeAgentIndex];
// Find the agent to reassign the task to
const target = taskAssigning
.map((agent, agentIndex) => {
if (agent.agent_id === assignee_id) return null
const taskIndex = agent.tasks.findIndex(
(task: TaskInfo) => task.id === task_id && !task.reAssignTo
)
return taskIndex !== -1 ? { agentIndex, taskIndex } : null
})
.find(Boolean)
if (target) {
const { agentIndex, taskIndex } = target
const agentName = taskAssigning.find((agent: Agent) => agent.agent_id === assignee_id)?.name
taskAssigning[agentIndex].tasks[taskIndex].reAssignTo = agentName
}
// Clear logs from the assignee agent that are related to this task
// This prevents logs from previous attempts appearing in the reassigned task
// This needs to happen whether it's a reassignment to a different agent or a retry with the same agent
if (taskState !== "waiting" && failure_count && failure_count > 0) {
taskAssigning[assigneeAgentIndex].log = taskAssigning[assigneeAgentIndex].log.filter(
(log) => log.data.process_task_id !== task_id
)
}
// Handle task assignment to taskAssigning based on state
if (taskState === "waiting") {
if (!taskAssigning[assigneeAgentIndex].tasks.find(item => item.id === task_id)) {
taskAssigning[assigneeAgentIndex].tasks.push(task ?? { id: task_id, content, status: "waiting" });
}
setTaskAssigning(taskId, [...taskAssigning]);
}
// The following logic is for when the task actually starts executing (running)
else 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";
if (failure_count !== 0) {
taskAssigning[assigneeAgentIndex].tasks[existingTaskIndex].failure_count = failure_count;
}
} else {
// Task doesn't exist, add it
let taskTemp = null
if (task) {
taskTemp = JSON.parse(JSON.stringify(task))
taskTemp.failure_count = 0
taskTemp.status = "running"
taskTemp.toolkits = []
taskTemp.report = ""
}
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
if(task){
task.status = taskState === "waiting" ? "waiting" : "running";
}
taskRunning!.push(
task ?? {
id: task_id,
content,
status: taskState === "waiting" ? "waiting" : "running",
agent: JSON.parse(JSON.stringify(taskAgent)),
}
);
} else {
// Task already in taskRunning, update it
taskRunning![taskRunningIndex] = {
...taskRunning![taskRunningIndex],
status: taskState === "waiting" ? "waiting" : "running",
agent: JSON.parse(JSON.stringify(taskAgent)),
};
}
setTaskRunning(taskId, [...taskRunning]);
setTaskAssigning(taskId, [...taskAssigning]);
return;
}
// Activate Toolkit
if (agentMessages.step === "activate_toolkit") {
if (agentMessages.data.method_name === 'send message to user') {
return
}
// add log
let taskAssigning = [...tasks[taskId].taskAssigning]
const assigneeAgentIndex = taskAssigning!.findIndex((agent: Agent) => agent.tasks.find((task: TaskInfo) => task.id === agentMessages.data.process_task_id));
if (assigneeAgentIndex !== -1) {
const message = filterMessage(agentMessages)
if (message) {
taskAssigning[assigneeAgentIndex].log.push(agentMessages);
setTaskAssigning(taskId, [...taskAssigning]);
}
}
console.log('agentMessages.data', agentMessages.data.toolkit_name, agentMessages.data.method_name)
if (agentMessages.data.toolkit_name === 'Browser Toolkit' && agentMessages.data.method_name === 'browser visit page') {
console.log('match success')
addWebViewUrl(taskId, agentMessages.data.message?.replace(/url=/g, '').replace(/'/g, '') as string, agentMessages.data.process_task_id as string)
}
if (agentMessages.data.toolkit_name === 'Browser Toolkit' && agentMessages.data.method_name === 'visit page') {
console.log('match success')
addWebViewUrl(taskId, agentMessages.data.message as string, agentMessages.data.process_task_id as string)
}
if (agentMessages.data.toolkit_name === 'ElectronToolkit' && agentMessages.data.method_name === 'browse_url') {
addWebViewUrl(taskId, agentMessages.data.message as string, agentMessages.data.process_task_id as string)
}
if (agentMessages.data.method_name === 'browser_navigate' && agentMessages.data.message?.startsWith('{"url"')) {
addWebViewUrl(taskId, JSON.parse(agentMessages.data.message)?.url as string, agentMessages.data.process_task_id as string)
}
let taskRunning = [...tasks[taskId].taskRunning]
const taskIndex = taskRunning.findIndex((task) => task.id === agentMessages.data.process_task_id);
if (taskIndex !== -1) {
const { toolkit_name, method_name } = agentMessages.data;
if (toolkit_name && method_name && assigneeAgentIndex !== -1) {
const task = taskAssigning[assigneeAgentIndex].tasks.find((task: TaskInfo) => task.id === agentMessages.data.process_task_id);
const message = filterMessage(agentMessages)
if (message) {
const toolkit = {
toolkitId: generateUniqueId(),
toolkitName: toolkit_name,
toolkitMethods: method_name,
message: message.data.message as string,
toolkitStatus: "running" as AgentStatus,
}
if (task) {
task.toolkits ??= []
task.toolkits.push({ ...toolkit });
task.status = "running";
setTaskAssigning(taskId, [...taskAssigning]);
}
taskRunning![taskIndex].status = "running";
taskRunning![taskIndex].toolkits ??= [];
taskRunning![taskIndex].toolkits.push({ ...toolkit });
}
}
}
setTaskRunning(taskId, taskRunning);
return;
}
// Deactivate Toolkit
if (agentMessages.step === "deactivate_toolkit") {
// add log
let taskAssigning = [...tasks[taskId].taskAssigning]
const assigneeAgentIndex = taskAssigning!.findIndex((agent: Agent) => agent.tasks.find((task: TaskInfo) => task.id === agentMessages.data.process_task_id));
if (assigneeAgentIndex !== -1) {
const message = filterMessage(agentMessages)
if (message) {
const task = taskAssigning[assigneeAgentIndex].tasks.find((task: TaskInfo) => task.id === agentMessages.data.process_task_id);
if (task) {
let index = task.toolkits?.findIndex((toolkit) => {
return toolkit.toolkitName === agentMessages.data.toolkit_name && toolkit.toolkitMethods === agentMessages.data.method_name && toolkit.toolkitStatus === 'running'
})
if (task.toolkits && index !== undefined && index != -1) {
task.toolkits[index].message += '\n' + message.data.message as string
task.toolkits[index].toolkitStatus = "completed"
}
// task.toolkits?.unshift({
// toolkitName: agentMessages.data.toolkit_name as string,
// toolkitMethods: agentMessages.data.method_name as string,
// message: message.data.message as string,
// toolkitStatus: "completed",
// });
// task.toolkits?.unshift({
// toolkitName: agentMessages.data.toolkit_name as string,
// toolkitMethods: agentMessages.data.method_name as string,
// message: message.data.message as string,
// toolkitStatus: "completed",
// });
}
taskAssigning[assigneeAgentIndex].log.push(agentMessages);
setTaskAssigning(taskId, [...taskAssigning]);
}
}
let taskRunning = [...tasks[taskId].taskRunning]
const { toolkit_name, method_name, message } =
agentMessages.data;
const taskIndex = taskRunning.findIndex((task) =>
task.agent?.type === agentMessages.data.agent_name &&
task.toolkits?.at(-1)?.toolkitName === toolkit_name
);
if (taskIndex !== -1) {
if (toolkit_name && method_name && message) {
const targetMessage = filterMessage(agentMessages)
if (targetMessage) {
taskRunning![taskIndex].toolkits?.unshift({
toolkitName: toolkit_name,
toolkitMethods: method_name,
message: targetMessage.data.message as string,
toolkitStatus: "completed",
});
}
}
}
setTaskAssigning(taskId, [...taskAssigning]);
setTaskRunning(taskId, taskRunning);
return;
}
// Terminal
if (agentMessages.step === "terminal") {
addTerminal(taskId, agentMessages.data.process_task_id as string, agentMessages.data.output as string)
return
}
// Write File
if (agentMessages.step === "write_file") {
console.log('write_to_file', agentMessages.data)
setNuwFileNum(taskId, tasks[taskId].nuwFileNum + 1)
const { file_path } = agentMessages.data;
const fileName = file_path?.replace(/\\/g, "/").split("/").pop() || "";
const fileType = fileName.split(".").pop() || "";
const fileInfo: FileInfo = {
name: fileName,
type: fileType,
path: file_path || "",
icon: FileText,
};
addFileList(taskId, agentMessages.data.process_task_id as string, fileInfo);
return;
}
if (agentMessages.step === "budget_not_enough") {
console.log('error', agentMessages.data)
showCreditsToast()
setStatus(taskId, 'pause');
uploadLog(taskId, type)
return
}
if (agentMessages.step === "error") {
console.error('Model error:', agentMessages.data)
const errorMessage = agentMessages.data.message || 'An error occurred while processing your request';
// Create a new task to avoid "Task already exists" error
// and completely reset the interface
const newTaskId = create();
// Prevent showing task skeleton after an error occurs
setActiveTaskId(newTaskId);
setHasWaitComfirm(newTaskId, true);
// Add error message to the new clean task
addMessages(newTaskId, {
id: generateUniqueId(),
role: "agent",
content: `❌ **Error**: ${errorMessage}`,
});
uploadLog(taskId, type)
return
}
if (agentMessages.step === "end") {
// compute task time
const { setTaskTime, setElapsed } = get();
console.log('tasks[taskId].snapshotsTemp', tasks[taskId].snapshotsTemp)
Promise.all(tasks[taskId].snapshotsTemp.map((snapshot) =>
proxyFetchPost(`/api/chat/snapshots`, { ...snapshot })
));
// Async file upload
let res = await window.ipcRenderer.invoke(
"get-file-list",
email,
taskId as string
);
if (!type && import.meta.env.VITE_USE_LOCAL_PROXY !== 'true' && res.length > 0) {
// Filter out directories, only upload actual files
const files = res.filter((file: any) => !file.isFolder);
// Upload files sequentially to avoid overwhelming the server
const uploadResults = await Promise.allSettled(
files.map(async (file: any) => {
try {
// Read file content using Electron API
const result = await window.ipcRenderer.invoke('read-file', file.path);
if (result.success && result.data) {
// Create FormData for file upload
const formData = new FormData();
const blob = new Blob([result.data], { type: 'application/octet-stream' });
formData.append('file', blob, file.name);
formData.append('task_id', taskId);
// Upload file
await uploadFile('/api/chat/files/upload', formData);
console.log('File uploaded successfully:', file.name);
return { success: true, fileName: file.name };
} else {
console.error('Failed to read file:', result.error);
return { success: false, fileName: file.name, error: result.error };
}
} catch (error) {
console.error('File upload failed:', error);
return { success: false, fileName: file.name, error };
}
})
);
// Count successful uploads
const successCount = uploadResults.filter(
result => result.status === 'fulfilled' && result.value.success
).length;
// Log failures
const failures = uploadResults.filter(
result => result.status === 'rejected' || (result.status === 'fulfilled' && !result.value.success)
);
if (failures.length > 0) {
console.error('Failed to upload files:', failures);
}
// add remote file count for successful uploads only
if (successCount > 0) {
proxyFetchPost(`/api/user/stat`, {
"action": "file_generate_count",
"value": successCount
})
}
}
if (!type && historyId) {
const obj = {
"project_name": tasks[taskId].summaryTask.split('|')[0],
"summary": tasks[taskId].summaryTask.split('|')[1],
"status": 2,
"tokens": getTokens(taskId)
}
proxyFetchPut(`/api/chat/history/${historyId}`, obj)
}
uploadLog(taskId, type)
let taskRunning = [...tasks[taskId].taskRunning];
let taskAssigning = [...tasks[taskId].taskAssigning];
taskAssigning = taskAssigning.map((agent) => {
agent.tasks = agent.tasks.map((task) => {
if (task.status !== "completed" && task.status !== "failed" && !type) {
task.status = "skipped"
}
return task
})
return agent
})
taskRunning = taskRunning.map((task) => {
console.log('task.status', task.status)
if (task.status !== "completed" && task.status !== "failed" && !type) {
task.status = "skipped"
}
return task
})
setTaskAssigning(taskId, [...taskAssigning]);
setTaskRunning(taskId, [...taskRunning]);
if (!taskId || !tasks[taskId]) return "N/A";
const task = tasks[taskId];
let taskTime = task.taskTime;
let elapsed = task.elapsed;
// if task is running, compute current time
if (taskTime !== 0) {
const currentTime = Date.now()
elapsed += currentTime - taskTime
}
setTaskTime(taskId, 0);
setElapsed(taskId, elapsed);
const fileList = tasks[taskId].taskAssigning.map((agent) => {
return agent.tasks.map((task) => {
return task.fileList || []
}).flat()
}).flat()
let endMessage = agentMessages.data as string
let summary = endMessage.match(/<summary>(.*?)<\/summary>/)?.[1]
let newMessage: Message | null = null
const agent_summary_end = tasks[taskId].messages.findLast((message: Message) => message.step === 'agent_summary_end')
console.log('summary', summary)
if (summary) {
endMessage = summary
}
else if (agent_summary_end) {
console.log('agent_summary_end', agent_summary_end)
endMessage = agent_summary_end.summary || ""
} else if (endMessage.indexOf('Result ---') !== -1) {
endMessage = endMessage.split('Result ---').at(-1) || ""
}
console.log('endMessage', endMessage)
newMessage = {
id: generateUniqueId(),
role: "agent",
content: endMessage || "",
step: agentMessages.step,
isConfirm: false,
fileList: fileList,
};
addMessages(taskId, newMessage);
setIsPending(taskId, false);
setStatus(taskId, 'finished');
// completed tasks move to history
setUpdateCount();
console.log(tasks[taskId], 'end');
return;
}
if (agentMessages.step === "notice") {
if (agentMessages.data.process_task_id !== '') {
let taskAssigning = [...tasks[taskId].taskAssigning]
const assigneeAgentIndex = taskAssigning!.findIndex((agent: Agent) => agent.tasks.find((task: TaskInfo) => task.id === agentMessages.data.process_task_id));
const task = taskAssigning[assigneeAgentIndex].tasks.find((task: TaskInfo) => task.id === agentMessages.data.process_task_id);
const toolkit = {
toolkitId: generateUniqueId(),
toolkitName: 'notice',
toolkitMethods: '',
message: agentMessages.data.notice as string,
toolkitStatus: "running" as AgentStatus,
}
if (assigneeAgentIndex !== -1 && task) {
task.toolkits ??= []
task.toolkits.push({ ...toolkit });
}
setTaskAssigning(taskId, [...taskAssigning]);
} else {
const messages = [...tasks[taskId].messages]
const noticeCardIndex = messages.findLastIndex((message) => message.step === 'notice_card')
if (noticeCardIndex === -1) {
const newMessage: Message = {
id: generateUniqueId(),
role: "agent",
content: "",
step: 'notice_card',
};
addMessages(taskId, newMessage)
}
setCotList(taskId, [...tasks[taskId].cotList, agentMessages.data.notice as string])
// addMessages(taskId, newMessage);
}
return
}
if (["sync"].includes(agentMessages.step)) return
if (agentMessages.step === "ask") {
if (tasks[taskId].activeAsk != '') {
const newMessage: Message = {
id: generateUniqueId(),
role: "agent",
agent_name: agentMessages.data.agent || '',
content:
agentMessages.data?.content ||
agentMessages.data?.notice ||
agentMessages.data?.answer ||
agentMessages.data?.question ||
agentMessages.data as string ||
"",
step: agentMessages.step,
isConfirm: false,
};
let activeAskList = tasks[taskId].askList
setActiveAskList(taskId, [...activeAskList, newMessage]);
return
}
setActiveAsk(taskId, agentMessages.data.agent || '')
setIsPending(taskId, false)
}
const newMessage: Message = {
id: generateUniqueId(),
role: "agent",
content:
agentMessages.data?.content ||
agentMessages.data?.notice ||
agentMessages.data?.answer ||
agentMessages.data?.question ||
agentMessages.data as string ||
"",
step: agentMessages.step,
isConfirm: false,
};
addMessages(taskId, newMessage);
},
async onopen(respond) {
console.log("open", respond);
const { setAttaches, activeTaskId } = get()
setAttaches(activeTaskId as string, [])
return;
},
onerror(err) {
console.error("Error:", err);
throw err;
},
// Server closes connection
onclose() {
console.log("server closed");
},
});
},
replay: async (taskId: string, question: string, time: number) => {
const { create, setHasMessages, addMessages, startTask, setActiveTaskId, handleConfirmTask } = get();
create(taskId, "replay");
setHasMessages(taskId, true);
addMessages(taskId, {
id: generateUniqueId(),
role: "user",
content: question.split("|")[0],
});
await startTask(taskId, "replay", undefined, time);
setActiveTaskId(taskId);
handleConfirmTask(taskId, "replay");
},
setUpdateCount() {
set((state) => ({
...state,
updateCount: state.updateCount + 1
}))
},
setActiveTaskId: (taskId: string) => {
set({
activeTaskId: taskId,
});
},
addMessages(taskId, message) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
messages: [
...state.tasks[taskId].messages,
message,
],
},
},
}))
},
setAttaches(taskId, attaches) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
attaches: [...attaches],
},
},
}))
},
setMessages(taskId, messages) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
messages: [
...messages,
],
},
},
}))
},
setCotList(taskId, cotList) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
cotList: [...cotList],
},
},
}))
},
setSummaryTask(taskId, summaryTask) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
summaryTask,
},
},
}))
},
setIsTakeControl(taskId, isTakeControl) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
isTakeControl,
},
},
}))
},
setHasWaitComfirm(taskId, hasWaitComfirm) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
hasWaitComfirm,
},
},
}))
},
setTaskInfo(taskId, taskInfo) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
taskInfo: [...taskInfo],
},
},
}))
},
setTaskRunning(taskId, taskRunning) {
const { computedProgressValue } = get()
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
taskRunning: [...taskRunning],
},
},
}))
computedProgressValue(taskId)
},
addWebViewUrl(taskId: string, webViewUrl: string, processTaskId: string) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
webViewUrls: [...state.tasks[taskId].webViewUrls, { url: webViewUrl, processTaskId: processTaskId }],
},
},
}))
},
setWebViewUrls(taskId: string, webViewUrls: { url: string, processTaskId: string }[]) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
webViewUrls: [...webViewUrls],
},
},
}))
},
setActiveAskList(taskId, askList) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
actuveAskList: [...askList],
},
},
}))
},
setTaskAssigning(taskId, taskAssigning) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
taskAssigning: [...taskAssigning],
},
},
}))
},
setStatus(taskId: string, status: 'running' | 'finished' | 'pending' | 'pause') {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
status
},
},
}))
},
handleConfirmTask: async (taskId: string, type?: string) => {
const { tasks, setMessages, setActiveWorkSpace, setStatus, setTaskTime, setTaskInfo, setTaskRunning } = get();
if (!taskId) return;
// record task start time
setTaskTime(taskId, Date.now());
const taskInfo = tasks[taskId].taskInfo.filter((task) => task.content !== '')
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/${taskId}`, {
task: taskInfo,
});
await fetchPost(`/task/${taskId}/start`, {});
}
setActiveWorkSpace(taskId, 'workflow')
setStatus(taskId, 'running')
let messages = [...tasks[taskId].messages]
const cardTaskIndex = messages.findLastIndex((message) => message.step === 'to_sub_tasks')
if (cardTaskIndex !== -1) {
messages[cardTaskIndex] = {
...messages[cardTaskIndex],
isConfirm: true,
taskType: 2,
}
setMessages(taskId, messages)
}
},
addTaskInfo() {
const { tasks, activeTaskId, setTaskInfo } = get()
if (!activeTaskId) return
let targetTaskInfo = [...tasks[activeTaskId].taskInfo]
const newTaskInfo = {
id: "",
content: "",
};
targetTaskInfo.push(newTaskInfo)
setTaskInfo(activeTaskId, targetTaskInfo)
},
addTerminal(taskId, processTaskId, terminal) {
if (!processTaskId) return
const { tasks, setTaskAssigning } = get()
const taskAssigning = [...tasks[taskId].taskAssigning]
const taskAssigningIndex = taskAssigning.findIndex((task) => task.tasks.find((task) => task.id === processTaskId))
if (taskAssigningIndex !== -1) {
const taskIndex = taskAssigning[taskAssigningIndex].tasks.findIndex((task) => task.id === processTaskId)
taskAssigning[taskAssigningIndex].tasks[taskIndex].terminal ??= []
taskAssigning[taskAssigningIndex].tasks[taskIndex].terminal?.push(terminal)
console.log(taskAssigning[taskAssigningIndex].tasks[taskIndex].terminal)
setTaskAssigning(taskId, taskAssigning)
}
},
setActiveAsk(taskId, agentName) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
activeAsk: agentName,
},
},
}))
},
setProgressValue(taskId: string, progressValue: number) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
progressValue
},
},
}))
},
setIsPending(taskId: string, isPending: boolean) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
isPending
},
},
}))
},
setActiveWorkSpace(taskId: string, activeWorkSpace: string) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
activeWorkSpace
},
},
}))
},
setActiveAgent(taskId: string, agent_id: string) {
console.log('setActiveAgent', taskId, agent_id)
set((state) => {
if (state.tasks[taskId]?.activeAgent === agent_id) {
return state;
}
return ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
activeAgent: agent_id
},
},
})
})
},
setHasMessages(taskId: string, hasMessages: boolean) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
hasMessages
},
},
}))
},
setHasAddWorker(taskId: string, hasAddWorker: boolean) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
hasAddWorker
},
},
}))
},
addFileList(taskId, processTaskId, fileInfo) {
const { tasks, setTaskAssigning } = get()
const taskAssigning = [...tasks[taskId].taskAssigning]
let agentId = ''
const taskAssigningIndex = taskAssigning.findIndex((agent) => {
const hasTask = agent.tasks.find((task) => task.id === processTaskId)
if (hasTask) {
agentId = agent.agent_id
}
return hasTask
})
const taskIndex = taskAssigning[taskAssigningIndex].tasks.findIndex((task) => task.id === processTaskId)
if (taskAssigningIndex !== -1) {
taskAssigning[taskAssigningIndex].tasks[taskIndex].fileList ??= []
taskAssigning[taskAssigningIndex].tasks[taskIndex].fileList?.push({ ...fileInfo, agent_id: agentId, task_id: processTaskId })
setTaskAssigning(taskId, taskAssigning)
}
},
setFileList(taskId, processTaskId, fileList: FileInfo[]) {
const { tasks, setTaskAssigning } = get()
const taskAssigning = [...tasks[taskId].taskAssigning]
const taskAssigningIndex = taskAssigning.findIndex((task) => task.tasks.find((task) => task.id === processTaskId))
const taskIndex = taskAssigning[taskAssigningIndex].tasks.findIndex((task) => task.id === processTaskId)
if (taskAssigningIndex !== -1) {
taskAssigning[taskAssigningIndex].tasks[taskIndex].fileList = [...fileList]
setTaskAssigning(taskId, taskAssigning)
}
},
updateTaskInfo(index: number, content: string) {
const { tasks, activeTaskId, setTaskInfo } = get()
if (!activeTaskId) return
let targetTaskInfo = [...tasks[activeTaskId].taskInfo]
if (targetTaskInfo) {
targetTaskInfo[index].content = content
}
setTaskInfo(activeTaskId, targetTaskInfo)
},
deleteTaskInfo(index: number) {
const { tasks, activeTaskId, setTaskInfo } = get()
if (!activeTaskId) return
let targetTaskInfo = [...tasks[activeTaskId].taskInfo]
if (targetTaskInfo) {
targetTaskInfo.splice(index, 1)
}
setTaskInfo(activeTaskId, targetTaskInfo)
},
getLastUserMessage() {
const { activeTaskId, tasks } = get();
if (!activeTaskId) return null
return tasks[activeTaskId]?.messages.findLast((message: Message) => message.role === 'user') || null
},
setTaskTime(taskId: string, taskTime: number) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
taskTime
},
},
}))
},
setNuwFileNum(taskId: string, nuwFileNum: number) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
nuwFileNum
},
},
}))
},
setType(taskId: string, type: string) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
type
},
},
}))
},
setDelayTime(taskId: string, delayTime: number) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
delayTime
},
},
}))
},
setElapsed(taskId: string, elapsed: number) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
elapsed
},
},
}))
},
getFormattedTaskTime(taskId: string) {
const { tasks } = get();
if (!taskId || !tasks[taskId]) return "N/A";
const task = tasks[taskId];
let taskTime = task.taskTime;
let elapsed = task.elapsed;
let time = 0
// if task is running, compute current time
if (taskTime !== 0) {
const currentTime = Date.now()
time = currentTime - taskTime + elapsed;
} else {
time = elapsed;
}
const hours = Math.floor(time / 3600000);
const minutes = Math.floor((time % 3600000) / 60000);
const seconds = Math.floor((time % 60000) / 1000);
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
},
addTokens(taskId: string, tokens: number) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
tokens: state.tasks[taskId].tokens + tokens
},
},
}))
},
getTokens(taskId: string) {
const { tasks } = get();
return tasks[taskId]?.tokens ?? 0;
},
setSelectedFile(taskId: string, selectedFile: FileInfo | null) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
selectedFile: selectedFile,
},
},
}))
},
setSnapshots(taskId: string, snapshots: any[]) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
snapshots,
},
},
}))
},
setSnapshotsTemp(taskId: string, snapshot: any) {
set((state) => {
const oldList = state.tasks[taskId]?.snapshotsTemp || [];
if (oldList.find(item => item.browser_url === snapshot.browser_url)) {
return state;
}
return {
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
snapshotsTemp: [...state.tasks[taskId].snapshotsTemp, snapshot],
},
},
}
})
},
setIsTaskEdit(taskId: string, isTaskEdit: boolean) {
set((state) => ({
...state,
tasks: {
...state.tasks,
[taskId]: {
...state.tasks[taskId],
isTaskEdit
},
},
}))
},
clearTasks: () => {
const { create } = get()
console.log('clearTasks')
window.ipcRenderer.invoke('restart-backend')
.then((res) => {
console.log('restart-backend', res)
})
.catch((error) => {
console.error('Error in clearTasks cleanup:', error)
})
// Immediately create new task to maintain UI responsiveness
const newTaskId = create()
set((state) => ({
...state,
tasks: {
[newTaskId]: {
...state.tasks[newTaskId],
},
},
}))
},
})
);
const filterMessage = (message: AgentMessage) => {
if (message.data.toolkit_name?.includes('Search ')) {
message.data.toolkit_name = 'Search Toolkit'
}
if (message.data.method_name?.includes('search')) {
message.data.method_name = 'search'
}
if (message.data.toolkit_name === 'Note Taking Toolkit') {
message.data.message = message.data.message!.replace(/content='/g, '').replace(/', update=False/g, '').replace(/', update=True/g, '')
}
if (message.data.method_name === 'scrape') {
message.data.message = message.data.message!.replace(/url='/g, '').slice(0, -1)
}
return message
}
export const useChatStore = chatStore;
export const getToolStore = () => chatStore.getState();