@lobehub/lobehub 2.0.0-next.35 → 2.0.0-next.36

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 (154) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/next.config.ts +5 -6
  4. package/package.json +2 -2
  5. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +112 -77
  6. package/packages/agent-runtime/src/core/runtime.ts +63 -18
  7. package/packages/agent-runtime/src/types/generalAgent.ts +55 -0
  8. package/packages/agent-runtime/src/types/index.ts +1 -0
  9. package/packages/agent-runtime/src/types/instruction.ts +10 -3
  10. package/packages/const/src/user.ts +0 -1
  11. package/packages/context-engine/src/processors/GroupMessageFlatten.ts +8 -6
  12. package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +12 -12
  13. package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-group-branches.json +249 -0
  14. package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/index.ts +4 -0
  15. package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/multi-assistant-group.json +260 -0
  16. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/active-index-1.json +4 -0
  17. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-group-branches.json +481 -0
  18. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/conversation.json +5 -1
  19. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/index.ts +4 -0
  20. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/multi-assistant-group.json +407 -0
  21. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/nested.json +18 -2
  22. package/packages/conversation-flow/src/__tests__/fixtures/outputs/complex-scenario.json +25 -3
  23. package/packages/conversation-flow/src/__tests__/parse.test.ts +12 -0
  24. package/packages/conversation-flow/src/index.ts +1 -1
  25. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +112 -34
  26. package/packages/conversation-flow/src/types/flatMessageList.ts +0 -12
  27. package/packages/conversation-flow/src/{types.ts → types/index.ts} +3 -14
  28. package/packages/database/src/models/message.ts +18 -19
  29. package/packages/types/src/aiChat.ts +2 -0
  30. package/packages/types/src/importer.ts +2 -2
  31. package/packages/types/src/message/ui/chat.ts +17 -1
  32. package/packages/types/src/message/ui/extra.ts +2 -2
  33. package/packages/types/src/message/ui/params.ts +2 -2
  34. package/packages/types/src/user/preference.ts +0 -4
  35. package/packages/utils/src/tokenizer/index.ts +3 -11
  36. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/Desktop/MessageFromUrl.tsx +3 -3
  37. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/index.tsx +1 -1
  38. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/useSend.ts +3 -3
  39. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/useSend.ts +6 -6
  40. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/Content.tsx +5 -3
  41. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/WelcomeChatItem/AgentWelcome/OpeningQuestions.tsx +2 -2
  42. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/WelcomeChatItem/GroupWelcome/GroupUsageSuggest.tsx +2 -2
  43. package/src/app/[variants]/(main)/labs/page.tsx +0 -9
  44. package/src/features/ChatInput/ActionBar/STT/browser.tsx +3 -3
  45. package/src/features/ChatInput/ActionBar/STT/openai.tsx +3 -3
  46. package/src/features/Conversation/Error/AccessCodeForm.tsx +1 -1
  47. package/src/features/Conversation/Error/ChatInvalidApiKey.tsx +1 -1
  48. package/src/features/Conversation/Error/ClerkLogin/index.tsx +1 -1
  49. package/src/features/Conversation/Error/OAuthForm.tsx +1 -1
  50. package/src/features/Conversation/Error/index.tsx +0 -5
  51. package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +13 -10
  52. package/src/features/Conversation/Messages/Assistant/Extra/index.test.tsx +3 -8
  53. package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +2 -6
  54. package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +7 -9
  55. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginResult.tsx +2 -2
  56. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginState.tsx +2 -2
  57. package/src/features/Conversation/Messages/Assistant/Tool/Render/PluginSettings.tsx +4 -1
  58. package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +2 -3
  59. package/src/features/Conversation/Messages/Assistant/index.tsx +57 -60
  60. package/src/features/Conversation/Messages/Default.tsx +1 -0
  61. package/src/features/Conversation/Messages/Group/Actions/WithContentId.tsx +38 -10
  62. package/src/features/Conversation/Messages/Group/Actions/index.tsx +1 -1
  63. package/src/features/Conversation/Messages/Group/ContentBlock.tsx +1 -3
  64. package/src/features/Conversation/Messages/Group/GroupChildren.tsx +12 -12
  65. package/src/features/Conversation/Messages/Group/MessageContent.tsx +7 -1
  66. package/src/features/Conversation/Messages/Group/Tool/Render/PluginSettings.tsx +1 -1
  67. package/src/features/Conversation/Messages/Group/index.tsx +2 -1
  68. package/src/features/Conversation/Messages/Supervisor/index.tsx +2 -2
  69. package/src/features/Conversation/Messages/User/{Actions.tsx → Actions/ActionsBar.tsx} +26 -25
  70. package/src/features/Conversation/Messages/User/Actions/MessageBranch.tsx +107 -0
  71. package/src/features/Conversation/Messages/User/Actions/index.tsx +42 -0
  72. package/src/features/Conversation/Messages/User/index.tsx +43 -44
  73. package/src/features/Conversation/Messages/index.tsx +3 -3
  74. package/src/features/Conversation/components/AutoScroll.tsx +3 -3
  75. package/src/features/Conversation/components/Extras/Usage/UsageDetail/AnimatedNumber.tsx +55 -0
  76. package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +5 -2
  77. package/src/features/Conversation/components/VirtualizedList/index.tsx +29 -20
  78. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +8 -10
  79. package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +3 -3
  80. package/src/hooks/useHotkeys/chatScope.ts +15 -7
  81. package/src/server/routers/lambda/__tests__/aiChat.test.ts +1 -1
  82. package/src/server/routers/lambda/__tests__/integration/message.integration.test.ts +0 -26
  83. package/src/server/routers/lambda/aiChat.ts +3 -2
  84. package/src/server/routers/lambda/message.ts +8 -16
  85. package/src/server/services/message/__tests__/index.test.ts +29 -39
  86. package/src/server/services/message/index.ts +41 -36
  87. package/src/services/electron/desktopNotification.ts +6 -6
  88. package/src/services/electron/file.ts +6 -6
  89. package/src/services/file/ClientS3/index.ts +8 -8
  90. package/src/services/message/__tests__/metadata-race-condition.test.ts +157 -0
  91. package/src/services/message/index.ts +21 -15
  92. package/src/services/upload.ts +11 -11
  93. package/src/services/utils/abortableRequest.test.ts +161 -0
  94. package/src/services/utils/abortableRequest.ts +67 -0
  95. package/src/store/chat/agents/GeneralChatAgent.ts +137 -0
  96. package/src/store/chat/agents/createAgentExecutors.ts +395 -0
  97. package/src/store/chat/helpers.test.ts +0 -99
  98. package/src/store/chat/helpers.ts +0 -11
  99. package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +332 -0
  100. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +257 -0
  101. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +11 -2
  102. package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +6 -6
  103. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +391 -0
  104. package/src/store/chat/slices/aiChat/actions/__tests__/streamingStates.test.ts +179 -0
  105. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +157 -0
  106. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +329 -0
  107. package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +14 -14
  108. package/src/store/chat/slices/aiChat/actions/index.ts +12 -6
  109. package/src/store/chat/slices/aiChat/actions/rag.ts +9 -6
  110. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +604 -0
  111. package/src/store/chat/slices/aiChat/actions/streamingStates.ts +84 -0
  112. package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +4 -4
  113. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +11 -11
  114. package/src/store/chat/slices/builtinTool/actions/interpreter.ts +8 -8
  115. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +2 -2
  116. package/src/store/chat/slices/builtinTool/actions/search.ts +8 -8
  117. package/src/store/chat/slices/message/action.test.ts +79 -68
  118. package/src/store/chat/slices/message/actions/index.ts +39 -0
  119. package/src/store/chat/slices/message/actions/internals.ts +77 -0
  120. package/src/store/chat/slices/message/actions/optimisticUpdate.ts +260 -0
  121. package/src/store/chat/slices/message/actions/publicApi.ts +224 -0
  122. package/src/store/chat/slices/message/actions/query.ts +120 -0
  123. package/src/store/chat/slices/message/actions/runtimeState.ts +108 -0
  124. package/src/store/chat/slices/message/initialState.ts +13 -0
  125. package/src/store/chat/slices/message/reducer.test.ts +48 -370
  126. package/src/store/chat/slices/message/reducer.ts +17 -81
  127. package/src/store/chat/slices/message/selectors/chat.test.ts +13 -50
  128. package/src/store/chat/slices/message/selectors/chat.ts +78 -242
  129. package/src/store/chat/slices/message/selectors/dbMessage.ts +140 -0
  130. package/src/store/chat/slices/message/selectors/displayMessage.ts +301 -0
  131. package/src/store/chat/slices/message/selectors/messageState.ts +5 -2
  132. package/src/store/chat/slices/plugin/action.test.ts +62 -64
  133. package/src/store/chat/slices/plugin/action.ts +34 -28
  134. package/src/store/chat/slices/thread/action.test.ts +28 -31
  135. package/src/store/chat/slices/thread/action.ts +13 -10
  136. package/src/store/chat/slices/thread/selectors/index.ts +8 -6
  137. package/src/store/chat/slices/topic/reducer.ts +11 -3
  138. package/src/store/chat/store.ts +1 -1
  139. package/src/store/user/slices/preference/selectors/labPrefer.ts +0 -3
  140. package/packages/database/src/models/__tests__/message.grouping.test.ts +0 -812
  141. package/packages/database/src/utils/__tests__/groupMessages.test.ts +0 -1132
  142. package/packages/database/src/utils/groupMessages.ts +0 -361
  143. package/packages/utils/src/tokenizer/client.ts +0 -35
  144. package/packages/utils/src/tokenizer/estimated.ts +0 -4
  145. package/packages/utils/src/tokenizer/server.ts +0 -11
  146. package/packages/utils/src/tokenizer/tokenizer.worker.ts +0 -12
  147. package/src/app/(backend)/webapi/tokenizer/index.test.ts +0 -32
  148. package/src/app/(backend)/webapi/tokenizer/route.ts +0 -8
  149. package/src/features/Conversation/Error/InvalidAccessCode.tsx +0 -79
  150. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -975
  151. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +0 -1050
  152. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +0 -720
  153. package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +0 -849
  154. package/src/store/chat/slices/message/action.ts +0 -629
@@ -1,361 +0,0 @@
1
- import {
2
- AssistantContentBlock,
3
- ChatToolPayloadWithResult,
4
- MessageMetadata,
5
- ModelPerformance,
6
- ModelUsage,
7
- UIChatMessage,
8
- } from '@lobechat/types';
9
-
10
- /**
11
- * Split MessageMetadata into usage and performance
12
- */
13
- function splitMetadata(metadata?: MessageMetadata | null): {
14
- performance?: ModelPerformance;
15
- usage?: ModelUsage;
16
- } {
17
- if (!metadata) return {};
18
-
19
- const usage: ModelUsage = {};
20
- const performance: ModelPerformance = {};
21
-
22
- // Extract usage fields (tokens and cost)
23
- const usageFields = [
24
- 'inputCachedTokens',
25
- 'inputCacheMissTokens',
26
- 'inputWriteCacheTokens',
27
- 'inputTextTokens',
28
- 'inputImageTokens',
29
- 'inputAudioTokens',
30
- 'inputCitationTokens',
31
- 'outputTextTokens',
32
- 'outputImageTokens',
33
- 'outputAudioTokens',
34
- 'outputReasoningTokens',
35
- 'acceptedPredictionTokens',
36
- 'rejectedPredictionTokens',
37
- 'totalInputTokens',
38
- 'totalOutputTokens',
39
- 'totalTokens',
40
- 'cost',
41
- ] as const;
42
-
43
- let hasUsage = false;
44
- usageFields.forEach((field) => {
45
- if (metadata[field] !== undefined) {
46
- usage[field] = metadata[field] as any;
47
- hasUsage = true;
48
- }
49
- });
50
-
51
- // Extract performance fields
52
- const performanceFields = ['tps', 'ttft', 'duration', 'latency'] as const;
53
- let hasPerformance = false;
54
- performanceFields.forEach((field) => {
55
- if (metadata[field] !== undefined) {
56
- performance[field] = metadata[field];
57
- hasPerformance = true;
58
- }
59
- });
60
-
61
- return {
62
- performance: hasPerformance ? performance : undefined,
63
- usage: hasUsage ? usage : undefined,
64
- };
65
- }
66
-
67
- /**
68
- * Aggregate metadata from all children blocks
69
- * Creates structured usage and performance metrics
70
- */
71
- function aggregateMetadata(
72
- children: AssistantContentBlock[],
73
- ): { performance?: ModelPerformance; usage?: ModelUsage } | null {
74
- const usage: ModelUsage = {};
75
- const performance: ModelPerformance = {};
76
- let hasUsageData = false;
77
- let hasPerformanceData = false;
78
- let tpsSum = 0;
79
- let tpsCount = 0;
80
-
81
- children.forEach((child) => {
82
- // Aggregate usage metrics (tokens and cost)
83
- if (child.usage) {
84
- const tokenFields = [
85
- 'inputCachedTokens',
86
- 'inputCacheMissTokens',
87
- 'inputWriteCacheTokens',
88
- 'inputTextTokens',
89
- 'inputImageTokens',
90
- 'inputAudioTokens',
91
- 'inputCitationTokens',
92
- 'outputTextTokens',
93
- 'outputImageTokens',
94
- 'outputAudioTokens',
95
- 'outputReasoningTokens',
96
- 'acceptedPredictionTokens',
97
- 'rejectedPredictionTokens',
98
- 'totalInputTokens',
99
- 'totalOutputTokens',
100
- 'totalTokens',
101
- ] as const;
102
-
103
- tokenFields.forEach((field) => {
104
- if (typeof child.usage![field] === 'number') {
105
- usage[field] = (usage[field] || 0) + child.usage![field]!;
106
- hasUsageData = true;
107
- }
108
- });
109
-
110
- if (typeof child.usage.cost === 'number') {
111
- usage.cost = (usage.cost || 0) + child.usage.cost;
112
- hasUsageData = true;
113
- }
114
- }
115
-
116
- // Aggregate performance metrics
117
- // - ttft: use the first child's value (time to first token)
118
- // - tps: calculate average across all children
119
- // - duration: sum all durations
120
- // - latency: sum all latencies
121
- if (child.performance) {
122
- if (child.performance.ttft !== undefined && performance.ttft === undefined) {
123
- performance.ttft = child.performance.ttft; // First child only
124
- hasPerformanceData = true;
125
- }
126
- if (typeof child.performance.tps === 'number') {
127
- tpsSum += child.performance.tps;
128
- tpsCount += 1;
129
- hasPerformanceData = true;
130
- }
131
- if (child.performance.duration !== undefined) {
132
- performance.duration = (performance.duration || 0) + child.performance.duration;
133
- hasPerformanceData = true;
134
- }
135
- if (child.performance.latency !== undefined) {
136
- performance.latency = (performance.latency || 0) + child.performance.latency;
137
- hasPerformanceData = true;
138
- }
139
- }
140
- });
141
-
142
- // Calculate average tps
143
- if (tpsCount > 0) {
144
- performance.tps = tpsSum / tpsCount;
145
- }
146
-
147
- // Return null if no data
148
- if (!hasUsageData && !hasPerformanceData) return null;
149
-
150
- // Return structured metrics
151
- const result: { performance?: ModelPerformance; usage?: ModelUsage } = {};
152
- if (hasUsageData) result.usage = usage;
153
- if (hasPerformanceData) result.performance = performance;
154
-
155
- return result;
156
- }
157
-
158
- /**
159
- * Group assistant messages with their tool results
160
- * Converts flat message list into grouped structure with children
161
- *
162
- * @param messages - Flat message list from database query
163
- * @returns Grouped message list with assistant children populated
164
- */
165
- export function groupAssistantMessages(messages: UIChatMessage[]): UIChatMessage[] {
166
- const result: UIChatMessage[] = [];
167
- const toolMessageIds = new Set<string>();
168
- const processedAssistantIds = new Set<string>();
169
-
170
- // 1. Create tool_call_id -> tool message mapping
171
- const toolMessageMap = new Map<string, UIChatMessage>();
172
- messages.forEach((msg) => {
173
- if (msg.role === 'tool' && msg.tool_call_id) {
174
- toolMessageMap.set(msg.tool_call_id, msg);
175
- }
176
- });
177
-
178
- // 2. Build message ID -> message mapping for quick lookup
179
- const messageMap = new Map<string, UIChatMessage>();
180
- messages.forEach((msg) => {
181
- messageMap.set(msg.id, msg);
182
- });
183
-
184
- // 3. Find follow-up assistants that have tool messages as parent
185
- // Map: tool message id -> follow-up assistant messages
186
- const toolToFollowUpAssistants = new Map<string, UIChatMessage[]>();
187
- messages.forEach((msg) => {
188
- if (msg.role === 'assistant' && msg.parentId) {
189
- const parent = messageMap.get(msg.parentId);
190
- if (parent && parent.role === 'tool') {
191
- const existing = toolToFollowUpAssistants.get(msg.parentId) || [];
192
- toolToFollowUpAssistants.set(msg.parentId, [...existing, msg]);
193
- }
194
- }
195
- });
196
-
197
- // 4. Process messages
198
- messages.forEach((msg) => {
199
- // Skip tool messages that have been merged
200
- if (msg.role === 'tool') {
201
- if (!toolMessageIds.has(msg.id)) {
202
- result.push(msg);
203
- }
204
- return;
205
- }
206
-
207
- // Handle non-assistant messages
208
- if (msg.role !== 'assistant') {
209
- result.push(msg);
210
- return;
211
- }
212
-
213
- // Skip assistant messages that have been processed as follow-ups
214
- if (processedAssistantIds.has(msg.id)) {
215
- return;
216
- }
217
-
218
- // 5. Process assistant messages
219
- const assistantMsg = { ...msg };
220
-
221
- // If no tools, add as-is (unless it's a follow-up, which should have been skipped above)
222
- if (!msg.tools || msg.tools.length === 0) {
223
- result.push(assistantMsg);
224
- return;
225
- }
226
-
227
- // 6. Build children structure
228
- const children: AssistantContentBlock[] = [];
229
-
230
- // First child: original assistant with tool results
231
- const toolsWithResults: ChatToolPayloadWithResult[] = msg.tools.map((tool) => {
232
- const toolMsg = toolMessageMap.get(tool.id);
233
-
234
- if (toolMsg) {
235
- // Mark tool message as merged
236
- toolMessageIds.add(toolMsg.id);
237
-
238
- return {
239
- ...tool,
240
- result: {
241
- content: toolMsg.content,
242
- error: toolMsg.pluginError,
243
- id: toolMsg.id,
244
- state: toolMsg.pluginState,
245
- },
246
- result_msg_id: toolMsg.id,
247
- };
248
- }
249
-
250
- // Tool message not yet available (still executing)
251
- return tool;
252
- });
253
-
254
- const { usage: msgUsage, performance: msgPerformance } = splitMetadata(msg.metadata);
255
- children.push({
256
- content: msg.content || '',
257
- error: msg.error,
258
- id: msg.id,
259
- imageList: msg.imageList && msg.imageList.length > 0 ? msg.imageList : undefined,
260
- performance: msgPerformance,
261
- reasoning: msg.reasoning || undefined,
262
- tools: toolsWithResults,
263
- usage: msgUsage,
264
- });
265
-
266
- // 7. Recursively add follow-up assistants as additional children
267
- // Keep track of tool result IDs that are part of this group
268
- const groupToolResultIds = new Set<string>();
269
- toolsWithResults.forEach((tool) => {
270
- if (tool.result) {
271
- groupToolResultIds.add(tool.result.id);
272
- }
273
- });
274
-
275
- // Recursively collect all follow-up assistants
276
- const collectFollowUpAssistants = (currentToolResultIds: Set<string>): void => {
277
- const newToolResultIds = new Set<string>();
278
-
279
- currentToolResultIds.forEach((toolResultId) => {
280
- const followUps = toolToFollowUpAssistants.get(toolResultId) || [];
281
- followUps.forEach((followUpMsg) => {
282
- // Skip if already processed
283
- if (processedAssistantIds.has(followUpMsg.id)) return;
284
-
285
- // Process follow-up assistant's tools and fill in their results
286
- const followUpToolsWithResults: ChatToolPayloadWithResult[] | undefined =
287
- followUpMsg.tools?.map((followUpTool) => {
288
- const followUpToolMsg = toolMessageMap.get(followUpTool.id);
289
-
290
- if (followUpToolMsg) {
291
- // Mark tool message as merged
292
- toolMessageIds.add(followUpToolMsg.id);
293
- // Track this tool result for next iteration
294
- newToolResultIds.add(followUpToolMsg.id);
295
-
296
- return {
297
- ...followUpTool,
298
- result: {
299
- content: followUpToolMsg.content,
300
- error: followUpToolMsg.pluginError,
301
- id: followUpToolMsg.id,
302
- state: followUpToolMsg.pluginState,
303
- },
304
- result_msg_id: followUpToolMsg.id,
305
- };
306
- }
307
-
308
- // Tool message not yet available
309
- return followUpTool;
310
- });
311
-
312
- const { usage: followUpUsage, performance: followUpPerformance } = splitMetadata(
313
- followUpMsg.metadata,
314
- );
315
- children.push({
316
- content: followUpMsg.content || '',
317
- error: followUpMsg.error,
318
- id: followUpMsg.id,
319
- imageList:
320
- followUpMsg.imageList && followUpMsg.imageList.length > 0
321
- ? followUpMsg.imageList
322
- : undefined,
323
- performance: followUpPerformance,
324
- reasoning: followUpMsg.reasoning || undefined,
325
- tools: followUpToolsWithResults,
326
- usage: followUpUsage,
327
- });
328
- processedAssistantIds.add(followUpMsg.id);
329
- });
330
- });
331
-
332
- // Recursively process the next level
333
- if (newToolResultIds.size > 0) {
334
- collectFollowUpAssistants(newToolResultIds);
335
- }
336
- };
337
-
338
- collectFollowUpAssistants(groupToolResultIds);
339
-
340
- // 8. Aggregate usage and performance from all children
341
- const aggregated = aggregateMetadata(children);
342
-
343
- // 9. Set children and aggregated metrics
344
- assistantMsg.role = 'group';
345
- assistantMsg.children = children;
346
- if (aggregated) {
347
- assistantMsg.usage = aggregated.usage;
348
- assistantMsg.performance = aggregated.performance;
349
- }
350
- delete assistantMsg.metadata; // Clear individual metadata
351
- delete assistantMsg.reasoning; // Reasoning moved to children blocks
352
- delete assistantMsg.tools;
353
- delete assistantMsg.imageList;
354
- delete assistantMsg.fileList;
355
- assistantMsg.content = ''; // Content moved to children
356
-
357
- result.push(assistantMsg);
358
- });
359
-
360
- return result;
361
- }
@@ -1,35 +0,0 @@
1
- let worker: Worker | null = null;
2
-
3
- const getWorker = () => {
4
- if (!worker && typeof Worker !== 'undefined') {
5
- worker = new Worker(new URL('tokenizer.worker.ts', import.meta.url));
6
- }
7
- return worker;
8
- };
9
-
10
- export const clientEncodeAsync = (str: string): Promise<number> =>
11
- new Promise((resolve, reject) => {
12
- const worker = getWorker();
13
-
14
- if (!worker) {
15
- // 如果 WebWorker 不可用,回退到字符串计算
16
- resolve(str.length);
17
- return;
18
- }
19
-
20
- const id = str;
21
-
22
- const handleMessage = (event: MessageEvent) => {
23
- if (event.data.id === id) {
24
- worker.removeEventListener('message', handleMessage);
25
- if (event.data.error) {
26
- reject(new Error(event.data.error));
27
- } else {
28
- resolve(event.data.result);
29
- }
30
- }
31
- };
32
-
33
- worker.addEventListener('message', handleMessage);
34
- worker.postMessage({ id, str });
35
- });
@@ -1,4 +0,0 @@
1
- import { approximateTokenSize } from 'tokenx';
2
-
3
- export const estimatedEncodeAsync = async (str: string): Promise<number> =>
4
- approximateTokenSize(str);
@@ -1,11 +0,0 @@
1
- export const serverEncodeAsync = async (str: string): Promise<number> => {
2
- try {
3
- const res = await fetch('/webapi/tokenizer', { body: str, method: 'POST' });
4
- const data = await res.json();
5
-
6
- return data.count;
7
- } catch (e) {
8
- console.error('serverEncodeAsync:', e);
9
- return str.length;
10
- }
11
- };
@@ -1,12 +0,0 @@
1
- addEventListener('message', async (event) => {
2
- const { id, str } = event.data;
3
- try {
4
- const { encode } = await import('gpt-tokenizer');
5
-
6
- const tokenCount = encode(str).length;
7
-
8
- postMessage({ id, result: tokenCount });
9
- } catch (error) {
10
- postMessage({ error: (error as Error).message, id });
11
- }
12
- });
@@ -1,32 +0,0 @@
1
- // @vitest-environment edge-runtime
2
- import { describe, expect, it } from 'vitest';
3
-
4
- import { POST } from './route';
5
-
6
- describe('tokenizer Route', () => {
7
- it('count hello world', async () => {
8
- const txt = 'Hello, world!';
9
- const request = new Request('https://test.com', {
10
- method: 'POST',
11
- body: txt,
12
- });
13
-
14
- const response = await POST(request);
15
-
16
- const data = await response.json();
17
- expect(data.count).toEqual(4);
18
- });
19
-
20
- it('count Chinese', async () => {
21
- const txt = '今天天气真好';
22
- const request = new Request('https://test.com', {
23
- method: 'POST',
24
- body: txt,
25
- });
26
-
27
- const response = await POST(request);
28
-
29
- const data = await response.json();
30
- expect(data.count).toEqual(5);
31
- });
32
- });
@@ -1,8 +0,0 @@
1
- import { encode } from 'gpt-tokenizer/encoding/o200k_base';
2
- import { NextResponse } from 'next/server';
3
-
4
- export const POST = async (req: Request) => {
5
- const str = await req.text();
6
-
7
- return NextResponse.json({ count: encode(str).length });
8
- };
@@ -1,79 +0,0 @@
1
- import { Icon, Segmented } from '@lobehub/ui';
2
- import { SegmentedLabeledOption } from 'antd/es/segmented';
3
- import { AsteriskSquare, KeySquare, ScanFace } from 'lucide-react';
4
- import { memo, useState } from 'react';
5
- import { useTranslation } from 'react-i18next';
6
- import { Flexbox } from 'react-layout-kit';
7
-
8
- import { useServerConfigStore } from '@/store/serverConfig';
9
- import { featureFlagsSelectors, serverConfigSelectors } from '@/store/serverConfig/selectors';
10
-
11
- import AccessCodeForm from './AccessCodeForm';
12
- import ChatInvalidAPIKey from './ChatInvalidApiKey';
13
- import OAuthForm from './OAuthForm';
14
- import { ErrorActionContainer } from './style';
15
-
16
- enum Tab {
17
- Api = 'api',
18
- Oauth = 'oauth',
19
- Password = 'password',
20
- }
21
-
22
- interface InvalidAccessCodeProps {
23
- id: string;
24
- provider?: string;
25
- }
26
-
27
- const InvalidAccessCode = memo<InvalidAccessCodeProps>(({ id, provider }) => {
28
- const { t } = useTranslation('error');
29
- const isEnabledOAuth = useServerConfigStore(serverConfigSelectors.enabledOAuthSSO);
30
- const defaultTab = isEnabledOAuth ? Tab.Oauth : Tab.Password;
31
- const [mode, setMode] = useState<Tab>(defaultTab);
32
- const { showOpenAIApiKey } = useServerConfigStore(featureFlagsSelectors);
33
- const isEnabledTab = showOpenAIApiKey || isEnabledOAuth;
34
-
35
- return (
36
- <ErrorActionContainer>
37
- {isEnabledTab && (
38
- <Segmented
39
- block
40
- onChange={(value) => setMode(value as Tab)}
41
- options={
42
- [
43
- isEnabledOAuth
44
- ? {
45
- icon: <Icon icon={ScanFace} />,
46
- label: t('oauth', { ns: 'common' }),
47
- value: Tab.Oauth,
48
- }
49
- : undefined,
50
- {
51
- icon: <Icon icon={AsteriskSquare} />,
52
- label: t('unlock.tabs.password'),
53
- value: Tab.Password,
54
- },
55
- showOpenAIApiKey
56
- ? {
57
- icon: <Icon icon={KeySquare} />,
58
- label: t('unlock.tabs.apiKey'),
59
- value: Tab.Api,
60
- }
61
- : undefined,
62
- ].filter(Boolean) as SegmentedLabeledOption[]
63
- }
64
- style={{ width: '100%' }}
65
- value={mode}
66
- variant={'filled'}
67
- />
68
- )}
69
-
70
- <Flexbox gap={24}>
71
- {mode === Tab.Password && <AccessCodeForm id={id} />}
72
- {showOpenAIApiKey && mode === Tab.Api && <ChatInvalidAPIKey id={id} provider={provider} />}
73
- {isEnabledOAuth && mode === Tab.Oauth && <OAuthForm id={id} />}
74
- </Flexbox>
75
- </ErrorActionContainer>
76
- );
77
- });
78
-
79
- export default InvalidAccessCode;