@lobehub/lobehub 2.0.0-next.85 → 2.0.0-next.86

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 (88) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/apps/desktop/src/main/modules/networkProxy/dispatcher.ts +16 -16
  3. package/apps/desktop/src/main/modules/networkProxy/tester.ts +11 -11
  4. package/apps/desktop/src/main/modules/networkProxy/urlBuilder.ts +3 -3
  5. package/apps/desktop/src/main/modules/networkProxy/validator.ts +10 -10
  6. package/changelog/v1.json +9 -0
  7. package/package.json +1 -1
  8. package/packages/agent-runtime/src/core/runtime.ts +36 -1
  9. package/packages/agent-runtime/src/types/event.ts +1 -0
  10. package/packages/agent-runtime/src/types/generalAgent.ts +16 -0
  11. package/packages/agent-runtime/src/types/instruction.ts +30 -0
  12. package/packages/agent-runtime/src/types/runtime.ts +7 -0
  13. package/packages/types/src/message/common/metadata.ts +3 -0
  14. package/packages/types/src/message/common/tools.ts +2 -2
  15. package/packages/types/src/tool/search/index.ts +8 -2
  16. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/index.tsx +2 -2
  17. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/useSend.ts +7 -2
  18. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/useSend.ts +15 -14
  19. package/src/app/[variants]/(main)/chat/session/features/SessionListContent/List/Item/index.tsx +2 -2
  20. package/src/features/ChatInput/ActionBar/STT/browser.tsx +2 -2
  21. package/src/features/ChatInput/ActionBar/STT/openai.tsx +2 -2
  22. package/src/features/Conversation/Messages/Group/Tool/Inspector/index.tsx +1 -1
  23. package/src/features/Conversation/Messages/User/index.tsx +3 -3
  24. package/src/features/Conversation/Messages/index.tsx +3 -3
  25. package/src/features/Conversation/components/AutoScroll.tsx +2 -2
  26. package/src/services/search.ts +2 -2
  27. package/src/store/chat/agents/GeneralChatAgent.ts +98 -0
  28. package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +366 -0
  29. package/src/store/chat/agents/__tests__/createAgentExecutors/call-llm.test.ts +1217 -0
  30. package/src/store/chat/agents/__tests__/createAgentExecutors/call-tool.test.ts +1976 -0
  31. package/src/store/chat/agents/__tests__/createAgentExecutors/finish.test.ts +453 -0
  32. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/index.ts +4 -0
  33. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockInstructions.ts +126 -0
  34. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockMessages.ts +94 -0
  35. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockOperations.ts +96 -0
  36. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockStore.ts +138 -0
  37. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/assertions.ts +185 -0
  38. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/index.ts +3 -0
  39. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/operationTestUtils.ts +94 -0
  40. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/testExecutor.ts +139 -0
  41. package/src/store/chat/agents/__tests__/createAgentExecutors/request-human-approve.test.ts +545 -0
  42. package/src/store/chat/agents/__tests__/createAgentExecutors/resolve-aborted-tools.test.ts +686 -0
  43. package/src/store/chat/agents/createAgentExecutors.ts +313 -80
  44. package/src/store/chat/selectors.ts +1 -0
  45. package/src/store/chat/slices/aiChat/__tests__/ai-chat.integration.test.ts +667 -0
  46. package/src/store/chat/slices/aiChat/actions/__tests__/cancel-functionality.test.ts +137 -27
  47. package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +163 -125
  48. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +12 -2
  49. package/src/store/chat/slices/aiChat/actions/__tests__/fixtures.ts +0 -2
  50. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +0 -2
  51. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +286 -19
  52. package/src/store/chat/slices/aiChat/actions/__tests__/streamingStates.test.ts +0 -112
  53. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +42 -99
  54. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +90 -57
  55. package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +5 -25
  56. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +220 -98
  57. package/src/store/chat/slices/aiChat/actions/streamingStates.ts +0 -34
  58. package/src/store/chat/slices/aiChat/initialState.ts +0 -28
  59. package/src/store/chat/slices/aiChat/selectors.test.ts +280 -0
  60. package/src/store/chat/slices/aiChat/selectors.ts +31 -7
  61. package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +21 -30
  62. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +29 -49
  63. package/src/store/chat/slices/builtinTool/actions/interpreter.ts +83 -48
  64. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +78 -28
  65. package/src/store/chat/slices/builtinTool/actions/search.ts +146 -59
  66. package/src/store/chat/slices/builtinTool/selectors.test.ts +258 -0
  67. package/src/store/chat/slices/builtinTool/selectors.ts +25 -4
  68. package/src/store/chat/slices/message/action.test.ts +134 -16
  69. package/src/store/chat/slices/message/actions/internals.ts +33 -7
  70. package/src/store/chat/slices/message/actions/optimisticUpdate.ts +85 -52
  71. package/src/store/chat/slices/message/initialState.ts +0 -10
  72. package/src/store/chat/slices/message/selectors/messageState.ts +34 -12
  73. package/src/store/chat/slices/operation/__tests__/actions.test.ts +712 -16
  74. package/src/store/chat/slices/operation/__tests__/integration.test.ts +342 -0
  75. package/src/store/chat/slices/operation/__tests__/selectors.test.ts +257 -17
  76. package/src/store/chat/slices/operation/actions.ts +218 -11
  77. package/src/store/chat/slices/operation/selectors.ts +135 -6
  78. package/src/store/chat/slices/operation/types.ts +29 -3
  79. package/src/store/chat/slices/plugin/action.test.ts +30 -322
  80. package/src/store/chat/slices/plugin/actions/internals.ts +0 -14
  81. package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +21 -19
  82. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +45 -27
  83. package/src/store/chat/slices/plugin/actions/publicApi.ts +3 -4
  84. package/src/store/chat/slices/plugin/actions/workflow.ts +0 -55
  85. package/src/store/chat/slices/thread/selectors/index.ts +4 -2
  86. package/src/store/chat/slices/translate/action.ts +54 -41
  87. package/src/tools/web-browsing/ExecutionRuntime/index.ts +5 -2
  88. package/src/tools/web-browsing/Portal/Search/Footer.tsx +11 -9
@@ -115,41 +115,6 @@ describe('ChatPluginAction', () => {
115
115
  });
116
116
  });
117
117
 
118
- describe('internal_togglePluginApiCalling', () => {
119
- it('should toggle plugin API calling state', () => {
120
- const internal_toggleLoadingArraysMock = vi.fn();
121
-
122
- act(() => {
123
- useChatStore.setState({
124
- internal_toggleLoadingArrays: internal_toggleLoadingArraysMock,
125
- });
126
- });
127
-
128
- const { result } = renderHook(() => useChatStore());
129
-
130
- const messageId = 'message-id';
131
- const action = 'test-action';
132
-
133
- result.current.internal_togglePluginApiCalling(true, messageId, action);
134
-
135
- expect(internal_toggleLoadingArraysMock).toHaveBeenCalledWith(
136
- 'pluginApiLoadingIds',
137
- true,
138
- messageId,
139
- action,
140
- );
141
-
142
- result.current.internal_togglePluginApiCalling(false, messageId, action);
143
-
144
- expect(internal_toggleLoadingArraysMock).toHaveBeenCalledWith(
145
- 'pluginApiLoadingIds',
146
- false,
147
- messageId,
148
- action,
149
- );
150
- });
151
- });
152
-
153
118
  describe('fillPluginMessageContent', () => {
154
119
  it('should update message content and trigger the ai message', async () => {
155
120
  // 设置模拟函数的返回值
@@ -234,7 +199,6 @@ describe('ChatPluginAction', () => {
234
199
 
235
200
  vi.spyOn(storeState, 'refreshMessages');
236
201
  vi.spyOn(storeState, 'triggerAIMessage').mockResolvedValue(undefined);
237
- vi.spyOn(storeState, 'internal_togglePluginApiCalling').mockReturnValue(undefined);
238
202
  vi.spyOn(storeState, 'optimisticUpdateMessageContent').mockResolvedValue();
239
203
 
240
204
  const runSpy = vi.spyOn(chatService, 'runPluginApi').mockResolvedValue({
@@ -248,25 +212,12 @@ describe('ChatPluginAction', () => {
248
212
  await result.current.invokeDefaultTypePlugin(messageId, pluginPayload);
249
213
  });
250
214
 
251
- expect(storeState.internal_togglePluginApiCalling).toHaveBeenCalledWith(
252
- true,
253
- messageId,
254
- expect.any(String),
255
- );
256
215
  expect(runSpy).toHaveBeenCalledWith(pluginPayload, { signal: undefined, trace: {} });
257
216
  expect(storeState.optimisticUpdateMessageContent).toHaveBeenCalledWith(
258
217
  messageId,
259
218
  pluginApiResponse,
260
219
  undefined,
261
- {
262
- sessionId: undefined,
263
- topicId: undefined,
264
- },
265
- );
266
- expect(storeState.internal_togglePluginApiCalling).toHaveBeenCalledWith(
267
- false,
268
- 'message-id',
269
- 'plugin/fetchPlugin/end',
220
+ undefined,
270
221
  );
271
222
  });
272
223
 
@@ -285,7 +236,6 @@ describe('ChatPluginAction', () => {
285
236
  const storeState = useChatStore.getState();
286
237
  const replaceMessagesSpy = vi.spyOn(storeState, 'replaceMessages');
287
238
  vi.spyOn(storeState, 'triggerAIMessage').mockResolvedValue(undefined);
288
- vi.spyOn(storeState, 'internal_togglePluginApiCalling').mockReturnValue(undefined);
289
239
 
290
240
  vi.spyOn(chatService, 'runPluginApi').mockRejectedValue(error);
291
241
 
@@ -294,11 +244,6 @@ describe('ChatPluginAction', () => {
294
244
  await result.current.invokeDefaultTypePlugin(messageId, pluginPayload);
295
245
  });
296
246
 
297
- expect(storeState.internal_togglePluginApiCalling).toHaveBeenCalledWith(
298
- true,
299
- messageId,
300
- expect.any(String),
301
- );
302
247
  expect(chatService.runPluginApi).toHaveBeenCalledWith(pluginPayload, { trace: {} });
303
248
  expect(messageService.updateMessageError).toHaveBeenCalledWith(messageId, error, {
304
249
  sessionId: undefined,
@@ -308,260 +253,10 @@ describe('ChatPluginAction', () => {
308
253
  sessionId: undefined,
309
254
  topicId: undefined,
310
255
  });
311
- expect(storeState.internal_togglePluginApiCalling).toHaveBeenCalledWith(
312
- false,
313
- 'message-id',
314
- 'plugin/fetchPlugin/end',
315
- );
316
256
  expect(storeState.triggerAIMessage).not.toHaveBeenCalled(); // 确保在错误情况下不调用此方法
317
257
  });
318
258
  });
319
259
 
320
- describe('triggerToolCalls', () => {
321
- it('should trigger tool calls for the assistant message', async () => {
322
- const assistantId = 'assistant-id';
323
- const message = {
324
- id: assistantId,
325
- role: 'assistant',
326
- content: 'Assistant message',
327
- tools: [
328
- {
329
- id: 'tool1',
330
- type: 'standalone',
331
- identifier: 'plugin1',
332
- apiName: 'api1',
333
- arguments: '{}',
334
- },
335
- {
336
- id: 'tool2',
337
- type: 'markdown',
338
- identifier: 'plugin2',
339
- apiName: 'api2',
340
- arguments: '{}',
341
- },
342
- {
343
- id: 'tool3',
344
- type: 'builtin',
345
- identifier: 'builtin1',
346
- apiName: 'api3',
347
- arguments: '{}',
348
- },
349
- {
350
- id: 'tool4',
351
- type: 'default',
352
- identifier: 'plugin3',
353
- apiName: 'api4',
354
- arguments: '{}',
355
- },
356
- ],
357
- } as UIChatMessage;
358
-
359
- const invokeStandaloneTypePluginMock = vi.fn();
360
- const invokeMarkdownTypePluginMock = vi.fn();
361
- const invokeBuiltinToolMock = vi.fn();
362
- const invokeDefaultTypePluginMock = vi.fn().mockResolvedValue('Default tool response');
363
- const triggerAIMessageMock = vi.fn();
364
- const optimisticCreateMessageMock = vi
365
- .fn()
366
- .mockResolvedValue({ id: 'tool-message-id', messages: [] });
367
- const getTraceIdByMessageIdMock = vi.fn().mockReturnValue('trace-id');
368
-
369
- act(() => {
370
- useChatStore.setState({
371
- messagesMap: {
372
- [messageMapKey('session-id', 'topic-id')]: [message],
373
- },
374
- invokeStandaloneTypePlugin: invokeStandaloneTypePluginMock,
375
- invokeMarkdownTypePlugin: invokeMarkdownTypePluginMock,
376
- invokeBuiltinTool: invokeBuiltinToolMock,
377
- invokeDefaultTypePlugin: invokeDefaultTypePluginMock,
378
- triggerAIMessage: triggerAIMessageMock,
379
- optimisticCreateMessage: optimisticCreateMessageMock,
380
- activeId: 'session-id',
381
- activeTopicId: 'topic-id',
382
- });
383
- });
384
-
385
- const { result } = renderHook(() => useChatStore());
386
-
387
- await act(async () => {
388
- await result.current.triggerToolCalls(assistantId);
389
- });
390
-
391
- // Verify that tool messages were created for each tool call
392
- expect(optimisticCreateMessageMock).toHaveBeenCalledTimes(4);
393
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
394
- 1,
395
- {
396
- content: '',
397
- parentId: assistantId,
398
- plugin: message.tools![0],
399
- role: 'tool',
400
- sessionId: 'session-id',
401
- tool_call_id: 'tool1',
402
- topicId: 'topic-id',
403
- threadId: undefined,
404
- groupId: undefined,
405
- },
406
- {
407
- sessionId: 'session-id',
408
- topicId: 'topic-id',
409
- },
410
- );
411
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
412
- 2,
413
- {
414
- content: '',
415
- parentId: assistantId,
416
- plugin: message.tools![1],
417
- role: 'tool',
418
- sessionId: 'session-id',
419
- tool_call_id: 'tool2',
420
- topicId: 'topic-id',
421
- threadId: undefined,
422
- groupId: undefined,
423
- },
424
- {
425
- sessionId: 'session-id',
426
- topicId: 'topic-id',
427
- },
428
- );
429
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
430
- 3,
431
- {
432
- content: '',
433
- parentId: assistantId,
434
- plugin: message.tools![2],
435
- role: 'tool',
436
- sessionId: 'session-id',
437
- tool_call_id: 'tool3',
438
- topicId: 'topic-id',
439
- threadId: undefined,
440
- groupId: undefined,
441
- },
442
- {
443
- sessionId: 'session-id',
444
- topicId: 'topic-id',
445
- },
446
- );
447
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
448
- 4,
449
- {
450
- content: '',
451
- parentId: assistantId,
452
- plugin: message.tools![3],
453
- role: 'tool',
454
- sessionId: 'session-id',
455
- tool_call_id: 'tool4',
456
- topicId: 'topic-id',
457
- threadId: undefined,
458
- groupId: undefined,
459
- },
460
- {
461
- sessionId: 'session-id',
462
- topicId: 'topic-id',
463
- },
464
- );
465
-
466
- // Verify that the appropriate plugin types were invoked
467
- expect(invokeStandaloneTypePluginMock).toHaveBeenCalledWith(
468
- 'tool-message-id',
469
- message.tools![0],
470
- );
471
- expect(invokeMarkdownTypePluginMock).toHaveBeenCalledWith(
472
- 'tool-message-id',
473
- message.tools![1],
474
- );
475
- expect(invokeBuiltinToolMock).toHaveBeenCalledWith('tool-message-id', message.tools![2]);
476
- expect(invokeDefaultTypePluginMock).toHaveBeenCalledWith(
477
- 'tool-message-id',
478
- message.tools![3],
479
- );
480
-
481
- // Verify that AI message was triggered for default type tool call
482
- // expect(getTraceIdByMessageIdMock).toHaveBeenCalledWith('tool-message-id');
483
- // expect(triggerAIMessageMock).toHaveBeenCalledWith({ traceId: 'trace-id' });
484
- });
485
-
486
- it('should not trigger AI message if no default type tool calls', async () => {
487
- const assistantId = 'assistant-id';
488
- const message = {
489
- id: assistantId,
490
- role: 'assistant',
491
- content: 'Assistant message',
492
- tools: [
493
- {
494
- id: 'tool1',
495
- type: 'standalone',
496
- identifier: 'plugin1',
497
- apiName: 'api1',
498
- arguments: '{}',
499
- },
500
- {
501
- id: 'tool2',
502
- type: 'markdown',
503
- identifier: 'plugin2',
504
- apiName: 'api2',
505
- arguments: '{}',
506
- },
507
- {
508
- id: 'tool3',
509
- type: 'builtin',
510
- identifier: 'builtin1',
511
- apiName: 'api3',
512
- arguments: '{}',
513
- },
514
- ],
515
- } as UIChatMessage;
516
-
517
- const invokeStandaloneTypePluginMock = vi.fn();
518
- const invokeMarkdownTypePluginMock = vi.fn();
519
- const invokeBuiltinToolMock = vi.fn();
520
- const triggerAIMessageMock = vi.fn();
521
- const optimisticCreateMessageMock = vi
522
- .fn()
523
- .mockResolvedValue({ id: 'tool-message-id', messages: [] });
524
-
525
- act(() => {
526
- useChatStore.setState({
527
- invokeStandaloneTypePlugin: invokeStandaloneTypePluginMock,
528
- invokeMarkdownTypePlugin: invokeMarkdownTypePluginMock,
529
- invokeBuiltinTool: invokeBuiltinToolMock,
530
- triggerAIMessage: triggerAIMessageMock,
531
- optimisticCreateMessage: optimisticCreateMessageMock,
532
- activeId: 'session-id',
533
- messagesMap: {
534
- [messageMapKey('session-id', 'topic-id')]: [message],
535
- },
536
- activeTopicId: 'topic-id',
537
- });
538
- });
539
-
540
- const { result } = renderHook(() => useChatStore());
541
-
542
- await act(async () => {
543
- await result.current.triggerToolCalls(assistantId);
544
- });
545
-
546
- // Verify that tool messages were created for each tool call
547
- expect(optimisticCreateMessageMock).toHaveBeenCalledTimes(3);
548
-
549
- // Verify that the appropriate plugin types were invoked
550
- expect(invokeStandaloneTypePluginMock).toHaveBeenCalledWith(
551
- 'tool-message-id',
552
- message.tools![0],
553
- );
554
- expect(invokeMarkdownTypePluginMock).toHaveBeenCalledWith(
555
- 'tool-message-id',
556
- message.tools![1],
557
- );
558
- expect(invokeBuiltinToolMock).toHaveBeenCalledWith('tool-message-id', message.tools![2]);
559
-
560
- // Verify that AI message was not triggered
561
- expect(triggerAIMessageMock).not.toHaveBeenCalled();
562
- });
563
- });
564
-
565
260
  describe('updatePluginState', () => {
566
261
  it('should update the plugin state for a message', async () => {
567
262
  const messageId = 'message-id';
@@ -896,10 +591,7 @@ describe('ChatPluginAction', () => {
896
591
  await result.current.reInvokeToolMessage(messageId);
897
592
  });
898
593
 
899
- expect(internal_updateMessageErrorMock).toHaveBeenCalledWith(messageId, null, {
900
- sessionId: undefined,
901
- topicId: undefined,
902
- });
594
+ expect(internal_updateMessageErrorMock).toHaveBeenCalledWith(messageId, null, undefined);
903
595
  });
904
596
  });
905
597
 
@@ -973,7 +665,6 @@ describe('ChatPluginAction', () => {
973
665
 
974
666
  act(() => {
975
667
  useChatStore.setState({
976
- internal_togglePluginApiCalling: vi.fn(),
977
668
  optimisticUpdateMessageContent: vi.fn(),
978
669
  refreshMessages: vi.fn(),
979
670
  });
@@ -990,10 +681,7 @@ describe('ChatPluginAction', () => {
990
681
  messageId,
991
682
  apiResponse,
992
683
  undefined,
993
- {
994
- sessionId: undefined,
995
- topicId: undefined,
996
- },
684
+ undefined,
997
685
  );
998
686
  expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, { traceId: 'trace-id' });
999
687
  });
@@ -1022,7 +710,6 @@ describe('ChatPluginAction', () => {
1022
710
 
1023
711
  act(() => {
1024
712
  useChatStore.setState({
1025
- internal_togglePluginApiCalling: vi.fn(),
1026
713
  replaceMessages: replaceMessagesSpy,
1027
714
  });
1028
715
  });
@@ -1238,10 +925,17 @@ describe('ChatPluginAction', () => {
1238
925
 
1239
926
  const replaceMessagesSpy = vi.spyOn(result.current, 'replaceMessages');
1240
927
 
928
+ let operationId: string;
1241
929
  await act(async () => {
930
+ // Create operation with desired context
931
+ const op = result.current.startOperation({
932
+ type: 'sendMessage',
933
+ context: { sessionId: contextSessionId, topicId: contextTopicId },
934
+ });
935
+ operationId = op.operationId;
936
+
1242
937
  await result.current.optimisticUpdatePluginState(messageId, pluginState, {
1243
- sessionId: contextSessionId,
1244
- topicId: contextTopicId,
938
+ operationId,
1245
939
  });
1246
940
  });
1247
941
 
@@ -1298,10 +992,17 @@ describe('ChatPluginAction', () => {
1298
992
  messages: [],
1299
993
  });
1300
994
 
995
+ let operationId: string;
1301
996
  await act(async () => {
997
+ // Create operation with desired context
998
+ const op = result.current.startOperation({
999
+ type: 'sendMessage',
1000
+ context: { sessionId: contextSessionId, topicId: contextTopicId },
1001
+ });
1002
+ operationId = op.operationId;
1003
+
1302
1004
  await result.current.optimisticUpdatePluginError(messageId, error, {
1303
- sessionId: contextSessionId,
1304
- topicId: contextTopicId,
1005
+ operationId,
1305
1006
  });
1306
1007
  });
1307
1008
 
@@ -1331,7 +1032,15 @@ describe('ChatPluginAction', () => {
1331
1032
 
1332
1033
  // Set up both dbMessagesMap and messagesMap
1333
1034
  const key = messageMapKey(contextSessionId, contextTopicId);
1035
+ let operationId: string;
1334
1036
  act(() => {
1037
+ // Create operation with desired context
1038
+ const op = result.current.startOperation({
1039
+ type: 'sendMessage',
1040
+ context: { sessionId: contextSessionId, topicId: contextTopicId },
1041
+ });
1042
+ operationId = op.operationId;
1043
+
1335
1044
  useChatStore.setState({
1336
1045
  dbMessagesMap: {
1337
1046
  [key]: [message],
@@ -1346,8 +1055,7 @@ describe('ChatPluginAction', () => {
1346
1055
 
1347
1056
  await act(async () => {
1348
1057
  await result.current.internal_refreshToUpdateMessageTools(messageId, {
1349
- sessionId: contextSessionId,
1350
- topicId: contextTopicId,
1058
+ operationId,
1351
1059
  });
1352
1060
  });
1353
1061
 
@@ -8,7 +8,6 @@ import { ChatStore } from '@/store/chat/store';
8
8
  import { useToolStore } from '@/store/tool';
9
9
  import { pluginSelectors } from '@/store/tool/selectors';
10
10
  import { builtinTools } from '@/tools';
11
- import { Action } from '@/utils/storeDebug';
12
11
 
13
12
  import { displayMessageSelectors } from '../../message/selectors';
14
13
 
@@ -17,15 +16,6 @@ import { displayMessageSelectors } from '../../message/selectors';
17
16
  * These are building blocks used by other actions
18
17
  */
19
18
  export interface PluginInternalsAction {
20
- /**
21
- * Toggle plugin API calling state
22
- */
23
- internal_togglePluginApiCalling: (
24
- loading: boolean,
25
- id?: string,
26
- action?: Action,
27
- ) => AbortController | undefined;
28
-
29
19
  /**
30
20
  * Transform tool calls from runtime format to storage format
31
21
  */
@@ -43,10 +33,6 @@ export const pluginInternals: StateCreator<
43
33
  [],
44
34
  PluginInternalsAction
45
35
  > = (set, get) => ({
46
- internal_togglePluginApiCalling: (loading, id, action) => {
47
- return get().internal_toggleLoadingArrays('pluginApiLoadingIds', loading, id, action);
48
- },
49
-
50
36
  internal_transformToolCalls: (toolCalls) => {
51
37
  const toolNameResolver = new ToolNameResolver();
52
38
 
@@ -86,13 +86,15 @@ export const pluginOptimisticUpdate: StateCreator<
86
86
  PluginOptimisticUpdateAction
87
87
  > = (set, get) => ({
88
88
  optimisticUpdatePluginState: async (id, value, context) => {
89
- const { replaceMessages } = get();
89
+ const { replaceMessages, internal_getSessionContext } = get();
90
90
 
91
91
  // optimistic update
92
- get().internal_dispatchMessage({ id, type: 'updateMessage', value: { pluginState: value } });
92
+ get().internal_dispatchMessage(
93
+ { id, type: 'updateMessage', value: { pluginState: value } },
94
+ context,
95
+ );
93
96
 
94
- const sessionId = context?.sessionId ?? get().activeId;
95
- const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
97
+ const { sessionId, topicId } = internal_getSessionContext(context);
96
98
 
97
99
  const result = await messageService.updateMessagePluginState(id, value, {
98
100
  sessionId,
@@ -152,17 +154,19 @@ export const pluginOptimisticUpdate: StateCreator<
152
154
  },
153
155
 
154
156
  optimisticUpdatePlugin: async (id, value, context) => {
155
- const { replaceMessages } = get();
157
+ const { replaceMessages, internal_getSessionContext } = get();
156
158
 
157
159
  // optimistic update
158
- get().internal_dispatchMessage({
159
- id,
160
- type: 'updateMessagePlugin',
161
- value,
162
- });
160
+ get().internal_dispatchMessage(
161
+ {
162
+ id,
163
+ type: 'updateMessagePlugin',
164
+ value,
165
+ },
166
+ context,
167
+ );
163
168
 
164
- const sessionId = context?.sessionId ?? get().activeId;
165
- const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
169
+ const { sessionId, topicId } = internal_getSessionContext(context);
166
170
 
167
171
  const result = await messageService.updateMessagePlugin(id, value, {
168
172
  sessionId,
@@ -202,12 +206,11 @@ export const pluginOptimisticUpdate: StateCreator<
202
206
  },
203
207
 
204
208
  optimisticUpdatePluginError: async (id, error, context) => {
205
- const { replaceMessages } = get();
209
+ const { replaceMessages, internal_getSessionContext } = get();
206
210
 
207
- get().internal_dispatchMessage({ id, type: 'updateMessage', value: { error } });
211
+ get().internal_dispatchMessage({ id, type: 'updateMessage', value: { error } }, context);
208
212
 
209
- const sessionId = context?.sessionId ?? get().activeId;
210
- const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
213
+ const { sessionId, topicId } = internal_getSessionContext(context);
211
214
 
212
215
  const result = await messageService.updateMessage(
213
216
  id,
@@ -227,10 +230,9 @@ export const pluginOptimisticUpdate: StateCreator<
227
230
  const message = dbMessageSelectors.getDbMessageById(id)(get());
228
231
  if (!message || !message.tools) return;
229
232
 
230
- const { internal_toggleMessageLoading, replaceMessages } = get();
233
+ const { internal_toggleMessageLoading, replaceMessages, internal_getSessionContext } = get();
231
234
 
232
- const sessionId = context?.sessionId ?? get().activeId;
233
- const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
235
+ const { sessionId, topicId } = internal_getSessionContext(context);
234
236
 
235
237
  internal_toggleMessageLoading(true, id);
236
238
  const result = await messageService.updateMessage(