@lobehub/lobehub 2.0.9 → 2.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/Dockerfile +44 -52
- package/changelog/v2.json +18 -0
- package/locales/ar/chat.json +4 -0
- package/locales/ar/models.json +65 -0
- package/locales/bg-BG/chat.json +4 -0
- package/locales/bg-BG/models.json +10 -0
- package/locales/de-DE/chat.json +4 -0
- package/locales/de-DE/models.json +41 -0
- package/locales/en-US/chat.json +4 -0
- package/locales/es-ES/chat.json +4 -0
- package/locales/es-ES/models.json +50 -0
- package/locales/fa-IR/chat.json +4 -0
- package/locales/fa-IR/models.json +39 -0
- package/locales/fr-FR/chat.json +4 -0
- package/locales/fr-FR/models.json +9 -0
- package/locales/it-IT/chat.json +4 -0
- package/locales/it-IT/models.json +62 -0
- package/locales/ja-JP/chat.json +4 -0
- package/locales/ja-JP/models.json +40 -0
- package/locales/ko-KR/chat.json +4 -0
- package/locales/ko-KR/models.json +31 -0
- package/locales/nl-NL/chat.json +4 -0
- package/locales/nl-NL/models.json +52 -0
- package/locales/pl-PL/chat.json +4 -0
- package/locales/pl-PL/models.json +43 -0
- package/locales/pt-BR/chat.json +4 -0
- package/locales/pt-BR/models.json +92 -0
- package/locales/ru-RU/chat.json +4 -0
- package/locales/ru-RU/models.json +34 -0
- package/locales/tr-TR/chat.json +4 -0
- package/locales/tr-TR/models.json +55 -0
- package/locales/vi-VN/chat.json +4 -0
- package/locales/vi-VN/models.json +31 -0
- package/locales/zh-CN/chat.json +4 -0
- package/locales/zh-TW/chat.json +4 -0
- package/package.json +1 -1
- package/packages/agent-runtime/src/groupOrchestration/GroupOrchestrationSupervisor.ts +18 -1
- package/packages/agent-runtime/src/groupOrchestration/__tests__/GroupOrchestrationSupervisor.test.ts +76 -5
- package/packages/agent-runtime/src/groupOrchestration/types.ts +3 -3
- package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTask.tsx +11 -11
- package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTasks.tsx +78 -79
- package/packages/builtin-tool-group-management/src/client/Render/ExecuteTask/index.tsx +3 -3
- package/packages/builtin-tool-group-management/src/client/Render/ExecuteTasks/index.tsx +61 -63
- package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTask/index.tsx +3 -3
- package/packages/builtin-tool-group-management/src/executor.test.ts +7 -9
- package/packages/builtin-tool-group-management/src/executor.ts +3 -3
- package/packages/builtin-tool-group-management/src/manifest.ts +49 -50
- package/packages/builtin-tool-group-management/src/systemRole.ts +153 -5
- package/packages/builtin-tool-group-management/src/types.ts +3 -2
- package/packages/builtin-tool-gtd/src/systemRole.ts +4 -4
- package/packages/context-engine/src/processors/TasksFlatten.ts +7 -5
- package/packages/context-engine/src/processors/__tests__/TasksFlatten.test.ts +164 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/index.ts +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/supervisor-after-multi-tasks.json +91 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/supervisor-content-only.json +74 -0
- package/packages/conversation-flow/src/__tests__/parse.test.ts +37 -0
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +70 -4
- package/packages/conversation-flow/src/transformation/__tests__/FlatListBuilder.test.ts +147 -0
- package/packages/model-bank/src/aiModels/cerebras.ts +2 -22
- package/packages/model-bank/src/aiModels/google.ts +1 -44
- package/packages/model-bank/src/aiModels/nvidia.ts +12 -16
- package/packages/model-bank/src/aiModels/siliconcloud.ts +20 -0
- package/packages/model-bank/src/aiModels/volcengine.ts +69 -0
- package/packages/model-bank/src/aiModels/wenxin.ts +41 -38
- package/packages/model-bank/src/aiModels/zhipu.ts +58 -28
- package/packages/model-bank/src/types/aiModel.ts +29 -0
- package/packages/model-runtime/src/core/usageConverters/utils/computeChatCost.test.ts +2 -2
- package/packages/model-runtime/src/providers/google/createImage.test.ts +12 -12
- package/packages/model-runtime/src/providers/openrouter/index.test.ts +102 -0
- package/packages/model-runtime/src/providers/openrouter/index.ts +19 -7
- package/packages/model-runtime/src/providers/vercelaigateway/index.test.ts +47 -0
- package/packages/model-runtime/src/providers/vercelaigateway/index.ts +7 -1
- package/packages/types/src/message/ui/chat.ts +2 -0
- package/packages/types/src/tool/builtin.ts +5 -5
- package/src/features/Conversation/ChatItem/components/Title.tsx +1 -1
- package/src/features/Conversation/ChatList/index.tsx +0 -1
- package/src/features/Conversation/Messages/GroupTasks/TaskItem/ClientTaskItem.tsx +183 -0
- package/src/features/Conversation/Messages/GroupTasks/TaskItem/ServerTaskItem.tsx +94 -0
- package/src/features/Conversation/Messages/GroupTasks/TaskItem/TaskTitle.tsx +177 -0
- package/src/features/Conversation/Messages/GroupTasks/TaskItem/index.tsx +26 -0
- package/src/features/Conversation/Messages/GroupTasks/TaskItem/useClientTaskStats.ts +93 -0
- package/src/features/Conversation/Messages/GroupTasks/index.tsx +151 -0
- package/src/features/Conversation/Messages/Supervisor/index.tsx +7 -1
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/index.tsx +72 -91
- package/src/features/Conversation/Messages/Task/TaskDetailPanel/StatusContent.tsx +46 -17
- package/src/features/Conversation/Messages/Tasks/TaskItem/ClientTaskItem.tsx +9 -24
- package/src/features/Conversation/Messages/Tasks/TaskItem/ServerTaskItem.tsx +18 -38
- package/src/features/Conversation/Messages/Tasks/shared/ErrorState.tsx +45 -2
- package/src/features/Conversation/Messages/Tasks/shared/InitializingState.tsx +16 -1
- package/src/features/Conversation/Messages/Tasks/shared/TaskContent.tsx +68 -0
- package/src/features/Conversation/Messages/Tasks/shared/TaskMessages.tsx +383 -0
- package/src/features/Conversation/Messages/Tasks/shared/index.ts +4 -0
- package/src/features/Conversation/Messages/Tasks/shared/useTaskPolling.ts +48 -0
- package/src/features/Conversation/Messages/index.tsx +5 -0
- package/src/locales/default/chat.ts +4 -0
- package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +4 -0
- package/src/server/modules/AgentRuntime/__tests__/RuntimeExecutors.test.ts +106 -1
- package/src/server/services/aiAgent/__tests__/execAgent.threadId.test.ts +2 -2
- package/src/server/utils/truncateToolResult.ts +1 -4
- package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +15 -15
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +22 -15
- package/src/store/chat/agents/__tests__/createAgentExecutors/exec-tasks.test.ts +21 -10
- package/src/store/chat/agents/createAgentExecutors.ts +2 -0
- package/src/store/chat/slices/aiAgent/actions/groupOrchestration.ts +10 -7
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/CompletedState.tsx +0 -108
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/InstructionAccordion.tsx +0 -63
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/ProcessingState.tsx +0 -123
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
|
|
5
|
+
import { useChatStore } from '@/store/chat';
|
|
5
6
|
import { type TaskDetail, ThreadStatus } from '@/types/index';
|
|
6
7
|
|
|
7
8
|
import {
|
|
8
|
-
CompletedState,
|
|
9
9
|
ErrorState,
|
|
10
10
|
InitializingState,
|
|
11
|
-
|
|
11
|
+
TaskMessages,
|
|
12
12
|
isProcessingStatus,
|
|
13
13
|
} from '../../Tasks/shared';
|
|
14
14
|
|
|
@@ -18,30 +18,59 @@ interface StatusContentProps {
|
|
|
18
18
|
taskDetail?: TaskDetail;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const StatusContent = memo<StatusContentProps>(({ taskDetail,
|
|
21
|
+
const StatusContent = memo<StatusContentProps>(({ taskDetail, messageId }) => {
|
|
22
22
|
const status = taskDetail?.status;
|
|
23
|
+
const threadId = taskDetail?.threadId;
|
|
24
|
+
const isProcessing = isProcessingStatus(status);
|
|
25
|
+
|
|
26
|
+
// Get polling hook - poll for task status to get messages
|
|
27
|
+
const [useEnablePollingTaskStatus, operations] = useChatStore((s) => [
|
|
28
|
+
s.useEnablePollingTaskStatus,
|
|
29
|
+
s.operations,
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
// Check if exec_async_task is already polling for this message
|
|
33
|
+
const hasActiveOperationPolling = Object.values(operations).some(
|
|
34
|
+
(op) =>
|
|
35
|
+
op.status === 'running' &&
|
|
36
|
+
op.type === 'execAgentRuntime' &&
|
|
37
|
+
op.context?.messageId === messageId,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Enable polling when task has threadId and no active operation is polling
|
|
41
|
+
// For completed tasks, this will fetch messages once (no refreshInterval needed)
|
|
42
|
+
const shouldPoll = !!threadId && !hasActiveOperationPolling;
|
|
43
|
+
const { data } = useEnablePollingTaskStatus(threadId, messageId, shouldPoll);
|
|
44
|
+
|
|
45
|
+
const messages = data?.messages;
|
|
23
46
|
|
|
24
47
|
// Initializing state: no status yet (task just created, waiting for backend)
|
|
25
48
|
if (!status) {
|
|
26
49
|
return <InitializingState />;
|
|
27
50
|
}
|
|
28
51
|
|
|
29
|
-
// Processing
|
|
30
|
-
if (
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
// Processing or Completed state with messages
|
|
53
|
+
if (messages && messages.length > 0) {
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<TaskMessages
|
|
57
|
+
duration={taskDetail?.duration}
|
|
58
|
+
isProcessing={isProcessing}
|
|
59
|
+
messages={messages}
|
|
60
|
+
startTime={taskDetail?.startedAt ? new Date(taskDetail.startedAt).getTime() : undefined}
|
|
61
|
+
totalCost={taskDetail?.totalCost}
|
|
62
|
+
/>
|
|
63
|
+
{
|
|
64
|
+
// Error states: Failed, Cancel
|
|
65
|
+
(status === ThreadStatus.Failed || status === ThreadStatus.Cancel) && (
|
|
66
|
+
<ErrorState taskDetail={taskDetail!} />
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
42
71
|
}
|
|
43
72
|
|
|
44
|
-
//
|
|
73
|
+
// Still loading messages
|
|
45
74
|
return <InitializingState />;
|
|
46
75
|
});
|
|
47
76
|
|
|
@@ -9,9 +9,7 @@ import { messageMapKey } from '@/store/chat/utils/messageMapKey';
|
|
|
9
9
|
import { ThreadStatus } from '@/types/index';
|
|
10
10
|
import type { UIChatMessage } from '@/types/index';
|
|
11
11
|
|
|
12
|
-
import
|
|
13
|
-
import ClientTaskDetailProcessingState from '../../Task/ClientTaskDetail/ProcessingState';
|
|
14
|
-
import { ErrorState, InitializingState, isProcessingStatus } from '../shared';
|
|
12
|
+
import { ErrorState, InitializingState, TaskMessages, isProcessingStatus } from '../shared';
|
|
15
13
|
import TaskTitle, { type TaskMetrics } from './TaskTitle';
|
|
16
14
|
|
|
17
15
|
interface ClientTaskItemProps {
|
|
@@ -43,8 +41,7 @@ const ClientTaskItem = memo<ClientTaskItemProps>(({ item }) => {
|
|
|
43
41
|
|
|
44
42
|
// Use task message's agentId (skip 'supervisor' as it's not a valid agent ID for queries)
|
|
45
43
|
// Fall back to activeAgentId if not available
|
|
46
|
-
const agentId =
|
|
47
|
-
itemAgentId && itemAgentId !== 'supervisor' ? itemAgentId : activeAgentId;
|
|
44
|
+
const agentId = itemAgentId && itemAgentId !== 'supervisor' ? itemAgentId : activeAgentId;
|
|
48
45
|
|
|
49
46
|
const threadContext = useMemo(
|
|
50
47
|
() => ({
|
|
@@ -135,33 +132,21 @@ const ClientTaskItem = memo<ClientTaskItemProps>(({ item }) => {
|
|
|
135
132
|
{/* Initializing State - no taskDetail yet or no blocks */}
|
|
136
133
|
{(isInitializing || (isProcessing && !hasBlocks)) && <InitializingState />}
|
|
137
134
|
|
|
138
|
-
{/* Processing State - show
|
|
139
|
-
{!isInitializing && isProcessing && hasBlocks && (
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
{/* Processing or Completed State - show blocks via TaskMessages */}
|
|
136
|
+
{!isInitializing && (isProcessing || isCompleted) && hasBlocks && threadMessages && (
|
|
137
|
+
<TaskMessages
|
|
138
|
+
duration={taskDetail?.duration}
|
|
139
|
+
isProcessing={isProcessing}
|
|
140
|
+
messages={threadMessages}
|
|
143
141
|
model={model ?? undefined}
|
|
144
142
|
provider={provider ?? undefined}
|
|
145
143
|
startTime={assistantGroupMessage?.createdAt}
|
|
144
|
+
totalCost={taskDetail?.totalCost}
|
|
146
145
|
/>
|
|
147
146
|
)}
|
|
148
147
|
|
|
149
148
|
{/* Error State */}
|
|
150
149
|
{!isInitializing && isError && taskDetail && <ErrorState taskDetail={taskDetail} />}
|
|
151
|
-
|
|
152
|
-
{/* Completed State - show blocks with final result */}
|
|
153
|
-
{!isInitializing && isCompleted && taskDetail && hasBlocks && (
|
|
154
|
-
<ClientTaskDetailCompletedState
|
|
155
|
-
assistantId={assistantGroupMessage!.id}
|
|
156
|
-
blocks={blocks!}
|
|
157
|
-
duration={taskDetail.duration}
|
|
158
|
-
model={model ?? undefined}
|
|
159
|
-
provider={provider ?? undefined}
|
|
160
|
-
totalCost={taskDetail.totalCost}
|
|
161
|
-
totalTokens={taskDetail.totalTokens}
|
|
162
|
-
totalToolCalls={taskDetail.totalToolCalls}
|
|
163
|
-
/>
|
|
164
|
-
)}
|
|
165
150
|
</Block>
|
|
166
151
|
</AccordionItem>
|
|
167
152
|
);
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { AccordionItem, Block
|
|
3
|
+
import { AccordionItem, Block } from '@lobehub/ui';
|
|
4
4
|
import { memo, useMemo, useState } from 'react';
|
|
5
5
|
|
|
6
6
|
import { ThreadStatus } from '@/types/index';
|
|
7
7
|
import type { UIChatMessage } from '@/types/index';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
CompletedState,
|
|
11
|
-
ErrorState,
|
|
12
|
-
InitializingState,
|
|
13
|
-
ProcessingState,
|
|
14
|
-
isProcessingStatus,
|
|
15
|
-
} from '../shared';
|
|
9
|
+
import { TaskContent } from '../shared';
|
|
16
10
|
import TaskTitle, { type TaskMetrics } from './TaskTitle';
|
|
17
11
|
|
|
18
12
|
interface ServerTaskItemProps {
|
|
@@ -20,17 +14,15 @@ interface ServerTaskItemProps {
|
|
|
20
14
|
}
|
|
21
15
|
|
|
22
16
|
const ServerTaskItem = memo<ServerTaskItemProps>(({ item }) => {
|
|
23
|
-
const { id,
|
|
17
|
+
const { id, metadata, taskDetail, tasks } = item;
|
|
24
18
|
const [expanded, setExpanded] = useState(false);
|
|
25
19
|
|
|
26
20
|
const title = taskDetail?.title || metadata?.taskTitle;
|
|
27
|
-
const instruction = metadata?.instruction;
|
|
28
21
|
const status = taskDetail?.status;
|
|
22
|
+
const threadId = taskDetail?.threadId;
|
|
29
23
|
|
|
30
|
-
const isProcessing = isProcessingStatus(status);
|
|
31
24
|
const isCompleted = status === ThreadStatus.Completed;
|
|
32
25
|
const isError = status === ThreadStatus.Failed || status === ThreadStatus.Cancel;
|
|
33
|
-
const isInitializing = !taskDetail || !status;
|
|
34
26
|
|
|
35
27
|
// Build metrics for TaskTitle (only for completed/error states)
|
|
36
28
|
const metrics: TaskMetrics | undefined = useMemo(() => {
|
|
@@ -42,7 +34,13 @@ const ServerTaskItem = memo<ServerTaskItemProps>(({ item }) => {
|
|
|
42
34
|
};
|
|
43
35
|
}
|
|
44
36
|
return undefined;
|
|
45
|
-
}, [
|
|
37
|
+
}, [
|
|
38
|
+
isCompleted,
|
|
39
|
+
isError,
|
|
40
|
+
taskDetail?.duration,
|
|
41
|
+
taskDetail?.totalSteps,
|
|
42
|
+
taskDetail?.totalToolCalls,
|
|
43
|
+
]);
|
|
46
44
|
|
|
47
45
|
return (
|
|
48
46
|
<AccordionItem
|
|
@@ -54,32 +52,14 @@ const ServerTaskItem = memo<ServerTaskItemProps>(({ item }) => {
|
|
|
54
52
|
title={<TaskTitle metrics={metrics} status={status} title={title} />}
|
|
55
53
|
>
|
|
56
54
|
<Block gap={16} padding={12} style={{ marginBlock: 8 }} variant={'outlined'}>
|
|
57
|
-
{
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)}
|
|
64
|
-
|
|
65
|
-
{/* Initializing State - no taskDetail yet */}
|
|
66
|
-
{isInitializing && <InitializingState />}
|
|
67
|
-
|
|
68
|
-
{/* Processing State */}
|
|
69
|
-
{!isInitializing && isProcessing && taskDetail && (
|
|
70
|
-
<ProcessingState messageId={id} taskDetail={taskDetail} variant="compact" />
|
|
71
|
-
)}
|
|
72
|
-
|
|
73
|
-
{/* Error State */}
|
|
74
|
-
{!isInitializing && isError && taskDetail && <ErrorState taskDetail={taskDetail} />}
|
|
75
|
-
|
|
76
|
-
{/* Completed State */}
|
|
77
|
-
{!isInitializing && isCompleted && taskDetail && (
|
|
78
|
-
<CompletedState
|
|
79
|
-
content={content}
|
|
80
|
-
expanded={expanded}
|
|
55
|
+
{expanded && (
|
|
56
|
+
<TaskContent
|
|
57
|
+
id={id}
|
|
58
|
+
isError={isError}
|
|
59
|
+
messages={tasks}
|
|
60
|
+
status={status}
|
|
81
61
|
taskDetail={taskDetail}
|
|
82
|
-
|
|
62
|
+
threadId={threadId}
|
|
83
63
|
/>
|
|
84
64
|
)}
|
|
85
65
|
</Block>
|
|
@@ -38,6 +38,46 @@ interface ErrorStateProps {
|
|
|
38
38
|
taskDetail: TaskDetail;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Extract displayable error content from various error structures
|
|
43
|
+
*/
|
|
44
|
+
const getErrorContent = (error: Record<string, any> | undefined): string | null => {
|
|
45
|
+
if (!error) return null;
|
|
46
|
+
|
|
47
|
+
// Try common error structures
|
|
48
|
+
// 1. error.error.body (TRPC style)
|
|
49
|
+
if (error.error?.body) {
|
|
50
|
+
return JSON.stringify(error.error.body, null, 2);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 2. error.body (direct body)
|
|
54
|
+
if (error.body && typeof error.body === 'object') {
|
|
55
|
+
return JSON.stringify(error.body, null, 2);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 3. error.message (if it's not "[object Object]")
|
|
59
|
+
if (error.message && typeof error.message === 'string' && error.message !== '[object Object]') {
|
|
60
|
+
return error.message;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 4. If error itself is an object with meaningful content, stringify it
|
|
64
|
+
// Skip if it only has a useless message field
|
|
65
|
+
const keys = Object.keys(error);
|
|
66
|
+
if (keys.length > 0) {
|
|
67
|
+
// Filter out useless "[object Object]" values
|
|
68
|
+
const meaningfulEntries = Object.entries(error).filter(([, value]) => {
|
|
69
|
+
if (typeof value === 'string' && value === '[object Object]') return false;
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (meaningfulEntries.length > 0) {
|
|
74
|
+
return JSON.stringify(Object.fromEntries(meaningfulEntries), null, 2);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
};
|
|
80
|
+
|
|
41
81
|
const ErrorState = memo<ErrorStateProps>(({ taskDetail }) => {
|
|
42
82
|
const { t } = useTranslation('chat');
|
|
43
83
|
|
|
@@ -49,6 +89,9 @@ const ErrorState = memo<ErrorStateProps>(({ taskDetail }) => {
|
|
|
49
89
|
const formattedDuration = useMemo(() => formatDuration(duration), [duration]);
|
|
50
90
|
const formattedCost = useMemo(() => formatCost(totalCost), [totalCost]);
|
|
51
91
|
|
|
92
|
+
// Extract error content
|
|
93
|
+
const errorContent = useMemo(() => getErrorContent(error), [error]);
|
|
94
|
+
|
|
52
95
|
const hasMetrics = !!(formattedDuration || totalToolCalls || totalMessages || formattedCost);
|
|
53
96
|
|
|
54
97
|
return (
|
|
@@ -56,14 +99,14 @@ const ErrorState = memo<ErrorStateProps>(({ taskDetail }) => {
|
|
|
56
99
|
{/* Error Content */}
|
|
57
100
|
<Alert
|
|
58
101
|
extra={
|
|
59
|
-
|
|
102
|
+
errorContent && (
|
|
60
103
|
<Highlighter
|
|
61
104
|
actionIconSize={'small'}
|
|
62
105
|
language={'json'}
|
|
63
106
|
padding={8}
|
|
64
107
|
variant={'borderless'}
|
|
65
108
|
>
|
|
66
|
-
{
|
|
109
|
+
{errorContent}
|
|
67
110
|
</Highlighter>
|
|
68
111
|
)
|
|
69
112
|
}
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import { Flexbox, Text } from '@lobehub/ui';
|
|
4
4
|
import { createStaticStyles, keyframes } from 'antd-style';
|
|
5
|
-
import { memo } from 'react';
|
|
5
|
+
import { memo, useEffect, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
8
|
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
|
9
9
|
import { shinyTextStyles } from '@/styles';
|
|
10
10
|
|
|
11
|
+
import { formatElapsedTime } from './utils';
|
|
12
|
+
|
|
11
13
|
const shimmer = keyframes`
|
|
12
14
|
0% {
|
|
13
15
|
transform: translateX(-100%);
|
|
@@ -48,6 +50,18 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
48
50
|
|
|
49
51
|
const InitializingState = memo(() => {
|
|
50
52
|
const { t } = useTranslation('chat');
|
|
53
|
+
const [elapsedTime, setElapsedTime] = useState(0);
|
|
54
|
+
|
|
55
|
+
// Timer for updating elapsed time every second
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
|
|
59
|
+
const timer = setInterval(() => {
|
|
60
|
+
setElapsedTime(Date.now() - startTime);
|
|
61
|
+
}, 1000);
|
|
62
|
+
|
|
63
|
+
return () => clearInterval(timer);
|
|
64
|
+
}, []);
|
|
51
65
|
|
|
52
66
|
return (
|
|
53
67
|
<Flexbox className={styles.container} gap={12}>
|
|
@@ -56,6 +70,7 @@ const InitializingState = memo(() => {
|
|
|
56
70
|
<Text className={shinyTextStyles.shinyText} weight={500}>
|
|
57
71
|
{t('task.status.initializing')}
|
|
58
72
|
</Text>
|
|
73
|
+
<Text type="secondary">({formatElapsedTime(elapsedTime)})</Text>
|
|
59
74
|
</Flexbox>
|
|
60
75
|
</Flexbox>
|
|
61
76
|
);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ThreadStatus } from '@lobechat/types';
|
|
4
|
+
import type { TaskDetail, UIChatMessage } from '@lobechat/types';
|
|
5
|
+
import { Flexbox, Text } from '@lobehub/ui';
|
|
6
|
+
import { memo } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
|
|
9
|
+
import BubblesLoading from '@/components/BubblesLoading';
|
|
10
|
+
|
|
11
|
+
import ErrorState from './ErrorState';
|
|
12
|
+
import InitializingState from './InitializingState';
|
|
13
|
+
import TaskMessages from './TaskMessages';
|
|
14
|
+
import { useTaskPolling } from './useTaskPolling';
|
|
15
|
+
|
|
16
|
+
export interface TaskContentProps {
|
|
17
|
+
id: string;
|
|
18
|
+
isError: boolean;
|
|
19
|
+
messages: UIChatMessage[] | undefined;
|
|
20
|
+
status: ThreadStatus | undefined;
|
|
21
|
+
taskDetail: TaskDetail | undefined;
|
|
22
|
+
threadId: string | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TaskContent = memo<TaskContentProps>(
|
|
26
|
+
({ id, threadId, status, messages, taskDetail, isError }) => {
|
|
27
|
+
const { t } = useTranslation('chat');
|
|
28
|
+
const { isProcessing } = useTaskPolling({
|
|
29
|
+
messageId: id,
|
|
30
|
+
status,
|
|
31
|
+
threadId,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// No messages yet
|
|
35
|
+
if (!messages || messages.length === 0) {
|
|
36
|
+
// Still processing: show full initializing state
|
|
37
|
+
if (isProcessing) {
|
|
38
|
+
return <InitializingState />;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Already completed but loading messages: show simple loading
|
|
42
|
+
return (
|
|
43
|
+
<Flexbox align="center" gap={4} horizontal>
|
|
44
|
+
<BubblesLoading />
|
|
45
|
+
<Text type="secondary">{t('task.status.fetchingDetails')}</Text>
|
|
46
|
+
</Flexbox>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<TaskMessages
|
|
53
|
+
duration={taskDetail?.duration}
|
|
54
|
+
isProcessing={isProcessing}
|
|
55
|
+
messages={messages}
|
|
56
|
+
startTime={taskDetail?.startedAt ? new Date(taskDetail.startedAt).getTime() : undefined}
|
|
57
|
+
totalCost={taskDetail?.totalCost}
|
|
58
|
+
/>
|
|
59
|
+
{/* Error states: Failed, Cancel */}
|
|
60
|
+
{isError && taskDetail && <ErrorState taskDetail={taskDetail} />}
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
TaskContent.displayName = 'TaskContent';
|
|
67
|
+
|
|
68
|
+
export default TaskContent;
|