@lobehub/lobehub 2.0.0-next.286 → 2.0.0-next.288

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 (72) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/apps/desktop/src/main/const/theme.ts +0 -3
  3. package/apps/desktop/src/main/core/browser/Browser.ts +1 -1
  4. package/apps/desktop/src/main/core/browser/WindowThemeManager.ts +3 -2
  5. package/apps/desktop/src/main/core/browser/__tests__/Browser.test.ts +0 -1
  6. package/apps/desktop/src/main/core/browser/__tests__/WindowThemeManager.test.ts +8 -5
  7. package/changelog/v1.json +14 -0
  8. package/locales/en-US/plugin.json +3 -5
  9. package/locales/zh-CN/plugin.json +3 -5
  10. package/locales/zh-CN/tool.json +2 -0
  11. package/package.json +1 -1
  12. package/packages/builtin-agents/src/agents/group-supervisor/index.ts +12 -1
  13. package/packages/builtin-agents/src/agents/group-supervisor/systemRole.ts +0 -7
  14. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/EditLocalFile/index.tsx +93 -0
  15. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/GlobLocalFiles/index.tsx +73 -0
  16. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/GrepContent/index.tsx +69 -0
  17. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ListLocalFiles/index.tsx +68 -0
  18. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ReadLocalFile/index.tsx +74 -0
  19. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/SearchLocalFiles/index.tsx +70 -0
  20. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/WriteLocalFile/index.tsx +57 -0
  21. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/index.ts +14 -0
  22. package/packages/builtin-tool-cloud-sandbox/src/client/Render/WriteFile/index.tsx +54 -35
  23. package/packages/builtin-tool-cloud-sandbox/src/client/components/FilePathDisplay.tsx +52 -0
  24. package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteTasks/index.tsx +90 -0
  25. package/packages/builtin-tool-group-management/src/client/Inspector/index.ts +2 -0
  26. package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTasks.tsx +237 -0
  27. package/packages/builtin-tool-group-management/src/client/Intervention/index.ts +4 -1
  28. package/packages/builtin-tool-group-management/src/client/Render/index.ts +1 -1
  29. package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTask/index.tsx +69 -0
  30. package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTasks/index.tsx +87 -0
  31. package/packages/builtin-tool-group-management/src/client/Streaming/index.ts +4 -0
  32. package/packages/builtin-tool-group-management/src/executor.test.ts +8 -311
  33. package/packages/builtin-tool-group-management/src/executor.ts +5 -160
  34. package/packages/builtin-tool-group-management/src/manifest.ts +50 -94
  35. package/packages/builtin-tool-group-management/src/systemRole.ts +251 -172
  36. package/packages/builtin-tool-group-management/src/types.ts +29 -40
  37. package/packages/context-engine/src/engine/messages/MessagesEngine.ts +6 -4
  38. package/packages/context-engine/src/engine/messages/types.ts +4 -4
  39. package/packages/context-engine/src/processors/GroupRoleTransform.ts +261 -0
  40. package/packages/context-engine/src/processors/__tests__/GroupRoleTransform.test.ts +553 -0
  41. package/packages/context-engine/src/processors/index.ts +2 -2
  42. package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +4 -16
  43. package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +23 -28
  44. package/packages/desktop-bridge/src/index.ts +3 -0
  45. package/packages/prompts/src/prompts/agentGroup/__snapshots__/index.test.ts.snap +0 -7
  46. package/packages/prompts/src/prompts/agentGroup/groupContext.ts +0 -7
  47. package/src/app/[variants]/(main)/group/features/Conversation/AgentWelcome/OpeningQuestions.tsx +4 -8
  48. package/src/app/[variants]/(main)/group/features/Conversation/MainChatInput/GroupChat.tsx +0 -3
  49. package/src/app/[variants]/(main)/group/features/Conversation/useGroupContext.ts +3 -0
  50. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +15 -2
  51. package/src/features/ChatInput/Desktop/index.tsx +1 -3
  52. package/src/features/Conversation/store/slices/message/action/crud.ts +2 -2
  53. package/src/features/ElectronTitlebar/Connection/ConnectionMode.tsx +2 -2
  54. package/src/features/ElectronTitlebar/SimpleTitleBar.tsx +1 -2
  55. package/src/features/ElectronTitlebar/index.tsx +2 -2
  56. package/src/hooks/useUserAvatar.test.ts +23 -4
  57. package/src/locales/default/plugin.ts +3 -5
  58. package/src/locales/default/tool.ts +3 -0
  59. package/src/services/chat/mecha/agentConfigResolver.test.ts +160 -0
  60. package/src/services/chat/mecha/agentConfigResolver.ts +15 -3
  61. package/src/services/chat/mecha/contextEngineering.ts +2 -1
  62. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +4 -2
  63. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +2 -0
  64. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +1 -18
  65. package/src/store/chat/slices/message/selectors/displayMessage.test.ts +24 -0
  66. package/src/store/chat/slices/message/selectors/displayMessage.ts +6 -1
  67. package/src/store/chat/slices/topic/action.test.ts +10 -4
  68. package/src/store/chat/slices/topic/action.ts +3 -2
  69. package/src/store/electron/selectors/sync.ts +17 -1
  70. package/packages/context-engine/src/processors/GroupMessageSender.ts +0 -138
  71. package/packages/context-engine/src/processors/__tests__/GroupMessageSender.test.ts +0 -274
  72. package/src/features/ElectronTitlebar/const.ts +0 -1
@@ -2,17 +2,12 @@
2
2
 
3
3
  /**
4
4
  * API names for Group Management tool
5
+ *
6
+ * Note: Member management APIs (searchAgent, inviteAgent, createAgent, removeAgent)
7
+ * are handled by group-agent-builder tool. This tool focuses on orchestration.
5
8
  */
6
9
  export const GroupManagementApiName = {
7
- // ==================== Member Management ====================
8
- /** Search for agents that can be invited to the group */
9
- searchAgent: 'searchAgent',
10
- /** Invite an agent to join the group */
11
- inviteAgent: 'inviteAgent',
12
- /** Create a new agent and add it to the group */
13
- createAgent: 'createAgent',
14
- /** Remove an agent from the group */
15
- removeAgent: 'removeAgent',
10
+ // ==================== Agent Info ====================
16
11
  /** Get detailed information about an agent */
17
12
  getAgentInfo: 'getAgentInfo',
18
13
 
@@ -26,7 +21,9 @@ export const GroupManagementApiName = {
26
21
 
27
22
  // ==================== Task Execution ====================
28
23
  /** Let an agent execute a task asynchronously */
29
- executeTask: 'executeTask',
24
+ executeAgentTask: 'executeAgentTask',
25
+ /** Let multiple agents execute different tasks in parallel */
26
+ executeAgentTasks: 'executeAgentTasks',
30
27
  /** Interrupt a running agent task */
31
28
  interrupt: 'interrupt',
32
29
 
@@ -44,28 +41,7 @@ export const GroupManagementApiName = {
44
41
  export type GroupManagementApiNameType =
45
42
  (typeof GroupManagementApiName)[keyof typeof GroupManagementApiName];
46
43
 
47
- // ==================== Member Management Params ====================
48
-
49
- export interface SearchAgentParams {
50
- limit?: number;
51
- query?: string;
52
- source?: 'user' | 'community';
53
- }
54
-
55
- export interface InviteAgentParams {
56
- agentId: string;
57
- }
58
-
59
- export interface CreateAgentParams {
60
- avatar?: string;
61
- description?: string;
62
- systemRole: string;
63
- title: string;
64
- }
65
-
66
- export interface RemoveAgentParams {
67
- agentId: string;
68
- }
44
+ // ==================== Agent Info Params ====================
69
45
 
70
46
  export interface GetAgentInfoParams {
71
47
  agentId: string;
@@ -116,6 +92,27 @@ export interface ExecuteTaskParams {
116
92
  timeout?: number;
117
93
  }
118
94
 
95
+ export interface TaskItem {
96
+ /** The ID of the agent to execute this task */
97
+ agentId: string;
98
+ /** Detailed instruction/prompt for the task execution */
99
+ instruction: string;
100
+ /** Optional timeout in milliseconds for this specific task */
101
+ timeout?: number;
102
+ /** Brief title describing what this task does (shown in UI) */
103
+ title: string;
104
+ }
105
+
106
+ export interface ExecuteTasksParams {
107
+ /**
108
+ * If true, the orchestration will end after all tasks complete,
109
+ * without calling the supervisor again.
110
+ */
111
+ skipCallSupervisor?: boolean;
112
+ /** Array of tasks to execute, each assigned to a specific agent */
113
+ tasks: TaskItem[];
114
+ }
115
+
119
116
  export interface InterruptParams {
120
117
  taskId: string;
121
118
  }
@@ -156,14 +153,6 @@ export interface VoteParams {
156
153
 
157
154
  // ==================== Result Types ====================
158
155
 
159
- export interface AgentSearchResult {
160
- avatar?: string;
161
- description?: string;
162
- id: string;
163
- source: 'user' | 'community';
164
- title: string;
165
- }
166
-
167
156
  export interface VoteResult {
168
157
  agentId: string;
169
158
  reasoning?: string;
@@ -7,7 +7,7 @@ import { ContextEngine } from '../../pipeline';
7
7
  import {
8
8
  AgentCouncilFlattenProcessor,
9
9
  GroupMessageFlattenProcessor,
10
- GroupMessageSenderProcessor,
10
+ GroupRoleTransformProcessor,
11
11
  HistoryTruncateProcessor,
12
12
  InputTemplateProcessor,
13
13
  MessageCleanupProcessor,
@@ -274,11 +274,13 @@ export class MessagesEngine {
274
274
  // 15. Supervisor role restore (convert role=supervisor back to role=assistant for model)
275
275
  new SupervisorRoleRestoreProcessor(),
276
276
 
277
- // 16. Group message sender identity injection (for multi-agent chat)
278
- ...(isAgentGroupEnabled
277
+ // 16. Group role transform (convert other agents' messages to user role with speaker tags)
278
+ // This must be BEFORE ToolCallProcessor so other agents' tool messages are converted first
279
+ ...(isAgentGroupEnabled && agentGroup.currentAgentId
279
280
  ? [
280
- new GroupMessageSenderProcessor({
281
+ new GroupRoleTransformProcessor({
281
282
  agentMap: agentGroup.agentMap!,
283
+ currentAgentId: agentGroup.currentAgentId,
282
284
  }),
283
285
  ]
284
286
  : []),
@@ -4,12 +4,12 @@ import type { RuntimeInitialContext, RuntimeStepContext } from '@lobechat/types'
4
4
 
5
5
  import type { OpenAIChatMessage, UIChatMessage } from '@/types/index';
6
6
 
7
- import type { AgentInfo } from '../../processors/GroupMessageSender';
7
+ import type { AgentInfo } from '../../processors/GroupRoleTransform';
8
8
  import type { AgentBuilderContext } from '../../providers/AgentBuilderContextInjector';
9
- import type { GroupAgentBuilderContext } from '../../providers/GroupAgentBuilderContextInjector';
10
- import type { GroupMemberInfo } from '../../providers/GroupContextInjector';
11
9
  import type { GTDPlan } from '../../providers/GTDPlanInjector';
12
10
  import type { GTDTodoList } from '../../providers/GTDTodoInjector';
11
+ import type { GroupAgentBuilderContext } from '../../providers/GroupAgentBuilderContextInjector';
12
+ import type { GroupMemberInfo } from '../../providers/GroupContextInjector';
13
13
  import type { LobeToolManifest } from '../tools/types';
14
14
 
15
15
  /**
@@ -249,7 +249,7 @@ export interface MessagesEngineResult {
249
249
 
250
250
  // Re-export types for convenience
251
251
 
252
- export { type AgentInfo } from '../../processors/GroupMessageSender';
252
+ export { type AgentInfo } from '../../processors/GroupRoleTransform';
253
253
  export { type AgentBuilderContext } from '../../providers/AgentBuilderContextInjector';
254
254
  export { type GroupAgentBuilderContext } from '../../providers/GroupAgentBuilderContextInjector';
255
255
  export { type GTDPlan } from '../../providers/GTDPlanInjector';
@@ -0,0 +1,261 @@
1
+ import debug from 'debug';
2
+
3
+ import { BaseProcessor } from '../base/BaseProcessor';
4
+ import type { Message, PipelineContext, ProcessorOptions } from '../types';
5
+
6
+ const log = debug('context-engine:processor:GroupRoleTransformProcessor');
7
+
8
+ /**
9
+ * Agent info for message sender identification
10
+ */
11
+ export interface AgentInfo {
12
+ name: string;
13
+ role: 'supervisor' | 'participant';
14
+ }
15
+
16
+ /**
17
+ * Configuration for GroupRoleTransformProcessor
18
+ */
19
+ export interface GroupRoleTransformConfig {
20
+ /**
21
+ * Mapping from agentId to agent info
22
+ * Used to look up agent name for each message
23
+ */
24
+ agentMap: Record<string, AgentInfo>;
25
+ /**
26
+ * The current agent ID that is responding
27
+ * Messages from this agent will remain as assistant role
28
+ */
29
+ currentAgentId: string;
30
+ /**
31
+ * Custom function to generate tool name from identifier and apiName
32
+ */
33
+ genToolName?: (identifier: string, apiName: string) => string;
34
+ }
35
+
36
+ /**
37
+ * Group Role Transform Processor
38
+ *
39
+ * Transforms messages from other agents to user role with speaker tags.
40
+ * This prevents the model from imitating speaker tags in its output.
41
+ *
42
+ * From the model's perspective:
43
+ * - role: assistant = "my" responses (current agent)
44
+ * - role: user = external input (human users and other agents)
45
+ *
46
+ * Processing logic:
47
+ * 1. Current agent's messages: Keep as assistant (no modifications)
48
+ * 2. Other agents' assistant messages: Convert to user with speaker tag
49
+ * 3. Other agents' tool messages: Convert to user with tool_result tag
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * const processor = new GroupRoleTransformProcessor({
54
+ * currentAgentId: 'travel-advisor',
55
+ * agentMap: {
56
+ * 'weather-expert': { name: 'Weather Expert', role: 'participant' },
57
+ * 'travel-advisor': { name: 'Travel Advisor', role: 'participant' },
58
+ * 'supervisor': { name: 'Supervisor', role: 'supervisor' },
59
+ * }
60
+ * });
61
+ * ```
62
+ */
63
+ export class GroupRoleTransformProcessor extends BaseProcessor {
64
+ readonly name = 'GroupRoleTransformProcessor';
65
+
66
+ constructor(
67
+ private config: GroupRoleTransformConfig,
68
+ options: ProcessorOptions = {},
69
+ ) {
70
+ super(options);
71
+ }
72
+
73
+ protected async doProcess(context: PipelineContext): Promise<PipelineContext> {
74
+ const clonedContext = this.cloneContext(context);
75
+
76
+ // Skip if no currentAgentId or agentMap provided
77
+ if (!this.config.currentAgentId || !this.config.agentMap) {
78
+ log('No currentAgentId or agentMap provided, skipping processing');
79
+ return this.markAsExecuted(clonedContext);
80
+ }
81
+
82
+ let assistantTransformed = 0;
83
+ let toolTransformed = 0;
84
+
85
+ clonedContext.messages = clonedContext.messages.map((msg: Message) => {
86
+ // Process assistant messages
87
+ if (msg.role === 'assistant' && msg.agentId) {
88
+ if (msg.agentId === this.config.currentAgentId) {
89
+ // Current agent: keep as assistant, no modifications
90
+ return msg;
91
+ }
92
+
93
+ // Other agent: transform to user with speaker tag
94
+ const transformed = this.transformAssistantMessage(msg);
95
+ if (transformed !== msg) {
96
+ assistantTransformed++;
97
+ log(`Transformed assistant message from agent: ${msg.agentId} to user`);
98
+ }
99
+ return transformed;
100
+ }
101
+
102
+ // Process tool messages
103
+ if (msg.role === 'tool' && msg.agentId) {
104
+ if (msg.agentId === this.config.currentAgentId) {
105
+ // Current agent: keep as tool
106
+ return msg;
107
+ }
108
+
109
+ // Other agent: transform to user with tool_result tag
110
+ const transformed = this.transformToolMessage(msg);
111
+ if (transformed !== msg) {
112
+ toolTransformed++;
113
+ log(`Transformed tool message from agent: ${msg.agentId} to user`);
114
+ }
115
+ return transformed;
116
+ }
117
+
118
+ return msg;
119
+ });
120
+
121
+ // Update metadata
122
+ clonedContext.metadata.groupRoleTransformProcessed = {
123
+ assistantTransformed,
124
+ toolTransformed,
125
+ };
126
+
127
+ log(
128
+ `Group role transform completed: ${assistantTransformed} assistant messages, ${toolTransformed} tool messages transformed`,
129
+ );
130
+
131
+ return this.markAsExecuted(clonedContext);
132
+ }
133
+
134
+ /**
135
+ * Transform an assistant message from another agent to a user message
136
+ */
137
+ private transformAssistantMessage(msg: Message): Message {
138
+ const agentInfo = this.config.agentMap[msg.agentId];
139
+ if (!agentInfo) {
140
+ // No agent info found, keep original
141
+ return msg;
142
+ }
143
+
144
+ const agentName = agentInfo.name;
145
+ let content = this.buildSpeakerTag(agentName);
146
+
147
+ // Add original content
148
+ const originalContent = this.getStringContent(msg.content);
149
+ if (originalContent) {
150
+ content += originalContent;
151
+ }
152
+
153
+ // Add tool_use section if message has tools
154
+ if (msg.tools && msg.tools.length > 0) {
155
+ content += this.buildToolUseSection(msg.tools);
156
+ }
157
+
158
+ return {
159
+ ...msg,
160
+ content,
161
+ role: 'user',
162
+ // Remove tool-related fields as they're now embedded in content
163
+ tools: undefined,
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Transform a tool result message from another agent to a user message
169
+ */
170
+ private transformToolMessage(msg: Message): Message {
171
+ const agentInfo = this.config.agentMap[msg.agentId];
172
+ if (!agentInfo) {
173
+ // No agent info found, keep original
174
+ return msg;
175
+ }
176
+
177
+ const agentName = agentInfo.name;
178
+ const toolName = this.getToolName(msg.plugin);
179
+ const toolCallId = msg.tool_call_id || 'unknown';
180
+ const resultContent = this.getStringContent(msg.content);
181
+
182
+ const content = `${this.buildSpeakerTag(agentName)}<tool_result id="${toolCallId}" name="${toolName}">
183
+ ${resultContent}
184
+ </tool_result>`;
185
+
186
+ return {
187
+ ...msg,
188
+ content,
189
+ // Remove tool-related fields
190
+ plugin: undefined,
191
+ role: 'user',
192
+ tool_call_id: undefined,
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Build the speaker tag
198
+ */
199
+ private buildSpeakerTag(agentName: string): string {
200
+ return `<speaker name="${agentName}" />\n`;
201
+ }
202
+
203
+ /**
204
+ * Build the tool_use section for assistant messages with tools
205
+ */
206
+ private buildToolUseSection(tools: any[]): string {
207
+ let section = '\n\n<tool_use>\n';
208
+
209
+ for (const tool of tools) {
210
+ const toolName = this.getToolName(tool);
211
+ const toolId = tool.id || 'unknown';
212
+ const args = tool.arguments || '';
213
+
214
+ section += `<tool id="${toolId}" name="${toolName}">\n`;
215
+ section += `${args}\n`;
216
+ section += `</tool>\n`;
217
+ }
218
+
219
+ section += '</tool_use>';
220
+ return section;
221
+ }
222
+
223
+ /**
224
+ * Get tool name from tool object
225
+ */
226
+ private getToolName(tool: any): string {
227
+ if (!tool) return 'unknown';
228
+
229
+ const identifier = tool.identifier || '';
230
+ const apiName = tool.apiName || '';
231
+
232
+ if (this.config.genToolName) {
233
+ return this.config.genToolName(identifier, apiName);
234
+ }
235
+
236
+ if (identifier && apiName) {
237
+ return `${identifier}.${apiName}`;
238
+ }
239
+
240
+ return identifier || apiName || 'unknown';
241
+ }
242
+
243
+ /**
244
+ * Extract string content from message content (handles both string and array formats)
245
+ */
246
+ private getStringContent(content: string | any[]): string {
247
+ if (typeof content === 'string') {
248
+ return content;
249
+ }
250
+
251
+ if (Array.isArray(content)) {
252
+ // Extract text from array content
253
+ return content
254
+ .filter((part: any) => part.type === 'text')
255
+ .map((part: any) => part.text || '')
256
+ .join('\n');
257
+ }
258
+
259
+ return '';
260
+ }
261
+ }