@lobehub/lobehub 2.0.0-next.308 → 2.0.0-next.309

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 (27) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/locales/en-US/plugin.json +1 -0
  4. package/locales/zh-CN/plugin.json +1 -0
  5. package/package.json +1 -1
  6. package/packages/agent-runtime/src/types/state.ts +2 -0
  7. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/GetAgentInfo/index.tsx +68 -0
  8. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/index.ts +3 -0
  9. package/packages/builtin-tool-memory/src/manifest.ts +581 -19
  10. package/packages/types/src/topic/thread.ts +2 -2
  11. package/packages/types/src/userMemory/layers.ts +19 -8
  12. package/packages/types/src/userMemory/shared.ts +7 -1
  13. package/src/locales/default/plugin.ts +1 -0
  14. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +11 -3
  15. package/src/server/modules/Mecha/AgentToolsEngine/index.ts +14 -6
  16. package/src/server/modules/Mecha/AgentToolsEngine/types.ts +4 -3
  17. package/src/server/routers/lambda/aiAgent.ts +10 -0
  18. package/src/server/services/agent/index.test.ts +155 -0
  19. package/src/server/services/agent/index.ts +25 -0
  20. package/src/server/services/agentRuntime/AgentRuntimeService.ts +2 -0
  21. package/src/server/services/agentRuntime/types.ts +1 -0
  22. package/src/server/services/aiAgent/__tests__/execAgent.threadId.test.ts +29 -9
  23. package/src/server/services/aiAgent/index.ts +175 -6
  24. package/src/server/services/lobehubSkill/index.ts +109 -0
  25. package/src/server/services/toolExecution/builtin.ts +28 -2
  26. package/src/server/services/toolExecution/types.ts +3 -0
  27. package/src/store/chat/agents/createAgentExecutors.ts +4 -2
@@ -10,19 +10,33 @@ export enum UserMemoryContextObjectType {
10
10
  Knowledge = 'knowledge',
11
11
  Other = 'other',
12
12
  Person = 'person',
13
- Place = 'place'
13
+ Place = 'place',
14
14
  }
15
+ export const CONTEXT_OBJECT_TYPES = Object.values(UserMemoryContextObjectType);
15
16
 
16
17
  export enum UserMemoryContextSubjectType {
17
18
  Item = 'item',
18
19
  Other = 'other',
19
20
  Person = 'person',
20
- Pet = 'pet'
21
+ Pet = 'pet',
21
22
  }
23
+ export const CONTEXT_SUBJECT_TYPES = Object.values(UserMemoryContextSubjectType);
22
24
 
23
25
  export interface UserMemoryContext extends UserMemoryTimestamps {
24
- associatedObjects: { extra?: Record<string, unknown> | null, name?: string, type?: UserMemoryContextObjectType }[] | null;
25
- associatedSubjects: { extra?: Record<string, unknown> | null, name?: string, type?: UserMemoryContextSubjectType }[] | null;
26
+ associatedObjects:
27
+ | {
28
+ extra?: Record<string, unknown> | null;
29
+ name?: string;
30
+ type?: UserMemoryContextObjectType;
31
+ }[]
32
+ | null;
33
+ associatedSubjects:
34
+ | {
35
+ extra?: Record<string, unknown> | null;
36
+ name?: string;
37
+ type?: UserMemoryContextSubjectType;
38
+ }[]
39
+ | null;
26
40
  currentStatus: string | null;
27
41
  description: string | null;
28
42
  descriptionVector: number[] | null;
@@ -97,7 +111,4 @@ export type UserMemoryPreferenceWithoutVectors = Omit<
97
111
  'conclusionDirectivesVector'
98
112
  >;
99
113
 
100
- export type UserMemoryPreferencesListItem = Omit<
101
- UserMemoryPreferenceWithoutVectors,
102
- 'suggestions'
103
- >;
114
+ export type UserMemoryPreferencesListItem = Omit<UserMemoryPreferenceWithoutVectors, 'suggestions'>;
@@ -30,17 +30,20 @@ export enum RelationshipEnum {
30
30
  Uncle = 'uncle',
31
31
  Wife = 'wife',
32
32
  }
33
+ export const RELATIONSHIPS = Object.values(RelationshipEnum);
33
34
 
34
35
  export enum MergeStrategyEnum {
35
36
  Merge = 'merge',
36
37
  Replace = 'replace',
37
38
  }
39
+ export const MERGE_STRATEGIES = Object.values(MergeStrategyEnum);
38
40
 
39
41
  export enum IdentityTypeEnum {
40
42
  Demographic = 'demographic',
41
43
  Personal = 'personal',
42
44
  Professional = 'professional',
43
45
  }
46
+ export const IDENTITY_TYPES = Object.values(IdentityTypeEnum);
44
47
 
45
48
  export enum LayersEnum {
46
49
  Context = 'context',
@@ -48,6 +51,7 @@ export enum LayersEnum {
48
51
  Identity = 'identity',
49
52
  Preference = 'preference',
50
53
  }
54
+ export const MEMORY_LAYERS = Object.values(LayersEnum);
51
55
 
52
56
  export enum TypesEnum {
53
57
  Activity = 'activity',
@@ -61,6 +65,7 @@ export enum TypesEnum {
61
65
  Technology = 'technology',
62
66
  Topic = 'topic',
63
67
  }
68
+ export const MEMORY_TYPES = Object.values(TypesEnum);
64
69
 
65
70
  export enum ContextStatusEnum {
66
71
  Aborted = 'aborted',
@@ -68,5 +73,6 @@ export enum ContextStatusEnum {
68
73
  Completed = 'completed',
69
74
  OnHold = 'on_hold',
70
75
  Ongoing = 'ongoing',
71
- Planned = 'planned'
76
+ Planned = 'planned',
72
77
  }
78
+ export const CONTEXT_STATUS = Object.values(ContextStatusEnum);
@@ -40,6 +40,7 @@ export default {
40
40
  'builtins.lobe-cloud-sandbox.title': 'Cloud Sandbox',
41
41
  'builtins.lobe-group-agent-builder.apiName.batchCreateAgents': 'Batch create agents',
42
42
  'builtins.lobe-group-agent-builder.apiName.createAgent': 'Create agent',
43
+ 'builtins.lobe-group-agent-builder.apiName.getAgentInfo': 'Get member info',
43
44
  'builtins.lobe-group-agent-builder.apiName.getAvailableModels': 'Get available models',
44
45
  'builtins.lobe-group-agent-builder.apiName.installPlugin': 'Install Skill',
45
46
  'builtins.lobe-group-agent-builder.apiName.inviteAgent': 'Invite member',
@@ -55,6 +55,8 @@ export const createRuntimeExecutors = (
55
55
  // Fallback to state's modelRuntimeConfig if not in payload
56
56
  const model = llmPayload.model || state.modelRuntimeConfig?.model;
57
57
  const provider = llmPayload.provider || state.modelRuntimeConfig?.provider;
58
+ // Fallback to state's tools if not in payload
59
+ const tools = llmPayload.tools || state.tools;
58
60
 
59
61
  if (!model || !provider) {
60
62
  throw new Error('Model and provider are required for call_llm instruction');
@@ -128,14 +130,14 @@ export const createRuntimeExecutors = (
128
130
  const chatPayload = {
129
131
  messages: llmPayload.messages,
130
132
  model,
131
- tools: llmPayload.tools,
133
+ tools,
132
134
  };
133
135
 
134
136
  log(
135
137
  `${stagePrefix} calling model-runtime chat (model: %s, messages: %d, tools: %d)`,
136
138
  model,
137
139
  llmPayload.messages.length,
138
- llmPayload.tools?.length ?? 0,
140
+ tools?.length ?? 0,
139
141
  );
140
142
 
141
143
  // Buffer: accumulate text and reasoning, send every 50ms
@@ -261,7 +263,12 @@ export const createRuntimeExecutors = (
261
263
  }
262
264
  },
263
265
  onToolsCalling: async ({ toolsCalling: raw }) => {
264
- const payload = new ToolNameResolver().resolve(raw, state.toolManifestMap);
266
+ const resolved = new ToolNameResolver().resolve(raw, state.toolManifestMap);
267
+ // Add source field from toolSourceMap for routing tool execution
268
+ const payload = resolved.map((p) => ({
269
+ ...p,
270
+ source: state.toolSourceMap?.[p.identifier],
271
+ }));
265
272
  // log(`[${operationLogId}][toolsCalling]`, payload);
266
273
  toolsCalling = payload;
267
274
  tool_calls = raw;
@@ -466,6 +473,7 @@ export const createRuntimeExecutors = (
466
473
  // Execute tool using ToolExecutionService
467
474
  log(`[${operationLogId}] Executing tool ${toolName} ...`);
468
475
  const executionResult = await toolExecutionService.executeTool(chatToolPayload, {
476
+ serverDB: ctx.serverDB,
469
477
  toolManifestMap: state.toolManifestMap,
470
478
  userId: ctx.userId,
471
479
  });
@@ -12,8 +12,7 @@
12
12
  import { KnowledgeBaseManifest } from '@lobechat/builtin-tool-knowledge-base';
13
13
  import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
14
14
  import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
15
- import { ToolsEngine } from '@lobechat/context-engine';
16
- import type { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
15
+ import { type LobeToolManifest, ToolsEngine } from '@lobechat/context-engine';
17
16
  import debug from 'debug';
18
17
 
19
18
  import { builtinTools } from '@/tools';
@@ -50,11 +49,11 @@ export const createServerToolsEngine = (
50
49
 
51
50
  // Get plugin manifests from installed plugins (from database)
52
51
  const pluginManifests = context.installedPlugins
53
- .map((plugin) => plugin.manifest as LobeChatPluginManifest)
52
+ .map((plugin) => plugin.manifest as LobeToolManifest)
54
53
  .filter(Boolean);
55
54
 
56
55
  // Get all builtin tool manifests
57
- const builtinManifests = builtinTools.map((tool) => tool.manifest as LobeChatPluginManifest);
56
+ const builtinManifests = builtinTools.map((tool) => tool.manifest as LobeToolManifest);
58
57
 
59
58
  // Combine all manifests
60
59
  const allManifests = [...pluginManifests, ...builtinManifests, ...additionalManifests];
@@ -87,18 +86,27 @@ export const createServerAgentToolsEngine = (
87
86
  context: ServerAgentToolsContext,
88
87
  params: ServerCreateAgentToolsEngineParams,
89
88
  ): ToolsEngine => {
90
- const { agentConfig, model, provider, hasEnabledKnowledgeBases = false } = params;
89
+ const {
90
+ additionalManifests,
91
+ agentConfig,
92
+ hasEnabledKnowledgeBases = false,
93
+ model,
94
+ provider,
95
+ } = params;
91
96
  const searchMode = agentConfig.chatConfig?.searchMode ?? 'off';
92
97
  const isSearchEnabled = searchMode !== 'off';
93
98
 
94
99
  log(
95
- 'Creating agent tools engine for model=%s, provider=%s, searchMode=%s',
100
+ 'Creating agent tools engine for model=%s, provider=%s, searchMode=%s, additionalManifests=%d',
96
101
  model,
97
102
  provider,
98
103
  searchMode,
104
+ additionalManifests?.length ?? 0,
99
105
  );
100
106
 
101
107
  return createServerToolsEngine(context, {
108
+ // Pass additional manifests (e.g., LobeHub Skills)
109
+ additionalManifests,
102
110
  // Add default tools based on configuration
103
111
  defaultToolIds: [WebBrowsingManifest.identifier, KnowledgeBaseManifest.identifier],
104
112
  // Create search-aware enableChecker for this request
@@ -1,6 +1,5 @@
1
- import type { PluginEnableChecker } from '@lobechat/context-engine';
1
+ import type { LobeToolManifest, PluginEnableChecker } from '@lobechat/context-engine';
2
2
  import type { LobeTool } from '@lobechat/types';
3
- import type { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
4
3
 
5
4
  /**
6
5
  * Installed plugin with manifest
@@ -22,7 +21,7 @@ export interface ServerAgentToolsContext {
22
21
  */
23
22
  export interface ServerAgentToolsEngineConfig {
24
23
  /** Additional manifests to include (e.g., Klavis tools) */
25
- additionalManifests?: LobeChatPluginManifest[];
24
+ additionalManifests?: LobeToolManifest[];
26
25
  /** Default tool IDs that will always be added */
27
26
  defaultToolIds?: string[];
28
27
  /** Custom enable checker for plugins */
@@ -33,6 +32,8 @@ export interface ServerAgentToolsEngineConfig {
33
32
  * Parameters for createServerAgentToolsEngine
34
33
  */
35
34
  export interface ServerCreateAgentToolsEngineParams {
35
+ /** Additional manifests to include (e.g., LobeHub Skills) */
36
+ additionalManifests?: LobeToolManifest[];
36
37
  /** Agent configuration containing plugins array */
37
38
  agentConfig: {
38
39
  /** Optional agent chat config with searchMode */
@@ -642,6 +642,16 @@ export const aiAgentRouter = router({
642
642
  const updatedStatus = updatedThread?.status ?? thread.status;
643
643
  const updatedTaskStatus = threadStatusToTaskStatus[updatedStatus] || 'processing';
644
644
 
645
+ // DEBUG: Log metadata for failed tasks
646
+ if (updatedTaskStatus === 'failed') {
647
+ console.log('[DEBUG] getSubAgentTaskStatus - failed task metadata:', {
648
+ threadId,
649
+ updatedMetadata,
650
+ 'updatedMetadata?.error': updatedMetadata?.error,
651
+ updatedStatus,
652
+ });
653
+ }
654
+
645
655
  // 6. Query thread messages for result content or current activity
646
656
  const threadMessages = await ctx.messageModel.query({ threadId });
647
657
  const sortedMessages = threadMessages.sort(
@@ -216,6 +216,161 @@ describe('AgentService', () => {
216
216
  });
217
217
  });
218
218
 
219
+ describe('getAgentConfig', () => {
220
+ it('should return null if agent does not exist', async () => {
221
+ const mockAgentModel = {
222
+ getAgentConfig: vi.fn().mockResolvedValue(null),
223
+ };
224
+
225
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
226
+ (parseAgentConfig as any).mockReturnValue({});
227
+
228
+ const newService = new AgentService(mockDb, mockUserId);
229
+ const result = await newService.getAgentConfig('non-existent');
230
+
231
+ expect(result).toBeNull();
232
+ });
233
+
234
+ it('should support lookup by agent id', async () => {
235
+ const mockAgent = {
236
+ id: 'agent-123',
237
+ model: 'gpt-4',
238
+ systemRole: 'Test role',
239
+ };
240
+
241
+ const mockAgentModel = {
242
+ getAgentConfig: vi.fn().mockResolvedValue(mockAgent),
243
+ };
244
+
245
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
246
+ (parseAgentConfig as any).mockReturnValue({});
247
+
248
+ const newService = new AgentService(mockDb, mockUserId);
249
+ const result = await newService.getAgentConfig('agent-123');
250
+
251
+ expect(mockAgentModel.getAgentConfig).toHaveBeenCalledWith('agent-123');
252
+ expect(result?.id).toBe('agent-123');
253
+ expect(result?.model).toBe('gpt-4');
254
+ });
255
+
256
+ it('should support lookup by slug', async () => {
257
+ const mockAgent = {
258
+ id: 'agent-123',
259
+ model: 'claude-3',
260
+ slug: 'my-agent',
261
+ };
262
+
263
+ const mockAgentModel = {
264
+ getAgentConfig: vi.fn().mockResolvedValue(mockAgent),
265
+ };
266
+
267
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
268
+ (parseAgentConfig as any).mockReturnValue({});
269
+
270
+ const newService = new AgentService(mockDb, mockUserId);
271
+ const result = await newService.getAgentConfig('my-agent');
272
+
273
+ expect(mockAgentModel.getAgentConfig).toHaveBeenCalledWith('my-agent');
274
+ expect(result?.id).toBe('agent-123');
275
+ });
276
+
277
+ it('should merge DEFAULT_AGENT_CONFIG and serverDefaultAgentConfig with agent config', async () => {
278
+ const mockAgent = {
279
+ id: 'agent-1',
280
+ systemRole: 'Custom system role',
281
+ };
282
+ const serverDefaultConfig = { model: 'gpt-4', params: { temperature: 0.7 } };
283
+
284
+ const mockAgentModel = {
285
+ getAgentConfig: vi.fn().mockResolvedValue(mockAgent),
286
+ };
287
+
288
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
289
+ (parseAgentConfig as any).mockReturnValue(serverDefaultConfig);
290
+
291
+ const newService = new AgentService(mockDb, mockUserId);
292
+ const result = await newService.getAgentConfig('agent-1');
293
+
294
+ expect(result).toMatchObject({
295
+ chatConfig: DEFAULT_AGENT_CONFIG.chatConfig,
296
+ plugins: DEFAULT_AGENT_CONFIG.plugins,
297
+ tts: DEFAULT_AGENT_CONFIG.tts,
298
+ model: 'gpt-4',
299
+ params: { temperature: 0.7 },
300
+ id: 'agent-1',
301
+ systemRole: 'Custom system role',
302
+ });
303
+ });
304
+
305
+ it('should use default model/provider when agent has none', async () => {
306
+ const mockAgent = {
307
+ id: 'agent-1',
308
+ systemRole: 'Test',
309
+ // No model or provider set
310
+ };
311
+
312
+ const mockAgentModel = {
313
+ getAgentConfig: vi.fn().mockResolvedValue(mockAgent),
314
+ };
315
+
316
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
317
+ (parseAgentConfig as any).mockReturnValue({});
318
+
319
+ const newService = new AgentService(mockDb, mockUserId);
320
+ const result = await newService.getAgentConfig('agent-1');
321
+
322
+ // Should have default model/provider from DEFAULT_AGENT_CONFIG
323
+ expect(result?.model).toBe(DEFAULT_AGENT_CONFIG.model);
324
+ expect(result?.provider).toBe(DEFAULT_AGENT_CONFIG.provider);
325
+ });
326
+
327
+ it('should prioritize agent model/provider over defaults', async () => {
328
+ const mockAgent = {
329
+ id: 'agent-1',
330
+ model: 'claude-3-opus',
331
+ provider: 'anthropic',
332
+ };
333
+ const serverDefaultConfig = { model: 'gpt-4', provider: 'openai' };
334
+
335
+ const mockAgentModel = {
336
+ getAgentConfig: vi.fn().mockResolvedValue(mockAgent),
337
+ };
338
+
339
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
340
+ (parseAgentConfig as any).mockReturnValue(serverDefaultConfig);
341
+
342
+ const newService = new AgentService(mockDb, mockUserId);
343
+ const result = await newService.getAgentConfig('agent-1');
344
+
345
+ // Agent config should override server default
346
+ expect(result?.model).toBe('claude-3-opus');
347
+ expect(result?.provider).toBe('anthropic');
348
+ });
349
+
350
+ it('should merge user default agent config', async () => {
351
+ const mockAgent = {
352
+ id: 'agent-1',
353
+ };
354
+ const userDefaultConfig = { model: 'user-preferred-model', provider: 'user-provider' };
355
+
356
+ const mockAgentModel = {
357
+ getAgentConfig: vi.fn().mockResolvedValue(mockAgent),
358
+ };
359
+
360
+ (AgentModel as any).mockImplementation(() => mockAgentModel);
361
+ (parseAgentConfig as any).mockReturnValue({});
362
+ // Use mockResolvedValueOnce to avoid affecting subsequent tests
363
+ mockUserModel.getUserSettingsDefaultAgentConfig.mockResolvedValueOnce({ config: userDefaultConfig });
364
+
365
+ const newService = new AgentService(mockDb, mockUserId);
366
+ const result = await newService.getAgentConfig('agent-1');
367
+
368
+ // User default config should be applied
369
+ expect(result?.model).toBe('user-preferred-model');
370
+ expect(result?.provider).toBe('user-provider');
371
+ });
372
+ });
373
+
219
374
  describe('getAgentConfigById', () => {
220
375
  it('should return null if agent does not exist', async () => {
221
376
  const mockAgentModel = {
@@ -17,6 +17,12 @@ import { type UpdateAgentResult } from './type';
17
17
 
18
18
  const log = debug('lobe-agent:service');
19
19
 
20
+ /**
21
+ * Agent config with required id field.
22
+ * Used when returning agent config from database (id is always present).
23
+ */
24
+ export type AgentConfigWithId = LobeAgentConfig & { id: string };
25
+
20
26
  interface AgentWelcomeData {
21
27
  openQuestions: string[];
22
28
  welcomeMessage: string;
@@ -78,6 +84,25 @@ export class AgentService {
78
84
  return mergedConfig;
79
85
  }
80
86
 
87
+ /**
88
+ * Get agent config by ID or slug with default config merged.
89
+ * Supports both agentId and slug lookup.
90
+ *
91
+ * The returned agent config is merged with:
92
+ * 1. DEFAULT_AGENT_CONFIG (hardcoded defaults)
93
+ * 2. Server's globalDefaultAgentConfig (from environment variable DEFAULT_AGENT_CONFIG)
94
+ * 3. User's defaultAgentConfig (from user settings)
95
+ * 4. The actual agent config from database
96
+ */
97
+ async getAgentConfig(idOrSlug: string): Promise<AgentConfigWithId | null> {
98
+ const [agent, defaultAgentConfig] = await Promise.all([
99
+ this.agentModel.getAgentConfig(idOrSlug),
100
+ this.userModel.getUserSettingsDefaultAgentConfig(),
101
+ ]);
102
+
103
+ return this.mergeDefaultConfig(agent, defaultAgentConfig) as AgentConfigWithId | null;
104
+ }
105
+
81
106
  /**
82
107
  * Get agent config by ID with default config merged.
83
108
  *
@@ -231,6 +231,7 @@ export class AgentRuntimeService {
231
231
  initialMessages = [],
232
232
  appContext,
233
233
  toolManifestMap,
234
+ toolSourceMap,
234
235
  stepCallbacks,
235
236
  } = params;
236
237
 
@@ -258,6 +259,7 @@ export class AgentRuntimeService {
258
259
  status: 'idle',
259
260
  stepCount: 0,
260
261
  toolManifestMap,
262
+ toolSourceMap,
261
263
  tools,
262
264
  } as Partial<AgentState>;
263
265
 
@@ -87,6 +87,7 @@ export interface OperationCreationParams {
87
87
  */
88
88
  stepCallbacks?: StepLifecycleCallbacks;
89
89
  toolManifestMap: Record<string, LobeToolManifest>;
90
+ toolSourceMap?: Record<string, 'builtin' | 'plugin' | 'mcp' | 'klavis' | 'lobehubSkill'>;
90
91
  tools?: any[];
91
92
  userId?: string;
92
93
  }
@@ -29,6 +29,22 @@ vi.mock('@/database/models/agent', () => ({
29
29
  })),
30
30
  }));
31
31
 
32
+ // Mock AgentService
33
+ vi.mock('@/server/services/agent', () => ({
34
+ AgentService: vi.fn().mockImplementation(() => ({
35
+ getAgentConfig: vi.fn().mockResolvedValue({
36
+ chatConfig: {},
37
+ files: [],
38
+ id: 'agent-1',
39
+ knowledgeBases: [],
40
+ model: 'gpt-4',
41
+ plugins: [],
42
+ provider: 'openai',
43
+ systemRole: 'You are a helpful assistant',
44
+ }),
45
+ })),
46
+ }));
47
+
32
48
  // Mock PluginModel
33
49
  vi.mock('@/database/models/plugin', () => ({
34
50
  PluginModel: vi.fn().mockImplementation(() => ({
@@ -74,15 +90,19 @@ vi.mock('@/server/modules/Mecha', () => ({
74
90
  }));
75
91
 
76
92
  // Mock model-bank
77
- vi.mock('model-bank', () => ({
78
- LOBE_DEFAULT_MODEL_LIST: [
79
- {
80
- abilities: { functionCall: true, video: false, vision: true },
81
- id: 'gpt-4',
82
- providerId: 'openai',
83
- },
84
- ],
85
- }));
93
+ vi.mock('model-bank', async (importOriginal) => {
94
+ const actual = await importOriginal<typeof import('model-bank')>();
95
+ return {
96
+ ...actual,
97
+ LOBE_DEFAULT_MODEL_LIST: [
98
+ {
99
+ abilities: { functionCall: true, video: false, vision: true },
100
+ id: 'gpt-4',
101
+ providerId: 'openai',
102
+ },
103
+ ],
104
+ };
105
+ });
86
106
 
87
107
  describe('AiAgentService.execAgent - threadId handling', () => {
88
108
  let service: AiAgentService;