@lobehub/lobehub 2.0.0-next.35 → 2.0.0-next.37
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.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/next.config.ts +5 -6
- package/package.json +2 -2
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +112 -77
- package/packages/agent-runtime/src/core/runtime.ts +63 -18
- package/packages/agent-runtime/src/types/generalAgent.ts +55 -0
- package/packages/agent-runtime/src/types/index.ts +1 -0
- package/packages/agent-runtime/src/types/instruction.ts +10 -3
- package/packages/const/src/user.ts +0 -1
- package/packages/context-engine/src/processors/GroupMessageFlatten.ts +8 -6
- package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +12 -12
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-group-branches.json +249 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/index.ts +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/multi-assistant-group.json +260 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/active-index-1.json +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-group-branches.json +481 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/conversation.json +5 -1
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/index.ts +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/multi-assistant-group.json +407 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/nested.json +18 -2
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/complex-scenario.json +25 -3
- package/packages/conversation-flow/src/__tests__/parse.test.ts +12 -0
- package/packages/conversation-flow/src/index.ts +1 -1
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +112 -34
- package/packages/conversation-flow/src/types/flatMessageList.ts +0 -12
- package/packages/conversation-flow/src/{types.ts → types/index.ts} +3 -14
- package/packages/database/src/models/__tests__/apiKey.test.ts +444 -0
- package/packages/database/src/models/message.ts +18 -19
- package/packages/types/src/aiChat.ts +2 -0
- package/packages/types/src/importer.ts +2 -2
- package/packages/types/src/message/ui/chat.ts +17 -1
- package/packages/types/src/message/ui/extra.ts +2 -2
- package/packages/types/src/message/ui/params.ts +2 -2
- package/packages/types/src/user/preference.ts +0 -4
- package/packages/utils/src/tokenizer/index.ts +3 -11
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/Desktop/MessageFromUrl.tsx +3 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/index.tsx +1 -1
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/useSend.ts +3 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/useSend.ts +6 -6
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/Content.tsx +5 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/WelcomeChatItem/AgentWelcome/OpeningQuestions.tsx +2 -2
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/WelcomeChatItem/GroupWelcome/GroupUsageSuggest.tsx +2 -2
- package/src/app/[variants]/(main)/labs/page.tsx +0 -9
- package/src/features/ChatInput/ActionBar/STT/browser.tsx +3 -3
- package/src/features/ChatInput/ActionBar/STT/openai.tsx +3 -3
- package/src/features/Conversation/Error/AccessCodeForm.tsx +1 -1
- package/src/features/Conversation/Error/ChatInvalidApiKey.tsx +1 -1
- package/src/features/Conversation/Error/ClerkLogin/index.tsx +1 -1
- package/src/features/Conversation/Error/OAuthForm.tsx +1 -1
- package/src/features/Conversation/Error/index.tsx +0 -5
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +13 -10
- package/src/features/Conversation/Messages/Assistant/Extra/index.test.tsx +3 -8
- package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +2 -6
- package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +7 -9
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginResult.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginState.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Render/PluginSettings.tsx +4 -1
- package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +2 -3
- package/src/features/Conversation/Messages/Assistant/index.tsx +57 -60
- package/src/features/Conversation/Messages/Default.tsx +1 -0
- package/src/features/Conversation/Messages/Group/Actions/WithContentId.tsx +38 -10
- package/src/features/Conversation/Messages/Group/Actions/index.tsx +1 -1
- package/src/features/Conversation/Messages/Group/ContentBlock.tsx +1 -3
- package/src/features/Conversation/Messages/Group/GroupChildren.tsx +12 -12
- package/src/features/Conversation/Messages/Group/MessageContent.tsx +7 -1
- package/src/features/Conversation/Messages/Group/Tool/Render/PluginSettings.tsx +1 -1
- package/src/features/Conversation/Messages/Group/index.tsx +2 -1
- package/src/features/Conversation/Messages/Supervisor/index.tsx +2 -2
- package/src/features/Conversation/Messages/User/{Actions.tsx → Actions/ActionsBar.tsx} +26 -25
- package/src/features/Conversation/Messages/User/Actions/MessageBranch.tsx +107 -0
- package/src/features/Conversation/Messages/User/Actions/index.tsx +42 -0
- package/src/features/Conversation/Messages/User/index.tsx +43 -44
- package/src/features/Conversation/Messages/index.tsx +3 -3
- package/src/features/Conversation/components/AutoScroll.tsx +3 -3
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/AnimatedNumber.tsx +55 -0
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +5 -2
- package/src/features/Conversation/components/VirtualizedList/index.tsx +29 -20
- package/src/features/Conversation/hooks/useChatListActionsBar.tsx +8 -10
- package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +3 -3
- package/src/hooks/useHotkeys/chatScope.ts +15 -7
- package/src/libs/trpc/client/lambda.ts +4 -3
- package/src/server/routers/lambda/__tests__/aiChat.test.ts +1 -1
- package/src/server/routers/lambda/__tests__/integration/message.integration.test.ts +0 -26
- package/src/server/routers/lambda/aiChat.ts +3 -2
- package/src/server/routers/lambda/message.ts +8 -16
- package/src/server/services/message/__tests__/index.test.ts +29 -39
- package/src/server/services/message/index.ts +41 -36
- package/src/services/electron/desktopNotification.ts +6 -6
- package/src/services/electron/file.ts +6 -6
- package/src/services/file/ClientS3/index.ts +8 -8
- package/src/services/message/__tests__/metadata-race-condition.test.ts +157 -0
- package/src/services/message/index.ts +21 -15
- package/src/services/upload.ts +11 -11
- package/src/services/utils/abortableRequest.test.ts +161 -0
- package/src/services/utils/abortableRequest.ts +67 -0
- package/src/store/chat/agents/GeneralChatAgent.ts +137 -0
- package/src/store/chat/agents/createAgentExecutors.ts +395 -0
- package/src/store/chat/helpers.test.ts +0 -99
- package/src/store/chat/helpers.ts +0 -11
- package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +332 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +257 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +11 -2
- package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +6 -6
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +391 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingStates.test.ts +179 -0
- package/src/store/chat/slices/aiChat/actions/conversationControl.ts +157 -0
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +329 -0
- package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +14 -14
- package/src/store/chat/slices/aiChat/actions/index.ts +12 -6
- package/src/store/chat/slices/aiChat/actions/rag.ts +9 -6
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +604 -0
- package/src/store/chat/slices/aiChat/actions/streamingStates.ts +84 -0
- package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +4 -4
- package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +11 -11
- package/src/store/chat/slices/builtinTool/actions/interpreter.ts +8 -8
- package/src/store/chat/slices/builtinTool/actions/localSystem.ts +2 -2
- package/src/store/chat/slices/builtinTool/actions/search.ts +8 -8
- package/src/store/chat/slices/message/action.test.ts +79 -68
- package/src/store/chat/slices/message/actions/index.ts +39 -0
- package/src/store/chat/slices/message/actions/internals.ts +77 -0
- package/src/store/chat/slices/message/actions/optimisticUpdate.ts +260 -0
- package/src/store/chat/slices/message/actions/publicApi.ts +224 -0
- package/src/store/chat/slices/message/actions/query.ts +120 -0
- package/src/store/chat/slices/message/actions/runtimeState.ts +108 -0
- package/src/store/chat/slices/message/initialState.ts +13 -0
- package/src/store/chat/slices/message/reducer.test.ts +48 -370
- package/src/store/chat/slices/message/reducer.ts +17 -81
- package/src/store/chat/slices/message/selectors/chat.test.ts +13 -50
- package/src/store/chat/slices/message/selectors/chat.ts +78 -242
- package/src/store/chat/slices/message/selectors/dbMessage.ts +140 -0
- package/src/store/chat/slices/message/selectors/displayMessage.ts +301 -0
- package/src/store/chat/slices/message/selectors/messageState.ts +5 -2
- package/src/store/chat/slices/plugin/action.test.ts +62 -64
- package/src/store/chat/slices/plugin/action.ts +34 -28
- package/src/store/chat/slices/thread/action.test.ts +28 -31
- package/src/store/chat/slices/thread/action.ts +13 -10
- package/src/store/chat/slices/thread/selectors/index.ts +8 -6
- package/src/store/chat/slices/topic/reducer.ts +11 -3
- package/src/store/chat/store.ts +1 -1
- package/src/store/user/slices/preference/selectors/labPrefer.ts +0 -3
- package/packages/database/src/models/__tests__/message.grouping.test.ts +0 -812
- package/packages/database/src/utils/__tests__/groupMessages.test.ts +0 -1132
- package/packages/database/src/utils/groupMessages.ts +0 -361
- package/packages/utils/src/tokenizer/client.ts +0 -35
- package/packages/utils/src/tokenizer/estimated.ts +0 -4
- package/packages/utils/src/tokenizer/server.ts +0 -11
- package/packages/utils/src/tokenizer/tokenizer.worker.ts +0 -12
- package/src/app/(backend)/webapi/tokenizer/index.test.ts +0 -32
- package/src/app/(backend)/webapi/tokenizer/route.ts +0 -8
- package/src/features/Conversation/Error/InvalidAccessCode.tsx +0 -79
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -975
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +0 -1050
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +0 -720
- package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +0 -849
- 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,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,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;
|