@lobehub/lobehub 2.0.0-next.287 → 2.0.0-next.289

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 (62) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/en-US/plugin.json +3 -5
  4. package/locales/zh-CN/plugin.json +3 -5
  5. package/locales/zh-CN/tool.json +2 -0
  6. package/package.json +1 -1
  7. package/packages/builtin-agents/src/agents/group-supervisor/index.ts +12 -1
  8. package/packages/builtin-agents/src/agents/group-supervisor/systemRole.ts +0 -7
  9. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/EditLocalFile/index.tsx +93 -0
  10. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/GlobLocalFiles/index.tsx +73 -0
  11. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/GrepContent/index.tsx +69 -0
  12. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ListLocalFiles/index.tsx +68 -0
  13. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ReadLocalFile/index.tsx +74 -0
  14. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/SearchLocalFiles/index.tsx +70 -0
  15. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/WriteLocalFile/index.tsx +57 -0
  16. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/index.ts +14 -0
  17. package/packages/builtin-tool-cloud-sandbox/src/client/Render/WriteFile/index.tsx +54 -35
  18. package/packages/builtin-tool-cloud-sandbox/src/client/components/FilePathDisplay.tsx +52 -0
  19. package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteTasks/index.tsx +90 -0
  20. package/packages/builtin-tool-group-management/src/client/Inspector/index.ts +2 -0
  21. package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTasks.tsx +237 -0
  22. package/packages/builtin-tool-group-management/src/client/Intervention/index.ts +4 -1
  23. package/packages/builtin-tool-group-management/src/client/Render/index.ts +1 -1
  24. package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTask/index.tsx +69 -0
  25. package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTasks/index.tsx +87 -0
  26. package/packages/builtin-tool-group-management/src/client/Streaming/index.ts +4 -0
  27. package/packages/builtin-tool-group-management/src/executor.test.ts +8 -311
  28. package/packages/builtin-tool-group-management/src/executor.ts +5 -160
  29. package/packages/builtin-tool-group-management/src/manifest.ts +50 -94
  30. package/packages/builtin-tool-group-management/src/systemRole.ts +251 -172
  31. package/packages/builtin-tool-group-management/src/types.ts +29 -40
  32. package/packages/context-engine/src/engine/messages/MessagesEngine.ts +22 -4
  33. package/packages/context-engine/src/engine/messages/types.ts +4 -4
  34. package/packages/context-engine/src/processors/GroupOrchestrationFilter.ts +211 -0
  35. package/packages/context-engine/src/processors/GroupRoleTransform.ts +261 -0
  36. package/packages/context-engine/src/processors/__tests__/GroupOrchestrationFilter.test.ts +770 -0
  37. package/packages/context-engine/src/processors/__tests__/GroupRoleTransform.test.ts +553 -0
  38. package/packages/context-engine/src/processors/index.ts +7 -2
  39. package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +4 -16
  40. package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +23 -28
  41. package/packages/prompts/src/prompts/agentGroup/__snapshots__/index.test.ts.snap +0 -7
  42. package/packages/prompts/src/prompts/agentGroup/groupContext.ts +0 -7
  43. package/src/app/[variants]/(main)/group/features/Conversation/AgentWelcome/OpeningQuestions.tsx +4 -8
  44. package/src/app/[variants]/(main)/group/features/Conversation/MainChatInput/GroupChat.tsx +0 -3
  45. package/src/app/[variants]/(main)/group/features/Conversation/useGroupContext.ts +3 -0
  46. package/src/features/ChatInput/Desktop/index.tsx +1 -3
  47. package/src/features/Conversation/store/slices/message/action/crud.ts +2 -2
  48. package/src/locales/default/plugin.ts +3 -5
  49. package/src/locales/default/tool.ts +3 -0
  50. package/src/services/chat/mecha/agentConfigResolver.test.ts +160 -0
  51. package/src/services/chat/mecha/agentConfigResolver.ts +15 -3
  52. package/src/services/chat/mecha/contextEngineering.ts +2 -1
  53. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +4 -2
  54. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +2 -0
  55. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +1 -18
  56. package/src/store/chat/slices/message/selectors/displayMessage.test.ts +24 -0
  57. package/src/store/chat/slices/message/selectors/displayMessage.ts +6 -1
  58. package/src/store/chat/slices/topic/action.test.ts +10 -4
  59. package/src/store/chat/slices/topic/action.ts +3 -2
  60. package/src/store/document/slices/document/action.ts +8 -0
  61. package/packages/context-engine/src/processors/GroupMessageSender.ts +0 -138
  62. package/packages/context-engine/src/processors/__tests__/GroupMessageSender.test.ts +0 -274
@@ -1,138 +0,0 @@
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:GroupMessageSenderProcessor');
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 GroupMessageSenderProcessor
18
- */
19
- export interface GroupMessageSenderConfig {
20
- /**
21
- * Mapping from agentId to agent info
22
- * Used to look up agent name and role for each message
23
- */
24
- agentMap: Record<string, AgentInfo>;
25
- }
26
-
27
- /**
28
- * Group Message Sender Processor
29
- *
30
- * Responsible for injecting sender identity information into assistant messages
31
- * in group chat scenarios. This helps the model understand which agent sent
32
- * each message in a multi-agent conversation.
33
- *
34
- * The processor appends a system context block at the end of each assistant
35
- * message that has an agentId, containing:
36
- * - Agent name
37
- * - Agent role (supervisor or agent)
38
- * - Agent ID (with instruction not to expose it in responses)
39
- *
40
- * @example
41
- * ```typescript
42
- * const processor = new GroupMessageSenderProcessor({
43
- * agentMap: {
44
- * 'agt_xxx': { name: 'Weather Expert', role: 'agent' },
45
- * 'agt_yyy': { name: 'Supervisor', role: 'supervisor' },
46
- * }
47
- * });
48
- * ```
49
- */
50
- export class GroupMessageSenderProcessor extends BaseProcessor {
51
- readonly name = 'GroupMessageSenderProcessor';
52
-
53
- constructor(
54
- private config: GroupMessageSenderConfig,
55
- options: ProcessorOptions = {},
56
- ) {
57
- super(options);
58
- }
59
-
60
- protected async doProcess(context: PipelineContext): Promise<PipelineContext> {
61
- const clonedContext = this.cloneContext(context);
62
-
63
- // Skip if no agentMap provided
64
- if (!this.config.agentMap || Object.keys(this.config.agentMap).length === 0) {
65
- log('No agentMap provided, skipping processing');
66
- return this.markAsExecuted(clonedContext);
67
- }
68
-
69
- let processedCount = 0;
70
-
71
- clonedContext.messages = clonedContext.messages.map((msg: Message) => {
72
- // Only process assistant messages with agentId
73
- if (msg.role === 'assistant' && msg.agentId) {
74
- const agentInfo = this.config.agentMap[msg.agentId];
75
-
76
- if (agentInfo) {
77
- // Build the sender tag
78
- const senderTag = this.buildSenderContext(msg.agentId, agentInfo);
79
-
80
- // Prepend to message content (at the beginning)
81
- if (typeof msg.content === 'string') {
82
- processedCount++;
83
- log(
84
- `Injecting sender info for message from agent: ${agentInfo.name} (${agentInfo.role})`,
85
- );
86
-
87
- return {
88
- ...msg,
89
- content: senderTag + msg.content,
90
- };
91
- }
92
- // Handle array content (multimodal messages)
93
- else if (Array.isArray(msg.content)) {
94
- const firstTextIndex = msg.content.findIndex((part: any) => part.type === 'text');
95
-
96
- if (firstTextIndex !== -1) {
97
- processedCount++;
98
- log(
99
- `Injecting sender info for multimodal message from agent: ${agentInfo.name} (${agentInfo.role})`,
100
- );
101
-
102
- const newContent = [...msg.content];
103
- newContent[firstTextIndex] = {
104
- ...newContent[firstTextIndex],
105
- text: senderTag + newContent[firstTextIndex].text,
106
- };
107
-
108
- return {
109
- ...msg,
110
- content: newContent,
111
- };
112
- }
113
- }
114
- }
115
- }
116
-
117
- return msg;
118
- });
119
-
120
- // Update metadata
121
- clonedContext.metadata.groupMessageSenderProcessed = processedCount;
122
-
123
- log(`Group message sender processing completed: ${processedCount} messages processed`);
124
-
125
- return this.markAsExecuted(clonedContext);
126
- }
127
-
128
- /**
129
- * Build the sender tag to prepend to assistant messages.
130
- *
131
- * Uses a self-closing XML tag at the beginning:
132
- * - Placed at start so model sees "who is speaking" before the content
133
- * - Self-closing tag is less likely to be reproduced as it's not a "wrapper"
134
- */
135
- private buildSenderContext(_agentId: string, agentInfo: AgentInfo): string {
136
- return `<speaker name="${agentInfo.name}" />\n`;
137
- }
138
- }
@@ -1,274 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { PipelineContext } from '../../types';
4
- import { GroupMessageSenderProcessor } from '../GroupMessageSender';
5
-
6
- describe('GroupMessageSenderProcessor', () => {
7
- const createContext = (messages: any[]): PipelineContext => ({
8
- initialState: { messages: [] },
9
- isAborted: false,
10
- messages,
11
- metadata: {},
12
- });
13
-
14
- describe('Basic Scenarios', () => {
15
- it('should inject sender info into assistant message with agentId', async () => {
16
- const processor = new GroupMessageSenderProcessor({
17
- agentMap: {
18
- agt_weather: { name: 'Weather Expert', role: 'participant' },
19
- },
20
- });
21
-
22
- const input: any[] = [
23
- { role: 'user', content: 'What is the weather?' },
24
- { role: 'assistant', content: 'The weather is sunny.', agentId: 'agt_weather' },
25
- ];
26
-
27
- const context = createContext(input);
28
- const result = await processor.process(context);
29
-
30
- expect(result.messages).toHaveLength(2);
31
-
32
- // User message should be unchanged
33
- expect(result.messages[0].content).toBe('What is the weather?');
34
-
35
- // Assistant message should have speaker tag prepended
36
- const assistantContent = result.messages[1].content;
37
- expect(assistantContent).toMatch(/^<speaker name="Weather Expert" \/>/);
38
- expect(assistantContent).toContain('The weather is sunny.');
39
-
40
- // Check metadata
41
- expect(result.metadata.groupMessageSenderProcessed).toBe(1);
42
- });
43
-
44
- it('should inject sender info for supervisor role', async () => {
45
- const processor = new GroupMessageSenderProcessor({
46
- agentMap: {
47
- agt_supervisor: { name: 'Group Supervisor', role: 'supervisor' },
48
- },
49
- });
50
-
51
- const input: any[] = [
52
- { role: 'assistant', content: 'I will coordinate the agents.', agentId: 'agt_supervisor' },
53
- ];
54
-
55
- const context = createContext(input);
56
- const result = await processor.process(context);
57
-
58
- const assistantContent = result.messages[0].content;
59
- expect(assistantContent).toMatch(/^<speaker name="Group Supervisor" \/>/);
60
- });
61
-
62
- it('should not modify assistant message without agentId', async () => {
63
- const processor = new GroupMessageSenderProcessor({
64
- agentMap: {
65
- agt_weather: { name: 'Weather Expert', role: 'participant' },
66
- },
67
- });
68
-
69
- const input: any[] = [{ role: 'assistant', content: 'Hello from assistant.' }];
70
-
71
- const context = createContext(input);
72
- const result = await processor.process(context);
73
-
74
- // Should be unchanged
75
- expect(result.messages[0].content).toBe('Hello from assistant.');
76
- expect(result.metadata.groupMessageSenderProcessed).toBe(0);
77
- });
78
-
79
- it('should not modify assistant message with unknown agentId', async () => {
80
- const processor = new GroupMessageSenderProcessor({
81
- agentMap: {
82
- agt_weather: { name: 'Weather Expert', role: 'participant' },
83
- },
84
- });
85
-
86
- const input: any[] = [{ role: 'assistant', content: 'Hello.', agentId: 'agt_unknown' }];
87
-
88
- const context = createContext(input);
89
- const result = await processor.process(context);
90
-
91
- // Should be unchanged because agentId not in map
92
- expect(result.messages[0].content).toBe('Hello.');
93
- expect(result.metadata.groupMessageSenderProcessed).toBe(0);
94
- });
95
-
96
- it('should not modify user or tool messages', async () => {
97
- const processor = new GroupMessageSenderProcessor({
98
- agentMap: {
99
- agt_weather: { name: 'Weather Expert', role: 'participant' },
100
- },
101
- });
102
-
103
- const input: any[] = [
104
- { role: 'user', content: 'Hello', agentId: 'agt_weather' },
105
- { role: 'tool', content: 'Tool result', agentId: 'agt_weather' },
106
- ];
107
-
108
- const context = createContext(input);
109
- const result = await processor.process(context);
110
-
111
- expect(result.messages[0].content).toBe('Hello');
112
- expect(result.messages[1].content).toBe('Tool result');
113
- expect(result.metadata.groupMessageSenderProcessed).toBe(0);
114
- });
115
- });
116
-
117
- describe('Multiple Messages', () => {
118
- it('should process multiple assistant messages from different agents', async () => {
119
- const processor = new GroupMessageSenderProcessor({
120
- agentMap: {
121
- agt_weather: { name: 'Weather Expert', role: 'participant' },
122
- agt_news: { name: 'News Reporter', role: 'participant' },
123
- agt_supervisor: { name: 'Supervisor', role: 'supervisor' },
124
- },
125
- });
126
-
127
- const input: any[] = [
128
- { role: 'user', content: 'Give me updates' },
129
- { role: 'assistant', content: 'Weather is sunny.', agentId: 'agt_weather' },
130
- { role: 'assistant', content: 'Top news today.', agentId: 'agt_news' },
131
- { role: 'assistant', content: 'Summary complete.', agentId: 'agt_supervisor' },
132
- ];
133
-
134
- const context = createContext(input);
135
- const result = await processor.process(context);
136
-
137
- expect(result.messages).toHaveLength(4);
138
-
139
- // Check each assistant message has correct speaker tag prepended
140
- expect(result.messages[1].content).toMatch(/^<speaker name="Weather Expert" \/>/);
141
- expect(result.messages[2].content).toMatch(/^<speaker name="News Reporter" \/>/);
142
- expect(result.messages[3].content).toMatch(/^<speaker name="Supervisor" \/>/);
143
-
144
- expect(result.metadata.groupMessageSenderProcessed).toBe(3);
145
- });
146
- });
147
-
148
- describe('Multimodal Messages', () => {
149
- it('should handle array content (multimodal messages)', async () => {
150
- const processor = new GroupMessageSenderProcessor({
151
- agentMap: {
152
- agt_weather: { name: 'Weather Expert', role: 'participant' },
153
- },
154
- });
155
-
156
- const input: any[] = [
157
- {
158
- role: 'assistant',
159
- content: [
160
- { type: 'text', text: 'Here is the weather chart.' },
161
- { type: 'image_url', image_url: { url: 'https://example.com/chart.png' } },
162
- ],
163
- agentId: 'agt_weather',
164
- },
165
- ];
166
-
167
- const context = createContext(input);
168
- const result = await processor.process(context);
169
-
170
- const content = result.messages[0].content as any[];
171
- expect(Array.isArray(content)).toBe(true);
172
-
173
- // The first text part should have speaker tag prepended
174
- const textPart = content.find((p: any) => p.type === 'text');
175
- expect(textPart.text).toMatch(/^<speaker name="Weather Expert" \/>/);
176
- expect(textPart.text).toContain('Here is the weather chart.');
177
-
178
- // Image part should be unchanged
179
- const imagePart = content.find((p: any) => p.type === 'image_url');
180
- expect(imagePart.image_url.url).toBe('https://example.com/chart.png');
181
-
182
- expect(result.metadata.groupMessageSenderProcessed).toBe(1);
183
- });
184
-
185
- it('should append to the last text part in multimodal content', async () => {
186
- const processor = new GroupMessageSenderProcessor({
187
- agentMap: {
188
- agt_weather: { name: 'Weather Expert', role: 'participant' },
189
- },
190
- });
191
-
192
- const input: any[] = [
193
- {
194
- role: 'assistant',
195
- content: [
196
- { type: 'text', text: 'First text.' },
197
- { type: 'image_url', image_url: { url: 'https://example.com/img.png' } },
198
- { type: 'text', text: 'Last text.' },
199
- ],
200
- agentId: 'agt_weather',
201
- },
202
- ];
203
-
204
- const context = createContext(input);
205
- const result = await processor.process(context);
206
-
207
- const content = result.messages[0].content;
208
-
209
- // First text part should have speaker tag prepended
210
- expect(content[0].text).toMatch(/^<speaker name="Weather Expert" \/>/);
211
- expect(content[0].text).toContain('First text.');
212
-
213
- // Last text should be unchanged
214
- expect(content[2].text).toBe('Last text.');
215
- });
216
- });
217
-
218
- describe('Edge Cases', () => {
219
- it('should skip processing with empty agentMap', async () => {
220
- const processor = new GroupMessageSenderProcessor({
221
- agentMap: {},
222
- });
223
-
224
- const input: any[] = [{ role: 'assistant', content: 'Hello', agentId: 'agt_weather' }];
225
-
226
- const context = createContext(input);
227
- const result = await processor.process(context);
228
-
229
- expect(result.messages[0].content).toBe('Hello');
230
- });
231
-
232
- it('should handle empty messages array', async () => {
233
- const processor = new GroupMessageSenderProcessor({
234
- agentMap: {
235
- agt_weather: { name: 'Weather Expert', role: 'participant' },
236
- },
237
- });
238
-
239
- const context = createContext([]);
240
- const result = await processor.process(context);
241
-
242
- expect(result.messages).toHaveLength(0);
243
- expect(result.metadata.groupMessageSenderProcessed).toBe(0);
244
- });
245
-
246
- it('should preserve original message properties', async () => {
247
- const processor = new GroupMessageSenderProcessor({
248
- agentMap: {
249
- agt_weather: { name: 'Weather Expert', role: 'participant' },
250
- },
251
- });
252
-
253
- const input: any[] = [
254
- {
255
- role: 'assistant',
256
- content: 'Weather info.',
257
- agentId: 'agt_weather',
258
- id: 'msg-123',
259
- createdAt: '2025-01-01T00:00:00Z',
260
- customField: 'custom value',
261
- },
262
- ];
263
-
264
- const context = createContext(input);
265
- const result = await processor.process(context);
266
-
267
- const msg = result.messages[0];
268
- expect(msg.id).toBe('msg-123');
269
- expect(msg.createdAt).toBe('2025-01-01T00:00:00Z');
270
- expect(msg.customField).toBe('custom value');
271
- expect(msg.agentId).toBe('agt_weather');
272
- });
273
- });
274
- });