@lobehub/chat 1.47.23 → 1.48.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 (91) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/locales/ar/chat.json +4 -0
  4. package/locales/ar/components.json +1 -0
  5. package/locales/ar/models.json +6 -0
  6. package/locales/bg-BG/chat.json +4 -0
  7. package/locales/bg-BG/components.json +1 -0
  8. package/locales/bg-BG/models.json +6 -0
  9. package/locales/de-DE/chat.json +4 -0
  10. package/locales/de-DE/components.json +1 -0
  11. package/locales/de-DE/models.json +6 -0
  12. package/locales/en-US/chat.json +4 -0
  13. package/locales/en-US/components.json +1 -0
  14. package/locales/en-US/models.json +6 -0
  15. package/locales/es-ES/chat.json +4 -0
  16. package/locales/es-ES/components.json +1 -0
  17. package/locales/es-ES/models.json +6 -0
  18. package/locales/fa-IR/chat.json +4 -0
  19. package/locales/fa-IR/components.json +1 -0
  20. package/locales/fa-IR/models.json +6 -0
  21. package/locales/fr-FR/chat.json +4 -0
  22. package/locales/fr-FR/components.json +1 -0
  23. package/locales/fr-FR/models.json +6 -0
  24. package/locales/it-IT/chat.json +4 -0
  25. package/locales/it-IT/components.json +1 -0
  26. package/locales/it-IT/models.json +6 -0
  27. package/locales/ja-JP/chat.json +4 -0
  28. package/locales/ja-JP/components.json +1 -0
  29. package/locales/ja-JP/models.json +6 -0
  30. package/locales/ko-KR/chat.json +4 -0
  31. package/locales/ko-KR/components.json +1 -0
  32. package/locales/ko-KR/models.json +6 -0
  33. package/locales/nl-NL/chat.json +4 -0
  34. package/locales/nl-NL/components.json +1 -0
  35. package/locales/nl-NL/models.json +6 -0
  36. package/locales/pl-PL/chat.json +4 -0
  37. package/locales/pl-PL/components.json +1 -0
  38. package/locales/pl-PL/models.json +6 -0
  39. package/locales/pt-BR/chat.json +4 -0
  40. package/locales/pt-BR/components.json +1 -0
  41. package/locales/pt-BR/models.json +6 -0
  42. package/locales/ru-RU/chat.json +4 -0
  43. package/locales/ru-RU/components.json +1 -0
  44. package/locales/ru-RU/models.json +6 -0
  45. package/locales/tr-TR/chat.json +4 -0
  46. package/locales/tr-TR/components.json +1 -0
  47. package/locales/tr-TR/models.json +6 -0
  48. package/locales/vi-VN/chat.json +4 -0
  49. package/locales/vi-VN/components.json +1 -0
  50. package/locales/vi-VN/models.json +6 -0
  51. package/locales/zh-CN/chat.json +4 -0
  52. package/locales/zh-CN/components.json +1 -0
  53. package/locales/zh-CN/modelProvider.json +2 -2
  54. package/locales/zh-CN/models.json +7 -1
  55. package/locales/zh-TW/chat.json +4 -0
  56. package/locales/zh-TW/components.json +1 -0
  57. package/locales/zh-TW/models.json +6 -0
  58. package/package.json +1 -1
  59. package/src/components/ModelSelect/index.tsx +16 -1
  60. package/src/config/aiModels/deepseek.ts +3 -0
  61. package/src/database/client/migrations.json +13 -2
  62. package/src/database/migrations/0014_add_message_reasoning.sql +1 -0
  63. package/src/database/migrations/meta/0014_snapshot.json +3961 -0
  64. package/src/database/migrations/meta/_journal.json +7 -0
  65. package/src/database/schemas/message.ts +2 -3
  66. package/src/database/server/models/__tests__/message.test.ts +5 -4
  67. package/src/database/server/models/message.ts +35 -13
  68. package/src/database/server/models/topic.ts +3 -2
  69. package/src/features/Conversation/Messages/Assistant/Reasoning/index.tsx +123 -0
  70. package/src/features/Conversation/Messages/Assistant/index.tsx +8 -1
  71. package/src/features/Conversation/components/MarkdownElements/LobeThinking/index.ts +2 -2
  72. package/src/libs/agent-runtime/google/index.ts +7 -5
  73. package/src/libs/agent-runtime/utils/streams/openai.test.ts +203 -0
  74. package/src/libs/agent-runtime/utils/streams/openai.ts +8 -1
  75. package/src/libs/agent-runtime/utils/streams/protocol.ts +1 -1
  76. package/src/locales/default/chat.ts +4 -0
  77. package/src/locales/default/components.ts +1 -0
  78. package/src/server/routers/lambda/message.ts +4 -2
  79. package/src/services/message/client.test.ts +1 -1
  80. package/src/services/message/type.ts +1 -1
  81. package/src/store/chat/selectors.ts +1 -0
  82. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +60 -14
  83. package/src/store/chat/slices/aiChat/initialState.ts +5 -0
  84. package/src/store/chat/slices/aiChat/selectors.ts +9 -0
  85. package/src/store/chat/slices/message/action.ts +4 -1
  86. package/src/types/aiModel.ts +5 -14
  87. package/src/types/message/base.ts +59 -0
  88. package/src/types/message/chat.ts +136 -0
  89. package/src/types/message/index.ts +2 -135
  90. package/src/utils/fetch/__tests__/fetchSSE.test.ts +34 -0
  91. package/src/utils/fetch/fetchSSE.ts +38 -3
@@ -154,6 +154,40 @@ describe('fetchSSE', () => {
154
154
  });
155
155
  });
156
156
 
157
+ it('should handle reasoning event with smoothing correctly', async () => {
158
+ const mockOnMessageHandle = vi.fn();
159
+ const mockOnFinish = vi.fn();
160
+
161
+ (fetchEventSource as any).mockImplementationOnce(
162
+ async (url: string, options: FetchEventSourceInit) => {
163
+ options.onopen!({ clone: () => ({ ok: true, headers: new Headers() }) } as any);
164
+ options.onmessage!({ event: 'reasoning', data: JSON.stringify('Hello') } as any);
165
+ await sleep(100);
166
+ options.onmessage!({ event: 'reasoning', data: JSON.stringify(' World') } as any);
167
+ await sleep(100);
168
+ options.onmessage!({ event: 'text', data: JSON.stringify('hi') } as any);
169
+ },
170
+ );
171
+
172
+ await fetchSSE('/', {
173
+ onMessageHandle: mockOnMessageHandle,
174
+ onFinish: mockOnFinish,
175
+ smoothing: true,
176
+ });
177
+
178
+ expect(mockOnMessageHandle).toHaveBeenNthCalledWith(1, { text: 'Hell', type: 'reasoning' });
179
+ expect(mockOnMessageHandle).toHaveBeenNthCalledWith(2, { text: 'o', type: 'reasoning' });
180
+ expect(mockOnMessageHandle).toHaveBeenNthCalledWith(3, { text: ' Wor', type: 'reasoning' });
181
+ // more assertions for each character...
182
+ expect(mockOnFinish).toHaveBeenCalledWith('hi', {
183
+ observationId: null,
184
+ toolCalls: undefined,
185
+ reasoning: 'Hello World',
186
+ traceId: null,
187
+ type: 'done',
188
+ });
189
+ });
190
+
157
191
  it('should handle tool_calls event with smoothing correctly', async () => {
158
192
  const mockOnMessageHandle = vi.fn();
159
193
  const mockOnFinish = vi.fn();
@@ -21,6 +21,7 @@ export type OnFinishHandler = (
21
21
  text: string,
22
22
  context: {
23
23
  observationId?: string | null;
24
+ reasoning?: string;
24
25
  toolCalls?: MessageToolCall[];
25
26
  traceId?: string | null;
26
27
  type?: SSEFinishType;
@@ -32,6 +33,11 @@ export interface MessageTextChunk {
32
33
  type: 'text';
33
34
  }
34
35
 
36
+ export interface MessageReasoningChunk {
37
+ text: string;
38
+ type: 'reasoning';
39
+ }
40
+
35
41
  interface MessageToolCallsChunk {
36
42
  isAnimationActives?: boolean[];
37
43
  tool_calls: MessageToolCall[];
@@ -43,7 +49,9 @@ export interface FetchSSEOptions {
43
49
  onAbort?: (text: string) => Promise<void>;
44
50
  onErrorHandle?: (error: ChatMessageError) => void;
45
51
  onFinish?: OnFinishHandler;
46
- onMessageHandle?: (chunk: MessageTextChunk | MessageToolCallsChunk) => void;
52
+ onMessageHandle?: (
53
+ chunk: MessageTextChunk | MessageToolCallsChunk | MessageReasoningChunk,
54
+ ) => void;
47
55
  smoothing?: SmoothingParams | boolean;
48
56
  }
49
57
 
@@ -233,7 +241,6 @@ const createSmoothToolCalls = (params: {
233
241
  */
234
242
  // eslint-disable-next-line no-undef
235
243
  export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptions = {}) => {
236
- let output = '';
237
244
  let toolCalls: undefined | MessageToolCall[];
238
245
  let triggerOnMessageHandler = false;
239
246
 
@@ -247,6 +254,7 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
247
254
  typeof smoothing === 'boolean' ? smoothing : (smoothing?.toolsCalling ?? true);
248
255
  const smoothingSpeed = isObject(smoothing) ? smoothing.speed : undefined;
249
256
 
257
+ let output = '';
250
258
  const textController = createSmoothMessage({
251
259
  onTextUpdate: (delta, text) => {
252
260
  output = text;
@@ -255,6 +263,15 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
255
263
  startSpeed: smoothingSpeed,
256
264
  });
257
265
 
266
+ let thinking = '';
267
+ const thinkingController = createSmoothMessage({
268
+ onTextUpdate: (delta, text) => {
269
+ thinking = text;
270
+ options.onMessageHandle?.({ text: delta, type: 'reasoning' });
271
+ },
272
+ startSpeed: smoothingSpeed,
273
+ });
274
+
258
275
  const toolCallsController = createSmoothToolCalls({
259
276
  onToolCallsUpdate: (toolCalls, isAnimationActives) => {
260
277
  options.onMessageHandle?.({ isAnimationActives, tool_calls: toolCalls, type: 'tool_calls' });
@@ -333,6 +350,18 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
333
350
 
334
351
  break;
335
352
  }
353
+ case 'reasoning': {
354
+ if (textSmoothing) {
355
+ thinkingController.pushToQueue(data);
356
+
357
+ if (!thinkingController.isAnimationActive) thinkingController.startAnimation();
358
+ } else {
359
+ thinking += data;
360
+ options.onMessageHandle?.({ text: data, type: 'reasoning' });
361
+ }
362
+
363
+ break;
364
+ }
336
365
 
337
366
  case 'tool_calls': {
338
367
  // get finial
@@ -389,7 +418,13 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
389
418
  await toolCallsController.startAnimations(END_ANIMATION_SPEED);
390
419
  }
391
420
 
392
- await options?.onFinish?.(output, { observationId, toolCalls, traceId, type: finishedType });
421
+ await options?.onFinish?.(output, {
422
+ observationId,
423
+ reasoning: !!thinking ? thinking : undefined,
424
+ toolCalls,
425
+ traceId,
426
+ type: finishedType,
427
+ });
393
428
  }
394
429
  }
395
430