mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-06-02 07:12:02 +00:00
Merge branch 'main' into fix-win-0.0.82-add-mac-intel
This commit is contained in:
commit
f007da58ed
20 changed files with 536 additions and 264 deletions
|
|
@ -23,8 +23,10 @@ import camel
|
|||
from camel.societies.workforce.events import (LogEvent, TaskAssignedEvent,
|
||||
TaskCompletedEvent,
|
||||
TaskCreatedEvent,
|
||||
TaskDecomposedEvent,
|
||||
TaskFailedEvent,
|
||||
TaskStartedEvent,
|
||||
TaskUpdatedEvent,
|
||||
WorkerCreatedEvent)
|
||||
from camel.societies.workforce.workforce_metrics import WorkforceMetrics
|
||||
from opentelemetry import trace
|
||||
|
|
@ -58,11 +60,16 @@ ATTR_TASK_DESCRIPTION = "eigent.task.description"
|
|||
ATTR_TASK_PARENT_ID = "eigent.task.parent_id"
|
||||
ATTR_TASK_TYPE = "eigent.task.type"
|
||||
ATTR_TASK_STATUS = "eigent.task.status"
|
||||
ATTR_TASK_UPDATE_TYPE = "eigent.task.update_type"
|
||||
ATTR_TASK_UPDATE_OLD_VALUE = "eigent.task.update.old_value"
|
||||
ATTR_TASK_UPDATE_NEW_VALUE = "eigent.task.update.new_value"
|
||||
ATTR_TASK_UPDATE_METADATA = "eigent.task.update.metadata"
|
||||
ATTR_TASK_QUEUE_TIME_SECONDS = "eigent.task.queue_time_seconds"
|
||||
ATTR_TASK_PROCESSING_TIME_SECONDS = "eigent.task.processing_time_seconds"
|
||||
ATTR_TASK_QUALITY_SCORE = "eigent.task.quality_score"
|
||||
ATTR_TASK_TIMESTAMP = "eigent.task.timestamp"
|
||||
ATTR_TASK_DEPENDENCIES = "eigent.task.dependencies"
|
||||
ATTR_TASK_SUBTASK_IDS = "eigent.task.subtask_ids"
|
||||
|
||||
# Attribute keys for eigent.worker namespace
|
||||
ATTR_WORKER_ID = "eigent.worker.id"
|
||||
|
|
@ -86,7 +93,9 @@ TRACER_NAME_WORKFORCE = "eigent.workforce"
|
|||
SPAN_WORKFORCE_EXECUTION = "workforce.execution"
|
||||
SPAN_WORKER_CREATED = "worker.created"
|
||||
SPAN_TASK_CREATED = "task.created"
|
||||
SPAN_TASK_DECOMPOSED = "task.decomposed"
|
||||
SPAN_TASK_ASSIGNED = "task.assigned"
|
||||
SPAN_TASK_UPDATED = "task.updated"
|
||||
SPAN_TASK_EXECUTION = "task.execution"
|
||||
SPAN_LOG_MESSAGE = "log.message"
|
||||
SPAN_ALL_TASKS_COMPLETED = "workforce.all_tasks_completed"
|
||||
|
|
@ -318,6 +327,27 @@ class WorkforceMetricsCallback(WorkforceMetrics):
|
|||
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
|
||||
def log_task_decomposed(self, event: TaskDecomposedEvent) -> None:
|
||||
"""Log task decomposition as a span.
|
||||
|
||||
Args:
|
||||
event (TaskDecomposedEvent): Task decomposed event from CAMEL
|
||||
"""
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
ctx = trace.set_span_in_context(self.root_span)
|
||||
with self.tracer.start_as_current_span(SPAN_TASK_DECOMPOSED,
|
||||
context=ctx) as span:
|
||||
span.set_attribute(ATTR_TASK_PARENT_ID, event.parent_task_id)
|
||||
span.set_attribute(ATTR_PROJECT_ID, self.project_id)
|
||||
|
||||
if event.subtask_ids:
|
||||
span.set_attribute(ATTR_TASK_SUBTASK_IDS,
|
||||
json.dumps(event.subtask_ids))
|
||||
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
|
||||
def log_task_assigned(self, event: TaskAssignedEvent) -> None:
|
||||
"""Log task assignment as a span.
|
||||
|
||||
|
|
@ -345,6 +375,41 @@ class WorkforceMetricsCallback(WorkforceMetrics):
|
|||
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
|
||||
def log_task_updated(self, event: TaskUpdatedEvent) -> None:
|
||||
"""Log task update events (replan/reassign/manual) as a span.
|
||||
|
||||
Args:
|
||||
event: Task updated event from CAMEL
|
||||
"""
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
ctx = trace.set_span_in_context(self.root_span)
|
||||
with self.tracer.start_as_current_span(SPAN_TASK_UPDATED,
|
||||
context=ctx) as span:
|
||||
span.set_attribute(ATTR_TASK_ID, event.task_id)
|
||||
span.set_attribute(ATTR_PROJECT_ID, self.project_id)
|
||||
span.set_attribute(ATTR_TASK_UPDATE_TYPE, event.update_type)
|
||||
|
||||
if event.worker_id:
|
||||
span.set_attribute(ATTR_WORKER_ID, event.worker_id)
|
||||
if event.parent_task_id:
|
||||
span.set_attribute(ATTR_TASK_PARENT_ID, event.parent_task_id)
|
||||
if event.old_value is not None:
|
||||
span.set_attribute(ATTR_TASK_UPDATE_OLD_VALUE,
|
||||
event.old_value)
|
||||
if event.new_value is not None:
|
||||
span.set_attribute(ATTR_TASK_UPDATE_NEW_VALUE,
|
||||
event.new_value)
|
||||
if event.metadata:
|
||||
span.set_attribute(ATTR_TASK_UPDATE_METADATA,
|
||||
json.dumps(event.metadata))
|
||||
if hasattr(event, 'timestamp') and event.timestamp:
|
||||
span.set_attribute(ATTR_TASK_TIMESTAMP,
|
||||
event.timestamp.isoformat())
|
||||
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
|
||||
def log_task_started(self, event: TaskStartedEvent) -> None:
|
||||
"""Log task start and create a span for the task execution.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,17 @@
|
|||
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
|
||||
"""Tests for workforce metrics telemetry."""
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
|
@ -8,8 +22,10 @@ from app.utils.telemetry.workforce_metrics import WorkforceMetricsCallback
|
|||
from camel.societies.workforce.events import (LogEvent, TaskAssignedEvent,
|
||||
TaskCompletedEvent,
|
||||
TaskCreatedEvent,
|
||||
TaskDecomposedEvent,
|
||||
TaskFailedEvent,
|
||||
TaskStartedEvent,
|
||||
TaskUpdatedEvent,
|
||||
WorkerCreatedEvent)
|
||||
|
||||
|
||||
|
|
@ -90,6 +106,24 @@ def test_log_task_created(metrics_callback):
|
|||
assert mock_span.set_status.called
|
||||
|
||||
|
||||
def test_log_task_decomposed(metrics_callback):
|
||||
"""Test log_task_decomposed function."""
|
||||
event = TaskDecomposedEvent(
|
||||
parent_task_id="parent_1",
|
||||
subtask_ids=["task_1", "task_2"],
|
||||
)
|
||||
|
||||
mock_span = Mock()
|
||||
metrics_callback.tracer.start_as_current_span = Mock(return_value=Mock(
|
||||
__enter__=Mock(return_value=mock_span), __exit__=Mock()))
|
||||
|
||||
metrics_callback.log_task_decomposed(event)
|
||||
|
||||
# Verify span attributes were set
|
||||
assert mock_span.set_attribute.called
|
||||
assert mock_span.set_status.called
|
||||
|
||||
|
||||
def test_log_task_assigned(metrics_callback):
|
||||
"""Test log_task_assigned function."""
|
||||
event = TaskAssignedEvent(
|
||||
|
|
@ -110,6 +144,29 @@ def test_log_task_assigned(metrics_callback):
|
|||
assert mock_span.set_status.called
|
||||
|
||||
|
||||
def test_log_task_updated(metrics_callback):
|
||||
"""Test log_task_updated function."""
|
||||
event = TaskUpdatedEvent(
|
||||
task_id="task_1",
|
||||
worker_id="worker_1",
|
||||
update_type="replan",
|
||||
old_value="old plan",
|
||||
new_value="new plan",
|
||||
parent_task_id="parent_1",
|
||||
metadata={"source": "recovery"},
|
||||
)
|
||||
|
||||
mock_span = Mock()
|
||||
metrics_callback.tracer.start_as_current_span = Mock(return_value=Mock(
|
||||
__enter__=Mock(return_value=mock_span), __exit__=Mock()))
|
||||
|
||||
metrics_callback.log_task_updated(event)
|
||||
|
||||
# Verify span attributes were set
|
||||
assert mock_span.set_attribute.called
|
||||
assert mock_span.set_status.called
|
||||
|
||||
|
||||
def test_log_task_started(metrics_callback):
|
||||
"""Test log_task_started function."""
|
||||
event = TaskStartedEvent(task_id="task_1", worker_id="worker_1")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { TaskState } from '../TaskState';
|
||||
import { Button } from '../ui/button';
|
||||
import { TaskStatus } from "@/types/constants";
|
||||
|
||||
export default function Home() {
|
||||
//Get Chatstore for the active project's task
|
||||
|
|
@ -223,26 +224,26 @@ export default function Home() {
|
|||
}
|
||||
done={
|
||||
activeAgent?.tasks?.filter(
|
||||
(task) => task.status === 'completed'
|
||||
(task) => task.status === TaskStatus.COMPLETED
|
||||
).length || 0
|
||||
}
|
||||
progress={
|
||||
activeAgent?.tasks?.filter(
|
||||
(task) =>
|
||||
task.status !== 'failed' &&
|
||||
task.status !== 'completed' &&
|
||||
task.status !== 'skipped' &&
|
||||
task.status !== 'waiting'
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.SKIPPED &&
|
||||
task.status !== TaskStatus.WAITING
|
||||
).length || 0
|
||||
}
|
||||
failed={
|
||||
activeAgent?.tasks?.filter((task) => task.status === 'failed')
|
||||
activeAgent?.tasks?.filter((task) => task.status === TaskStatus.FAILED)
|
||||
.length || 0
|
||||
}
|
||||
skipped={
|
||||
activeAgent?.tasks?.filter(
|
||||
(task) =>
|
||||
task.status === 'skipped' || task.status === 'waiting'
|
||||
task.status === TaskStatus.SKIPPED || task.status === TaskStatus.WAITING
|
||||
).length || 0
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { BoxAction } from './BoxAction';
|
|||
import { BoxHeaderConfirm, BoxHeaderSplitting } from './BoxHeader';
|
||||
import { FileAttachment, Inputbox, InputboxProps } from './InputBox';
|
||||
import { QueuedBox, QueuedMessage } from './QueuedBox';
|
||||
import { type ChatTaskStatusType } from "@/types/constants";
|
||||
|
||||
export type BottomBoxState =
|
||||
| 'input'
|
||||
|
|
@ -42,7 +43,7 @@ interface BottomBoxProps {
|
|||
// Task info
|
||||
tokens?: number;
|
||||
taskTime?: string;
|
||||
taskStatus?: 'running' | 'finished' | 'pending' | 'pause';
|
||||
taskStatus?: ChatTaskStatusType;
|
||||
|
||||
// Replay
|
||||
onReplay?: () => void;
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@
|
|||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { ChatTaskStatus, type ChatTaskStatusType } from '@/types/constants';
|
||||
|
||||
export interface FloatingActionProps {
|
||||
/** Current task status */
|
||||
status: 'running' | 'pause' | 'pending' | 'finished';
|
||||
status: ChatTaskStatusType;
|
||||
/** Callback when pause button is clicked */
|
||||
// onPause?: () => void; // Commented out - temporary not needed
|
||||
/** Callback when resume button is clicked */
|
||||
|
|
@ -39,7 +40,7 @@ export const FloatingAction = ({
|
|||
className,
|
||||
}: FloatingActionProps) => {
|
||||
// Only show when task is running (removed pause state)
|
||||
if (status !== 'running') {
|
||||
if (status !== ChatTaskStatus.RUNNING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { motion } from 'framer-motion';
|
|||
import React from 'react';
|
||||
import { FloatingAction } from './FloatingAction';
|
||||
import { UserQueryGroup } from './UserQueryGroup';
|
||||
import { AgentStep } from '@/types/constants';
|
||||
|
||||
interface ProjectSectionProps {
|
||||
chatId: string;
|
||||
|
|
@ -161,7 +162,7 @@ function groupMessagesByQuery(messages: any[]) {
|
|||
userMessage: message,
|
||||
otherMessages: [],
|
||||
};
|
||||
} else if (message.step === 'to_sub_tasks') {
|
||||
} else if (message.step === AgentStep.TO_SUB_TASKS) {
|
||||
// Task planning message - each should get its own panel
|
||||
|
||||
// Skip if we've already processed this to_sub_tasks
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import {
|
|||
import { useMemo, useState, useRef, useEffect } from "react";
|
||||
import { TaskState, TaskStateType } from "@/components/TaskState";
|
||||
import useChatStoreAdapter from "@/hooks/useChatStoreAdapter";
|
||||
import { TaskStatus, ChatTaskStatus } from "@/types/constants";
|
||||
|
||||
interface TaskCardProps {
|
||||
taskInfo: any[];
|
||||
|
|
@ -87,24 +88,24 @@ export function TaskCard({
|
|||
const newFiltered = tasks.filter((task) => {
|
||||
switch (selectedState) {
|
||||
case "done":
|
||||
return task.status === "completed" && !task.reAssignTo;
|
||||
return task.status === TaskStatus.COMPLETED && !task.reAssignTo;
|
||||
case "ongoing":
|
||||
return (
|
||||
task.status !== "failed" &&
|
||||
task.status !== "completed" &&
|
||||
task.status !== "skipped" &&
|
||||
task.status !== "waiting" &&
|
||||
task.status !== ""
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.SKIPPED &&
|
||||
task.status !== TaskStatus.WAITING &&
|
||||
task.status !== TaskStatus.EMPTY
|
||||
);
|
||||
case "pending":
|
||||
return (
|
||||
(task.status === "skipped" ||
|
||||
task.status === "waiting" ||
|
||||
task.status === "") &&
|
||||
(task.status === TaskStatus.SKIPPED ||
|
||||
task.status === TaskStatus.WAITING ||
|
||||
task.status === TaskStatus.EMPTY) &&
|
||||
!task.reAssignTo
|
||||
);
|
||||
case "failed":
|
||||
return task.status === "failed";
|
||||
return task.status === TaskStatus.FAILED;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -115,7 +116,7 @@ export function TaskCard({
|
|||
|
||||
const isAllTaskFinished = useMemo(() => {
|
||||
return (
|
||||
chatStore.tasks[chatStore.activeTaskId as string].status === "finished"
|
||||
chatStore.tasks[chatStore.activeTaskId as string].status === ChatTaskStatus.FINISHED
|
||||
);
|
||||
}, [chatStore.tasks[chatStore.activeTaskId as string].status]);
|
||||
|
||||
|
|
@ -207,32 +208,32 @@ export function TaskCard({
|
|||
done={
|
||||
taskInfo.filter(
|
||||
(task) =>
|
||||
task.content !== "" && task.status === "completed"
|
||||
task.content !== "" && task.status === TaskStatus.COMPLETED
|
||||
).length || 0
|
||||
}
|
||||
progress={
|
||||
taskInfo.filter(
|
||||
(task) =>
|
||||
task.content !== "" &&
|
||||
task.status !== "completed" &&
|
||||
task.status !== "failed" &&
|
||||
task.status !== "skipped" &&
|
||||
task.status !== "waiting" &&
|
||||
task.status !== ""
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
task.status !== TaskStatus.SKIPPED &&
|
||||
task.status !== TaskStatus.WAITING &&
|
||||
task.status !== TaskStatus.EMPTY
|
||||
).length || 0
|
||||
}
|
||||
skipped={
|
||||
taskInfo.filter(
|
||||
(task) =>
|
||||
task.content !== "" &&
|
||||
(task.status === "skipped" ||
|
||||
task.status === "waiting" ||
|
||||
task.status === "")
|
||||
(task.status === TaskStatus.SKIPPED ||
|
||||
task.status === TaskStatus.WAITING ||
|
||||
task.status === TaskStatus.EMPTY)
|
||||
).length || 0
|
||||
}
|
||||
failed={
|
||||
taskInfo.filter(
|
||||
(task) => task.content !== "" && task.status === "failed"
|
||||
(task) => task.content !== "" && task.status === TaskStatus.FAILED
|
||||
).length || 0
|
||||
}
|
||||
forceVisible={true}
|
||||
|
|
@ -243,29 +244,29 @@ export function TaskCard({
|
|||
<TaskState
|
||||
all={taskRunning?.length || 0}
|
||||
done={
|
||||
taskRunning?.filter((task) => task.status === "completed")
|
||||
taskRunning?.filter((task) => task.status === TaskStatus.COMPLETED)
|
||||
.length || 0
|
||||
}
|
||||
progress={
|
||||
taskRunning?.filter(
|
||||
(task) =>
|
||||
task.status !== "completed" &&
|
||||
task.status !== "failed" &&
|
||||
task.status !== "skipped" &&
|
||||
task.status !== "waiting" &&
|
||||
task.status !== ""
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
task.status !== TaskStatus.SKIPPED &&
|
||||
task.status !== TaskStatus.WAITING &&
|
||||
task.status !== TaskStatus.EMPTY
|
||||
).length || 0
|
||||
}
|
||||
skipped={
|
||||
taskRunning?.filter(
|
||||
(task) =>
|
||||
task.status === "skipped" ||
|
||||
task.status === "waiting" ||
|
||||
task.status === ""
|
||||
task.status === TaskStatus.SKIPPED ||
|
||||
task.status === TaskStatus.WAITING ||
|
||||
task.status === TaskStatus.EMPTY
|
||||
).length || 0
|
||||
}
|
||||
failed={
|
||||
taskRunning?.filter((task) => task.status === "failed")
|
||||
taskRunning?.filter((task) => task.status === TaskStatus.FAILED)
|
||||
.length || 0
|
||||
}
|
||||
forceVisible={true}
|
||||
|
|
@ -288,8 +289,8 @@ export function TaskCard({
|
|||
<div className="text-text-tertiary text-xs font-medium leading-17">
|
||||
{taskRunning?.filter(
|
||||
(task) =>
|
||||
task.status === "completed" ||
|
||||
task.status === "failed"
|
||||
task.status === TaskStatus.COMPLETED ||
|
||||
task.status === TaskStatus.FAILED
|
||||
).length || 0}
|
||||
/{taskRunning?.length || 0}
|
||||
</div>
|
||||
|
|
@ -371,70 +372,70 @@ export function TaskCard({
|
|||
}
|
||||
}}
|
||||
key={`taskList-${task.id}`}
|
||||
className={`rounded-lg flex gap-2 py-sm px-sm transition-all duration-300 ease-in-out animate-in fade-in-0 slide-in-from-left-2 ${task.status === "completed"
|
||||
className={`rounded-lg flex gap-2 py-sm px-sm transition-all duration-300 ease-in-out animate-in fade-in-0 slide-in-from-left-2 ${task.status === TaskStatus.COMPLETED
|
||||
? "bg-task-fill-success"
|
||||
: task.status === "failed"
|
||||
: task.status === TaskStatus.FAILED
|
||||
? "bg-task-fill-error"
|
||||
: task.status === "running"
|
||||
: task.status === TaskStatus.RUNNING
|
||||
? "bg-task-fill-running"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "bg-task-fill-warning"
|
||||
: "bg-task-fill-running"
|
||||
} border border-solid border-transparent cursor-pointer ${task.status === "completed"
|
||||
} border border-solid border-transparent cursor-pointer ${task.status === TaskStatus.COMPLETED
|
||||
? "hover:border-bg-fill-success-primary"
|
||||
: task.status === "failed"
|
||||
: task.status === TaskStatus.FAILED
|
||||
? "hover:border-task-border-focus-error"
|
||||
: task.status === "running"
|
||||
: task.status === TaskStatus.RUNNING
|
||||
? "hover:border-border-primary"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "hover:border-task-border-focus-warning"
|
||||
: "border-transparent"
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="pt-0.5">
|
||||
{task.status === "running" && (
|
||||
{task.status === TaskStatus.RUNNING && (
|
||||
<LoaderCircle
|
||||
size={16}
|
||||
className={`text-icon-information ${chatStore.tasks[
|
||||
chatStore.activeTaskId as string
|
||||
].status === "running" && "animate-spin"
|
||||
].status === ChatTaskStatus.RUNNING && "animate-spin"
|
||||
} `}
|
||||
/>
|
||||
)}
|
||||
{task.status === "skipped" && (
|
||||
{task.status === TaskStatus.SKIPPED && (
|
||||
<LoaderCircle
|
||||
size={16}
|
||||
className={`text-icon-secondary `}
|
||||
/>
|
||||
)}
|
||||
{task.status === "completed" && (
|
||||
{task.status === TaskStatus.COMPLETED && (
|
||||
<CircleCheckBig
|
||||
size={16}
|
||||
className="text-icon-success"
|
||||
/>
|
||||
)}
|
||||
{task.status === "failed" && (
|
||||
{task.status === TaskStatus.FAILED && (
|
||||
<CircleSlash
|
||||
size={16}
|
||||
className="text-icon-cuation"
|
||||
/>
|
||||
)}
|
||||
{task.status === "blocked" && (
|
||||
{task.status === TaskStatus.BLOCKED && (
|
||||
<TriangleAlert
|
||||
size={16}
|
||||
className="text-icon-warning"
|
||||
/>
|
||||
)}
|
||||
{task.status === "" && (
|
||||
{task.status === TaskStatus.EMPTY && (
|
||||
<Circle size={16} className="text-icon-secondary" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col items-start justify-center">
|
||||
<div
|
||||
className={` w-full break-words whitespace-pre-line ${task.status === "failed"
|
||||
className={` w-full break-words whitespace-pre-line ${task.status === TaskStatus.FAILED
|
||||
? "text-text-cuation-default"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "text-text-body"
|
||||
: "text-text-primary"
|
||||
} text-sm font-medium leading-13 `}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { UserMessageCard } from './MessageItem/UserMessageCard';
|
|||
import { StreamingTaskList } from './TaskBox/StreamingTaskList';
|
||||
import { TaskCard } from './TaskBox/TaskCard';
|
||||
import { TypeCardSkeleton } from './TaskBox/TypeCardSkeleton';
|
||||
import { AgentStep, ChatTaskStatus } from '@/types/constants';
|
||||
|
||||
interface QueryGroup {
|
||||
queryId: string;
|
||||
|
|
@ -86,7 +87,7 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
|
|||
if (userMessageIndex > 0) {
|
||||
// Check the previous message - if it's an agent message with step 'ask', this is a human-reply
|
||||
const prevMessage = messages[userMessageIndex - 1];
|
||||
return prevMessage?.role === 'agent' && prevMessage?.step === 'ask';
|
||||
return prevMessage?.role === 'agent' && prevMessage?.step === AgentStep.ASK;
|
||||
}
|
||||
return false;
|
||||
})());
|
||||
|
|
@ -102,7 +103,7 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
|
|||
.filter((m: any) => m.role === 'user')
|
||||
.pop()?.id &&
|
||||
// Only show during active phases (not finished)
|
||||
chatState.tasks[activeTaskId].status !== 'finished';
|
||||
chatState.tasks[activeTaskId].status !== ChatTaskStatus.FINISHED;
|
||||
|
||||
// Only show the fallback task box for the newest query while the agent is still splitting work.
|
||||
// Simple Q&A sessions set hasWaitComfirm to true, so we should not render an empty task box there.
|
||||
|
|
@ -185,11 +186,11 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
|
|||
|
||||
// Check if we're in skeleton phase
|
||||
const anyToSubTasksMessage = task?.messages.find(
|
||||
(m: any) => m.step === 'to_sub_tasks'
|
||||
(m: any) => m.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
const isSkeletonPhase =
|
||||
task &&
|
||||
((task.status !== 'finished' &&
|
||||
((task.status !== ChatTaskStatus.FINISHED &&
|
||||
!anyToSubTasksMessage &&
|
||||
!task.hasWaitComfirm &&
|
||||
task.messages.length > 0) ||
|
||||
|
|
@ -282,7 +283,7 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
|
|||
{/* Other Messages */}
|
||||
{queryGroup.otherMessages.map((message) => {
|
||||
if (message.content.length > 0) {
|
||||
if (message.step === 'end') {
|
||||
if (message.step === AgentStep.END) {
|
||||
return (
|
||||
<motion.div
|
||||
key={`end-${message.id}`}
|
||||
|
|
@ -375,7 +376,7 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
|
|||
</motion.div>
|
||||
);
|
||||
}
|
||||
} else if (message.step === 'end' && message.content === '') {
|
||||
} else if (message.step === AgentStep.END && message.content === '') {
|
||||
return (
|
||||
<motion.div
|
||||
key={`end-empty-${message.id}`}
|
||||
|
|
@ -423,7 +424,7 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
|
|||
|
||||
// Notice Card
|
||||
if (
|
||||
message.step === 'notice_card' &&
|
||||
message.step === AgentStep.NOTICE_CARD &&
|
||||
!task?.isTakeControl &&
|
||||
task?.cotList &&
|
||||
task.cotList.length > 0
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
|
|||
import { toast } from 'sonner';
|
||||
import BottomBox from './BottomBox';
|
||||
import { ProjectChatContainer } from './ProjectChatContainer';
|
||||
import { AgentStep, ChatTaskStatus } from '@/types/constants';
|
||||
|
||||
export default function ChatBox(): JSX.Element {
|
||||
const [message, setMessage] = useState<string>('');
|
||||
|
|
@ -191,7 +192,7 @@ export default function ChatBox(): JSX.Element {
|
|||
if (!chatStore) return;
|
||||
const _hasSubTask = chatStore.tasks[
|
||||
chatStore.activeTaskId as string
|
||||
]?.messages?.find((message) => message.step === 'to_sub_tasks')
|
||||
]?.messages?.find((message) => message.step === AgentStep.TO_SUB_TASKS)
|
||||
? true
|
||||
: false;
|
||||
setHasSubTask(_hasSubTask);
|
||||
|
|
@ -253,12 +254,12 @@ export default function ChatBox(): JSX.Element {
|
|||
const task = chatStore.tasks[chatStore.activeTaskId];
|
||||
return (
|
||||
// running or paused
|
||||
task.status === 'running' ||
|
||||
task.status === 'pause' ||
|
||||
task.status === ChatTaskStatus.RUNNING ||
|
||||
task.status === ChatTaskStatus.PAUSE ||
|
||||
// splitting phase
|
||||
task.messages.some((m) => m.step === 'to_sub_tasks' && !m.isConfirm) ||
|
||||
task.messages.some((m) => m.step === AgentStep.TO_SUB_TASKS && !m.isConfirm) ||
|
||||
// skeleton/computing phase
|
||||
(!task.messages.find((m) => m.step === 'to_sub_tasks') &&
|
||||
(!task.messages.find((m) => m.step === AgentStep.TO_SUB_TASKS) &&
|
||||
!task.hasWaitComfirm &&
|
||||
task.messages.length > 0) ||
|
||||
task.isTakeControl
|
||||
|
|
@ -424,17 +425,17 @@ export default function ChatBox(): JSX.Element {
|
|||
const requiresHumanReply = Boolean(task?.activeAsk);
|
||||
const isTaskBusy =
|
||||
// running or paused counts as busy
|
||||
(task.status === 'running' && task.hasMessages) ||
|
||||
task.status === 'pause' ||
|
||||
(task.status === ChatTaskStatus.RUNNING && task.hasMessages) ||
|
||||
task.status === ChatTaskStatus.PAUSE ||
|
||||
// splitting phase: has to_sub_tasks not confirmed OR skeleton computing
|
||||
task.messages.some((m) => m.step === 'to_sub_tasks' && !m.isConfirm) ||
|
||||
(!task.messages.find((m) => m.step === 'to_sub_tasks') &&
|
||||
task.messages.some((m) => m.step === AgentStep.TO_SUB_TASKS && !m.isConfirm) ||
|
||||
(!task.messages.find((m) => m.step === AgentStep.TO_SUB_TASKS) &&
|
||||
!task.hasWaitComfirm &&
|
||||
task.messages.length > 0) ||
|
||||
task.isTakeControl ||
|
||||
// explicit confirm wait while task is pending but card not confirmed yet
|
||||
(!!task.messages.find((m) => m.step === 'to_sub_tasks' && !m.isConfirm) &&
|
||||
task.status === 'pending');
|
||||
(!!task.messages.find((m) => m.step === AgentStep.TO_SUB_TASKS && !m.isConfirm) &&
|
||||
task.status === ChatTaskStatus.PENDING);
|
||||
const isReplayChatStore = task?.type === 'replay';
|
||||
if (!requiresHumanReply && isTaskBusy && !isReplayChatStore) {
|
||||
toast.error(
|
||||
|
|
@ -489,7 +490,7 @@ export default function ChatBox(): JSX.Element {
|
|||
const hasMessages =
|
||||
chatStore.tasks[_taskId as string].messages.length > 0;
|
||||
const isFinished =
|
||||
chatStore.tasks[_taskId as string].status === 'finished';
|
||||
chatStore.tasks[_taskId as string].status === ChatTaskStatus.FINISHED;
|
||||
const hasWaitComfirm =
|
||||
chatStore.tasks[_taskId as string]?.hasWaitComfirm;
|
||||
|
||||
|
|
@ -497,7 +498,7 @@ export default function ChatBox(): JSX.Element {
|
|||
const wasTaskStopped =
|
||||
isFinished &&
|
||||
!chatStore.tasks[_taskId as string].messages.some(
|
||||
(m) => m.step === 'end' // Natural completion has an "end" step message
|
||||
(m) => m.step === AgentStep.END // Natural completion has an "end" step message
|
||||
);
|
||||
|
||||
// Continue conversation if:
|
||||
|
|
@ -508,16 +509,16 @@ export default function ChatBox(): JSX.Element {
|
|||
(hasWaitComfirm && !wasTaskStopped) ||
|
||||
(isFinished && !wasTaskStopped) ||
|
||||
(hasMessages &&
|
||||
chatStore.tasks[_taskId as string].status === 'pending');
|
||||
chatStore.tasks[_taskId as string].status === ChatTaskStatus.PENDING);
|
||||
|
||||
if (shouldContinueConversation) {
|
||||
// Check if this is the very first message and task hasn't started
|
||||
const hasSimpleResponse = chatStore.tasks[
|
||||
_taskId as string
|
||||
].messages.some((m) => m.step === 'wait_confirm');
|
||||
].messages.some((m) => m.step === AgentStep.WAIT_CONFIRM);
|
||||
const hasComplexTask = chatStore.tasks[
|
||||
_taskId as string
|
||||
].messages.some((m) => m.step === 'to_sub_tasks');
|
||||
].messages.some((m) => m.step === AgentStep.TO_SUB_TASKS);
|
||||
const hasErrorMessage = chatStore.tasks[
|
||||
_taskId as string
|
||||
].messages.some(
|
||||
|
|
@ -527,7 +528,7 @@ export default function ChatBox(): JSX.Element {
|
|||
// Only start a new task if: pending, no messages processed yet
|
||||
// OR while or after replaying a project
|
||||
if (
|
||||
(chatStore.tasks[_taskId as string].status === 'pending' &&
|
||||
(chatStore.tasks[_taskId as string].status === ChatTaskStatus.PENDING &&
|
||||
!hasSimpleResponse &&
|
||||
!hasComplexTask &&
|
||||
!isFinished) ||
|
||||
|
|
@ -692,7 +693,7 @@ export default function ChatBox(): JSX.Element {
|
|||
const handlePauseResume = () => {
|
||||
const taskId = chatStore.activeTaskId as string;
|
||||
const task = chatStore.tasks[taskId];
|
||||
const type = task.status === 'running' ? 'pause' : 'resume';
|
||||
const type = task.status === ChatTaskStatus.RUNNING ? 'pause' : 'resume';
|
||||
|
||||
setIsPauseResumeLoading(true);
|
||||
if (type === 'pause') {
|
||||
|
|
@ -701,10 +702,10 @@ export default function ChatBox(): JSX.Element {
|
|||
elapsed += now - taskTime;
|
||||
chatStore.setElapsed(taskId, elapsed);
|
||||
chatStore.setTaskTime(taskId, 0);
|
||||
chatStore.setStatus(taskId, 'pause');
|
||||
chatStore.setStatus(taskId, ChatTaskStatus.PAUSE);
|
||||
} else {
|
||||
chatStore.setTaskTime(taskId, Date.now());
|
||||
chatStore.setStatus(taskId, 'running');
|
||||
chatStore.setStatus(taskId, ChatTaskStatus.RUNNING);
|
||||
}
|
||||
|
||||
fetchPut(`/task/${projectStore.activeProjectId}/take-control`, {
|
||||
|
|
@ -802,7 +803,7 @@ export default function ChatBox(): JSX.Element {
|
|||
|
||||
// Get question and attachments before any deletions
|
||||
const messageIndex = chatStore.tasks[taskId].messages.findLastIndex(
|
||||
(item) => item.step === 'to_sub_tasks'
|
||||
(item) => item.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
const questionMessage = chatStore.tasks[taskId].messages[messageIndex - 2];
|
||||
const question = questionMessage.content;
|
||||
|
|
@ -856,16 +857,16 @@ export default function ChatBox(): JSX.Element {
|
|||
|
||||
// Check for any to_sub_tasks message (confirmed or not)
|
||||
const anyToSubTasksMessage = task.messages.find(
|
||||
(m) => m.step === 'to_sub_tasks'
|
||||
(m) => m.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
const toSubTasksMessage = task.messages.find(
|
||||
(m) => m.step === 'to_sub_tasks' && !m.isConfirm
|
||||
(m) => m.step === AgentStep.TO_SUB_TASKS && !m.isConfirm
|
||||
);
|
||||
|
||||
// Determine if we're in the "splitting in progress" phase (skeleton visible)
|
||||
// Only show splitting if there's NO to_sub_tasks message yet (not even confirmed)
|
||||
const isSkeletonPhase =
|
||||
(task.status !== 'finished' &&
|
||||
(task.status !== ChatTaskStatus.FINISHED &&
|
||||
!anyToSubTasksMessage &&
|
||||
!task.hasWaitComfirm &&
|
||||
task.messages.length > 0) ||
|
||||
|
|
@ -879,7 +880,7 @@ export default function ChatBox(): JSX.Element {
|
|||
if (
|
||||
toSubTasksMessage &&
|
||||
!toSubTasksMessage.isConfirm &&
|
||||
task.status === 'pending'
|
||||
task.status === ChatTaskStatus.PENDING
|
||||
) {
|
||||
return 'confirm';
|
||||
}
|
||||
|
|
@ -890,11 +891,11 @@ export default function ChatBox(): JSX.Element {
|
|||
}
|
||||
|
||||
// Check task status
|
||||
if (task.status === 'running' || task.status === 'pause') {
|
||||
if (task.status === ChatTaskStatus.RUNNING || task.status === ChatTaskStatus.PAUSE) {
|
||||
return 'running';
|
||||
}
|
||||
|
||||
if (task.status === 'finished' && task.type !== '') {
|
||||
if (task.status === ChatTaskStatus.FINISHED && task.type !== '') {
|
||||
return 'finished';
|
||||
}
|
||||
|
||||
|
|
@ -938,7 +939,7 @@ export default function ChatBox(): JSX.Element {
|
|||
// Note: Replay creates a new chatstore, so no conflicts
|
||||
const task = chatStore.tasks[chatStore.activeTaskId as string];
|
||||
// Only skip backend call if task is finished or hasn't started yet (no messages)
|
||||
if (task && task.messages.length > 0 && task.status !== 'finished') {
|
||||
if (task && task.messages.length > 0 && task.status !== ChatTaskStatus.FINISHED) {
|
||||
try {
|
||||
await fetchDelete(`/chat/${project_id}/remove-task/${task_id}`, {
|
||||
project_id: project_id,
|
||||
|
|
@ -1010,7 +1011,7 @@ export default function ChatBox(): JSX.Element {
|
|||
taskStatus={chatStore.tasks[chatStore.activeTaskId]?.status}
|
||||
onReplay={handleReplay}
|
||||
replayDisabled={
|
||||
chatStore.tasks[chatStore.activeTaskId]?.status !== 'finished'
|
||||
chatStore.tasks[chatStore.activeTaskId]?.status !== ChatTaskStatus.FINISHED
|
||||
}
|
||||
replayLoading={isReplayLoading}
|
||||
onPauseResume={handlePauseResume}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import useChatStoreAdapter from '@/hooks/useChatStoreAdapter';
|
|||
import { replayProject } from '@/lib/replay';
|
||||
import { useProjectStore } from '@/store/projectStore';
|
||||
import { ProjectGroup as ProjectGroupType } from '@/types/history';
|
||||
import { ChatTaskStatus } from "@/types/constants";
|
||||
import { motion } from 'framer-motion';
|
||||
import {
|
||||
Edit,
|
||||
|
|
@ -100,7 +101,7 @@ export default function ProjectGroup({
|
|||
// Check if any task in chatStore with matching task_id has pending status
|
||||
return Object.entries(chatStore.tasks).some(
|
||||
([taskId, task]) =>
|
||||
projectTaskIds.includes(taskId) && task.status === 'pending'
|
||||
projectTaskIds.includes(taskId) && task.status === ChatTaskStatus.PENDING
|
||||
);
|
||||
}, [chatStore?.tasks, project.tasks]);
|
||||
const _hasIssue = hasHumanInLoop;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
import { Tag } from '@/components/ui/tag';
|
||||
import { TooltipSimple } from '@/components/ui/tooltip';
|
||||
import { HistoryTask } from '@/types/history';
|
||||
import { ChatTaskStatus } from '@/types/constants';
|
||||
import {
|
||||
CheckCircle,
|
||||
CirclePause,
|
||||
|
|
@ -63,7 +64,7 @@ export default function TaskItem({
|
|||
const { t } = useTranslation();
|
||||
|
||||
// Check if task is paused (for ongoing tasks)
|
||||
const isPaused = (task as any)._taskData?.status === 'pause';
|
||||
const isPaused = (task as any)._taskData?.status === ChatTaskStatus.PAUSE;
|
||||
|
||||
const getStatusTag = (status: number) => {
|
||||
// ChatStatus enum: ongoing = 1, done = 2
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import {
|
|||
import { Tag } from '../ui/tag';
|
||||
import { TooltipSimple } from '../ui/tooltip';
|
||||
import SearchInput from './SearchInput';
|
||||
import { ChatTaskStatus } from "@/types/constants";
|
||||
|
||||
export default function HistorySidebar() {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -90,7 +91,7 @@ export default function HistorySidebar() {
|
|||
Object.keys(csState.tasks || {}).forEach((taskId) => {
|
||||
const task = csState.tasks[taskId];
|
||||
// Only include ongoing tasks
|
||||
if (task.status !== 'finished' && !task.type) {
|
||||
if (task.status !== ChatTaskStatus.FINISHED && !task.type) {
|
||||
hasOngoingTasks = true;
|
||||
taskCount++;
|
||||
if (task.tokens) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { toast } from 'sonner';
|
||||
import { ChatTaskStatus } from '@/types/constants';
|
||||
|
||||
function HeaderWin() {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -144,7 +145,7 @@ function HeaderWin() {
|
|||
const task = chatStore.tasks[taskId];
|
||||
|
||||
// Stop the task if it's running
|
||||
if (task && task.status === 'running') {
|
||||
if (task && task.status === ChatTaskStatus.RUNNING) {
|
||||
await fetchPut(`/task/${taskId}/take-control`, {
|
||||
action: 'stop',
|
||||
});
|
||||
|
|
@ -158,7 +159,7 @@ function HeaderWin() {
|
|||
}
|
||||
|
||||
// Delete from history using historyId
|
||||
if (historyId && task.status !== 'finished') {
|
||||
if (historyId && task.status !== ChatTaskStatus.FINISHED) {
|
||||
try {
|
||||
await proxyFetchDelete(`/api/chat/history/${historyId}`);
|
||||
// Remove from local store
|
||||
|
|
@ -333,7 +334,7 @@ function HeaderWin() {
|
|||
chatStore.tasks[chatStore.activeTaskId as string]
|
||||
?.hasMessages ||
|
||||
chatStore.tasks[chatStore.activeTaskId as string]?.status !==
|
||||
'pending') && (
|
||||
ChatTaskStatus.PENDING) && (
|
||||
<TooltipSimple
|
||||
content={t('layout.end-project')}
|
||||
side="bottom"
|
||||
|
|
@ -352,7 +353,7 @@ function HeaderWin() {
|
|||
)}
|
||||
{chatStore.activeTaskId &&
|
||||
chatStore.tasks[chatStore.activeTaskId as string]?.status ===
|
||||
'finished' && (
|
||||
ChatTaskStatus.FINISHED && (
|
||||
<TooltipSimple
|
||||
content={t('layout.share')}
|
||||
side="bottom"
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import {
|
|||
} from "../ui/popover";
|
||||
import { AddWorker } from "@/components/AddWorker";
|
||||
import useChatStoreAdapter from "@/hooks/useChatStoreAdapter";
|
||||
import { TaskStatus, ChatTaskStatus, AgentStatusValue } from "@/types/constants";
|
||||
|
||||
interface NodeProps {
|
||||
id: string;
|
||||
|
|
@ -84,27 +85,27 @@ export function Node({ id, data }: NodeProps) {
|
|||
const newFiltered = tasks.filter((task) => {
|
||||
switch (selectedState) {
|
||||
case "done":
|
||||
return task.status === "completed" && !task.reAssignTo;
|
||||
return task.status === TaskStatus.COMPLETED && !task.reAssignTo;
|
||||
case "reassigned":
|
||||
return !!task.reAssignTo;
|
||||
case "ongoing":
|
||||
return (
|
||||
task.status !== "failed" &&
|
||||
task.status !== "completed" &&
|
||||
task.status !== "skipped" &&
|
||||
task.status !== "waiting" &&
|
||||
task.status !== "" &&
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.SKIPPED &&
|
||||
task.status !== TaskStatus.WAITING &&
|
||||
task.status !== TaskStatus.EMPTY &&
|
||||
!task.reAssignTo
|
||||
);
|
||||
case "pending":
|
||||
return (
|
||||
(task.status === "skipped" ||
|
||||
task.status === "waiting" ||
|
||||
task.status === "") &&
|
||||
(task.status === TaskStatus.SKIPPED ||
|
||||
task.status === TaskStatus.WAITING ||
|
||||
task.status === TaskStatus.EMPTY) &&
|
||||
!task.reAssignTo
|
||||
);
|
||||
case "failed":
|
||||
return task.status === "failed";
|
||||
return task.status === TaskStatus.FAILED;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -136,13 +137,13 @@ export function Node({ id, data }: NodeProps) {
|
|||
// Find running task with active toolkits
|
||||
const runningTaskWithToolkits = tasks.find(
|
||||
(task) =>
|
||||
task.status === "running" &&
|
||||
task.status === TaskStatus.RUNNING &&
|
||||
task.toolkits &&
|
||||
task.toolkits.length > 0
|
||||
);
|
||||
|
||||
// Reset tracking when no tasks are running
|
||||
const hasRunningTasks = tasks.some((task) => task.status === "running");
|
||||
const hasRunningTasks = tasks.some((task) => task.status === TaskStatus.RUNNING);
|
||||
if (!hasRunningTasks && lastAutoExpandedTaskIdRef.current) {
|
||||
lastAutoExpandedTaskIdRef.current = null;
|
||||
}
|
||||
|
|
@ -164,8 +165,8 @@ export function Node({ id, data }: NodeProps) {
|
|||
data.agent?.tasks,
|
||||
// Add specific dependencies that actually change
|
||||
data.agent?.tasks?.length,
|
||||
data.agent?.tasks?.find((t) => t.status === "running")?.id,
|
||||
data.agent?.tasks?.find((t) => t.status === "running")?.toolkits?.length,
|
||||
data.agent?.tasks?.find((t) => t.status === TaskStatus.RUNNING)?.id,
|
||||
data.agent?.tasks?.find((t) => t.status === TaskStatus.RUNNING)?.toolkits?.length,
|
||||
id,
|
||||
data.onExpandChange,
|
||||
isExpanded,
|
||||
|
|
@ -198,7 +199,7 @@ export function Node({ id, data }: NodeProps) {
|
|||
const handleShowLog = () => {
|
||||
if (!isExpanded) {
|
||||
setSelectedTask(
|
||||
data.agent?.tasks.find((task) => task.status === "running") ||
|
||||
data.agent?.tasks.find((task) => task.status === TaskStatus.RUNNING) ||
|
||||
data.agent?.tasks[0]
|
||||
);
|
||||
}
|
||||
|
|
@ -318,7 +319,7 @@ export function Node({ id, data }: NodeProps) {
|
|||
borderColor: "border-bg-fill-multimodal-active",
|
||||
bgColorLight: "bg-fuchsia-200",
|
||||
},
|
||||
social_medium_agent: {
|
||||
social_media_agent: {
|
||||
name: "Social Media Agent",
|
||||
icon: <Bird size={16} className="text-text-primary" />,
|
||||
textColor: "text-purple-700",
|
||||
|
|
@ -549,7 +550,7 @@ export function Node({ id, data }: NodeProps) {
|
|||
all={data.agent.tasks?.length || 0}
|
||||
done={
|
||||
data.agent?.tasks?.filter(
|
||||
(task) => task.status === "completed" && !task.reAssignTo
|
||||
(task) => task.status === TaskStatus.COMPLETED && !task.reAssignTo
|
||||
).length || 0
|
||||
}
|
||||
reAssignTo={
|
||||
|
|
@ -559,26 +560,26 @@ export function Node({ id, data }: NodeProps) {
|
|||
progress={
|
||||
data.agent?.tasks?.filter(
|
||||
(task) =>
|
||||
task.status !== "failed" &&
|
||||
task.status !== "completed" &&
|
||||
task.status !== "skipped" &&
|
||||
task.status !== "waiting" &&
|
||||
task.status !== "" &&
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.SKIPPED &&
|
||||
task.status !== TaskStatus.WAITING &&
|
||||
task.status !== TaskStatus.EMPTY &&
|
||||
!task.reAssignTo
|
||||
).length || 0
|
||||
}
|
||||
skipped={
|
||||
data.agent?.tasks?.filter(
|
||||
(task) =>
|
||||
(task.status === "skipped" ||
|
||||
task.status === "waiting" ||
|
||||
task.status === "") &&
|
||||
(task.status === TaskStatus.SKIPPED ||
|
||||
task.status === TaskStatus.WAITING ||
|
||||
task.status === TaskStatus.EMPTY) &&
|
||||
!task.reAssignTo
|
||||
).length || 0
|
||||
}
|
||||
failed={
|
||||
data.agent?.tasks?.filter(
|
||||
(task) => task.status === "failed"
|
||||
(task) => task.status === TaskStatus.FAILED
|
||||
).length || 0
|
||||
}
|
||||
selectedState={selectedState}
|
||||
|
|
@ -625,32 +626,32 @@ export function Node({ id, data }: NodeProps) {
|
|||
key={`taskList-${task.id}-${task.failure_count}`}
|
||||
className={`rounded-lg flex gap-2 py-sm px-sm transition-all duration-300 ease-in-out animate-in fade-in-0 slide-in-from-left-2 ${task.reAssignTo
|
||||
? "bg-task-fill-warning"
|
||||
: task.status === "completed"
|
||||
: task.status === TaskStatus.COMPLETED
|
||||
? "bg-task-fill-success"
|
||||
: task.status === "failed"
|
||||
: task.status === TaskStatus.FAILED
|
||||
? "bg-task-fill-error"
|
||||
: task.status === "running"
|
||||
: task.status === TaskStatus.RUNNING
|
||||
? "bg-task-fill-running"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "bg-task-fill-warning"
|
||||
: "bg-task-fill-running"
|
||||
} border border-solid border-transparent cursor-pointer ${task.status === "completed"
|
||||
} border border-solid border-transparent cursor-pointer ${task.status === TaskStatus.COMPLETED
|
||||
? "hover:border-bg-fill-success-primary"
|
||||
: task.status === "failed"
|
||||
: task.status === TaskStatus.FAILED
|
||||
? "hover:border-task-border-focus-error"
|
||||
: task.status === "running"
|
||||
: task.status === TaskStatus.RUNNING
|
||||
? "hover:border-border-primary"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "hover:border-task-border-focus-warning"
|
||||
: "border-transparent"
|
||||
} ${selectedTask?.id === task.id
|
||||
? task.status === "completed"
|
||||
? task.status === TaskStatus.COMPLETED
|
||||
? "!border-bg-fill-success-primary"
|
||||
: task.status === "failed"
|
||||
: task.status === TaskStatus.FAILED
|
||||
? "!border-text-cuation-primary"
|
||||
: task.status === "running"
|
||||
: task.status === TaskStatus.RUNNING
|
||||
? "!border-border-primary"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "!border-text-warning-primary"
|
||||
: "border-transparent"
|
||||
: "border-transparent"
|
||||
|
|
@ -663,41 +664,41 @@ export function Node({ id, data }: NodeProps) {
|
|||
) : (
|
||||
// normal task
|
||||
<>
|
||||
{task.status === "running" && (
|
||||
{task.status === TaskStatus.RUNNING && (
|
||||
<LoaderCircle
|
||||
size={16}
|
||||
className={`text-icon-information ${chatStore.tasks[
|
||||
chatStore.activeTaskId as string
|
||||
].status === "running" && "animate-spin"
|
||||
].status === ChatTaskStatus.RUNNING && "animate-spin"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
{task.status === "skipped" && (
|
||||
{task.status === TaskStatus.SKIPPED && (
|
||||
<LoaderCircle
|
||||
size={16}
|
||||
className={`text-icon-secondary `}
|
||||
/>
|
||||
)}
|
||||
{task.status === "completed" && (
|
||||
{task.status === TaskStatus.COMPLETED && (
|
||||
<CircleCheckBig
|
||||
size={16}
|
||||
className="text-icon-success"
|
||||
/>
|
||||
)}
|
||||
{task.status === "failed" && (
|
||||
{task.status === TaskStatus.FAILED && (
|
||||
<CircleSlash
|
||||
size={16}
|
||||
className="text-icon-cuation"
|
||||
/>
|
||||
)}
|
||||
{task.status === "blocked" && (
|
||||
{task.status === TaskStatus.BLOCKED && (
|
||||
<TriangleAlert
|
||||
size={16}
|
||||
className="text-icon-warning"
|
||||
/>
|
||||
)}
|
||||
{(task.status === "" ||
|
||||
task.status === "waiting") && (
|
||||
{(task.status === TaskStatus.EMPTY ||
|
||||
task.status === TaskStatus.WAITING) && (
|
||||
<Circle size={16} className="text-slate-400" />
|
||||
)}
|
||||
</>
|
||||
|
|
@ -705,9 +706,9 @@ export function Node({ id, data }: NodeProps) {
|
|||
</div>
|
||||
<div className="flex-1 flex flex-col items-start justify-center">
|
||||
<div
|
||||
className={`w-full flex-grow-0 ${task.status === "failed"
|
||||
className={`w-full flex-grow-0 ${task.status === TaskStatus.FAILED
|
||||
? "text-text-cuation-default"
|
||||
: task.status === "blocked"
|
||||
: task.status === TaskStatus.BLOCKED
|
||||
? "text-text-body"
|
||||
: "text-text-primary"
|
||||
} text-xs font-medium leading-13 select-text pointer-events-auto break-all text-wrap whitespace-pre-line`}
|
||||
|
|
@ -723,9 +724,9 @@ export function Node({ id, data }: NodeProps) {
|
|||
) : (
|
||||
(task.failure_count ?? 0) > 0 && (
|
||||
<div
|
||||
className={`${task.status === "failed"
|
||||
className={`${task.status === TaskStatus.FAILED
|
||||
? "bg-surface-error-subtle text-text-cuation"
|
||||
: task.status === "completed"
|
||||
: task.status === TaskStatus.COMPLETED
|
||||
? "bg-tag-fill-developer text-text-success-default"
|
||||
: "bg-tag-surface-hover text-text-label"
|
||||
} text-xs font-bold leading-none rounded-lg px-1 py-0.5`}
|
||||
|
|
@ -737,7 +738,7 @@ export function Node({ id, data }: NodeProps) {
|
|||
</div>
|
||||
<div>{task.content}</div>
|
||||
</div>
|
||||
{task?.status === "running" && (
|
||||
{task?.status === TaskStatus.RUNNING && (
|
||||
<div className="flex items-center gap-2 mt-xs animate-in fade-in-0 slide-in-from-bottom-2 duration-400">
|
||||
{/* active toolkit */}
|
||||
{task.toolkits &&
|
||||
|
|
@ -746,7 +747,7 @@ export function Node({ id, data }: NodeProps) {
|
|||
.filter(
|
||||
(tool: any) => tool.toolkitName !== "notice"
|
||||
)
|
||||
.at(-1)?.toolkitStatus === "running" && (
|
||||
.at(-1)?.toolkitStatus === AgentStatusValue.RUNNING && (
|
||||
<div className="flex-1 min-w-0 flex justify-start items-center gap-sm animate-in fade-in-0 slide-in-from-right-2 duration-300">
|
||||
{agentMap[data.type]?.icon ?? (
|
||||
<Bot className="w-3 h-3" />
|
||||
|
|
@ -830,12 +831,12 @@ export function Node({ id, data }: NodeProps) {
|
|||
>
|
||||
{/* {toolkit.toolkitStatus} */}
|
||||
<div>
|
||||
{toolkit.toolkitStatus === "running" ? (
|
||||
{toolkit.toolkitStatus === AgentStatusValue.RUNNING ? (
|
||||
<LoaderCircle
|
||||
size={16}
|
||||
className={`${chatStore.tasks[
|
||||
chatStore.activeTaskId as string
|
||||
].status === "running" && "animate-spin"
|
||||
].status === ChatTaskStatus.RUNNING && "animate-spin"
|
||||
}`}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { Bird, CodeXml, FileText, Globe, Image } from 'lucide-react';
|
|||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ChatTaskStatus } from '@/types/constants';
|
||||
|
||||
export default function Project() {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -214,9 +215,9 @@ export default function Project() {
|
|||
action: type,
|
||||
});
|
||||
if (type === 'pause') {
|
||||
chatStore.setStatus(taskId, 'pause');
|
||||
chatStore.setStatus(taskId, ChatTaskStatus.PAUSE);
|
||||
} else {
|
||||
chatStore.setStatus(taskId, 'running');
|
||||
chatStore.setStatus(taskId, ChatTaskStatus.RUNNING);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// limitations under the License.
|
||||
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
|
||||
import { ChatTaskStatus } from "@/types/constants";
|
||||
import ChatBox from "@/components/ChatBox";
|
||||
import Workflow from "@/components/WorkFlow";
|
||||
import Folder from "@/components/Folder";
|
||||
|
|
@ -88,7 +89,7 @@ export default function Home() {
|
|||
// capture webview
|
||||
const captureWebview = async () => {
|
||||
const activeTask = chatStore.tasks[chatStore.activeTaskId as string];
|
||||
if (!activeTask || activeTask.status === "finished") {
|
||||
if (!activeTask || activeTask.status === ChatTaskStatus.FINISHED) {
|
||||
return;
|
||||
}
|
||||
webviews.map((webview) => {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@ import {
|
|||
import { showCreditsToast } from '@/components/Toast/creditsToast';
|
||||
import { showStorageToast } from '@/components/Toast/storageToast';
|
||||
import { generateUniqueId, uploadLog } from '@/lib';
|
||||
import {
|
||||
AgentMessageStatus,
|
||||
AgentStatusValue,
|
||||
AgentStep,
|
||||
ChatTaskStatus,
|
||||
TaskStatus,
|
||||
type ChatTaskStatusType,
|
||||
} from '@/types/constants';
|
||||
import { fetchEventSource } from '@microsoft/fetch-event-source';
|
||||
import { FileText } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
|
|
@ -50,7 +58,7 @@ interface Task {
|
|||
activeWorkSpace: string | null;
|
||||
hasMessages: boolean;
|
||||
activeAgent: string;
|
||||
status: 'running' | 'finished' | 'pending' | 'pause';
|
||||
status: ChatTaskStatusType;
|
||||
taskTime: number;
|
||||
elapsed: number;
|
||||
tokens: number;
|
||||
|
|
@ -77,10 +85,7 @@ export interface ChatStore {
|
|||
create: (id?: string, type?: any) => string;
|
||||
removeTask: (taskId: string) => void;
|
||||
stopTask: (taskId: string) => void;
|
||||
setStatus: (
|
||||
taskId: string,
|
||||
status: 'running' | 'finished' | 'pending' | 'pause'
|
||||
) => void;
|
||||
setStatus: (taskId: string, status: ChatTaskStatusType) => void;
|
||||
setActiveTaskId: (taskId: string) => void;
|
||||
replay: (taskId: string, question: string, time: number) => Promise<void>;
|
||||
startTask: (
|
||||
|
|
@ -251,7 +256,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
activeWorkSpace: 'workflow',
|
||||
hasMessages: false,
|
||||
activeAgent: '',
|
||||
status: 'pending',
|
||||
status: ChatTaskStatus.PENDING,
|
||||
taskTime: 0,
|
||||
tokens: 0,
|
||||
elapsed: 0,
|
||||
|
|
@ -275,7 +280,9 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
const { tasks, setProgressValue, activeTaskId } = get();
|
||||
const taskRunning = [...tasks[taskId].taskRunning];
|
||||
const finishedTask = taskRunning?.filter(
|
||||
(task) => task.status === 'completed' || task.status === 'failed'
|
||||
(task) =>
|
||||
task.status === TaskStatus.COMPLETED ||
|
||||
task.status === TaskStatus.FAILED
|
||||
).length;
|
||||
const taskProgress = (
|
||||
((finishedTask || 0) / (taskRunning?.length || 0)) *
|
||||
|
|
@ -380,7 +387,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
...state.tasks,
|
||||
[taskId]: {
|
||||
...state.tasks[taskId],
|
||||
status: 'finished',
|
||||
status: ChatTaskStatus.FINISHED,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -752,11 +759,12 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// - Task switching: confirmed, new_task_state, end
|
||||
// - Multi-turn simple answer: wait_confirm
|
||||
const isTaskSwitchingEvent =
|
||||
agentMessages.step === 'confirmed' ||
|
||||
agentMessages.step === 'new_task_state' ||
|
||||
agentMessages.step === 'end';
|
||||
agentMessages.step === AgentStep.CONFIRMED ||
|
||||
agentMessages.step === AgentStep.NEW_TASK_STATE ||
|
||||
agentMessages.step === AgentStep.END;
|
||||
|
||||
const isMultiTurnSimpleAnswer = agentMessages.step === 'wait_confirm';
|
||||
const isMultiTurnSimpleAnswer =
|
||||
agentMessages.step === AgentStep.WAIT_CONFIRM;
|
||||
|
||||
if (!currentTask) {
|
||||
console.log(
|
||||
|
|
@ -766,7 +774,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
}
|
||||
|
||||
if (
|
||||
currentTask.status === 'finished' &&
|
||||
currentTask.status === ChatTaskStatus.FINISHED &&
|
||||
!isTaskSwitchingEvent &&
|
||||
!isMultiTurnSimpleAnswer
|
||||
) {
|
||||
|
|
@ -795,7 +803,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
*/
|
||||
let currentTaskId = getCurrentTaskId();
|
||||
const previousChatStore = getCurrentChatStore();
|
||||
if (agentMessages.step === 'confirmed') {
|
||||
if (agentMessages.step === AgentStep.CONFIRMED) {
|
||||
const { question } = agentMessages.data;
|
||||
const shouldCreateNewChat =
|
||||
project_id && (question || messageContent);
|
||||
|
|
@ -890,7 +898,10 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
} else {
|
||||
//NOTE: Triggered only with first "confirmed" in the project
|
||||
//Handle Original cases - with old chatStore
|
||||
previousChatStore.setStatus(currentTaskId, 'pending');
|
||||
previousChatStore.setStatus(
|
||||
currentTaskId,
|
||||
ChatTaskStatus.PENDING
|
||||
);
|
||||
previousChatStore.setHasWaitComfirm(currentTaskId, false);
|
||||
}
|
||||
|
||||
|
|
@ -940,8 +951,8 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
} = getCurrentChatStore();
|
||||
|
||||
currentTaskId = getCurrentTaskId();
|
||||
// if (tasks[currentTaskId].status === 'finished') return
|
||||
if (agentMessages.step === 'decompose_text') {
|
||||
// if (tasks[currentTaskId].status === ChatTaskStatus.FINISHED) return
|
||||
if (agentMessages.step === AgentStep.DECOMPOSE_TEXT) {
|
||||
const { content } = agentMessages.data;
|
||||
const text = content;
|
||||
const currentId = getCurrentTaskId();
|
||||
|
|
@ -992,7 +1003,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
|
||||
if (agentMessages.step === 'to_sub_tasks') {
|
||||
if (agentMessages.step === AgentStep.TO_SUB_TASKS) {
|
||||
// Clear streaming decompose text when task splitting is done
|
||||
clearStreamingDecomposeText(currentTaskId);
|
||||
// Clean up TTFT tracking
|
||||
|
|
@ -1001,18 +1012,20 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// Check if task is already confirmed - don't overwrite user edits
|
||||
const existingToSubTasksMessage = tasks[
|
||||
currentTaskId
|
||||
].messages.findLast((m: Message) => m.step === 'to_sub_tasks');
|
||||
].messages.findLast(
|
||||
(m: Message) => m.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
if (existingToSubTasksMessage?.isConfirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a multi-turn scenario after task completion
|
||||
const isMultiTurnAfterCompletion =
|
||||
tasks[currentTaskId].status === 'finished';
|
||||
tasks[currentTaskId].status === ChatTaskStatus.FINISHED;
|
||||
|
||||
// Reset status for multi-turn complex tasks to allow splitting panel to show
|
||||
if (isMultiTurnAfterCompletion) {
|
||||
setStatus(currentTaskId, 'pending');
|
||||
setStatus(currentTaskId, ChatTaskStatus.PENDING);
|
||||
}
|
||||
|
||||
// Each splitting round starts in a clean editing state
|
||||
|
|
@ -1020,7 +1033,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
|
||||
const messages = [...tasks[currentTaskId].messages];
|
||||
const toSubTaskIndex = messages.findLastIndex(
|
||||
(message: Message) => message.step === 'to_sub_tasks'
|
||||
(message: Message) => message.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
// For multi-turn scenarios, always create a new to_sub_tasks message
|
||||
// even if one already exists from a previous task
|
||||
|
|
@ -1044,7 +1057,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
const { tasks, handleConfirmTask, setIsTaskEdit } =
|
||||
currentStore;
|
||||
const message = tasks[currentId].messages.findLast(
|
||||
(item) => item.step === 'to_sub_tasks'
|
||||
(item) => item.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
const isConfirm = message?.isConfirm || false;
|
||||
const isTakeControl = tasks[currentId].isTakeControl;
|
||||
|
|
@ -1076,7 +1089,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
id: generateUniqueId(),
|
||||
role: 'agent',
|
||||
content: '',
|
||||
step: 'notice_card',
|
||||
step: AgentStep.NOTICE_CARD,
|
||||
};
|
||||
addMessages(currentTaskId, newNoticeMessage);
|
||||
const shouldAutoConfirm = !!type && !isMultiTurnAfterCompletion;
|
||||
|
|
@ -1102,7 +1115,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
}
|
||||
agentMessages.data.sub_tasks = agentMessages.data.sub_tasks?.map(
|
||||
(item) => {
|
||||
item.status = '';
|
||||
item.status = TaskStatus.EMPTY;
|
||||
return item;
|
||||
}
|
||||
);
|
||||
|
|
@ -1132,7 +1145,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
// Create agent
|
||||
if (agentMessages.step === 'create_agent') {
|
||||
if (agentMessages.step === AgentStep.CREATE_AGENT) {
|
||||
const { agent_name, agent_id } = agentMessages.data;
|
||||
if (!agent_name || !agent_id) return;
|
||||
|
||||
|
|
@ -1188,7 +1201,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (agentMessages.step === 'wait_confirm') {
|
||||
if (agentMessages.step === AgentStep.WAIT_CONFIRM) {
|
||||
const { content, question } = agentMessages.data;
|
||||
setHasWaitComfirm(currentTaskId, true);
|
||||
setIsPending(currentTaskId, false);
|
||||
|
|
@ -1213,7 +1226,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
id: generateUniqueId(),
|
||||
role: 'user',
|
||||
content: question as string,
|
||||
step: 'wait_confirm',
|
||||
step: AgentStep.WAIT_CONFIRM,
|
||||
isConfirm: false,
|
||||
});
|
||||
}
|
||||
|
|
@ -1221,13 +1234,13 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
id: generateUniqueId(),
|
||||
role: 'agent',
|
||||
content: content as string,
|
||||
step: 'wait_confirm',
|
||||
step: AgentStep.WAIT_CONFIRM,
|
||||
isConfirm: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Task State
|
||||
if (agentMessages.step === 'task_state') {
|
||||
if (agentMessages.step === AgentStep.TASK_STATE) {
|
||||
const { state, task_id, result, failure_count } =
|
||||
agentMessages.data;
|
||||
if (!state && !task_id) return;
|
||||
|
|
@ -1247,7 +1260,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
targetTaskAssigningIndex
|
||||
].tasks.findIndex((task: TaskInfo) => task.id === task_id);
|
||||
taskAssigning[targetTaskAssigningIndex].tasks[taskIndex].status =
|
||||
state === 'DONE' ? 'completed' : 'failed';
|
||||
state === 'DONE' ? TaskStatus.COMPLETED : TaskStatus.FAILED;
|
||||
taskAssigning[targetTaskAssigningIndex].tasks[
|
||||
taskIndex
|
||||
].failure_count = failure_count || 0;
|
||||
|
|
@ -1288,7 +1301,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
id: generateUniqueId(),
|
||||
role: 'agent',
|
||||
content: targetResult,
|
||||
step: 'failed',
|
||||
step: AgentStep.FAILED,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1296,7 +1309,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
if (targetTaskIndex !== -1) {
|
||||
console.log('targetTaskIndex', targetTaskIndex, state);
|
||||
taskRunning[targetTaskIndex].status =
|
||||
state === 'DONE' ? 'completed' : 'failed';
|
||||
state === 'DONE' ? TaskStatus.COMPLETED : TaskStatus.FAILED;
|
||||
}
|
||||
setTaskRunning(currentTaskId, taskRunning);
|
||||
setTaskAssigning(currentTaskId, taskAssigning);
|
||||
|
|
@ -1306,7 +1319,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
* @deprecated
|
||||
* Side effect handled on top of the message handler
|
||||
*/
|
||||
if (agentMessages.step === 'new_task_state') {
|
||||
if (agentMessages.step === AgentStep.NEW_TASK_STATE) {
|
||||
const {
|
||||
task_id,
|
||||
content,
|
||||
|
|
@ -1323,8 +1336,8 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
|
||||
// Activate agent
|
||||
if (
|
||||
agentMessages.step === 'activate_agent' ||
|
||||
agentMessages.step === 'deactivate_agent'
|
||||
agentMessages.step === AgentStep.ACTIVATE_AGENT ||
|
||||
agentMessages.step === AgentStep.DEACTIVATE_AGENT
|
||||
) {
|
||||
let taskAssigning = [...tasks[currentTaskId].taskAssigning];
|
||||
let taskRunning = [...tasks[currentTaskId].taskRunning];
|
||||
|
|
@ -1346,32 +1359,33 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// }
|
||||
|
||||
const message = filterMessage(agentMessages);
|
||||
if (agentMessages.step === 'activate_agent') {
|
||||
taskAssigning[agentIndex].status = 'running';
|
||||
if (agentMessages.step === AgentStep.ACTIVATE_AGENT) {
|
||||
taskAssigning[agentIndex].status = AgentStatusValue.RUNNING;
|
||||
if (message) {
|
||||
taskAssigning[agentIndex].log.push({
|
||||
...agentMessages,
|
||||
status: 'running',
|
||||
status: AgentMessageStatus.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';
|
||||
taskRunning![taskIndex].agent!.status =
|
||||
AgentStatusValue.RUNNING;
|
||||
taskRunning![taskIndex]!.status = TaskStatus.RUNNING;
|
||||
|
||||
const task = taskAssigning[agentIndex].tasks.find(
|
||||
(task: TaskInfo) => task.id === process_task_id
|
||||
);
|
||||
if (task) {
|
||||
task.status = 'running';
|
||||
task.status = TaskStatus.RUNNING;
|
||||
}
|
||||
}
|
||||
setTaskRunning(currentTaskId, [...taskRunning]);
|
||||
setTaskAssigning(currentTaskId, [...taskAssigning]);
|
||||
}
|
||||
if (agentMessages.step === 'deactivate_agent') {
|
||||
if (agentMessages.step === AgentStep.DEACTIVATE_AGENT) {
|
||||
if (message) {
|
||||
const index = taskAssigning[agentIndex].log.findLastIndex(
|
||||
(log) =>
|
||||
|
|
@ -1379,7 +1393,8 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
log.data.toolkit_name === agentMessages.data.toolkit_name
|
||||
);
|
||||
if (index != -1) {
|
||||
taskAssigning[agentIndex].log[index].status = 'completed';
|
||||
taskAssigning[agentIndex].log[index].status =
|
||||
AgentMessageStatus.COMPLETED;
|
||||
setTaskAssigning(currentTaskId, [...taskAssigning]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1405,7 +1420,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
// Assign task
|
||||
if (agentMessages.step === 'assign_task') {
|
||||
if (agentMessages.step === AgentStep.ASSIGN_TASK) {
|
||||
if (
|
||||
!agentMessages.data?.assignee_id ||
|
||||
!agentMessages.data?.task_id
|
||||
|
|
@ -1475,21 +1490,25 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// 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) {
|
||||
if (
|
||||
taskState !== TaskStatus.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 (taskState === TaskStatus.WAITING) {
|
||||
if (
|
||||
!taskAssigning[assigneeAgentIndex].tasks.find(
|
||||
(item) => item.id === task_id
|
||||
)
|
||||
) {
|
||||
taskAssigning[assigneeAgentIndex].tasks.push(
|
||||
task ?? { id: task_id, content, status: 'waiting' }
|
||||
task ?? { id: task_id, content, status: TaskStatus.WAITING }
|
||||
);
|
||||
}
|
||||
setTaskAssigning(currentTaskId, [...taskAssigning]);
|
||||
|
|
@ -1505,7 +1524,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// Task already exists, update its status
|
||||
taskAssigning[assigneeAgentIndex].tasks[
|
||||
existingTaskIndex
|
||||
].status = 'running';
|
||||
].status = TaskStatus.RUNNING;
|
||||
if (failure_count !== 0) {
|
||||
taskAssigning[assigneeAgentIndex].tasks[
|
||||
existingTaskIndex
|
||||
|
|
@ -1517,12 +1536,16 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
if (task) {
|
||||
taskTemp = JSON.parse(JSON.stringify(task));
|
||||
taskTemp.failure_count = 0;
|
||||
taskTemp.status = 'running';
|
||||
taskTemp.status = TaskStatus.RUNNING;
|
||||
taskTemp.toolkits = [];
|
||||
taskTemp.report = '';
|
||||
}
|
||||
taskAssigning[assigneeAgentIndex].tasks.push(
|
||||
taskTemp ?? { id: task_id, content, status: 'running' }
|
||||
taskTemp ?? {
|
||||
id: task_id,
|
||||
content,
|
||||
status: TaskStatus.RUNNING,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1531,13 +1554,19 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
if (taskRunningIndex === -1) {
|
||||
// Task not in taskRunning, add it
|
||||
if (task) {
|
||||
task.status = taskState === 'waiting' ? 'waiting' : 'running';
|
||||
task.status =
|
||||
taskState === TaskStatus.WAITING
|
||||
? TaskStatus.WAITING
|
||||
: TaskStatus.RUNNING;
|
||||
}
|
||||
taskRunning!.push(
|
||||
task ?? {
|
||||
id: task_id,
|
||||
content,
|
||||
status: taskState === 'waiting' ? 'waiting' : 'running',
|
||||
status:
|
||||
taskState === TaskStatus.WAITING
|
||||
? TaskStatus.WAITING
|
||||
: TaskStatus.RUNNING,
|
||||
agent: JSON.parse(JSON.stringify(taskAgent)),
|
||||
}
|
||||
);
|
||||
|
|
@ -1545,7 +1574,10 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// Task already in taskRunning, update it
|
||||
taskRunning![taskRunningIndex] = {
|
||||
...taskRunning![taskRunningIndex],
|
||||
status: taskState === 'waiting' ? 'waiting' : 'running',
|
||||
status:
|
||||
taskState === TaskStatus.WAITING
|
||||
? TaskStatus.WAITING
|
||||
: TaskStatus.RUNNING,
|
||||
agent: JSON.parse(JSON.stringify(taskAgent)),
|
||||
};
|
||||
}
|
||||
|
|
@ -1555,7 +1587,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
// Activate Toolkit
|
||||
if (agentMessages.step === 'activate_toolkit') {
|
||||
if (agentMessages.step === AgentStep.ACTIVATE_TOOLKIT) {
|
||||
// add log
|
||||
let taskAssigning = [...tasks[currentTaskId].taskAssigning];
|
||||
const resolvedProcessTaskId = resolveProcessTaskIdForToolkitEvent(
|
||||
|
|
@ -1654,7 +1686,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
toolkitName: toolkit_name,
|
||||
toolkitMethods: method_name,
|
||||
message: normalizeToolkitMessage(message.data.message),
|
||||
toolkitStatus: 'running' as AgentStatus,
|
||||
toolkitStatus: AgentStatusValue.RUNNING,
|
||||
};
|
||||
|
||||
// Update taskAssigning if we found the agent
|
||||
|
|
@ -1665,13 +1697,13 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
if (task) {
|
||||
task.toolkits ??= [];
|
||||
task.toolkits.push({ ...toolkit });
|
||||
task.status = 'running';
|
||||
task.status = TaskStatus.RUNNING;
|
||||
setTaskAssigning(currentTaskId, [...taskAssigning]);
|
||||
}
|
||||
}
|
||||
|
||||
// Always update taskRunning (even if assigneeAgentIndex is -1)
|
||||
taskRunning![taskIndex].status = 'running';
|
||||
taskRunning![taskIndex].status = TaskStatus.RUNNING;
|
||||
taskRunning![taskIndex].toolkits ??= [];
|
||||
taskRunning![taskIndex].toolkits.push({ ...toolkit });
|
||||
}
|
||||
|
|
@ -1681,7 +1713,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
// Deactivate Toolkit
|
||||
if (agentMessages.step === 'deactivate_toolkit') {
|
||||
if (agentMessages.step === AgentStep.DEACTIVATE_TOOLKIT) {
|
||||
// add log
|
||||
let taskAssigning = [...tasks[currentTaskId].taskAssigning];
|
||||
const resolvedProcessTaskId = resolveProcessTaskIdForToolkitEvent(
|
||||
|
|
@ -1709,14 +1741,15 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
toolkit.toolkitName === agentMessages.data.toolkit_name &&
|
||||
toolkit.toolkitMethods ===
|
||||
agentMessages.data.method_name &&
|
||||
toolkit.toolkitStatus === 'running'
|
||||
toolkit.toolkitStatus === AgentStatusValue.RUNNING
|
||||
);
|
||||
});
|
||||
|
||||
if (task.toolkits && index !== -1 && index !== undefined) {
|
||||
task.toolkits[index].message =
|
||||
`${normalizeToolkitMessage(task.toolkits[index].message)}\n${normalizeToolkitMessage(message.data.message)}`.trim();
|
||||
task.toolkits[index].toolkitStatus = 'completed';
|
||||
task.toolkits[index].toolkitStatus =
|
||||
AgentStatusValue.COMPLETED;
|
||||
}
|
||||
// task.toolkits?.unshift({
|
||||
// toolkitName: agentMessages.data.toolkit_name as string,
|
||||
|
|
@ -1756,7 +1789,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
message: normalizeToolkitMessage(
|
||||
targetMessage.data.message
|
||||
),
|
||||
toolkitStatus: 'completed',
|
||||
toolkitStatus: AgentStatusValue.COMPLETED,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1766,7 +1799,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
// Terminal
|
||||
if (agentMessages.step === 'terminal') {
|
||||
if (agentMessages.step === AgentStep.TERMINAL) {
|
||||
addTerminal(
|
||||
currentTaskId,
|
||||
agentMessages.data.process_task_id as string,
|
||||
|
|
@ -1775,7 +1808,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
// Write File
|
||||
if (agentMessages.step === 'write_file') {
|
||||
if (agentMessages.step === AgentStep.WRITE_FILE) {
|
||||
console.log('write_to_file', agentMessages.data);
|
||||
setNuwFileNum(currentTaskId, tasks[currentTaskId].nuwFileNum + 1);
|
||||
const { file_path } = agentMessages.data;
|
||||
|
|
@ -1796,15 +1829,15 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
|
||||
if (agentMessages.step === 'budget_not_enough') {
|
||||
if (agentMessages.step === AgentStep.BUDGET_NOT_ENOUGH) {
|
||||
console.log('error', agentMessages.data);
|
||||
showCreditsToast();
|
||||
setStatus(currentTaskId, 'pause');
|
||||
setStatus(currentTaskId, ChatTaskStatus.PAUSE);
|
||||
uploadLog(currentTaskId, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (agentMessages.step === 'context_too_long') {
|
||||
if (agentMessages.step === AgentStep.CONTEXT_TOO_LONG) {
|
||||
console.error('Context too long:', agentMessages.data);
|
||||
const currentLength = agentMessages.data.current_length || 0;
|
||||
const maxLength = agentMessages.data.max_length || 100000;
|
||||
|
|
@ -1821,12 +1854,12 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
|
||||
// Set flag to block input and set status to pause
|
||||
setIsContextExceeded(currentTaskId, true);
|
||||
setStatus(currentTaskId, 'pause');
|
||||
setStatus(currentTaskId, ChatTaskStatus.PAUSE);
|
||||
uploadLog(currentTaskId, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (agentMessages.step === 'error') {
|
||||
if (agentMessages.step === AgentStep.ERROR) {
|
||||
try {
|
||||
console.error('Model error:', agentMessages.data);
|
||||
|
||||
|
|
@ -1852,8 +1885,11 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
|
||||
// Update taskRunning - mark non-completed tasks as failed
|
||||
taskRunning = taskRunning.map((task) => {
|
||||
if (task.status !== 'completed' && task.status !== 'failed') {
|
||||
task.status = 'failed';
|
||||
if (
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.FAILED
|
||||
) {
|
||||
task.status = TaskStatus.FAILED;
|
||||
}
|
||||
return task;
|
||||
});
|
||||
|
|
@ -1861,8 +1897,11 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// Update taskAssigning - mark non-completed tasks as failed
|
||||
taskAssigning = taskAssigning.map((agent) => {
|
||||
agent.tasks = agent.tasks.map((task) => {
|
||||
if (task.status !== 'completed' && task.status !== 'failed') {
|
||||
task.status = 'failed';
|
||||
if (
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.FAILED
|
||||
) {
|
||||
task.status = TaskStatus.FAILED;
|
||||
}
|
||||
return task;
|
||||
});
|
||||
|
|
@ -1874,7 +1913,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
setTaskAssigning(currentTaskId, taskAssigning);
|
||||
|
||||
// Complete the current task with error status
|
||||
setStatus(currentTaskId, 'finished');
|
||||
setStatus(currentTaskId, ChatTaskStatus.FINISHED);
|
||||
setIsPending(currentTaskId, false);
|
||||
|
||||
// Add error message to the current task
|
||||
|
|
@ -1927,7 +1966,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
}
|
||||
|
||||
// Handle add_task events for project store
|
||||
if (agentMessages.step === 'add_task') {
|
||||
if (agentMessages.step === AgentStep.ADD_TASK) {
|
||||
try {
|
||||
const taskData = agentMessages.data;
|
||||
if (taskData && taskData.project_id && taskData.content) {
|
||||
|
|
@ -1964,7 +2003,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
}
|
||||
|
||||
// Handle remove_task events for project store
|
||||
if (agentMessages.step === 'remove_task') {
|
||||
if (agentMessages.step === AgentStep.REMOVE_TASK) {
|
||||
try {
|
||||
const taskIdToRemove = agentMessages.data.task_id as string;
|
||||
if (taskIdToRemove) {
|
||||
|
|
@ -1999,7 +2038,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
return;
|
||||
}
|
||||
|
||||
if (agentMessages.step === 'end') {
|
||||
if (agentMessages.step === AgentStep.END) {
|
||||
// compute task time
|
||||
console.log(
|
||||
'tasks[taskId].snapshotsTemp',
|
||||
|
|
@ -2107,11 +2146,11 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
taskAssigning = taskAssigning.map((agent) => {
|
||||
agent.tasks = agent.tasks.map((task) => {
|
||||
if (
|
||||
task.status !== 'completed' &&
|
||||
task.status !== 'failed' &&
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
!type
|
||||
) {
|
||||
task.status = 'skipped';
|
||||
task.status = TaskStatus.SKIPPED;
|
||||
}
|
||||
return task;
|
||||
});
|
||||
|
|
@ -2121,11 +2160,11 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
taskRunning = taskRunning.map((task) => {
|
||||
console.log('task.status', task.status);
|
||||
if (
|
||||
task.status !== 'completed' &&
|
||||
task.status !== 'failed' &&
|
||||
task.status !== TaskStatus.COMPLETED &&
|
||||
task.status !== TaskStatus.FAILED &&
|
||||
!type
|
||||
) {
|
||||
task.status = 'skipped';
|
||||
task.status = TaskStatus.SKIPPED;
|
||||
}
|
||||
return task;
|
||||
});
|
||||
|
|
@ -2158,7 +2197,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
let summary = endMessage.match(/<summary>(.*?)<\/summary>/)?.[1];
|
||||
let newMessage: Message | null = null;
|
||||
const agent_summary_end = tasks[currentTaskId].messages.findLast(
|
||||
(message: Message) => message.step === 'agent_summary_end'
|
||||
(message: Message) => message.step === AgentStep.AGENT_SUMMARY_END
|
||||
);
|
||||
console.log('summary', summary);
|
||||
if (summary) {
|
||||
|
|
@ -2181,7 +2220,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
addMessages(currentTaskId, newMessage);
|
||||
|
||||
setIsPending(currentTaskId, false);
|
||||
setStatus(currentTaskId, 'finished');
|
||||
setStatus(currentTaskId, ChatTaskStatus.FINISHED);
|
||||
// completed tasks move to history
|
||||
setUpdateCount();
|
||||
|
||||
|
|
@ -2189,7 +2228,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
|
||||
return;
|
||||
}
|
||||
if (agentMessages.step === 'notice') {
|
||||
if (agentMessages.step === AgentStep.NOTICE) {
|
||||
if (agentMessages.data.process_task_id !== '') {
|
||||
let taskAssigning = [...tasks[currentTaskId].taskAssigning];
|
||||
|
||||
|
|
@ -2209,7 +2248,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
toolkitName: 'notice',
|
||||
toolkitMethods: '',
|
||||
message: agentMessages.data.notice as string,
|
||||
toolkitStatus: 'running' as AgentStatus,
|
||||
toolkitStatus: AgentStatusValue.RUNNING,
|
||||
};
|
||||
if (assigneeAgentIndex !== -1 && task) {
|
||||
task.toolkits ??= [];
|
||||
|
|
@ -2219,14 +2258,14 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
} else {
|
||||
const messages = [...tasks[currentTaskId].messages];
|
||||
const noticeCardIndex = messages.findLastIndex(
|
||||
(message) => message.step === 'notice_card'
|
||||
(message) => message.step === AgentStep.NOTICE_CARD
|
||||
);
|
||||
if (noticeCardIndex === -1) {
|
||||
const newMessage: Message = {
|
||||
id: generateUniqueId(),
|
||||
role: 'agent',
|
||||
content: '',
|
||||
step: 'notice_card',
|
||||
step: AgentStep.NOTICE_CARD,
|
||||
};
|
||||
addMessages(currentTaskId, newMessage);
|
||||
}
|
||||
|
|
@ -2237,8 +2276,8 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (['sync'].includes(agentMessages.step)) return;
|
||||
if (agentMessages.step === 'ask') {
|
||||
if (agentMessages.step === AgentStep.SYNC) return;
|
||||
if (agentMessages.step === AgentStep.ASK) {
|
||||
if (tasks[currentTaskId].activeAsk != '') {
|
||||
const newMessage: Message = {
|
||||
id: generateUniqueId(),
|
||||
|
|
@ -2568,10 +2607,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
},
|
||||
}));
|
||||
},
|
||||
setStatus(
|
||||
taskId: string,
|
||||
status: 'running' | 'finished' | 'pending' | 'pause'
|
||||
) {
|
||||
setStatus(taskId: string, status: ChatTaskStatusType) {
|
||||
set((state) => ({
|
||||
...state,
|
||||
tasks: {
|
||||
|
|
@ -2630,7 +2666,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
// 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'
|
||||
(message) => message.step === AgentStep.TO_SUB_TASKS
|
||||
);
|
||||
if (cardTaskIndex !== -1) {
|
||||
messages[cardTaskIndex] = {
|
||||
|
|
@ -2648,7 +2684,7 @@ const chatStore = (initial?: Partial<ChatStore>) =>
|
|||
await fetchPost(`/task/${project_id}/start`, {});
|
||||
|
||||
setActiveWorkSpace(taskId, 'workflow');
|
||||
setStatus(taskId, 'running');
|
||||
setStatus(taskId, ChatTaskStatus.RUNNING);
|
||||
}
|
||||
|
||||
// Reset editing state after manual confirmation so next round can auto-start
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
import { generateUniqueId } from '@/lib';
|
||||
import { create } from 'zustand';
|
||||
import { createChatStoreInstance, VanillaChatStore } from './chatStore';
|
||||
import { ChatTaskStatus } from '@/types/constants';
|
||||
|
||||
export enum ProjectType {
|
||||
NORMAL = 'normal',
|
||||
|
|
@ -173,7 +174,7 @@ const isEmptyProject = (project: Project): boolean => {
|
|||
task.summaryTask === '' &&
|
||||
task.progressValue === 0 &&
|
||||
task.isPending === false &&
|
||||
task.status === 'pending' &&
|
||||
task.status === ChatTaskStatus.PENDING &&
|
||||
task.taskTime === 0 &&
|
||||
task.tokens === 0 &&
|
||||
task.elapsed === 0 &&
|
||||
|
|
|
|||
12
src/types/chatbox.d.ts
vendored
12
src/types/chatbox.d.ts
vendored
|
|
@ -12,6 +12,8 @@
|
|||
// limitations under the License.
|
||||
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
|
||||
import type { AgentStepType, AgentMessageStatusType, TaskStatusType, ChatTaskStatusType, AgentStatusType } from './constants';
|
||||
|
||||
// Global type definitions for ChatBox component
|
||||
|
||||
declare global {
|
||||
|
|
@ -40,7 +42,7 @@ declare global {
|
|||
report?: string | undefined;
|
||||
id: string;
|
||||
content: string;
|
||||
status?: string;
|
||||
status?: TaskStatusType;
|
||||
agent?: Agent;
|
||||
terminal?: string[];
|
||||
fileList?: FileInfo[];
|
||||
|
|
@ -60,7 +62,7 @@ declare global {
|
|||
filePath: string;
|
||||
}
|
||||
|
||||
type AgentStatus = 'pending' | 'running' | 'completed' | 'failed';
|
||||
type AgentStatus = AgentStatusType;
|
||||
|
||||
interface ActiveWebView {
|
||||
id: string;
|
||||
|
|
@ -92,7 +94,7 @@ declare global {
|
|||
id: string;
|
||||
role: 'user' | 'agent';
|
||||
content: string;
|
||||
step?: string;
|
||||
step?: AgentStepType;
|
||||
agent_id?: string;
|
||||
isConfirm?: boolean;
|
||||
taskType?: 1 | 2 | 3;
|
||||
|
|
@ -110,7 +112,7 @@ declare global {
|
|||
}
|
||||
|
||||
interface AgentMessage {
|
||||
step: string;
|
||||
step: AgentStepType;
|
||||
data: {
|
||||
project_id?: string;
|
||||
failure_count?: number;
|
||||
|
|
@ -140,7 +142,7 @@ declare global {
|
|||
max_length?: number;
|
||||
text?: string;
|
||||
};
|
||||
status?: 'running' | 'filled' | 'completed';
|
||||
status?: AgentMessageStatusType;
|
||||
}
|
||||
|
||||
type AgentNameType =
|
||||
|
|
|
|||
97
src/types/constants.ts
Normal file
97
src/types/constants.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
|
||||
/**
|
||||
* SSE step values received from the backend in AgentMessage.step.
|
||||
*/
|
||||
export const AgentStep = {
|
||||
CONFIRMED: 'confirmed',
|
||||
NEW_TASK_STATE: 'new_task_state',
|
||||
END: 'end',
|
||||
WAIT_CONFIRM: 'wait_confirm',
|
||||
DECOMPOSE_TEXT: 'decompose_text',
|
||||
TO_SUB_TASKS: 'to_sub_tasks',
|
||||
CREATE_AGENT: 'create_agent',
|
||||
TASK_STATE: 'task_state',
|
||||
ACTIVATE_AGENT: 'activate_agent',
|
||||
DEACTIVATE_AGENT: 'deactivate_agent',
|
||||
ASSIGN_TASK: 'assign_task',
|
||||
ACTIVATE_TOOLKIT: 'activate_toolkit',
|
||||
DEACTIVATE_TOOLKIT: 'deactivate_toolkit',
|
||||
TERMINAL: 'terminal',
|
||||
WRITE_FILE: 'write_file',
|
||||
BUDGET_NOT_ENOUGH: 'budget_not_enough',
|
||||
CONTEXT_TOO_LONG: 'context_too_long',
|
||||
ERROR: 'error',
|
||||
ADD_TASK: 'add_task',
|
||||
REMOVE_TASK: 'remove_task',
|
||||
NOTICE: 'notice',
|
||||
ASK: 'ask',
|
||||
SYNC: 'sync',
|
||||
NOTICE_CARD: 'notice_card',
|
||||
FAILED: 'failed',
|
||||
AGENT_SUMMARY_END: 'agent_summary_end',
|
||||
} as const;
|
||||
|
||||
export type AgentStepType = (typeof AgentStep)[keyof typeof AgentStep];
|
||||
|
||||
/**
|
||||
* Status values on AgentMessage.status (SSE message lifecycle).
|
||||
*/
|
||||
export const AgentMessageStatus = {
|
||||
RUNNING: 'running',
|
||||
FILLED: 'filled',
|
||||
COMPLETED: 'completed',
|
||||
} as const;
|
||||
|
||||
export type AgentMessageStatusType = (typeof AgentMessageStatus)[keyof typeof AgentMessageStatus];
|
||||
|
||||
/**
|
||||
* Status values for TaskInfo (individual sub-task progress).
|
||||
*/
|
||||
export const TaskStatus = {
|
||||
COMPLETED: 'completed',
|
||||
FAILED: 'failed',
|
||||
SKIPPED: 'skipped',
|
||||
WAITING: 'waiting',
|
||||
RUNNING: 'running',
|
||||
BLOCKED: 'blocked',
|
||||
EMPTY: '',
|
||||
} as const;
|
||||
|
||||
export type TaskStatusType = (typeof TaskStatus)[keyof typeof TaskStatus];
|
||||
|
||||
/**
|
||||
* Top-level task status in the ChatStore Task interface.
|
||||
*/
|
||||
export const ChatTaskStatus = {
|
||||
RUNNING: 'running',
|
||||
FINISHED: 'finished',
|
||||
PENDING: 'pending',
|
||||
PAUSE: 'pause',
|
||||
} as const;
|
||||
|
||||
export type ChatTaskStatusType = (typeof ChatTaskStatus)[keyof typeof ChatTaskStatus];
|
||||
|
||||
/**
|
||||
* Status values for individual agent lifecycle (toolkit operations, agent progress).
|
||||
*/
|
||||
export const AgentStatusValue = {
|
||||
PENDING: 'pending',
|
||||
RUNNING: 'running',
|
||||
COMPLETED: 'completed',
|
||||
FAILED: 'failed',
|
||||
} as const;
|
||||
|
||||
export type AgentStatusType = (typeof AgentStatusValue)[keyof typeof AgentStatusValue];
|
||||
Loading…
Add table
Add a link
Reference in a new issue