@lobehub/lobehub 2.0.10 → 2.0.12

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 (101) 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/database/src/repositories/agentGroup/index.ts +4 -0
  61. package/packages/types/src/message/ui/chat.ts +2 -0
  62. package/packages/types/src/tool/builtin.ts +5 -5
  63. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/ForkGroupAndChat.tsx +2 -1
  64. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/index.tsx +2 -2
  65. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/useMarketGroupPublish.ts +11 -12
  66. package/src/features/Conversation/ChatItem/components/Title.tsx +1 -1
  67. package/src/features/Conversation/ChatList/index.tsx +0 -1
  68. package/src/features/Conversation/Messages/GroupTasks/TaskItem/ClientTaskItem.tsx +183 -0
  69. package/src/features/Conversation/Messages/GroupTasks/TaskItem/ServerTaskItem.tsx +94 -0
  70. package/src/features/Conversation/Messages/GroupTasks/TaskItem/TaskTitle.tsx +177 -0
  71. package/src/features/Conversation/Messages/GroupTasks/TaskItem/index.tsx +26 -0
  72. package/src/features/Conversation/Messages/GroupTasks/TaskItem/useClientTaskStats.ts +93 -0
  73. package/src/features/Conversation/Messages/GroupTasks/index.tsx +151 -0
  74. package/src/features/Conversation/Messages/Supervisor/index.tsx +7 -1
  75. package/src/features/Conversation/Messages/Task/ClientTaskDetail/index.tsx +72 -91
  76. package/src/features/Conversation/Messages/Task/TaskDetailPanel/StatusContent.tsx +46 -17
  77. package/src/features/Conversation/Messages/Tasks/TaskItem/ClientTaskItem.tsx +9 -24
  78. package/src/features/Conversation/Messages/Tasks/TaskItem/ServerTaskItem.tsx +18 -38
  79. package/src/features/Conversation/Messages/Tasks/shared/ErrorState.tsx +45 -2
  80. package/src/features/Conversation/Messages/Tasks/shared/InitializingState.tsx +16 -1
  81. package/src/features/Conversation/Messages/Tasks/shared/TaskContent.tsx +68 -0
  82. package/src/features/Conversation/Messages/Tasks/shared/TaskMessages.tsx +383 -0
  83. package/src/features/Conversation/Messages/Tasks/shared/index.ts +4 -0
  84. package/src/features/Conversation/Messages/Tasks/shared/useTaskPolling.ts +48 -0
  85. package/src/features/Conversation/Messages/index.tsx +5 -0
  86. package/src/locales/default/chat.ts +4 -0
  87. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +4 -0
  88. package/src/server/modules/AgentRuntime/__tests__/RuntimeExecutors.test.ts +106 -1
  89. package/src/server/routers/lambda/agentGroup.ts +2 -0
  90. package/src/server/routers/lambda/market/agent.ts +17 -45
  91. package/src/server/routers/lambda/market/agentGroup.ts +13 -25
  92. package/src/server/services/aiAgent/__tests__/execAgent.threadId.test.ts +2 -2
  93. package/src/server/utils/truncateToolResult.ts +1 -4
  94. package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +15 -15
  95. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +22 -15
  96. package/src/store/chat/agents/__tests__/createAgentExecutors/exec-tasks.test.ts +21 -10
  97. package/src/store/chat/agents/createAgentExecutors.ts +2 -0
  98. package/src/store/chat/slices/aiAgent/actions/groupOrchestration.ts +10 -7
  99. package/src/features/Conversation/Messages/Task/ClientTaskDetail/CompletedState.tsx +0 -108
  100. package/src/features/Conversation/Messages/Task/ClientTaskDetail/InstructionAccordion.tsx +0 -63
  101. package/src/features/Conversation/Messages/Task/ClientTaskDetail/ProcessingState.tsx +0 -123
@@ -1,6 +1,10 @@
1
1
  import type { Message } from '../../../../types';
2
2
  import speakDifferentAgent from './speak-different-agent.json';
3
+ import supervisorAfterMultiTasks from './supervisor-after-multi-tasks.json';
4
+ import supervisorContentOnly from './supervisor-content-only.json';
3
5
 
4
6
  export const agentGroup = {
5
7
  speakDifferentAgent: speakDifferentAgent as Message[],
8
+ supervisorAfterMultiTasks: supervisorAfterMultiTasks as Message[],
9
+ supervisorContentOnly: supervisorContentOnly as Message[],
6
10
  };
@@ -0,0 +1,91 @@
1
+ [
2
+ {
3
+ "id": "msg-user-1",
4
+ "role": "user",
5
+ "content": "帮我调研下 clawdbot",
6
+ "parentId": null,
7
+ "createdAt": 1704067200000,
8
+ "updatedAt": 1704067200000
9
+ },
10
+ {
11
+ "id": "msg-supervisor-1",
12
+ "role": "assistant",
13
+ "agentId": "supervisor",
14
+ "content": "我会安排团队成员进行调研。",
15
+ "parentId": "msg-user-1",
16
+ "tools": [
17
+ {
18
+ "id": "call_tasks_1",
19
+ "type": "builtin",
20
+ "apiName": "executeAgentTasks",
21
+ "arguments": "{\"tasks\":[{\"agentId\":\"agent-1\",\"title\":\"任务1\"},{\"agentId\":\"agent-2\",\"title\":\"任务2\"}]}",
22
+ "identifier": "lobe-group-management"
23
+ }
24
+ ],
25
+ "createdAt": 1704067201000,
26
+ "updatedAt": 1704067201000,
27
+ "metadata": {
28
+ "isSupervisor": true
29
+ }
30
+ },
31
+ {
32
+ "id": "msg-tool-1",
33
+ "role": "tool",
34
+ "content": "Triggered 2 tasks.",
35
+ "parentId": "msg-supervisor-1",
36
+ "tool_call_id": "call_tasks_1",
37
+ "createdAt": 1704067202000,
38
+ "updatedAt": 1704067202000
39
+ },
40
+ {
41
+ "id": "msg-task-1",
42
+ "role": "task",
43
+ "content": "调研结果1...",
44
+ "parentId": "msg-tool-1",
45
+ "agentId": "agent-1",
46
+ "createdAt": 1704067203000,
47
+ "updatedAt": 1704067203000,
48
+ "metadata": {
49
+ "taskTitle": "任务1"
50
+ },
51
+ "taskDetail": {
52
+ "status": "completed",
53
+ "threadId": "thd_xxx1",
54
+ "title": "任务1"
55
+ }
56
+ },
57
+ {
58
+ "id": "msg-task-2",
59
+ "role": "task",
60
+ "content": "调研结果2...",
61
+ "parentId": "msg-tool-1",
62
+ "agentId": "agent-2",
63
+ "createdAt": 1704067204000,
64
+ "updatedAt": 1704067204000,
65
+ "metadata": {
66
+ "taskTitle": "任务2"
67
+ },
68
+ "taskDetail": {
69
+ "status": "completed",
70
+ "threadId": "thd_xxx2",
71
+ "title": "任务2"
72
+ }
73
+ },
74
+ {
75
+ "id": "msg-supervisor-summary",
76
+ "role": "assistant",
77
+ "agentId": "supervisor",
78
+ "content": "调研完成!这是综合汇总报告...",
79
+ "parentId": "msg-task-2",
80
+ "tools": null,
81
+ "createdAt": 1704067210000,
82
+ "updatedAt": 1704067210000,
83
+ "metadata": {
84
+ "isSupervisor": true,
85
+ "tps": 78.99,
86
+ "cost": 0.208
87
+ },
88
+ "model": "claude-sonnet-4",
89
+ "provider": "anthropic"
90
+ }
91
+ ]
@@ -0,0 +1,74 @@
1
+ [
2
+ {
3
+ "id": "msg-user-1",
4
+ "role": "user",
5
+ "content": "帮我调研下 clawdbot",
6
+ "parentId": null,
7
+ "createdAt": 1704067200000,
8
+ "updatedAt": 1704067200000
9
+ },
10
+ {
11
+ "id": "msg-supervisor-1",
12
+ "role": "assistant",
13
+ "agentId": "supervisor",
14
+ "content": "我会安排团队成员进行调研。",
15
+ "parentId": "msg-user-1",
16
+ "tools": [
17
+ {
18
+ "id": "call_tasks_1",
19
+ "type": "builtin",
20
+ "apiName": "executeAgentTasks",
21
+ "arguments": "{\"tasks\":[{\"agentId\":\"agent-1\",\"title\":\"调研任务\"}]}",
22
+ "identifier": "lobe-group-management"
23
+ }
24
+ ],
25
+ "createdAt": 1704067201000,
26
+ "updatedAt": 1704067201000,
27
+ "metadata": {
28
+ "isSupervisor": true
29
+ }
30
+ },
31
+ {
32
+ "id": "msg-tool-1",
33
+ "role": "tool",
34
+ "content": "Triggered 1 task.",
35
+ "parentId": "msg-supervisor-1",
36
+ "tool_call_id": "call_tasks_1",
37
+ "createdAt": 1704067202000,
38
+ "updatedAt": 1704067202000
39
+ },
40
+ {
41
+ "id": "msg-task-1",
42
+ "role": "task",
43
+ "content": "调研结果内容...",
44
+ "parentId": "msg-tool-1",
45
+ "agentId": "agent-1",
46
+ "createdAt": 1704067203000,
47
+ "updatedAt": 1704067203000,
48
+ "metadata": {
49
+ "taskTitle": "调研任务"
50
+ },
51
+ "taskDetail": {
52
+ "status": "completed",
53
+ "threadId": "thd_xxx",
54
+ "title": "调研任务"
55
+ }
56
+ },
57
+ {
58
+ "id": "msg-supervisor-summary",
59
+ "role": "assistant",
60
+ "agentId": "supervisor",
61
+ "content": "调研完成!这是综合汇总报告...",
62
+ "parentId": "msg-task-1",
63
+ "tools": null,
64
+ "createdAt": 1704067210000,
65
+ "updatedAt": 1704067210000,
66
+ "metadata": {
67
+ "isSupervisor": true,
68
+ "tps": 78.99,
69
+ "cost": 0.208
70
+ },
71
+ "model": "claude-sonnet-4",
72
+ "provider": "anthropic"
73
+ }
74
+ ]
@@ -153,6 +153,43 @@ describe('parse', () => {
153
153
 
154
154
  expect(serializeParseResult(result)).toEqual(outputs.agentGroup.speakDifferentAgent);
155
155
  });
156
+
157
+ it('should handle supervisor content-only message (no tools)', () => {
158
+ const result = parse(inputs.agentGroup.supervisorContentOnly);
159
+
160
+ // The critical assertions:
161
+ // 1. The final supervisor message (content-only, no tools) should be transformed to role='supervisor'
162
+ // 2. Its content should be moved to children array
163
+ const supervisorSummary = result.flatList.find((m) => m.id === 'msg-supervisor-summary');
164
+ expect(supervisorSummary).toBeDefined();
165
+ expect(supervisorSummary?.role).toBe('supervisor');
166
+ expect((supervisorSummary as any)?.children).toHaveLength(1);
167
+ expect((supervisorSummary as any)?.children[0].content).toBe('调研完成!这是综合汇总报告...');
168
+ // The top-level content should be empty
169
+ expect(supervisorSummary?.content).toBe('');
170
+ });
171
+
172
+ it('should handle supervisor summary after multiple tasks (content folded into children)', () => {
173
+ const result = parse(inputs.agentGroup.supervisorAfterMultiTasks);
174
+
175
+ // The critical assertions:
176
+ // 1. flatList should have: user, supervisor(+tool), groupTasks(2 tasks), supervisor-summary
177
+ expect(result.flatList).toHaveLength(4);
178
+ expect(result.flatList[0].role).toBe('user');
179
+ expect(result.flatList[1].role).toBe('supervisor');
180
+ expect(result.flatList[2].role).toBe('groupTasks');
181
+ expect(result.flatList[3].role).toBe('supervisor');
182
+
183
+ // 2. groupTasks should have 2 tasks
184
+ expect((result.flatList[2] as any).tasks).toHaveLength(2);
185
+
186
+ // 3. The supervisor summary (no tools) should have content folded into children
187
+ const supervisorSummary = result.flatList[3];
188
+ expect(supervisorSummary.id).toBe('msg-supervisor-summary');
189
+ expect(supervisorSummary.content).toBe(''); // content should be empty
190
+ expect((supervisorSummary as any).children).toHaveLength(1);
191
+ expect((supervisorSummary as any).children[0].content).toBe('调研完成!这是综合汇总报告...');
192
+ });
156
193
  });
157
194
 
158
195
  describe('Tasks Aggregation', () => {
@@ -98,8 +98,16 @@ export class FlatListBuilder {
98
98
  return child?.role !== 'task';
99
99
  });
100
100
 
101
- // Create tasks virtual message
102
- const tasksMessage = this.createTasksMessage(parentMessage, taskChildren, processedIds);
101
+ // Check if tasks have different agentIds (groupTasks) or same agentId (tasks)
102
+ const taskAgentIds = new Set(
103
+ taskChildren.map((childId) => this.messageMap.get(childId)?.agentId).filter(Boolean),
104
+ );
105
+ const isGroupTasks = taskAgentIds.size > 1;
106
+
107
+ // Create appropriate virtual message based on agent diversity
108
+ const tasksMessage = isGroupTasks
109
+ ? this.createGroupTasksMessage(parentMessage, taskChildren, processedIds)
110
+ : this.createTasksMessage(parentMessage, taskChildren, processedIds);
103
111
  flatList.push(tasksMessage);
104
112
 
105
113
  // Continue with non-task children (e.g., final summary from assistant)
@@ -136,8 +144,18 @@ export class FlatListBuilder {
136
144
  taskGrandchild.tools &&
137
145
  taskGrandchild.tools.length > 0
138
146
  ) {
139
- this.processAssistantGroup(
140
- taskGrandchild,
147
+ this.processAssistantGroup(taskGrandchild, flatList, processedIds, allMessages);
148
+ } else if (
149
+ // Check if it's a supervisor message without tools (content-only)
150
+ taskGrandchild.role === 'assistant' &&
151
+ taskGrandchild.metadata?.isSupervisor &&
152
+ (!taskGrandchild.tools || taskGrandchild.tools.length === 0)
153
+ ) {
154
+ const supervisorMessage = this.createSupervisorContentMessage(taskGrandchild);
155
+ flatList.push(supervisorMessage);
156
+ processedIds.add(taskGrandchildId);
157
+ this.buildFlatListRecursive(
158
+ taskGrandchildId,
141
159
  flatList,
142
160
  processedIds,
143
161
  allMessages,
@@ -1037,4 +1055,52 @@ export class FlatListBuilder {
1037
1055
  updatedAt,
1038
1056
  } as Message;
1039
1057
  }
1058
+
1059
+ /**
1060
+ * Create a virtual groupTasks message for multiple tasks with different agentIds
1061
+ */
1062
+ private createGroupTasksMessage(
1063
+ parentMessage: Message,
1064
+ taskChildIds: string[],
1065
+ processedIds: Set<string>,
1066
+ ): Message {
1067
+ const taskMessages: Message[] = [];
1068
+
1069
+ for (const taskId of taskChildIds) {
1070
+ const taskMessage = this.messageMap.get(taskId);
1071
+ if (taskMessage) {
1072
+ taskMessages.push(taskMessage);
1073
+ processedIds.add(taskId);
1074
+ }
1075
+ }
1076
+
1077
+ // Sort by createdAt to maintain order
1078
+ taskMessages.sort((a, b) => a.createdAt - b.createdAt);
1079
+
1080
+ // Generate ID with parent message id and all task message ids
1081
+ const taskIdsStr = taskMessages.map((t) => t.id).join('-');
1082
+ const groupTasksId = `groupTasks-${parentMessage.id}-${taskIdsStr}`;
1083
+
1084
+ // Calculate timestamps from task messages
1085
+ const createdAt =
1086
+ taskMessages.length > 0
1087
+ ? Math.min(...taskMessages.map((m) => m.createdAt))
1088
+ : parentMessage.createdAt;
1089
+ const updatedAt =
1090
+ taskMessages.length > 0
1091
+ ? Math.max(...taskMessages.map((m) => m.updatedAt))
1092
+ : parentMessage.updatedAt;
1093
+
1094
+ return {
1095
+ content: '',
1096
+ createdAt,
1097
+ extra: {
1098
+ parentMessageId: parentMessage.id,
1099
+ },
1100
+ id: groupTasksId,
1101
+ role: 'groupTasks' as any,
1102
+ tasks: taskMessages as any,
1103
+ updatedAt,
1104
+ } as Message;
1105
+ }
1040
1106
  }
@@ -557,5 +557,152 @@ describe('FlatListBuilder', () => {
557
557
  expect(result[1].id).toBe('msg-2');
558
558
  expect(result[2].id).toBe('msg-3');
559
559
  });
560
+
561
+ it('should create tasks message when multiple tasks have same agentId', () => {
562
+ const messages: Message[] = [
563
+ {
564
+ content: 'User request',
565
+ createdAt: 0,
566
+ id: 'msg-1',
567
+ role: 'user',
568
+ updatedAt: 0,
569
+ },
570
+ {
571
+ content: 'Tool message',
572
+ createdAt: 0,
573
+ id: 'tool-1',
574
+ parentId: 'msg-1',
575
+ role: 'tool',
576
+ updatedAt: 0,
577
+ },
578
+ {
579
+ agentId: 'agent-1',
580
+ content: 'Task 1 result',
581
+ createdAt: 1,
582
+ id: 'task-1',
583
+ parentId: 'tool-1',
584
+ role: 'task',
585
+ updatedAt: 1,
586
+ },
587
+ {
588
+ agentId: 'agent-1',
589
+ content: 'Task 2 result',
590
+ createdAt: 2,
591
+ id: 'task-2',
592
+ parentId: 'tool-1',
593
+ role: 'task',
594
+ updatedAt: 2,
595
+ },
596
+ ];
597
+
598
+ const builder = createBuilder(messages);
599
+ const result = builder.flatten(messages);
600
+
601
+ // Should create tasks (not groupTasks) since all tasks have same agentId
602
+ expect(result).toHaveLength(3);
603
+ expect(result[0].id).toBe('msg-1');
604
+ expect(result[1].id).toBe('tool-1');
605
+ expect(result[2].role).toBe('tasks');
606
+ expect((result[2] as any).tasks).toHaveLength(2);
607
+ });
608
+
609
+ it('should create groupTasks message when multiple tasks have different agentIds', () => {
610
+ const messages: Message[] = [
611
+ {
612
+ content: 'User request',
613
+ createdAt: 0,
614
+ id: 'msg-1',
615
+ role: 'user',
616
+ updatedAt: 0,
617
+ },
618
+ {
619
+ content: 'Tool message',
620
+ createdAt: 0,
621
+ id: 'tool-1',
622
+ parentId: 'msg-1',
623
+ role: 'tool',
624
+ updatedAt: 0,
625
+ },
626
+ {
627
+ agentId: 'agent-1',
628
+ content: 'Task 1 result',
629
+ createdAt: 1,
630
+ id: 'task-1',
631
+ parentId: 'tool-1',
632
+ role: 'task',
633
+ updatedAt: 1,
634
+ },
635
+ {
636
+ agentId: 'agent-2',
637
+ content: 'Task 2 result',
638
+ createdAt: 2,
639
+ id: 'task-2',
640
+ parentId: 'tool-1',
641
+ role: 'task',
642
+ updatedAt: 2,
643
+ },
644
+ {
645
+ agentId: 'agent-3',
646
+ content: 'Task 3 result',
647
+ createdAt: 3,
648
+ id: 'task-3',
649
+ parentId: 'tool-1',
650
+ role: 'task',
651
+ updatedAt: 3,
652
+ },
653
+ ];
654
+
655
+ const builder = createBuilder(messages);
656
+ const result = builder.flatten(messages);
657
+
658
+ // Should create groupTasks since tasks have different agentIds
659
+ expect(result).toHaveLength(3);
660
+ expect(result[0].id).toBe('msg-1');
661
+ expect(result[1].id).toBe('tool-1');
662
+ expect(result[2].role).toBe('groupTasks');
663
+ expect((result[2] as any).tasks).toHaveLength(3);
664
+ // Verify ID format
665
+ expect(result[2].id).toContain('groupTasks-');
666
+ });
667
+
668
+ it('should create groupTasks with correct timestamps from task messages', () => {
669
+ const messages: Message[] = [
670
+ {
671
+ content: 'Tool message',
672
+ createdAt: 0,
673
+ id: 'tool-1',
674
+ role: 'tool',
675
+ updatedAt: 0,
676
+ },
677
+ {
678
+ agentId: 'agent-1',
679
+ content: 'Task 1',
680
+ createdAt: 100,
681
+ id: 'task-1',
682
+ parentId: 'tool-1',
683
+ role: 'task',
684
+ updatedAt: 150,
685
+ },
686
+ {
687
+ agentId: 'agent-2',
688
+ content: 'Task 2',
689
+ createdAt: 200,
690
+ id: 'task-2',
691
+ parentId: 'tool-1',
692
+ role: 'task',
693
+ updatedAt: 300,
694
+ },
695
+ ];
696
+
697
+ const builder = createBuilder(messages);
698
+ const result = builder.flatten(messages);
699
+
700
+ const groupTasksMsg = result.find((m) => m.role === 'groupTasks');
701
+ expect(groupTasksMsg).toBeDefined();
702
+ // createdAt should be min of task createdAt
703
+ expect(groupTasksMsg!.createdAt).toBe(100);
704
+ // updatedAt should be max of task updatedAt
705
+ expect(groupTasksMsg!.updatedAt).toBe(300);
706
+ });
560
707
  });
561
708
  });
@@ -17,9 +17,11 @@ import { LobeChatDatabase } from '../../type';
17
17
  export interface SupervisorAgentConfig {
18
18
  avatar?: string;
19
19
  backgroundColor?: string;
20
+ chatConfig?: any;
20
21
  description?: string;
21
22
  model?: string;
22
23
  params?: any;
24
+ plugins?: string[];
23
25
  provider?: string;
24
26
  systemRole?: string;
25
27
  tags?: string[];
@@ -172,9 +174,11 @@ export class AgentGroupRepository {
172
174
  .values({
173
175
  avatar: supervisorConfig?.avatar,
174
176
  backgroundColor: supervisorConfig?.backgroundColor,
177
+ chatConfig: supervisorConfig?.chatConfig,
175
178
  description: supervisorConfig?.description,
176
179
  model: supervisorConfig?.model,
177
180
  params: supervisorConfig?.params,
181
+ plugins: supervisorConfig?.plugins,
178
182
  provider: supervisorConfig?.provider,
179
183
  systemRole: supervisorConfig?.systemRole,
180
184
  tags: supervisorConfig?.tags,
@@ -25,6 +25,7 @@ export type UIMessageRoleType =
25
25
  | 'tool'
26
26
  | 'task'
27
27
  | 'tasks'
28
+ | 'groupTasks'
28
29
  | 'supervisor'
29
30
  | 'assistantGroup'
30
31
  | 'agentCouncil'
@@ -185,6 +186,7 @@ export interface UIChatMessage {
185
186
  /**
186
187
  * Task messages for role='tasks' virtual message
187
188
  * Contains aggregated task messages with same parentId
189
+ * Also used to store task execution messages (intermediate steps) from polling
188
190
  */
189
191
  tasks?: UIChatMessage[];
190
192
  threadId?: string | null;
@@ -433,6 +433,10 @@ export interface TriggerExecuteTaskParams extends GroupOrchestrationBaseParams {
433
433
  * The agent ID to execute the task
434
434
  */
435
435
  agentId: string;
436
+ /**
437
+ * The instruction/task description for the agent
438
+ */
439
+ instruction: string;
436
440
  /**
437
441
  * Whether to run on the desktop client (for local file/shell access).
438
442
  * MUST be true when task requires local-system tools. Default is false (server execution).
@@ -443,10 +447,6 @@ export interface TriggerExecuteTaskParams extends GroupOrchestrationBaseParams {
443
447
  * without calling the supervisor again.
444
448
  */
445
449
  skipCallSupervisor?: boolean;
446
- /**
447
- * The task description for the agent
448
- */
449
- task: string;
450
450
  /**
451
451
  * Optional timeout in milliseconds
452
452
  */
@@ -466,7 +466,7 @@ export interface TriggerExecuteTaskItem {
466
466
  */
467
467
  agentId: string;
468
468
  /**
469
- * Detailed instruction/prompt for the task execution
469
+ * Detailed instruction for the agent to execute
470
470
  */
471
471
  instruction: string;
472
472
  /**
@@ -134,7 +134,8 @@ const ForkGroupAndChat = memo<{ mobile?: boolean }>(() => {
134
134
  // Group content is the supervisor's systemRole (for backward compatibility)
135
135
  content: config.systemRole || supervisorConfig?.systemRole,
136
136
  ...meta,
137
- marketIdentifier: forkResult.group.identifier, // Store the new market identifier
137
+ // Store marketIdentifier at top-level (same as agents)
138
+ marketIdentifier: forkResult.group.identifier,
138
139
  };
139
140
 
140
141
  // Step 5: Prepare member agents from market data
@@ -28,8 +28,8 @@ const GroupPublishButton = memo(() => {
28
28
 
29
29
  // Determine action based on whether we have an existing marketIdentifier
30
30
  // Backend will verify ownership and decide to create new or update
31
- // marketIdentifier is stored in editorData
32
- const action = currentGroup?.editorData?.marketIdentifier ? 'upload' : 'submit';
31
+ // marketIdentifier is stored at top-level (same as agents)
32
+ const action = currentGroup?.marketIdentifier ? 'upload' : 'submit';
33
33
 
34
34
  return (
35
35
  <>
@@ -45,8 +45,8 @@ export const useMarketGroupPublish = ({ action, onSuccess }: UseMarketGroupPubli
45
45
  * Returns whether fork confirmation is needed and original group info
46
46
  */
47
47
  const checkOwnership = useCallback(async (): Promise<CheckOwnershipResult> => {
48
- // marketIdentifier is stored in editorData
49
- const identifier = currentGroup?.editorData?.marketIdentifier as string | undefined;
48
+ // marketIdentifier is stored at top-level (same as agents)
49
+ const identifier = currentGroup?.marketIdentifier;
50
50
 
51
51
  // No identifier means new group, no need to check
52
52
  if (!identifier) {
@@ -150,27 +150,26 @@ export const useMarketGroupPublish = ({ action, onSuccess }: UseMarketGroupPubli
150
150
  }),
151
151
  ...(currentGroupConfig.openingQuestions !== undefined &&
152
152
  currentGroupConfig.openingQuestions.length > 0 && {
153
- openingQuestions: currentGroupConfig.openingQuestions,
154
- }),
153
+ openingQuestions: currentGroupConfig.openingQuestions,
154
+ }),
155
155
  ...(currentGroupConfig.allowDM !== undefined && { allowDM: currentGroupConfig.allowDM }),
156
- ...(currentGroupConfig.revealDM !== undefined && { revealDM: currentGroupConfig.revealDM }),
156
+ ...(currentGroupConfig.revealDM !== undefined && {
157
+ revealDM: currentGroupConfig.revealDM,
158
+ }),
157
159
  },
158
160
  // Market requires at least 1 character for description
159
161
  description: currentGroupMeta.description || 'No description provided',
160
- // marketIdentifier is stored in editorData
161
- identifier: currentGroup.editorData?.marketIdentifier as string | undefined,
162
+ // marketIdentifier is stored at top-level (same as agents)
163
+ identifier: currentGroup.marketIdentifier,
162
164
  memberAgents,
163
165
  name: currentGroupMeta.title || 'Untitled Group',
164
166
  visibility: 'public', // TODO: Allow user to select visibility
165
167
  });
166
168
 
167
- // Save marketIdentifier to editorData if new group
169
+ // Save marketIdentifier at top-level if new group (same as agents)
168
170
  if (result.isNewGroup) {
169
171
  await updateGroupMeta({
170
- editorData: {
171
- ...currentGroup.editorData,
172
- marketIdentifier: result.identifier,
173
- },
172
+ marketIdentifier: result.identifier,
174
173
  });
175
174
  }
176
175
 
@@ -24,7 +24,7 @@ const Title = memo<TitleProps>(({ showTitle, time, avatar, titleAddon }) => {
24
24
  </Text>
25
25
  )}
26
26
  {showTitle ? titleAddon : undefined}
27
- {time && (
27
+ {!time ? null : (
28
28
  <Text
29
29
  aria-label="published-date"
30
30
  as={'time'}
@@ -91,7 +91,6 @@ const ChatList = memo<ChatListProps>(({ disableActionsBar, welcome, itemContent
91
91
  <MessageActionProvider withSingletonActionsBar={!disableActionsBar}>
92
92
  <VirtualizedList
93
93
  dataSource={displayMessageIds}
94
- // isGenerating={isGenerating}
95
94
  itemContent={itemContent ?? defaultItemContent}
96
95
  />
97
96
  </MessageActionProvider>