@lobehub/chat 0.156.1 → 0.157.0

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 (115) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/Dockerfile +4 -1
  3. package/package.json +3 -2
  4. package/src/config/modelProviders/anthropic.ts +3 -0
  5. package/src/config/modelProviders/google.ts +3 -0
  6. package/src/config/modelProviders/groq.ts +5 -1
  7. package/src/config/modelProviders/minimax.ts +10 -7
  8. package/src/config/modelProviders/mistral.ts +1 -0
  9. package/src/config/modelProviders/moonshot.ts +3 -0
  10. package/src/config/modelProviders/zhipu.ts +2 -6
  11. package/src/config/server/provider.ts +1 -1
  12. package/src/database/client/core/db.ts +32 -0
  13. package/src/database/client/core/schemas.ts +9 -0
  14. package/src/database/client/models/__tests__/message.test.ts +2 -2
  15. package/src/database/client/schemas/message.ts +8 -1
  16. package/src/features/AgentSetting/store/action.ts +15 -6
  17. package/src/features/Conversation/Actions/Tool.tsx +16 -0
  18. package/src/features/Conversation/Actions/index.ts +2 -2
  19. package/src/features/Conversation/Messages/Assistant/ToolCalls/index.tsx +78 -0
  20. package/src/features/Conversation/Messages/Assistant/ToolCalls/style.ts +25 -0
  21. package/src/features/Conversation/Messages/Assistant/index.tsx +47 -0
  22. package/src/features/Conversation/Messages/Default.tsx +4 -1
  23. package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/index.tsx +34 -35
  24. package/src/features/Conversation/Messages/Tool/index.tsx +44 -0
  25. package/src/features/Conversation/Messages/index.ts +3 -2
  26. package/src/features/Conversation/Plugins/Render/StandaloneType/Iframe.tsx +1 -1
  27. package/src/features/Conversation/components/SkeletonList.tsx +2 -2
  28. package/src/features/Conversation/index.tsx +2 -3
  29. package/src/libs/agent-runtime/BaseAI.ts +2 -9
  30. package/src/libs/agent-runtime/anthropic/index.test.ts +195 -0
  31. package/src/libs/agent-runtime/anthropic/index.ts +71 -15
  32. package/src/libs/agent-runtime/azureOpenai/index.ts +12 -13
  33. package/src/libs/agent-runtime/bedrock/index.ts +24 -18
  34. package/src/libs/agent-runtime/google/index.test.ts +154 -0
  35. package/src/libs/agent-runtime/google/index.ts +91 -10
  36. package/src/libs/agent-runtime/groq/index.test.ts +41 -72
  37. package/src/libs/agent-runtime/groq/index.ts +7 -0
  38. package/src/libs/agent-runtime/minimax/index.test.ts +2 -2
  39. package/src/libs/agent-runtime/minimax/index.ts +14 -37
  40. package/src/libs/agent-runtime/mistral/index.test.ts +0 -53
  41. package/src/libs/agent-runtime/mistral/index.ts +1 -0
  42. package/src/libs/agent-runtime/moonshot/index.test.ts +1 -71
  43. package/src/libs/agent-runtime/ollama/index.test.ts +197 -0
  44. package/src/libs/agent-runtime/ollama/index.ts +3 -3
  45. package/src/libs/agent-runtime/openai/index.test.ts +0 -53
  46. package/src/libs/agent-runtime/openrouter/index.test.ts +1 -53
  47. package/src/libs/agent-runtime/perplexity/index.test.ts +0 -71
  48. package/src/libs/agent-runtime/perplexity/index.ts +2 -3
  49. package/src/libs/agent-runtime/togetherai/__snapshots__/index.test.ts.snap +886 -0
  50. package/src/libs/agent-runtime/togetherai/fixtures/models.json +8111 -0
  51. package/src/libs/agent-runtime/togetherai/index.test.ts +16 -54
  52. package/src/libs/agent-runtime/types/chat.ts +19 -3
  53. package/src/libs/agent-runtime/utils/anthropicHelpers.test.ts +120 -1
  54. package/src/libs/agent-runtime/utils/anthropicHelpers.ts +67 -4
  55. package/src/libs/agent-runtime/utils/debugStream.test.ts +70 -0
  56. package/src/libs/agent-runtime/utils/debugStream.ts +39 -9
  57. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.test.ts +521 -0
  58. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +76 -5
  59. package/src/libs/agent-runtime/utils/response.ts +12 -0
  60. package/src/libs/agent-runtime/utils/streams/anthropic.test.ts +197 -0
  61. package/src/libs/agent-runtime/utils/streams/anthropic.ts +91 -0
  62. package/src/libs/agent-runtime/utils/streams/bedrock/claude.ts +21 -0
  63. package/src/libs/agent-runtime/utils/streams/bedrock/common.ts +32 -0
  64. package/src/libs/agent-runtime/utils/streams/bedrock/index.ts +3 -0
  65. package/src/libs/agent-runtime/utils/streams/bedrock/llama.test.ts +196 -0
  66. package/src/libs/agent-runtime/utils/streams/bedrock/llama.ts +51 -0
  67. package/src/libs/agent-runtime/utils/streams/google-ai.test.ts +97 -0
  68. package/src/libs/agent-runtime/utils/streams/google-ai.ts +68 -0
  69. package/src/libs/agent-runtime/utils/streams/index.ts +7 -0
  70. package/src/libs/agent-runtime/utils/streams/minimax.ts +39 -0
  71. package/src/libs/agent-runtime/utils/streams/ollama.test.ts +77 -0
  72. package/src/libs/agent-runtime/utils/streams/ollama.ts +38 -0
  73. package/src/libs/agent-runtime/utils/streams/openai.test.ts +263 -0
  74. package/src/libs/agent-runtime/utils/streams/openai.ts +79 -0
  75. package/src/libs/agent-runtime/utils/streams/protocol.ts +100 -0
  76. package/src/libs/agent-runtime/zeroone/index.test.ts +1 -53
  77. package/src/libs/agent-runtime/zhipu/index.test.ts +1 -1
  78. package/src/libs/agent-runtime/zhipu/index.ts +3 -2
  79. package/src/locales/default/plugin.ts +3 -4
  80. package/src/migrations/FromV4ToV5/fixtures/from-v1-to-v5-output.json +245 -0
  81. package/src/migrations/FromV4ToV5/fixtures/function-input-v4.json +96 -0
  82. package/src/migrations/FromV4ToV5/fixtures/function-output-v5.json +120 -0
  83. package/src/migrations/FromV4ToV5/index.ts +58 -0
  84. package/src/migrations/FromV4ToV5/migrations.test.ts +49 -0
  85. package/src/migrations/FromV4ToV5/types/v4.ts +21 -0
  86. package/src/migrations/FromV4ToV5/types/v5.ts +27 -0
  87. package/src/migrations/index.ts +8 -1
  88. package/src/services/__tests__/chat.test.ts +10 -20
  89. package/src/services/chat.ts +78 -65
  90. package/src/store/chat/slices/enchance/action.ts +15 -10
  91. package/src/store/chat/slices/message/action.test.ts +36 -86
  92. package/src/store/chat/slices/message/action.ts +70 -79
  93. package/src/store/chat/slices/message/reducer.ts +18 -1
  94. package/src/store/chat/slices/message/selectors.test.ts +38 -68
  95. package/src/store/chat/slices/message/selectors.ts +1 -22
  96. package/src/store/chat/slices/plugin/action.test.ts +147 -203
  97. package/src/store/chat/slices/plugin/action.ts +96 -82
  98. package/src/store/chat/slices/share/action.test.ts +3 -3
  99. package/src/store/chat/slices/share/action.ts +1 -1
  100. package/src/store/chat/slices/topic/action.ts +7 -2
  101. package/src/store/tool/selectors/tool.ts +6 -24
  102. package/src/store/tool/slices/builtin/action.test.ts +90 -0
  103. package/src/types/llm.ts +1 -1
  104. package/src/types/message/index.ts +9 -4
  105. package/src/types/message/tools.ts +57 -0
  106. package/src/types/openai/chat.ts +6 -0
  107. package/src/utils/fetch.test.ts +245 -1
  108. package/src/utils/fetch.ts +120 -44
  109. package/src/utils/toolCall.ts +21 -0
  110. package/src/features/Conversation/Messages/Assistant.tsx +0 -26
  111. package/src/features/Conversation/Messages/Function.tsx +0 -35
  112. package/src/libs/agent-runtime/ollama/stream.ts +0 -31
  113. /package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/PluginResultJSON.tsx +0 -0
  114. /package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/Settings.tsx +0 -0
  115. /package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/style.ts +0 -0
@@ -2,17 +2,20 @@ import { act, renderHook } from '@testing-library/react';
2
2
  import { Md5 } from 'ts-md5';
3
3
  import { Mock, afterEach, describe, expect, it, vi } from 'vitest';
4
4
 
5
+ import { LOADING_FLAT } from '@/const/message';
5
6
  import { PLUGIN_SCHEMA_API_MD5_PREFIX, PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
6
7
  import { chatService } from '@/services/chat';
7
8
  import { messageService } from '@/services/message';
8
9
  import { chatSelectors } from '@/store/chat/selectors';
9
10
  import { useChatStore } from '@/store/chat/store';
10
11
  import { useToolStore } from '@/store/tool';
11
- import { ChatPluginPayload } from '@/types/message';
12
+ import { ChatMessage, ChatToolPayload } from '@/types/message';
12
13
  import { LobeTool } from '@/types/tool';
13
14
 
14
15
  const invokeStandaloneTypePlugin = useChatStore.getState().invokeStandaloneTypePlugin;
15
16
 
17
+ vi.mock('zustand/traditional');
18
+
16
19
  // Mock messageService
17
20
  vi.mock('@/services/message', () => ({
18
21
  messageService: {
@@ -73,6 +76,7 @@ describe('ChatPluginAction', () => {
73
76
  const initialState = {
74
77
  messages: [],
75
78
  coreProcessMessage: vi.fn(),
79
+ internal_coreProcessMessage: vi.fn(),
76
80
  refreshMessages: vi.fn(),
77
81
  };
78
82
  useChatStore.setState(initialState);
@@ -130,7 +134,6 @@ describe('ChatPluginAction', () => {
130
134
  content: pluginApiResponse,
131
135
  });
132
136
  expect(storeState.refreshMessages).toHaveBeenCalled();
133
- expect(storeState.triggerAIMessage).toHaveBeenCalled();
134
137
  expect(storeState.internal_toggleChatLoading).toHaveBeenCalledWith(
135
138
  false,
136
139
  'message-id',
@@ -172,237 +175,178 @@ describe('ChatPluginAction', () => {
172
175
  });
173
176
  });
174
177
 
175
- describe('triggerFunctionCall', () => {
176
- it('should trigger a function call and update the plugin message accordingly', async () => {
177
- const messageId = 'message-id';
178
- const messageContent = JSON.stringify({
179
- tool_calls: [
178
+ describe('triggerToolCalls', () => {
179
+ it('should trigger tool calls for the assistant message', async () => {
180
+ const assistantId = 'assistant-id';
181
+ const message = {
182
+ id: assistantId,
183
+ role: 'assistant',
184
+ content: 'Assistant message',
185
+ tools: [
180
186
  {
181
- id: 'call_sbca',
182
- type: 'function',
183
- function: {
184
- name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName`,
185
- arguments: { key: 'value' },
186
- },
187
+ id: 'tool1',
188
+ type: 'standalone',
189
+ identifier: 'plugin1',
190
+ apiName: 'api1',
191
+ arguments: '{}',
187
192
  },
188
- ],
189
- });
190
- const messagePluginPayload = {
191
- apiName: 'apiName',
192
- identifier: 'pluginName',
193
- type: 'default',
194
- arguments: { key: 'value' },
195
- };
196
-
197
- const refreshSpy = vi.spyOn(useChatStore.getState(), 'refreshMessages');
198
- const invokeSpy = vi.spyOn(useChatStore.getState(), 'invokeDefaultTypePlugin');
199
- vi.spyOn(chatSelectors, 'getMessageById').mockImplementationOnce(
200
- () => () =>
201
- ({
202
- id: messageId,
203
- content: messageContent,
204
- }) as any,
205
- );
206
-
207
- const { result } = renderHook(() => useChatStore());
208
-
209
- await act(async () => {
210
- await result.current.triggerFunctionCall(messageId);
211
- });
212
-
213
- expect(chatSelectors.getMessageById).toHaveBeenCalledWith(messageId);
214
- expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, {
215
- content: '',
216
- plugin: messagePluginPayload,
217
- role: 'function',
218
- });
219
- expect(refreshSpy).toHaveBeenCalled();
220
- expect(invokeSpy).toHaveBeenCalledWith(messageId, messagePluginPayload);
221
- });
222
-
223
- it('should handle function call with MD5 prefixed API name', async () => {
224
- const messageId = 'message-id';
225
- const apiName = 'originalApiName';
226
- const id = 'pluginIdentifier';
227
- const md5ApiName = PLUGIN_SCHEMA_API_MD5_PREFIX + Md5.hashStr(apiName).toString();
228
- const messageContent = JSON.stringify({
229
- tool_calls: [
230
193
  {
231
- id: 'call_sbca',
232
- type: 'function',
233
- function: {
234
- name: id + PLUGIN_SCHEMA_SEPARATOR + md5ApiName,
235
- arguments: {},
236
- },
194
+ id: 'tool2',
195
+ type: 'markdown',
196
+ identifier: 'plugin2',
197
+ apiName: 'api2',
198
+ arguments: '{}',
199
+ },
200
+ {
201
+ id: 'tool3',
202
+ type: 'builtin',
203
+ identifier: 'builtin1',
204
+ apiName: 'api3',
205
+ arguments: '{}',
237
206
  },
238
- ],
239
- });
240
-
241
- const plugin = { identifier: id, manifest: { api: [{ name: apiName }] } } as LobeTool;
242
-
243
- useToolStore.setState({ installedPlugins: [plugin] });
244
-
245
- vi.spyOn(chatSelectors, 'getMessageById').mockImplementationOnce(
246
- () => () =>
247
- ({
248
- id: messageId,
249
- content: messageContent,
250
- }) as any,
251
- );
252
-
253
- const { result } = renderHook(() => useChatStore());
254
- vi.spyOn(result.current, 'invokeDefaultTypePlugin');
255
- vi.spyOn(result.current, 'refreshMessages');
256
-
257
- await act(async () => {
258
- await result.current.triggerFunctionCall(messageId);
259
- });
260
- expect(result.current.refreshMessages).toHaveBeenCalled();
261
-
262
- expect(messageService.updateMessage).toHaveBeenCalledWith(
263
- messageId,
264
- expect.objectContaining({
265
- // 确保正确的 API 名称被设置
266
- plugin: expect.objectContaining({ apiName }),
267
- }),
268
- );
269
- expect(result.current.invokeDefaultTypePlugin).toHaveBeenCalledWith(
270
- messageId,
271
- expect.objectContaining({
272
- apiName: apiName,
273
- }),
274
- );
275
- });
276
-
277
- it('should handle standalone plugin type', async () => {
278
- const messageId = 'message-id';
279
- const messageContent = JSON.stringify({
280
- tool_calls: [
281
207
  {
282
- id: 'call_scv',
283
- function: {
284
- name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName${PLUGIN_SCHEMA_SEPARATOR}standalone`,
285
- arguments: {},
286
- },
208
+ id: 'tool4',
209
+ type: 'default',
210
+ identifier: 'plugin3',
211
+ apiName: 'api4',
212
+ arguments: '{}',
287
213
  },
288
214
  ],
289
- });
215
+ } as ChatMessage;
290
216
 
291
- const invokeStandaloneTypePlugin = useChatStore.getState().invokeStandaloneTypePlugin;
217
+ const invokeStandaloneTypePluginMock = vi.fn();
218
+ const invokeMarkdownTypePluginMock = vi.fn();
219
+ const invokeBuiltinToolMock = vi.fn();
220
+ const invokeDefaultTypePluginMock = vi.fn().mockResolvedValue('Default tool response');
221
+ const triggerAIMessageMock = vi.fn();
222
+ const internal_createMessageMock = vi.fn().mockResolvedValue('tool-message-id');
223
+ const getTraceIdByMessageIdMock = vi.fn().mockReturnValue('trace-id');
292
224
 
293
225
  act(() => {
294
226
  useChatStore.setState({
295
- refreshMessages: vi.fn(),
296
- invokeStandaloneTypePlugin: vi.fn(),
227
+ messages: [message],
228
+ invokeStandaloneTypePlugin: invokeStandaloneTypePluginMock,
229
+ invokeMarkdownTypePlugin: invokeMarkdownTypePluginMock,
230
+ invokeBuiltinTool: invokeBuiltinToolMock,
231
+ invokeDefaultTypePlugin: invokeDefaultTypePluginMock,
232
+ triggerAIMessage: triggerAIMessageMock,
233
+ internal_createMessage: internal_createMessageMock,
234
+ activeId: 'session-id',
235
+ activeTopicId: 'topic-id',
297
236
  });
298
237
  });
299
238
 
300
- vi.spyOn(chatSelectors, 'getMessageById').mockImplementation(
301
- () => () =>
302
- ({
303
- id: messageId,
304
- content: messageContent,
305
- }) as any,
306
- );
307
-
308
239
  const { result } = renderHook(() => useChatStore());
309
240
 
310
241
  await act(async () => {
311
- await result.current.triggerFunctionCall(messageId);
312
- });
313
-
314
- // 验证 refreshMessages 是否被调用
315
- expect(result.current.refreshMessages).toHaveBeenCalled();
316
-
317
- // 验证 invokeDefaultTypePlugin 是否没有被调用,因为类型是 standalone
318
- expect(result.current.invokeDefaultTypePlugin).not.toHaveBeenCalled();
319
- expect(result.current.invokeStandaloneTypePlugin).toHaveBeenCalled();
242
+ await result.current.triggerToolCalls(assistantId);
243
+ });
244
+
245
+ // Verify that tool messages were created for each tool call
246
+ expect(internal_createMessageMock).toHaveBeenCalledTimes(4);
247
+ expect(internal_createMessageMock).toHaveBeenCalledWith({
248
+ content: LOADING_FLAT,
249
+ parentId: assistantId,
250
+ plugin: message.tools![0],
251
+ role: 'tool',
252
+ sessionId: 'session-id',
253
+ tool_call_id: 'tool1',
254
+ topicId: 'topic-id',
255
+ });
256
+ // ... similar assertions for other tool calls
257
+
258
+ // Verify that the appropriate plugin types were invoked
259
+ expect(invokeStandaloneTypePluginMock).toHaveBeenCalledWith(
260
+ 'tool-message-id',
261
+ message.tools![0],
262
+ );
263
+ expect(invokeMarkdownTypePluginMock).toHaveBeenCalledWith(
264
+ 'tool-message-id',
265
+ message.tools![1],
266
+ );
267
+ expect(invokeBuiltinToolMock).toHaveBeenCalledWith('tool-message-id', message.tools![2]);
268
+ expect(invokeDefaultTypePluginMock).toHaveBeenCalledWith(
269
+ 'tool-message-id',
270
+ message.tools![3],
271
+ );
320
272
 
321
- useChatStore.setState({ invokeStandaloneTypePlugin });
273
+ // Verify that AI message was triggered for default type tool call
274
+ // expect(getTraceIdByMessageIdMock).toHaveBeenCalledWith('tool-message-id');
275
+ // expect(triggerAIMessageMock).toHaveBeenCalledWith({ traceId: 'trace-id' });
322
276
  });
323
277
 
324
- it('should handle builtin plugin type', async () => {
325
- const messageId = 'message-id';
326
- const messageContent = JSON.stringify({
327
- tool_calls: [
278
+ it('should not trigger AI message if no default type tool calls', async () => {
279
+ const assistantId = 'assistant-id';
280
+ const message = {
281
+ id: assistantId,
282
+ role: 'assistant',
283
+ content: 'Assistant message',
284
+ tools: [
328
285
  {
329
- id: 'call_scv',
330
- function: {
331
- name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName${PLUGIN_SCHEMA_SEPARATOR}builtin`,
332
- arguments: {},
333
- },
286
+ id: 'tool1',
287
+ type: 'standalone',
288
+ identifier: 'plugin1',
289
+ apiName: 'api1',
290
+ arguments: '{}',
291
+ },
292
+ {
293
+ id: 'tool2',
294
+ type: 'markdown',
295
+ identifier: 'plugin2',
296
+ apiName: 'api2',
297
+ arguments: '{}',
334
298
  },
335
- ],
336
- });
337
-
338
- const invokeBuiltinTool = useChatStore.getState().invokeBuiltinTool;
339
- useChatStore.setState({ refreshMessages: vi.fn(), invokeBuiltinTool: vi.fn() });
340
-
341
- vi.spyOn(chatSelectors, 'getMessageById').mockImplementation(
342
- () => () =>
343
- ({
344
- id: messageId,
345
- content: messageContent,
346
- }) as any,
347
- );
348
-
349
- const { result } = renderHook(() => useChatStore());
350
-
351
- await act(async () => {
352
- await result.current.triggerFunctionCall(messageId);
353
- });
354
-
355
- // 验证 refreshMessages 是否被调用
356
- expect(result.current.refreshMessages).toHaveBeenCalled();
357
-
358
- // 验证 invokeDefaultTypePlugin 是否没有被调用,因为类型是 standalone
359
- expect(result.current.invokeDefaultTypePlugin).not.toHaveBeenCalled();
360
- expect(result.current.invokeBuiltinTool).toHaveBeenCalled();
361
-
362
- useChatStore.setState({ invokeBuiltinTool });
363
- });
364
-
365
- it('should handle markdown plugin type', async () => {
366
- const messageId = 'message-id';
367
- const messageContent = JSON.stringify({
368
- tool_calls: [
369
299
  {
370
- id: 'call_scv',
371
- function: {
372
- name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName${PLUGIN_SCHEMA_SEPARATOR}markdown`,
373
- arguments: {},
374
- },
300
+ id: 'tool3',
301
+ type: 'builtin',
302
+ identifier: 'builtin1',
303
+ apiName: 'api3',
304
+ arguments: '{}',
375
305
  },
376
306
  ],
377
- });
307
+ } as ChatMessage;
378
308
 
379
- const invokeMarkdownTypePlugin = useChatStore.getState().invokeMarkdownTypePlugin;
380
- useChatStore.setState({
381
- refreshMessages: vi.fn(),
382
- invokeMarkdownTypePlugin: vi.fn(),
383
- });
309
+ const invokeStandaloneTypePluginMock = vi.fn();
310
+ const invokeMarkdownTypePluginMock = vi.fn();
311
+ const invokeBuiltinToolMock = vi.fn();
312
+ const triggerAIMessageMock = vi.fn();
313
+ const internal_createMessageMock = vi.fn().mockResolvedValue('tool-message-id');
384
314
 
385
- vi.spyOn(chatSelectors, 'getMessageById').mockImplementation(
386
- () => () =>
387
- ({
388
- id: messageId,
389
- content: messageContent,
390
- }) as any,
391
- );
315
+ act(() => {
316
+ useChatStore.setState({
317
+ invokeStandaloneTypePlugin: invokeStandaloneTypePluginMock,
318
+ invokeMarkdownTypePlugin: invokeMarkdownTypePluginMock,
319
+ invokeBuiltinTool: invokeBuiltinToolMock,
320
+ triggerAIMessage: triggerAIMessageMock,
321
+ internal_createMessage: internal_createMessageMock,
322
+ activeId: 'session-id',
323
+ messages: [message],
324
+ activeTopicId: 'topic-id',
325
+ });
326
+ });
392
327
 
393
328
  const { result } = renderHook(() => useChatStore());
394
329
 
395
330
  await act(async () => {
396
- await result.current.triggerFunctionCall(messageId);
331
+ await result.current.triggerToolCalls(assistantId);
397
332
  });
398
333
 
399
- // 验证 refreshMessages 是否被调用
400
- expect(result.current.refreshMessages).toHaveBeenCalled();
334
+ // Verify that tool messages were created for each tool call
335
+ expect(internal_createMessageMock).toHaveBeenCalledTimes(3);
401
336
 
402
- expect(result.current.invokeDefaultTypePlugin).not.toHaveBeenCalled();
403
- expect(result.current.invokeMarkdownTypePlugin).toHaveBeenCalled();
337
+ // Verify that the appropriate plugin types were invoked
338
+ expect(invokeStandaloneTypePluginMock).toHaveBeenCalledWith(
339
+ 'tool-message-id',
340
+ message.tools![0],
341
+ );
342
+ expect(invokeMarkdownTypePluginMock).toHaveBeenCalledWith(
343
+ 'tool-message-id',
344
+ message.tools![1],
345
+ );
346
+ expect(invokeBuiltinToolMock).toHaveBeenCalledWith('tool-message-id', message.tools![2]);
404
347
 
405
- useChatStore.setState({ invokeMarkdownTypePlugin });
348
+ // Verify that AI message was not triggered
349
+ expect(triggerAIMessageMock).not.toHaveBeenCalled();
406
350
  });
407
351
  });
408
352
 
@@ -510,7 +454,7 @@ describe('ChatPluginAction', () => {
510
454
  const payload = {
511
455
  apiName: 'text2image',
512
456
  arguments: JSON.stringify({ key: 'value' }),
513
- } as ChatPluginPayload;
457
+ } as ChatToolPayload;
514
458
 
515
459
  const messageId = 'message-id';
516
460
  const toolResponse = JSON.stringify({ abc: 'data' });
@@ -557,7 +501,7 @@ describe('ChatPluginAction', () => {
557
501
  const payload = {
558
502
  apiName: 'text2image',
559
503
  arguments: JSON.stringify({ key: 'value' }),
560
- } as ChatPluginPayload;
504
+ } as ChatToolPayload;
561
505
 
562
506
  const messageId = 'message-id';
563
507
  const toolResponse = 'Builtin tool response';
@@ -606,7 +550,7 @@ describe('ChatPluginAction', () => {
606
550
  const payload = {
607
551
  apiName: 'builtinApi',
608
552
  arguments: JSON.stringify({ key: 'value' }),
609
- } as ChatPluginPayload;
553
+ } as ChatToolPayload;
610
554
 
611
555
  const messageId = 'message-id';
612
556
  const error = new Error('Builtin tool failed');
@@ -652,7 +596,7 @@ describe('ChatPluginAction', () => {
652
596
  identifier: 'abc',
653
597
  type: 'markdown',
654
598
  arguments: JSON.stringify({ key: 'value' }),
655
- } as ChatPluginPayload;
599
+ } as ChatToolPayload;
656
600
  const messageId = 'message-id';
657
601
 
658
602
  const runPluginApiMock = vi.fn();
@@ -678,7 +622,7 @@ describe('ChatPluginAction', () => {
678
622
 
679
623
  const payload = {
680
624
  identifier: 'pluginName',
681
- } as ChatPluginPayload;
625
+ } as ChatToolPayload;
682
626
 
683
627
  act(() => {
684
628
  useToolStore.setState({