@lobehub/lobehub 2.0.0-next.335 → 2.0.0-next.337

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 (53) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/changelog/v1.json +21 -0
  3. package/package.json +1 -1
  4. package/packages/builtin-tool-agent-builder/src/manifest.ts +0 -2
  5. package/packages/builtin-tool-group-management/src/manifest.ts +54 -53
  6. package/packages/builtin-tool-group-management/src/systemRole.ts +43 -111
  7. package/packages/builtin-tool-memory/src/client/Render/AddPreferenceMemory/index.tsx +17 -0
  8. package/packages/builtin-tool-memory/src/client/Render/index.ts +2 -0
  9. package/packages/builtin-tool-memory/src/client/Streaming/AddPreferenceMemory/index.tsx +17 -0
  10. package/packages/builtin-tool-memory/src/client/Streaming/index.ts +4 -3
  11. package/packages/builtin-tool-memory/src/client/components/PreferenceMemoryCard.tsx +357 -0
  12. package/packages/builtin-tool-memory/src/client/components/index.ts +1 -0
  13. package/packages/builtin-tool-memory/src/executor/index.ts +3 -3
  14. package/packages/builtin-tool-memory/src/systemRole.ts +1 -0
  15. package/packages/context-engine/src/engine/tools/ToolArgumentsRepairer.ts +129 -0
  16. package/packages/context-engine/src/engine/tools/__tests__/ToolArgumentsRepairer.test.ts +186 -0
  17. package/packages/context-engine/src/engine/tools/index.ts +3 -0
  18. package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/index.ts +2 -0
  19. package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/with-assistant-group.json +156 -0
  20. package/packages/conversation-flow/src/__tests__/parse.test.ts +22 -0
  21. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +88 -11
  22. package/packages/database/src/models/userMemory/model.ts +1 -1
  23. package/packages/memory-user-memory/src/extractors/context.test.ts +0 -1
  24. package/packages/memory-user-memory/src/extractors/experience.test.ts +0 -1
  25. package/packages/memory-user-memory/src/extractors/identity.test.ts +0 -1
  26. package/packages/memory-user-memory/src/extractors/preference.test.ts +0 -1
  27. package/packages/memory-user-memory/src/schemas/context.ts +0 -2
  28. package/packages/memory-user-memory/src/schemas/experience.ts +0 -2
  29. package/packages/memory-user-memory/src/schemas/identity.ts +1 -2
  30. package/packages/memory-user-memory/src/schemas/preference.ts +0 -2
  31. package/packages/types/src/openai/chat.ts +0 -4
  32. package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +5 -1
  33. package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +8 -8
  34. package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +142 -15
  35. package/src/app/[variants]/(main)/community/(detail)/user/features/useUserDetail.ts +45 -20
  36. package/src/server/routers/lambda/market/agentGroup.ts +179 -1
  37. package/src/server/routers/lambda/userMemories/tools.ts +5 -4
  38. package/src/server/routers/lambda/userMemories.ts +4 -4
  39. package/src/server/services/discover/index.ts +4 -0
  40. package/src/server/services/memory/userMemory/extract.ts +3 -3
  41. package/src/services/chat/chat.test.ts +109 -104
  42. package/src/services/chat/index.ts +13 -32
  43. package/src/services/chat/mecha/agentConfigResolver.test.ts +113 -0
  44. package/src/services/chat/mecha/agentConfigResolver.ts +15 -5
  45. package/src/services/marketApi.ts +14 -0
  46. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/testExecutor.ts +13 -0
  47. package/src/store/chat/agents/createAgentExecutors.ts +13 -1
  48. package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +5 -1
  49. package/src/store/chat/slices/aiChat/actions/__tests__/fixtures.ts +14 -0
  50. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +131 -7
  51. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +61 -62
  52. package/src/store/chat/slices/plugin/action.test.ts +71 -0
  53. package/src/store/chat/slices/plugin/actions/internals.ts +14 -5
@@ -618,7 +618,7 @@ export class MemoryExtractionExecutor {
618
618
  details: item.details ?? '',
619
619
  detailsEmbedding: detailsVector ?? undefined,
620
620
  memoryCategory: item.memoryCategory ?? null,
621
- memoryLayer: (item.memoryLayer as LayersEnum) ?? LayersEnum.Context,
621
+ memoryLayer: LayersEnum.Context,
622
622
  memoryType: (item.memoryType as TypesEnum) ?? TypesEnum.Context,
623
623
  summary: item.summary ?? '',
624
624
  summaryEmbedding: summaryVector ?? undefined,
@@ -684,7 +684,7 @@ export class MemoryExtractionExecutor {
684
684
  type: item.withExperience?.type ?? null,
685
685
  },
686
686
  memoryCategory: item.memoryCategory ?? null,
687
- memoryLayer: (item.memoryLayer as LayersEnum) ?? LayersEnum.Experience,
687
+ memoryLayer: LayersEnum.Experience,
688
688
  memoryType: (item.memoryType as TypesEnum) ?? TypesEnum.Activity,
689
689
  summary: item.summary ?? '',
690
690
  summaryEmbedding: summaryVector ?? undefined,
@@ -728,7 +728,7 @@ export class MemoryExtractionExecutor {
728
728
  details: item.details ?? '',
729
729
  detailsEmbedding: detailsVector ?? undefined,
730
730
  memoryCategory: item.memoryCategory ?? null,
731
- memoryLayer: (item.memoryLayer as LayersEnum) ?? LayersEnum.Preference,
731
+ memoryLayer: LayersEnum.Preference,
732
732
  memoryType: (item.memoryType as TypesEnum) ?? TypesEnum.Preference,
733
733
  preference: {
734
734
  capturedAt: job.sourceUpdatedAt,
@@ -15,6 +15,35 @@ import { aiModelSelectors } from '@/store/aiInfra';
15
15
  import { useToolStore } from '@/store/tool';
16
16
 
17
17
  import { chatService } from './index';
18
+ import type { ResolvedAgentConfig } from './mecha';
19
+
20
+ /**
21
+ * Default mock resolvedAgentConfig for tests
22
+ */
23
+ const createMockResolvedConfig = (overrides?: {
24
+ agentConfig?: Partial<ResolvedAgentConfig['agentConfig']>;
25
+ chatConfig?: Partial<ResolvedAgentConfig['chatConfig']>;
26
+ plugins?: string[];
27
+ isBuiltinAgent?: boolean;
28
+ }): ResolvedAgentConfig =>
29
+ ({
30
+ agentConfig: {
31
+ model: DEFAULT_AGENT_CONFIG.model,
32
+ provider: 'openai',
33
+ systemRole: '',
34
+ chatConfig: {},
35
+ params: {},
36
+ tts: {},
37
+ ...overrides?.agentConfig,
38
+ },
39
+ chatConfig: {
40
+ searchMode: 'off',
41
+ autoCreateTopicThreshold: 2,
42
+ ...overrides?.chatConfig,
43
+ },
44
+ isBuiltinAgent: overrides?.isBuiltinAgent ?? false,
45
+ plugins: overrides?.plugins ?? [],
46
+ }) as ResolvedAgentConfig;
18
47
 
19
48
  // Mocking external dependencies
20
49
  vi.mock('i18next', () => ({
@@ -109,7 +138,10 @@ describe('ChatService', () => {
109
138
  ],
110
139
  });
111
140
  });
112
- await chatService.createAssistantMessage({ messages, plugins: enabledPlugins });
141
+ await chatService.createAssistantMessage({
142
+ messages,
143
+ resolvedAgentConfig: createMockResolvedConfig({ plugins: enabledPlugins }),
144
+ });
113
145
 
114
146
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
115
147
  expect.objectContaining({
@@ -136,21 +168,14 @@ describe('ChatService', () => {
136
168
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
137
169
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['enableReasoning']);
138
170
 
139
- // Mock agent chat config with reasoning enabled
140
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
141
- () =>
142
- ({
143
- enableReasoning: true,
144
- reasoningBudgetToken: 2048,
145
- searchMode: 'off',
146
- }) as any,
147
- );
148
-
149
171
  await chatService.createAssistantMessage({
150
172
  messages,
151
173
  model: 'deepseek-reasoner',
152
174
  provider: 'deepseek',
153
- plugins: [],
175
+ resolvedAgentConfig: createMockResolvedConfig({
176
+ agentConfig: { model: 'deepseek-reasoner', provider: 'deepseek' },
177
+ chatConfig: { enableReasoning: true, reasoningBudgetToken: 2048 },
178
+ }),
154
179
  });
155
180
 
156
181
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -172,20 +197,14 @@ describe('ChatService', () => {
172
197
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
173
198
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['enableReasoning']);
174
199
 
175
- // Mock agent chat config with reasoning disabled
176
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
177
- () =>
178
- ({
179
- enableReasoning: false,
180
- searchMode: 'off',
181
- }) as any,
182
- );
183
-
184
200
  await chatService.createAssistantMessage({
185
201
  messages,
186
202
  model: 'deepseek-reasoner',
187
203
  provider: 'deepseek',
188
- plugins: [],
204
+ resolvedAgentConfig: createMockResolvedConfig({
205
+ agentConfig: { model: 'deepseek-reasoner', provider: 'deepseek' },
206
+ chatConfig: { enableReasoning: false },
207
+ }),
189
208
  });
190
209
 
191
210
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -207,21 +226,15 @@ describe('ChatService', () => {
207
226
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
208
227
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['enableReasoning']);
209
228
 
210
- // Mock agent chat config with reasoning enabled but no custom budget
211
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
212
- () =>
213
- ({
214
- enableReasoning: true,
215
- // reasoningBudgetToken is undefined
216
- searchMode: 'off',
217
- }) as any,
218
- );
219
-
220
229
  await chatService.createAssistantMessage({
221
230
  messages,
222
231
  model: 'deepseek-reasoner',
223
232
  provider: 'deepseek',
224
- plugins: [],
233
+ resolvedAgentConfig: createMockResolvedConfig({
234
+ agentConfig: { model: 'deepseek-reasoner', provider: 'deepseek' },
235
+ // enableReasoning is true, but reasoningBudgetToken is undefined
236
+ chatConfig: { enableReasoning: true },
237
+ }),
225
238
  });
226
239
 
227
240
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -243,20 +256,14 @@ describe('ChatService', () => {
243
256
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
244
257
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['reasoningEffort']);
245
258
 
246
- // Mock agent chat config with reasoning effort set
247
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
248
- () =>
249
- ({
250
- reasoningEffort: 'high',
251
- searchMode: 'off',
252
- }) as any,
253
- );
254
-
255
259
  await chatService.createAssistantMessage({
256
260
  messages,
257
261
  model: 'test-model',
258
262
  provider: 'test-provider',
259
- plugins: [],
263
+ resolvedAgentConfig: createMockResolvedConfig({
264
+ agentConfig: { model: 'test-model', provider: 'test-provider' },
265
+ chatConfig: { reasoningEffort: 'high' },
266
+ }),
260
267
  });
261
268
 
262
269
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -275,20 +282,14 @@ describe('ChatService', () => {
275
282
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
276
283
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['thinkingBudget']);
277
284
 
278
- // Mock agent chat config with thinking budget set
279
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
280
- () =>
281
- ({
282
- thinkingBudget: 5000,
283
- searchMode: 'off',
284
- }) as any,
285
- );
286
-
287
285
  await chatService.createAssistantMessage({
288
286
  messages,
289
287
  model: 'test-model',
290
288
  provider: 'test-provider',
291
- plugins: [],
289
+ resolvedAgentConfig: createMockResolvedConfig({
290
+ agentConfig: { model: 'test-model', provider: 'test-provider' },
291
+ chatConfig: { thinkingBudget: 5000 },
292
+ }),
292
293
  });
293
294
 
294
295
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -329,9 +330,11 @@ describe('ChatService', () => {
329
330
  const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
330
331
  await chatService.createAssistantMessage({
331
332
  messages,
332
- plugins: [],
333
333
  model: 'gpt-4-vision-preview',
334
334
  provider: 'openai',
335
+ resolvedAgentConfig: createMockResolvedConfig({
336
+ agentConfig: { model: 'gpt-4-vision-preview', provider: 'openai' },
337
+ }),
335
338
  });
336
339
 
337
340
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -378,7 +381,10 @@ describe('ChatService', () => {
378
381
  ] as UIChatMessage[];
379
382
 
380
383
  const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
381
- await chatService.createAssistantMessage({ messages, plugins: [] });
384
+ await chatService.createAssistantMessage({
385
+ messages,
386
+ resolvedAgentConfig: createMockResolvedConfig(),
387
+ });
382
388
 
383
389
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
384
390
  {
@@ -435,8 +441,10 @@ describe('ChatService', () => {
435
441
 
436
442
  await chatService.createAssistantMessage({
437
443
  messages,
438
- plugins: [],
439
444
  model: 'gpt-4-vision-preview',
445
+ resolvedAgentConfig: createMockResolvedConfig({
446
+ agentConfig: { model: 'gpt-4-vision-preview' },
447
+ }),
440
448
  });
441
449
 
442
450
  // Verify the utility functions were called
@@ -525,8 +533,10 @@ describe('ChatService', () => {
525
533
 
526
534
  await chatService.createAssistantMessage({
527
535
  messages,
528
- plugins: [],
529
536
  model: 'gpt-4-vision-preview',
537
+ resolvedAgentConfig: createMockResolvedConfig({
538
+ agentConfig: { model: 'gpt-4-vision-preview' },
539
+ }),
530
540
  });
531
541
 
532
542
  // Verify the utility functions were called
@@ -630,8 +640,10 @@ describe('ChatService', () => {
630
640
 
631
641
  await chatService.createAssistantMessage({
632
642
  messages,
633
- plugins: [],
634
643
  model: 'gpt-4-vision-preview',
644
+ resolvedAgentConfig: createMockResolvedConfig({
645
+ agentConfig: { model: 'gpt-4-vision-preview' },
646
+ }),
635
647
  });
636
648
 
637
649
  // Verify isDesktopLocalStaticServerUrl was called for each image
@@ -730,7 +742,10 @@ describe('ChatService', () => {
730
742
  messages,
731
743
  model: 'gpt-3.5-turbo-1106',
732
744
  top_p: 1,
733
- plugins: ['seo'],
745
+ resolvedAgentConfig: createMockResolvedConfig({
746
+ agentConfig: { model: 'gpt-3.5-turbo-1106' },
747
+ plugins: ['seo'],
748
+ }),
734
749
  });
735
750
 
736
751
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -832,7 +847,10 @@ describe('ChatService', () => {
832
847
  messages,
833
848
  model: 'gpt-3.5-turbo-1106',
834
849
  top_p: 1,
835
- plugins: ['seo'],
850
+ resolvedAgentConfig: createMockResolvedConfig({
851
+ agentConfig: { model: 'gpt-3.5-turbo-1106' },
852
+ plugins: ['seo'],
853
+ }),
836
854
  });
837
855
 
838
856
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -888,7 +906,9 @@ describe('ChatService', () => {
888
906
  messages,
889
907
  model: 'gpt-3.5-turbo-1106',
890
908
  top_p: 1,
891
- plugins: ['ttt'],
909
+ resolvedAgentConfig: createMockResolvedConfig({
910
+ agentConfig: { model: 'gpt-3.5-turbo-1106' },
911
+ }),
892
912
  });
893
913
 
894
914
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -949,7 +969,10 @@ describe('ChatService', () => {
949
969
  mockToolsEngine as any,
950
970
  );
951
971
 
952
- await chatService.createAssistantMessage({ messages, plugins: [] });
972
+ await chatService.createAssistantMessage({
973
+ messages,
974
+ resolvedAgentConfig: createMockResolvedConfig(),
975
+ });
953
976
 
954
977
  // Verify tools were passed to getChatCompletion
955
978
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -1003,7 +1026,10 @@ describe('ChatService', () => {
1003
1026
  mockToolsEngine as any,
1004
1027
  );
1005
1028
 
1006
- await chatService.createAssistantMessage({ messages, plugins: [] });
1029
+ await chatService.createAssistantMessage({
1030
+ messages,
1031
+ resolvedAgentConfig: createMockResolvedConfig(),
1032
+ });
1007
1033
 
1008
1034
  // Verify enabledSearch was set to true
1009
1035
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -1051,7 +1077,10 @@ describe('ChatService', () => {
1051
1077
  mockToolsEngine as any,
1052
1078
  );
1053
1079
 
1054
- await chatService.createAssistantMessage({ messages, plugins: [] });
1080
+ await chatService.createAssistantMessage({
1081
+ messages,
1082
+ resolvedAgentConfig: createMockResolvedConfig(),
1083
+ });
1055
1084
 
1056
1085
  // Verify enabledSearch was not set
1057
1086
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -1342,20 +1371,14 @@ describe('ChatService private methods', () => {
1342
1371
  'disableContextCaching',
1343
1372
  ]);
1344
1373
 
1345
- // Mock agent chat config with context caching disabled
1346
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
1347
- () =>
1348
- ({
1349
- disableContextCaching: true,
1350
- searchMode: 'off',
1351
- }) as any,
1352
- );
1353
-
1354
1374
  await chatService.createAssistantMessage({
1355
1375
  messages,
1356
1376
  model: 'test-model',
1357
1377
  provider: 'test-provider',
1358
- plugins: [],
1378
+ resolvedAgentConfig: createMockResolvedConfig({
1379
+ agentConfig: { model: 'test-model', provider: 'test-provider' },
1380
+ chatConfig: { disableContextCaching: true },
1381
+ }),
1359
1382
  });
1360
1383
 
1361
1384
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -1378,20 +1401,14 @@ describe('ChatService private methods', () => {
1378
1401
  'disableContextCaching',
1379
1402
  ]);
1380
1403
 
1381
- // Mock agent chat config with context caching enabled (default)
1382
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
1383
- () =>
1384
- ({
1385
- disableContextCaching: false,
1386
- searchMode: 'off',
1387
- }) as any,
1388
- );
1389
-
1390
1404
  await chatService.createAssistantMessage({
1391
1405
  messages,
1392
1406
  model: 'test-model',
1393
1407
  provider: 'test-provider',
1394
- plugins: [],
1408
+ resolvedAgentConfig: createMockResolvedConfig({
1409
+ agentConfig: { model: 'test-model', provider: 'test-provider' },
1410
+ chatConfig: { disableContextCaching: false },
1411
+ }),
1395
1412
  });
1396
1413
 
1397
1414
  // enabledContextCaching should not be present in the call
@@ -1407,20 +1424,14 @@ describe('ChatService private methods', () => {
1407
1424
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
1408
1425
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['reasoningEffort']);
1409
1426
 
1410
- // Mock agent chat config with reasoning effort set
1411
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
1412
- () =>
1413
- ({
1414
- reasoningEffort: 'high',
1415
- searchMode: 'off',
1416
- }) as any,
1417
- );
1418
-
1419
1427
  await chatService.createAssistantMessage({
1420
1428
  messages,
1421
1429
  model: 'test-model',
1422
1430
  provider: 'test-provider',
1423
- plugins: [],
1431
+ resolvedAgentConfig: createMockResolvedConfig({
1432
+ agentConfig: { model: 'test-model', provider: 'test-provider' },
1433
+ chatConfig: { reasoningEffort: 'high' },
1434
+ }),
1424
1435
  });
1425
1436
 
1426
1437
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -1439,20 +1450,14 @@ describe('ChatService private methods', () => {
1439
1450
  vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValue(() => true);
1440
1451
  vi.spyOn(aiModelSelectors, 'modelExtendParams').mockReturnValue(() => ['thinkingBudget']);
1441
1452
 
1442
- // Mock agent chat config with thinking budget set
1443
- vi.spyOn(chatConfigByIdSelectors, 'getChatConfigById').mockReturnValue(
1444
- () =>
1445
- ({
1446
- thinkingBudget: 5000,
1447
- searchMode: 'off',
1448
- }) as any,
1449
- );
1450
-
1451
1453
  await chatService.createAssistantMessage({
1452
1454
  messages,
1453
1455
  model: 'test-model',
1454
1456
  provider: 'test-provider',
1455
- plugins: [],
1457
+ resolvedAgentConfig: createMockResolvedConfig({
1458
+ agentConfig: { model: 'test-model', provider: 'test-provider' },
1459
+ chatConfig: { thinkingBudget: 5000 },
1460
+ }),
1456
1461
  });
1457
1462
 
1458
1463
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
@@ -27,7 +27,7 @@ import { ModelProvider } from 'model-bank';
27
27
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
28
28
  import { enableAuth } from '@/envs/auth';
29
29
  import { getSearchConfig } from '@/helpers/getSearchConfig';
30
- import { createAgentToolsEngine, createToolsEngine } from '@/helpers/toolEngineering';
30
+ import { createAgentToolsEngine } from '@/helpers/toolEngineering';
31
31
  import { getAgentStoreState } from '@/store/agent';
32
32
  import {
33
33
  agentByIdSelectors,
@@ -58,10 +58,10 @@ import { createHeaderWithAuth } from '../_auth';
58
58
  import { API_ENDPOINTS } from '../_url';
59
59
  import { findDeploymentName, isEnableFetchOnClient, resolveRuntimeProvider } from './helper';
60
60
  import {
61
+ type ResolvedAgentConfig,
61
62
  contextEngineering,
62
63
  getTargetAgentId,
63
64
  initializeWithClientStore,
64
- resolveAgentConfig,
65
65
  resolveModelExtendParams,
66
66
  } from './mecha';
67
67
  import { type FetchOptions } from './types';
@@ -70,6 +70,11 @@ interface GetChatCompletionPayload extends Partial<Omit<ChatStreamPayload, 'mess
70
70
  agentId?: string;
71
71
  groupId?: string;
72
72
  messages: UIChatMessage[];
73
+ /**
74
+ * Pre-resolved agent config from AgentRuntime layer.
75
+ * Required to ensure config consistency and proper isSubTask filtering.
76
+ */
77
+ resolvedAgentConfig: ResolvedAgentConfig;
73
78
  scope?: MessageMapScope;
74
79
  topicId?: string;
75
80
  }
@@ -107,12 +112,11 @@ interface CreateAssistantMessageStream extends FetchSSEOptions {
107
112
  class ChatService {
108
113
  createAssistantMessage = async (
109
114
  {
110
- plugins: enabledPlugins,
111
115
  messages,
112
116
  agentId,
113
117
  groupId,
114
- scope,
115
118
  topicId,
119
+ resolvedAgentConfig,
116
120
  ...params
117
121
  }: GetChatCompletionPayload,
118
122
  options?: FetchOptions,
@@ -126,24 +130,13 @@ class ChatService {
126
130
  params,
127
131
  );
128
132
 
129
- // =================== 1. resolve agent config =================== //
133
+ // =================== 1. use pre-resolved agent config =================== //
134
+ // Config is resolved in AgentRuntime layer (internal_createAgentState)
135
+ // which handles isSubTask filtering and other runtime modifications
130
136
 
131
137
  const targetAgentId = getTargetAgentId(agentId);
132
138
 
133
- // Resolve agent config with builtin agent runtime config merged
134
- // plugins is already merged (runtime plugins > agent config plugins)
135
- const {
136
- agentConfig,
137
- chatConfig,
138
- plugins: pluginIds,
139
- } = resolveAgentConfig({
140
- agentId: targetAgentId,
141
- groupId, // Pass groupId for supervisor detection
142
- model: payload.model,
143
- plugins: enabledPlugins,
144
- provider: payload.provider,
145
- scope, // Pass scope to preserve page-agent injection
146
- });
139
+ const { agentConfig, chatConfig, plugins: pluginIds } = resolvedAgentConfig;
147
140
 
148
141
  // Get search config with agentId for agent-specific settings
149
142
  const searchConfig = getSearchConfig(payload.model, payload.provider!, targetAgentId);
@@ -495,26 +488,14 @@ class ChatService {
495
488
  onLoadingChange?.(true);
496
489
 
497
490
  try {
498
- // Use simple tools engine without complex search logic
499
- const toolsEngine = createToolsEngine();
500
- const { tools, enabledManifests } = toolsEngine.generateToolsDetailed({
501
- model: params.model!,
502
- provider: params.provider!,
503
- toolIds: params.plugins,
504
- });
505
-
506
491
  const llmMessages = await contextEngineering({
507
- manifests: enabledManifests,
508
492
  messages: params.messages as any,
509
493
  model: params.model!,
510
494
  provider: params.provider!,
511
- tools: params.plugins,
512
495
  });
513
496
 
514
- // remove plugins
515
- delete params.plugins;
516
497
  await this.getChatCompletion(
517
- { ...params, messages: llmMessages, tools },
498
+ { ...params, messages: llmMessages },
518
499
  {
519
500
  onErrorHandle: (error) => {
520
501
  errorHandle(new Error(error.message), error);
@@ -800,4 +800,117 @@ describe('resolveAgentConfig', () => {
800
800
  expect(result.agentConfig.systemRole).toBe('Supervisor system role');
801
801
  });
802
802
  });
803
+
804
+ describe('sub-task filtering (isSubTask)', () => {
805
+ beforeEach(() => {
806
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentSlugById').mockReturnValue(() => undefined);
807
+ });
808
+
809
+ it('should filter out lobe-gtd when isSubTask is true for regular agent', () => {
810
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentConfigById').mockReturnValue(
811
+ () =>
812
+ ({
813
+ ...mockAgentConfig,
814
+ plugins: ['lobe-gtd', 'plugin-a', 'plugin-b'],
815
+ }) as any,
816
+ );
817
+
818
+ const result = resolveAgentConfig({
819
+ agentId: 'test-agent',
820
+ isSubTask: true,
821
+ });
822
+
823
+ expect(result.plugins).not.toContain('lobe-gtd');
824
+ expect(result.plugins).toEqual(['plugin-a', 'plugin-b']);
825
+ });
826
+
827
+ it('should keep lobe-gtd when isSubTask is false', () => {
828
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentConfigById').mockReturnValue(
829
+ () =>
830
+ ({
831
+ ...mockAgentConfig,
832
+ plugins: ['lobe-gtd', 'plugin-a', 'plugin-b'],
833
+ }) as any,
834
+ );
835
+
836
+ const result = resolveAgentConfig({
837
+ agentId: 'test-agent',
838
+ isSubTask: false,
839
+ });
840
+
841
+ expect(result.plugins).toContain('lobe-gtd');
842
+ expect(result.plugins).toEqual(['lobe-gtd', 'plugin-a', 'plugin-b']);
843
+ });
844
+
845
+ it('should keep lobe-gtd when isSubTask is undefined', () => {
846
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentConfigById').mockReturnValue(
847
+ () =>
848
+ ({
849
+ ...mockAgentConfig,
850
+ plugins: ['lobe-gtd', 'plugin-a'],
851
+ }) as any,
852
+ );
853
+
854
+ const result = resolveAgentConfig({ agentId: 'test-agent' });
855
+
856
+ expect(result.plugins).toContain('lobe-gtd');
857
+ });
858
+
859
+ it('should filter lobe-gtd in page scope when isSubTask is true', () => {
860
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentConfigById').mockReturnValue(
861
+ () =>
862
+ ({
863
+ ...mockAgentConfig,
864
+ plugins: ['lobe-gtd', 'plugin-a'],
865
+ }) as any,
866
+ );
867
+ vi.spyOn(builtinAgents, 'getAgentRuntimeConfig').mockReturnValue({
868
+ systemRole: 'Page agent system role',
869
+ });
870
+
871
+ const result = resolveAgentConfig({
872
+ agentId: 'test-agent',
873
+ scope: 'page',
874
+ isSubTask: true,
875
+ });
876
+
877
+ expect(result.plugins).not.toContain('lobe-gtd');
878
+ expect(result.plugins).toContain(PageAgentIdentifier);
879
+ });
880
+
881
+ it('should filter lobe-gtd for builtin agent when isSubTask is true', () => {
882
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentSlugById').mockReturnValue(
883
+ () => 'some-builtin-slug',
884
+ );
885
+ vi.spyOn(builtinAgents, 'getAgentRuntimeConfig').mockReturnValue({
886
+ plugins: ['lobe-gtd', 'runtime-plugin'],
887
+ systemRole: 'Runtime system role',
888
+ });
889
+
890
+ const result = resolveAgentConfig({
891
+ agentId: 'builtin-agent',
892
+ isSubTask: true,
893
+ });
894
+
895
+ expect(result.plugins).not.toContain('lobe-gtd');
896
+ expect(result.plugins).toContain('runtime-plugin');
897
+ });
898
+
899
+ it('should keep lobe-gtd for builtin agent when isSubTask is false', () => {
900
+ vi.spyOn(agentSelectors.agentSelectors, 'getAgentSlugById').mockReturnValue(
901
+ () => 'some-builtin-slug',
902
+ );
903
+ vi.spyOn(builtinAgents, 'getAgentRuntimeConfig').mockReturnValue({
904
+ plugins: ['lobe-gtd', 'runtime-plugin'],
905
+ systemRole: 'Runtime system role',
906
+ });
907
+
908
+ const result = resolveAgentConfig({
909
+ agentId: 'builtin-agent',
910
+ isSubTask: false,
911
+ });
912
+
913
+ expect(result.plugins).toContain('lobe-gtd');
914
+ });
915
+ });
803
916
  });