@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.
Files changed (108) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/Dockerfile +44 -52
  3. package/changelog/v2.json +18 -0
  4. package/locales/ar/chat.json +4 -0
  5. package/locales/ar/models.json +65 -0
  6. package/locales/bg-BG/chat.json +4 -0
  7. package/locales/bg-BG/models.json +10 -0
  8. package/locales/de-DE/chat.json +4 -0
  9. package/locales/de-DE/models.json +41 -0
  10. package/locales/en-US/chat.json +4 -0
  11. package/locales/es-ES/chat.json +4 -0
  12. package/locales/es-ES/models.json +50 -0
  13. package/locales/fa-IR/chat.json +4 -0
  14. package/locales/fa-IR/models.json +39 -0
  15. package/locales/fr-FR/chat.json +4 -0
  16. package/locales/fr-FR/models.json +9 -0
  17. package/locales/it-IT/chat.json +4 -0
  18. package/locales/it-IT/models.json +62 -0
  19. package/locales/ja-JP/chat.json +4 -0
  20. package/locales/ja-JP/models.json +40 -0
  21. package/locales/ko-KR/chat.json +4 -0
  22. package/locales/ko-KR/models.json +31 -0
  23. package/locales/nl-NL/chat.json +4 -0
  24. package/locales/nl-NL/models.json +52 -0
  25. package/locales/pl-PL/chat.json +4 -0
  26. package/locales/pl-PL/models.json +43 -0
  27. package/locales/pt-BR/chat.json +4 -0
  28. package/locales/pt-BR/models.json +92 -0
  29. package/locales/ru-RU/chat.json +4 -0
  30. package/locales/ru-RU/models.json +34 -0
  31. package/locales/tr-TR/chat.json +4 -0
  32. package/locales/tr-TR/models.json +55 -0
  33. package/locales/vi-VN/chat.json +4 -0
  34. package/locales/vi-VN/models.json +31 -0
  35. package/locales/zh-CN/chat.json +4 -0
  36. package/locales/zh-TW/chat.json +4 -0
  37. package/package.json +1 -1
  38. package/packages/agent-runtime/src/groupOrchestration/GroupOrchestrationSupervisor.ts +18 -1
  39. package/packages/agent-runtime/src/groupOrchestration/__tests__/GroupOrchestrationSupervisor.test.ts +76 -5
  40. package/packages/agent-runtime/src/groupOrchestration/types.ts +3 -3
  41. package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTask.tsx +11 -11
  42. package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTasks.tsx +78 -79
  43. package/packages/builtin-tool-group-management/src/client/Render/ExecuteTask/index.tsx +3 -3
  44. package/packages/builtin-tool-group-management/src/client/Render/ExecuteTasks/index.tsx +61 -63
  45. package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTask/index.tsx +3 -3
  46. package/packages/builtin-tool-group-management/src/executor.test.ts +7 -9
  47. package/packages/builtin-tool-group-management/src/executor.ts +3 -3
  48. package/packages/builtin-tool-group-management/src/manifest.ts +49 -50
  49. package/packages/builtin-tool-group-management/src/systemRole.ts +153 -5
  50. package/packages/builtin-tool-group-management/src/types.ts +3 -2
  51. package/packages/builtin-tool-gtd/src/systemRole.ts +4 -4
  52. package/packages/context-engine/src/processors/TasksFlatten.ts +7 -5
  53. package/packages/context-engine/src/processors/__tests__/TasksFlatten.test.ts +164 -0
  54. package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/index.ts +4 -0
  55. package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/supervisor-after-multi-tasks.json +91 -0
  56. package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/supervisor-content-only.json +74 -0
  57. package/packages/conversation-flow/src/__tests__/parse.test.ts +37 -0
  58. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +70 -4
  59. package/packages/conversation-flow/src/transformation/__tests__/FlatListBuilder.test.ts +147 -0
  60. package/packages/model-bank/src/aiModels/cerebras.ts +2 -22
  61. package/packages/model-bank/src/aiModels/google.ts +1 -44
  62. package/packages/model-bank/src/aiModels/nvidia.ts +12 -16
  63. package/packages/model-bank/src/aiModels/siliconcloud.ts +20 -0
  64. package/packages/model-bank/src/aiModels/volcengine.ts +69 -0
  65. package/packages/model-bank/src/aiModels/wenxin.ts +41 -38
  66. package/packages/model-bank/src/aiModels/zhipu.ts +58 -28
  67. package/packages/model-bank/src/types/aiModel.ts +29 -0
  68. package/packages/model-runtime/src/core/usageConverters/utils/computeChatCost.test.ts +2 -2
  69. package/packages/model-runtime/src/providers/google/createImage.test.ts +12 -12
  70. package/packages/model-runtime/src/providers/openrouter/index.test.ts +102 -0
  71. package/packages/model-runtime/src/providers/openrouter/index.ts +19 -7
  72. package/packages/model-runtime/src/providers/vercelaigateway/index.test.ts +47 -0
  73. package/packages/model-runtime/src/providers/vercelaigateway/index.ts +7 -1
  74. package/packages/types/src/message/ui/chat.ts +2 -0
  75. package/packages/types/src/tool/builtin.ts +5 -5
  76. package/src/features/Conversation/ChatItem/components/Title.tsx +1 -1
  77. package/src/features/Conversation/ChatList/index.tsx +0 -1
  78. package/src/features/Conversation/Messages/GroupTasks/TaskItem/ClientTaskItem.tsx +183 -0
  79. package/src/features/Conversation/Messages/GroupTasks/TaskItem/ServerTaskItem.tsx +94 -0
  80. package/src/features/Conversation/Messages/GroupTasks/TaskItem/TaskTitle.tsx +177 -0
  81. package/src/features/Conversation/Messages/GroupTasks/TaskItem/index.tsx +26 -0
  82. package/src/features/Conversation/Messages/GroupTasks/TaskItem/useClientTaskStats.ts +93 -0
  83. package/src/features/Conversation/Messages/GroupTasks/index.tsx +151 -0
  84. package/src/features/Conversation/Messages/Supervisor/index.tsx +7 -1
  85. package/src/features/Conversation/Messages/Task/ClientTaskDetail/index.tsx +72 -91
  86. package/src/features/Conversation/Messages/Task/TaskDetailPanel/StatusContent.tsx +46 -17
  87. package/src/features/Conversation/Messages/Tasks/TaskItem/ClientTaskItem.tsx +9 -24
  88. package/src/features/Conversation/Messages/Tasks/TaskItem/ServerTaskItem.tsx +18 -38
  89. package/src/features/Conversation/Messages/Tasks/shared/ErrorState.tsx +45 -2
  90. package/src/features/Conversation/Messages/Tasks/shared/InitializingState.tsx +16 -1
  91. package/src/features/Conversation/Messages/Tasks/shared/TaskContent.tsx +68 -0
  92. package/src/features/Conversation/Messages/Tasks/shared/TaskMessages.tsx +383 -0
  93. package/src/features/Conversation/Messages/Tasks/shared/index.ts +4 -0
  94. package/src/features/Conversation/Messages/Tasks/shared/useTaskPolling.ts +48 -0
  95. package/src/features/Conversation/Messages/index.tsx +5 -0
  96. package/src/locales/default/chat.ts +4 -0
  97. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +4 -0
  98. package/src/server/modules/AgentRuntime/__tests__/RuntimeExecutors.test.ts +106 -1
  99. package/src/server/services/aiAgent/__tests__/execAgent.threadId.test.ts +2 -2
  100. package/src/server/utils/truncateToolResult.ts +1 -4
  101. package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +15 -15
  102. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +22 -15
  103. package/src/store/chat/agents/__tests__/createAgentExecutors/exec-tasks.test.ts +21 -10
  104. package/src/store/chat/agents/createAgentExecutors.ts +2 -0
  105. package/src/store/chat/slices/aiAgent/actions/groupOrchestration.ts +10 -7
  106. package/src/features/Conversation/Messages/Task/ClientTaskDetail/CompletedState.tsx +0 -108
  107. package/src/features/Conversation/Messages/Task/ClientTaskDetail/InstructionAccordion.tsx +0 -63
  108. package/src/features/Conversation/Messages/Task/ClientTaskDetail/ProcessingState.tsx +0 -123
@@ -139,8 +139,8 @@ describe('createGroupOrchestrationExecutors', () => {
139
139
  {
140
140
  payload: {
141
141
  tasks: [
142
- { agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' },
143
- { agentId: TEST_IDS.AGENT_2_ID, task: 'Task 2', title: 'Task 2 Title' },
142
+ { agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' },
143
+ { agentId: TEST_IDS.AGENT_2_ID, instruction: 'Task 2', title: 'Task 2 Title' },
144
144
  ],
145
145
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
146
146
  },
@@ -187,8 +187,8 @@ describe('createGroupOrchestrationExecutors', () => {
187
187
  {
188
188
  payload: {
189
189
  tasks: [
190
- { agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' },
191
- { agentId: TEST_IDS.AGENT_2_ID, task: 'Task 2', title: 'Task 2 Title' },
190
+ { agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' },
191
+ { agentId: TEST_IDS.AGENT_2_ID, instruction: 'Task 2', title: 'Task 2 Title' },
192
192
  ],
193
193
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
194
194
  },
@@ -263,8 +263,8 @@ describe('createGroupOrchestrationExecutors', () => {
263
263
  {
264
264
  payload: {
265
265
  tasks: [
266
- { agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' },
267
- { agentId: TEST_IDS.AGENT_2_ID, task: 'Task 2', title: 'Task 2 Title' },
266
+ { agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' },
267
+ { agentId: TEST_IDS.AGENT_2_ID, instruction: 'Task 2', title: 'Task 2 Title' },
268
268
  ],
269
269
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
270
270
  },
@@ -327,8 +327,8 @@ describe('createGroupOrchestrationExecutors', () => {
327
327
  {
328
328
  payload: {
329
329
  tasks: [
330
- { agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' },
331
- { agentId: TEST_IDS.AGENT_2_ID, task: 'Task 2', title: 'Task 2 Title' },
330
+ { agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' },
331
+ { agentId: TEST_IDS.AGENT_2_ID, instruction: 'Task 2', title: 'Task 2 Title' },
332
332
  ],
333
333
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
334
334
  },
@@ -386,8 +386,8 @@ describe('createGroupOrchestrationExecutors', () => {
386
386
  {
387
387
  payload: {
388
388
  tasks: [
389
- { agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' },
390
- { agentId: TEST_IDS.AGENT_2_ID, task: 'Task 2', title: 'Task 2 Title' },
389
+ { agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' },
390
+ { agentId: TEST_IDS.AGENT_2_ID, instruction: 'Task 2', title: 'Task 2 Title' },
391
391
  ],
392
392
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
393
393
  },
@@ -445,8 +445,8 @@ describe('createGroupOrchestrationExecutors', () => {
445
445
  {
446
446
  payload: {
447
447
  tasks: [
448
- { agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' },
449
- { agentId: TEST_IDS.AGENT_2_ID, task: 'Task 2', title: 'Task 2 Title' },
448
+ { agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' },
449
+ { agentId: TEST_IDS.AGENT_2_ID, instruction: 'Task 2', title: 'Task 2 Title' },
450
450
  ],
451
451
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
452
452
  },
@@ -498,7 +498,7 @@ describe('createGroupOrchestrationExecutors', () => {
498
498
  const result = await batchExecTasksExecutor(
499
499
  {
500
500
  payload: {
501
- tasks: [{ agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' }],
501
+ tasks: [{ agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' }],
502
502
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
503
503
  },
504
504
  type: 'batch_exec_async_tasks',
@@ -546,7 +546,7 @@ describe('createGroupOrchestrationExecutors', () => {
546
546
  const result = await batchExecTasksExecutor(
547
547
  {
548
548
  payload: {
549
- tasks: [{ agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' }],
549
+ tasks: [{ agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' }],
550
550
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
551
551
  },
552
552
  type: 'batch_exec_async_tasks',
@@ -604,7 +604,7 @@ describe('createGroupOrchestrationExecutors', () => {
604
604
  await batchExecTasksExecutor(
605
605
  {
606
606
  payload: {
607
- tasks: [{ agentId: TEST_IDS.AGENT_1_ID, task: 'Task 1', title: 'Task 1 Title' }],
607
+ tasks: [{ agentId: TEST_IDS.AGENT_1_ID, instruction: 'Task 1', title: 'Task 1 Title' }],
608
608
  toolMessageId: TEST_IDS.TOOL_MESSAGE_ID,
609
609
  },
610
610
  type: 'batch_exec_async_tasks',
@@ -369,14 +369,17 @@ export const createGroupOrchestrationExecutors = (
369
369
  *
370
370
  * Returns: task_completed result
371
371
  */
372
- exec_async_task: async (instruction, state): Promise<GroupOrchestrationExecutorOutput> => {
373
- const { agentId, task, timeout, title, toolMessageId } = (
374
- instruction as SupervisorInstructionExecAsyncTask
372
+ exec_async_task: async (
373
+ supervisorInstruction,
374
+ state,
375
+ ): Promise<GroupOrchestrationExecutorOutput> => {
376
+ const { agentId, instruction, timeout, title, toolMessageId } = (
377
+ supervisorInstruction as SupervisorInstructionExecAsyncTask
375
378
  ).payload;
376
379
 
377
380
  const sessionLogId = `${state.operationId}:exec_async_task`;
378
381
  log(
379
- `[${sessionLogId}] Executing async task for agent: ${agentId}, task: ${task}, timeout: ${timeout}`,
382
+ `[${sessionLogId}] Executing async task for agent: ${agentId}, instruction: ${instruction}, timeout: ${timeout}`,
380
383
  );
381
384
 
382
385
  const { groupId, topicId } = messageContext;
@@ -400,7 +403,7 @@ export const createGroupOrchestrationExecutors = (
400
403
  agentId,
401
404
  content: '',
402
405
  groupId,
403
- metadata: { instruction: task, taskTitle: title },
406
+ metadata: { instruction, taskTitle: title },
404
407
  parentId: toolMessageId,
405
408
  role: 'task',
406
409
  topicId,
@@ -427,7 +430,7 @@ export const createGroupOrchestrationExecutors = (
427
430
  const createResult = await aiAgentService.execSubAgentTask({
428
431
  agentId,
429
432
  groupId,
430
- instruction: task,
433
+ instruction,
431
434
  parentMessageId: taskMessageId,
432
435
  title,
433
436
  topicId,
@@ -600,9 +603,12 @@ export const createGroupOrchestrationExecutors = (
600
603
  *
601
604
  * Returns: task_completed result
602
605
  */
603
- exec_client_async_task: async (instruction, state): Promise<GroupOrchestrationExecutorOutput> => {
604
- const { agentId, task, title, toolMessageId } = (
605
- instruction as SupervisorInstructionExecClientAsyncTask
606
+ exec_client_async_task: async (
607
+ supervisorInstruction,
608
+ state,
609
+ ): Promise<GroupOrchestrationExecutorOutput> => {
610
+ const { agentId, instruction, title, toolMessageId } = (
611
+ supervisorInstruction as SupervisorInstructionExecClientAsyncTask
606
612
  ).payload;
607
613
 
608
614
  const sessionLogId = `${state.operationId}:exec_client_async_task`;
@@ -629,7 +635,7 @@ export const createGroupOrchestrationExecutors = (
629
635
  agentId,
630
636
  content: '',
631
637
  groupId,
632
- metadata: { instruction: task, taskTitle: title },
638
+ metadata: { instruction, taskTitle: title },
633
639
  parentId: toolMessageId,
634
640
  role: 'task',
635
641
  topicId,
@@ -656,7 +662,7 @@ export const createGroupOrchestrationExecutors = (
656
662
  // Use Group-specific API that handles different agentIds in thread context
657
663
  const threadResult = await aiAgentService.createClientGroupAgentTaskThread({
658
664
  groupId: groupId!,
659
- instruction: task,
665
+ instruction,
660
666
  parentMessageId: taskMessageId,
661
667
  subAgentId: agentId,
662
668
  title,
@@ -861,9 +867,9 @@ export const createGroupOrchestrationExecutors = (
861
867
  interface TaskTracker {
862
868
  agentId: string;
863
869
  error?: string;
870
+ instruction: string;
864
871
  result?: string;
865
872
  status: 'pending' | 'running' | 'completed' | 'failed';
866
- task: string;
867
873
  taskMessageId?: string;
868
874
  threadId?: string;
869
875
  timeout: number;
@@ -873,7 +879,7 @@ export const createGroupOrchestrationExecutors = (
873
879
  const taskTrackers: TaskTracker[] = tasks.map((t) => ({
874
880
  agentId: t.agentId,
875
881
  status: 'pending',
876
- task: t.task,
882
+ instruction: t.instruction,
877
883
  timeout: t.timeout || 1_800_000, // Default 30 minutes
878
884
  title: t.title,
879
885
  }));
@@ -887,8 +893,9 @@ export const createGroupOrchestrationExecutors = (
887
893
  {
888
894
  agentId: tracker.agentId,
889
895
  content: '',
896
+ createdAt: Date.now() + index,
890
897
  groupId,
891
- metadata: { instruction: tracker.task, taskTitle: tracker.title },
898
+ metadata: { instruction: tracker.instruction, taskTitle: tracker.title },
892
899
  parentId: toolMessageId,
893
900
  role: 'task',
894
901
  topicId,
@@ -922,7 +929,7 @@ export const createGroupOrchestrationExecutors = (
922
929
  const createResult = await aiAgentService.execSubAgentTask({
923
930
  agentId: tracker.agentId,
924
931
  groupId,
925
- instruction: tracker.task,
932
+ instruction: tracker.instruction,
926
933
  parentMessageId: tracker.taskMessageId,
927
934
  title: tracker.title,
928
935
  topicId,
@@ -66,7 +66,8 @@ describe('exec_tasks executor', () => {
66
66
  expect(result.nextContext).toBeDefined();
67
67
  expect((result.nextContext as AgentRuntimeContext).phase).toBe('tasks_batch_result');
68
68
 
69
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
69
+ const payload = (result.nextContext as AgentRuntimeContext)
70
+ .payload as TasksBatchResultPayload;
70
71
  expect(payload.results).toHaveLength(1);
71
72
  expect(payload.results[0].success).toBe(true);
72
73
  expect(payload.results[0].threadId).toBe('thread_1');
@@ -131,7 +132,8 @@ describe('exec_tasks executor', () => {
131
132
 
132
133
  // Then
133
134
  expect(result.nextContext).toBeDefined();
134
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
135
+ const payload = (result.nextContext as AgentRuntimeContext)
136
+ .payload as TasksBatchResultPayload;
135
137
  expect(payload.results).toHaveLength(3);
136
138
  expect(payload.results.every((r) => r.success)).toBe(true);
137
139
  });
@@ -170,7 +172,8 @@ describe('exec_tasks executor', () => {
170
172
 
171
173
  // Then
172
174
  expect(result.nextContext).toBeDefined();
173
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
175
+ const payload = (result.nextContext as AgentRuntimeContext)
176
+ .payload as TasksBatchResultPayload;
174
177
  expect(payload.results).toHaveLength(1);
175
178
  expect(payload.results[0].success).toBe(false);
176
179
  expect(payload.results[0].error).toBe('No valid context available');
@@ -196,7 +199,8 @@ describe('exec_tasks executor', () => {
196
199
  });
197
200
 
198
201
  // Then
199
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
202
+ const payload = (result.nextContext as AgentRuntimeContext)
203
+ .payload as TasksBatchResultPayload;
200
204
  expect(payload.results[0].success).toBe(false);
201
205
  expect(payload.results[0].error).toBe('Failed to create task message');
202
206
  });
@@ -228,7 +232,8 @@ describe('exec_tasks executor', () => {
228
232
  });
229
233
 
230
234
  // Then
231
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
235
+ const payload = (result.nextContext as AgentRuntimeContext)
236
+ .payload as TasksBatchResultPayload;
232
237
  expect(payload.results[0].success).toBe(false);
233
238
  expect(payload.results[0].error).toBe('API error');
234
239
  expect(mockStore.optimisticUpdateMessageContent).toHaveBeenCalledWith(
@@ -270,7 +275,8 @@ describe('exec_tasks executor', () => {
270
275
  });
271
276
 
272
277
  // Then
273
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
278
+ const payload = (result.nextContext as AgentRuntimeContext)
279
+ .payload as TasksBatchResultPayload;
274
280
  expect(payload.results[0].success).toBe(false);
275
281
  expect(payload.results[0].error).toBe('Execution error');
276
282
  });
@@ -318,7 +324,8 @@ describe('exec_tasks executor', () => {
318
324
  },
319
325
  { operationId: 'test-op' },
320
326
  );
321
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
327
+ const payload = (result.nextContext as AgentRuntimeContext)
328
+ .payload as TasksBatchResultPayload;
322
329
  expect(payload.results[0].success).toBe(true);
323
330
  });
324
331
 
@@ -353,7 +360,8 @@ describe('exec_tasks executor', () => {
353
360
  });
354
361
 
355
362
  // Then
356
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
363
+ const payload = (result.nextContext as AgentRuntimeContext)
364
+ .payload as TasksBatchResultPayload;
357
365
  expect(payload.results[0].success).toBe(false);
358
366
  expect(payload.results[0].error).toBe('Task was cancelled');
359
367
  expect(mockStore.optimisticUpdateMessageContent).toHaveBeenCalledWith(
@@ -402,7 +410,8 @@ describe('exec_tasks executor', () => {
402
410
  });
403
411
 
404
412
  // Then
405
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
413
+ const payload = (result.nextContext as AgentRuntimeContext)
414
+ .payload as TasksBatchResultPayload;
406
415
  expect(payload.results[0].success).toBe(false);
407
416
  expect(payload.results[0].error).toBe('Operation cancelled');
408
417
  // getSubAgentTaskStatus should not be called since operation was cancelled before poll
@@ -532,6 +541,7 @@ describe('exec_tasks executor', () => {
532
541
  {
533
542
  agentId: 'agent_1',
534
543
  content: '',
544
+ createdAt: expect.any(Number),
535
545
  metadata: { instruction: 'Do something important' },
536
546
  parentId: 'msg_parent',
537
547
  role: 'task',
@@ -588,7 +598,8 @@ describe('exec_tasks executor', () => {
588
598
  });
589
599
 
590
600
  // Then
591
- const payload = (result.nextContext as AgentRuntimeContext).payload as TasksBatchResultPayload;
601
+ const payload = (result.nextContext as AgentRuntimeContext)
602
+ .payload as TasksBatchResultPayload;
592
603
  expect(payload.results).toHaveLength(2);
593
604
  expect(payload.results[0].success).toBe(true);
594
605
  expect(payload.results[1].success).toBe(false);
@@ -1349,6 +1349,7 @@ export const createAgentExecutors = (context: {
1349
1349
  {
1350
1350
  agentId,
1351
1351
  content: '',
1352
+ createdAt: Date.now() + taskIndex,
1352
1353
  metadata: { instruction: task.instruction },
1353
1354
  parentId: parentMessageId,
1354
1355
  role: 'task',
@@ -2035,6 +2036,7 @@ export const createAgentExecutors = (context: {
2035
2036
  {
2036
2037
  agentId,
2037
2038
  content: '',
2039
+ createdAt: Date.now() + taskIndex,
2038
2040
  metadata: { instruction: task.instruction, taskTitle: task.description },
2039
2041
  parentId: parentMessageId,
2040
2042
  role: 'task',
@@ -216,17 +216,17 @@ export const groupOrchestrationSlice: StateCreator<
216
216
  const {
217
217
  supervisorAgentId,
218
218
  agentId,
219
- task,
219
+ instruction,
220
220
  timeout,
221
221
  toolMessageId,
222
222
  skipCallSupervisor,
223
223
  runInClient,
224
224
  } = params;
225
225
  log(
226
- '[triggerExecuteTask] Starting orchestration with execute_task: supervisorAgentId=%s, agentId=%s, task=%s, timeout=%s, toolMessageId=%s, skipCallSupervisor=%s, runInClient=%s',
226
+ '[triggerExecuteTask] Starting orchestration with execute_task: supervisorAgentId=%s, agentId=%s, instruction=%s, timeout=%s, toolMessageId=%s, skipCallSupervisor=%s, runInClient=%s',
227
227
  supervisorAgentId,
228
228
  agentId,
229
- task,
229
+ instruction,
230
230
  timeout,
231
231
  toolMessageId,
232
232
  skipCallSupervisor,
@@ -248,7 +248,7 @@ export const groupOrchestrationSlice: StateCreator<
248
248
  type: 'supervisor_decided',
249
249
  payload: {
250
250
  decision: 'execute_task',
251
- params: { agentId, runInClient, task, timeout, toolMessageId },
251
+ params: { agentId, instruction, runInClient, timeout, toolMessageId },
252
252
  skipCallSupervisor: skipCallSupervisor ?? false,
253
253
  },
254
254
  },
@@ -446,12 +446,15 @@ export const groupOrchestrationSlice: StateCreator<
446
446
  revalidateOnReconnect: false,
447
447
  refreshInterval: POLLING_INTERVAL,
448
448
  onSuccess: (data) => {
449
- if (data?.taskDetail && messageId) {
450
- // Update taskDetail
449
+ if (data && messageId) {
450
+ // Update taskDetail and tasks (intermediate messages)
451
451
  get().internal_dispatchMessage({
452
452
  id: messageId,
453
453
  type: 'updateMessage',
454
- value: { taskDetail: data.taskDetail },
454
+ value: {
455
+ taskDetail: data.taskDetail,
456
+ tasks: data.messages,
457
+ },
455
458
  });
456
459
 
457
460
  // Update content when task is completed or failed
@@ -1,108 +0,0 @@
1
- 'use client';
2
-
3
- import { type AssistantContentBlock } from '@lobechat/types';
4
- import { Accordion, AccordionItem, Block, Flexbox, Icon, Text } from '@lobehub/ui';
5
- import { cssVar } from 'antd-style';
6
- import { Workflow } from 'lucide-react';
7
- import { memo, useMemo } from 'react';
8
- import { useTranslation } from 'react-i18next';
9
-
10
- import ContentBlock from '../../AssistantGroup/components/ContentBlock';
11
- import { formatDuration } from '../../Tasks/shared/utils';
12
- import Usage from '../../components/Extras/Usage';
13
-
14
- interface CompletedStateProps {
15
- assistantId: string;
16
- blocks: AssistantContentBlock[];
17
- duration?: number;
18
- model?: string;
19
- provider?: string;
20
- totalCost?: number;
21
- totalTokens?: number;
22
- totalToolCalls?: number;
23
- }
24
-
25
- const CompletedState = memo<CompletedStateProps>(
26
- ({ blocks, assistantId, duration, totalToolCalls, model, provider, totalTokens, totalCost }) => {
27
- const { t } = useTranslation('chat');
28
-
29
- // Split blocks: intermediate steps (all but last) and final result (last)
30
- const { intermediateBlocks, finalBlock } = useMemo(() => {
31
- if (blocks.length === 0) return { finalBlock: null, intermediateBlocks: [] };
32
- if (blocks.length === 1) return { finalBlock: blocks[0], intermediateBlocks: [] };
33
-
34
- return {
35
- finalBlock: blocks.at(-1)!,
36
- intermediateBlocks: blocks.slice(0, -1),
37
- };
38
- }, [blocks]);
39
-
40
- if (!finalBlock) return null;
41
-
42
- const title = (
43
- <Flexbox align="center" gap={8} horizontal>
44
- <Block
45
- align="center"
46
- flex="none"
47
- gap={4}
48
- height={24}
49
- horizontal
50
- justify="center"
51
- style={{ fontSize: 12 }}
52
- variant="outlined"
53
- width={24}
54
- >
55
- <Icon color={cssVar.colorTextSecondary} icon={Workflow} />
56
- </Block>
57
- <Flexbox align="center" gap={4} horizontal>
58
- <Text as="span" type="secondary" weight={500}>
59
- {totalToolCalls}
60
- </Text>
61
- <Text as="span" type="secondary">
62
- {t('task.metrics.toolCallsShort')}
63
- </Text>
64
- {/* Duration display */}
65
- {duration && (
66
- <Text as="span" type="secondary">
67
- {t('task.metrics.duration', { duration: formatDuration(duration) })}
68
- </Text>
69
- )}
70
- </Flexbox>
71
- </Flexbox>
72
- );
73
-
74
- return (
75
- <Flexbox gap={8}>
76
- {/* Intermediate steps - collapsed by default */}
77
- {intermediateBlocks.length > 0 && (
78
- <Accordion defaultExpandedKeys={[]} gap={8}>
79
- <AccordionItem itemKey="intermediate" paddingBlock={4} paddingInline={4} title={title}>
80
- <Flexbox gap={8} paddingInline={4} style={{ marginTop: 8 }}>
81
- {intermediateBlocks.map((block) => (
82
- <ContentBlock
83
- {...block}
84
- assistantId={assistantId}
85
- disableEditing
86
- key={block.id}
87
- />
88
- ))}
89
- </Flexbox>
90
- </AccordionItem>
91
- </Accordion>
92
- )}
93
-
94
- {/* Final result - always visible */}
95
- <ContentBlock {...finalBlock} assistantId={assistantId} disableEditing />
96
-
97
- {/* Usage display */}
98
- {model && provider && (
99
- <Usage model={model} provider={provider} usage={{ cost: totalCost, totalTokens }} />
100
- )}
101
- </Flexbox>
102
- );
103
- },
104
- );
105
-
106
- CompletedState.displayName = 'ClientCompletedState';
107
-
108
- export default CompletedState;
@@ -1,63 +0,0 @@
1
- import { Accordion, AccordionItem, Block, Flexbox, Icon, Markdown, Text } from '@lobehub/ui';
2
- import { cssVar } from 'antd-style';
3
- import { ScrollText } from 'lucide-react';
4
- import { memo, useEffect, useState } from 'react';
5
- import { useTranslation } from 'react-i18next';
6
-
7
- interface InstructionAccordionProps {
8
- childrenCount: number;
9
- instruction: string;
10
- }
11
-
12
- const InstructionAccordion = memo<InstructionAccordionProps>(({ instruction, childrenCount }) => {
13
- const { t } = useTranslation('chat');
14
-
15
- // Auto-collapse instruction when children count exceeds threshold
16
- const [expandedKeys, setExpandedKeys] = useState<string[]>(['instruction']);
17
-
18
- useEffect(() => {
19
- if (childrenCount > 1) {
20
- setExpandedKeys([]);
21
- }
22
- }, [childrenCount > 1]);
23
-
24
- return (
25
- <Accordion
26
- expandedKeys={expandedKeys}
27
- gap={8}
28
- onExpandedChange={(keys) => setExpandedKeys(keys as string[])}
29
- >
30
- <AccordionItem
31
- itemKey="instruction"
32
- paddingBlock={4}
33
- paddingInline={4}
34
- title={
35
- <Flexbox align="center" gap={8} horizontal>
36
- <Block
37
- align="center"
38
- flex="none"
39
- gap={4}
40
- height={24}
41
- horizontal
42
- justify="center"
43
- style={{ fontSize: 12 }}
44
- variant="outlined"
45
- width={24}
46
- >
47
- <Icon color={cssVar.colorTextSecondary} icon={ScrollText} />
48
- </Block>
49
- <Text as="span" type="secondary">
50
- {t('task.instruction')}
51
- </Text>
52
- </Flexbox>
53
- }
54
- >
55
- <Block padding={12} style={{ marginBlock: 8, maxHeight: 300, overflow: 'auto' }} variant={'outlined'}>
56
- <Markdown variant={'chat'}>{instruction}</Markdown>
57
- </Block>
58
- </AccordionItem>
59
- </Accordion>
60
- );
61
- });
62
-
63
- export default InstructionAccordion;
@@ -1,123 +0,0 @@
1
- 'use client';
2
-
3
- import { type AssistantContentBlock } from '@lobechat/types';
4
- import { Block, Flexbox, ScrollShadow, Text } from '@lobehub/ui';
5
- import { createStaticStyles } from 'antd-style';
6
- import { type RefObject, memo, useEffect, useMemo, useState } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
-
9
- import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
10
- import AnimatedNumber from '@/features/Conversation/Messages/components/Extras/Usage/UsageDetail/AnimatedNumber';
11
- import { useAutoScroll } from '@/hooks/useAutoScroll';
12
-
13
- import ContentBlock from '../../AssistantGroup/components/ContentBlock';
14
- import { accumulateUsage, formatElapsedTime } from '../../Tasks/shared/utils';
15
- import Usage from '../../components/Extras/Usage';
16
-
17
- const styles = createStaticStyles(({ css }) => ({
18
- contentScroll: css`
19
- max-height: min(50vh, 300px);
20
- `,
21
- }));
22
-
23
- interface ProcessingStateProps {
24
- assistantId: string;
25
- blocks: AssistantContentBlock[];
26
- model?: string;
27
- provider?: string;
28
- startTime?: number;
29
- }
30
-
31
- const ProcessingState = memo<ProcessingStateProps>(
32
- ({ blocks, assistantId, startTime, model, provider }) => {
33
- const { t } = useTranslation('chat');
34
- const [elapsedTime, setElapsedTime] = useState(0);
35
- const { ref, handleScroll } = useAutoScroll<HTMLDivElement>({
36
- deps: [blocks],
37
- enabled: true,
38
- });
39
-
40
- const totalToolCalls = useMemo(
41
- () => blocks.reduce((sum, block) => sum + (block.tools?.length || 0), 0),
42
- [blocks],
43
- );
44
-
45
- // Accumulate usage from all blocks
46
- const accumulatedUsage = useMemo(() => accumulateUsage(blocks), [blocks]);
47
-
48
- // Calculate initial elapsed time
49
- useEffect(() => {
50
- if (startTime) {
51
- setElapsedTime(Math.max(0, Date.now() - startTime));
52
- }
53
- }, [startTime]);
54
-
55
- // Timer for updating elapsed time every second
56
- useEffect(() => {
57
- if (!startTime) return;
58
-
59
- const timer = setInterval(() => {
60
- setElapsedTime(Math.max(0, Date.now() - startTime));
61
- }, 1000);
62
-
63
- return () => clearInterval(timer);
64
- }, [startTime]);
65
-
66
- return (
67
- <Flexbox gap={8}>
68
- <Flexbox align="center" gap={8} horizontal paddingInline={4}>
69
- <Block
70
- align="center"
71
- flex="none"
72
- gap={4}
73
- height={24}
74
- horizontal
75
- justify="center"
76
- style={{ fontSize: 12 }}
77
- variant="outlined"
78
- width={24}
79
- >
80
- <NeuralNetworkLoading size={16} />
81
- </Block>
82
- <Flexbox align="center" gap={4} horizontal>
83
- <Text as="span" type="secondary" weight={500}>
84
- <AnimatedNumber
85
- duration={500}
86
- formatter={(v) => Math.round(v).toString()}
87
- value={totalToolCalls}
88
- />
89
- </Text>
90
- <Text as="span" type="secondary">
91
- {t('task.metrics.toolCallsShort')}
92
- </Text>
93
- {startTime && (
94
- <Text as="span" type="secondary">
95
- ({formatElapsedTime(elapsedTime)})
96
- </Text>
97
- )}
98
- </Flexbox>
99
- </Flexbox>
100
- <ScrollShadow
101
- className={styles.contentScroll}
102
- offset={12}
103
- onScroll={handleScroll}
104
- ref={ref as RefObject<HTMLDivElement>}
105
- size={8}
106
- >
107
- <Flexbox gap={8}>
108
- {blocks.map((block) => (
109
- <ContentBlock {...block} assistantId={assistantId} disableEditing key={block.id} />
110
- ))}
111
- </Flexbox>
112
- </ScrollShadow>
113
-
114
- {/* Usage display */}
115
- {model && provider && <Usage model={model} provider={provider} usage={accumulatedUsage} />}
116
- </Flexbox>
117
- );
118
- },
119
- );
120
-
121
- ProcessingState.displayName = 'ClientProcessingState';
122
-
123
- export default ProcessingState;