@lobehub/chat 1.134.7 → 1.135.1
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/locales/ar/chat.json +2 -2
- package/locales/ar/models.json +3 -0
- package/locales/bg-BG/chat.json +2 -2
- package/locales/bg-BG/models.json +3 -0
- package/locales/de-DE/chat.json +2 -2
- package/locales/de-DE/models.json +3 -0
- package/locales/en-US/chat.json +2 -2
- package/locales/en-US/models.json +3 -0
- package/locales/es-ES/chat.json +2 -2
- package/locales/es-ES/models.json +3 -0
- package/locales/fa-IR/chat.json +2 -2
- package/locales/fa-IR/models.json +3 -0
- package/locales/fr-FR/chat.json +2 -2
- package/locales/fr-FR/models.json +3 -0
- package/locales/it-IT/chat.json +2 -2
- package/locales/it-IT/models.json +3 -0
- package/locales/ja-JP/chat.json +2 -2
- package/locales/ja-JP/models.json +3 -0
- package/locales/ko-KR/chat.json +2 -2
- package/locales/ko-KR/models.json +3 -0
- package/locales/nl-NL/chat.json +2 -2
- package/locales/nl-NL/models.json +3 -0
- package/locales/pl-PL/chat.json +2 -2
- package/locales/pl-PL/models.json +3 -0
- package/locales/pt-BR/chat.json +2 -2
- package/locales/pt-BR/models.json +3 -0
- package/locales/ru-RU/chat.json +2 -2
- package/locales/ru-RU/models.json +3 -0
- package/locales/tr-TR/chat.json +2 -2
- package/locales/tr-TR/models.json +3 -0
- package/locales/vi-VN/chat.json +2 -2
- package/locales/vi-VN/models.json +3 -0
- package/locales/zh-CN/chat.json +2 -2
- package/locales/zh-CN/models.json +3 -0
- package/locales/zh-TW/chat.json +2 -2
- package/locales/zh-TW/models.json +3 -0
- package/next.config.ts +5 -6
- package/package.json +1 -1
- package/packages/context-engine/src/tools/ToolsEngine.ts +27 -5
- package/packages/context-engine/src/tools/__tests__/ToolsEngine.test.ts +89 -0
- package/packages/model-bank/src/aiModels/fal.ts +28 -0
- package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +16 -27
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +51 -11
- package/packages/model-runtime/src/core/streams/protocol.ts +2 -15
- package/packages/model-runtime/src/providers/fal/index.ts +12 -7
- package/packages/model-runtime/src/providers/newapi/index.test.ts +28 -3
- package/packages/model-runtime/src/providers/newapi/index.ts +34 -88
- package/packages/model-runtime/src/types/index.ts +0 -1
- package/packages/types/src/message/base.ts +1 -0
- package/packages/utils/package.json +2 -1
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/index.tsx +1 -17
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatMinimap/index.tsx +7 -4
- package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/index.tsx +16 -17
- package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/ListItem/index.tsx +2 -2
- package/src/app/[variants]/(main)/image/@menu/components/SizeSelect/index.tsx +24 -1
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/BuiltinPluginTitle.tsx +15 -17
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/ToolTitle.tsx +5 -7
- package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments/index.tsx +1 -8
- package/src/locales/default/chat.ts +2 -2
- package/src/server/modules/EdgeConfig/index.ts +15 -33
- package/src/server/modules/EdgeConfig/types.ts +13 -0
- package/packages/model-runtime/src/types/usage.ts +0 -27
|
@@ -20,41 +20,21 @@ export interface NewAPIPricing {
|
|
|
20
20
|
model_name: string;
|
|
21
21
|
model_price?: number;
|
|
22
22
|
model_ratio?: number;
|
|
23
|
-
|
|
23
|
+
/** 0: Pay-per-token, 1: Pay-per-call */
|
|
24
|
+
quota_type: number;
|
|
24
25
|
supported_endpoint_types?: string[];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
const handlePayload = (payload: ChatStreamPayload) => {
|
|
28
|
-
//
|
|
29
|
+
// Handle OpenAI responses API mode
|
|
29
30
|
if (
|
|
30
31
|
responsesAPIModels.has(payload.model) ||
|
|
31
32
|
payload.model.includes('gpt-') ||
|
|
32
33
|
/^o\d/.test(payload.model)
|
|
33
34
|
) {
|
|
34
|
-
return { ...payload, apiMode: 'responses' }
|
|
35
|
+
return { ...payload, apiMode: 'responses' };
|
|
35
36
|
}
|
|
36
|
-
return payload
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// 根据 owned_by 字段判断提供商(基于 NewAPI 的 channel name)
|
|
40
|
-
const getProviderFromOwnedBy = (ownedBy: string): string => {
|
|
41
|
-
const normalizedOwnedBy = ownedBy.toLowerCase();
|
|
42
|
-
|
|
43
|
-
if (normalizedOwnedBy.includes('claude') || normalizedOwnedBy.includes('anthropic')) {
|
|
44
|
-
return 'anthropic';
|
|
45
|
-
}
|
|
46
|
-
if (normalizedOwnedBy.includes('google') || normalizedOwnedBy.includes('gemini')) {
|
|
47
|
-
return 'google';
|
|
48
|
-
}
|
|
49
|
-
if (normalizedOwnedBy.includes('xai') || normalizedOwnedBy.includes('grok')) {
|
|
50
|
-
return 'xai';
|
|
51
|
-
}
|
|
52
|
-
if (normalizedOwnedBy.includes('ali') || normalizedOwnedBy.includes('qwen')) {
|
|
53
|
-
return 'qwen';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 默认为 openai
|
|
57
|
-
return 'openai';
|
|
37
|
+
return payload;
|
|
58
38
|
};
|
|
59
39
|
|
|
60
40
|
export const LobeNewAPIAI = createRouterRuntime({
|
|
@@ -66,16 +46,16 @@ export const LobeNewAPIAI = createRouterRuntime({
|
|
|
66
46
|
},
|
|
67
47
|
id: ModelProvider.NewAPI,
|
|
68
48
|
models: async ({ client: openAIClient }) => {
|
|
69
|
-
//
|
|
49
|
+
// Get base URL (remove trailing API version paths like /v1, /v1beta, etc.)
|
|
70
50
|
const baseURL = openAIClient.baseURL.replace(/\/v\d+[a-z]*\/?$/, '');
|
|
71
51
|
|
|
72
52
|
const modelsPage = (await openAIClient.models.list()) as any;
|
|
73
53
|
const modelList: NewAPIModelCard[] = modelsPage.data || [];
|
|
74
54
|
|
|
75
|
-
//
|
|
55
|
+
// Try to get pricing information to enrich model details
|
|
76
56
|
let pricingMap: Map<string, NewAPIPricing> = new Map();
|
|
77
57
|
try {
|
|
78
|
-
//
|
|
58
|
+
// Use saved baseURL
|
|
79
59
|
const pricingResponse = await fetch(`${baseURL}/api/pricing`, {
|
|
80
60
|
headers: {
|
|
81
61
|
Authorization: `Bearer ${openAIClient.apiKey}`,
|
|
@@ -99,22 +79,22 @@ export const LobeNewAPIAI = createRouterRuntime({
|
|
|
99
79
|
const enrichedModelList = modelList.map((model) => {
|
|
100
80
|
let enhancedModel: any = { ...model };
|
|
101
81
|
|
|
102
|
-
//
|
|
82
|
+
// add pricing info
|
|
103
83
|
const pricing = pricingMap.get(model.id);
|
|
104
84
|
if (pricing) {
|
|
105
|
-
// NewAPI
|
|
106
|
-
// - quota_type: 0
|
|
107
|
-
// - model_ratio:
|
|
108
|
-
// - model_price:
|
|
109
|
-
// - completion_ratio:
|
|
85
|
+
// NewAPI pricing calculation logic:
|
|
86
|
+
// - quota_type: 0 means pay-per-token, 1 means pay-per-call
|
|
87
|
+
// - model_ratio: multiplier relative to base price (base price = $0.002/1K tokens)
|
|
88
|
+
// - model_price: directly specified price (takes priority)
|
|
89
|
+
// - completion_ratio: output price multiplier relative to input price
|
|
110
90
|
//
|
|
111
|
-
// LobeChat
|
|
91
|
+
// LobeChat required format: USD per million tokens
|
|
112
92
|
|
|
113
93
|
let inputPrice: number | undefined;
|
|
114
94
|
let outputPrice: number | undefined;
|
|
115
95
|
|
|
116
96
|
if (pricing.quota_type === 0) {
|
|
117
|
-
//
|
|
97
|
+
// Pay-per-token
|
|
118
98
|
if (pricing.model_price && pricing.model_price > 0) {
|
|
119
99
|
// model_price is a direct price value; need to confirm its unit.
|
|
120
100
|
// Assumption: model_price is the price per 1,000 tokens (i.e., $/1K tokens).
|
|
@@ -124,62 +104,38 @@ export const LobeNewAPIAI = createRouterRuntime({
|
|
|
124
104
|
inputPrice = pricing.model_price * 2;
|
|
125
105
|
} else if (pricing.model_ratio) {
|
|
126
106
|
// model_ratio × $0.002/1K = model_ratio × $2/1M
|
|
127
|
-
inputPrice = pricing.model_ratio * 2; //
|
|
107
|
+
inputPrice = pricing.model_ratio * 2; // Convert to $/1M tokens
|
|
128
108
|
}
|
|
129
109
|
|
|
130
110
|
if (inputPrice !== undefined) {
|
|
131
|
-
//
|
|
111
|
+
// Calculate output price
|
|
132
112
|
outputPrice = inputPrice * (pricing.completion_ratio || 1);
|
|
133
113
|
|
|
134
114
|
enhancedModel.pricing = {
|
|
135
|
-
|
|
136
|
-
|
|
115
|
+
units: [
|
|
116
|
+
{
|
|
117
|
+
name: 'textInput',
|
|
118
|
+
rate: inputPrice,
|
|
119
|
+
strategy: 'fixed',
|
|
120
|
+
unit: 'millionTokens',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'textOutput',
|
|
124
|
+
rate: outputPrice,
|
|
125
|
+
strategy: 'fixed',
|
|
126
|
+
unit: 'millionTokens',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
137
129
|
};
|
|
138
130
|
}
|
|
139
131
|
}
|
|
140
|
-
// quota_type === 1
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// 2. 根据优先级处理 provider 信息并缓存路由
|
|
144
|
-
let detectedProvider = 'openai'; // 默认
|
|
145
|
-
|
|
146
|
-
// 优先级1:使用 supported_endpoint_types
|
|
147
|
-
if (model.supported_endpoint_types && model.supported_endpoint_types.length > 0) {
|
|
148
|
-
if (model.supported_endpoint_types.includes('anthropic')) {
|
|
149
|
-
detectedProvider = 'anthropic';
|
|
150
|
-
} else if (model.supported_endpoint_types.includes('gemini')) {
|
|
151
|
-
detectedProvider = 'google';
|
|
152
|
-
} else if (model.supported_endpoint_types.includes('xai')) {
|
|
153
|
-
detectedProvider = 'xai';
|
|
154
|
-
} else if (model.supported_endpoint_types.includes('qwen')) {
|
|
155
|
-
detectedProvider = 'qwen';
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
// 优先级2:使用 owned_by 字段
|
|
159
|
-
else if (model.owned_by) {
|
|
160
|
-
detectedProvider = getProviderFromOwnedBy(model.owned_by);
|
|
161
|
-
}
|
|
162
|
-
// 优先级3:基于模型名称检测
|
|
163
|
-
else {
|
|
164
|
-
detectedProvider = detectModelProvider(model.id);
|
|
132
|
+
// quota_type === 1 pay-per-call is not currently supported
|
|
165
133
|
}
|
|
166
134
|
|
|
167
|
-
// 将检测到的 provider 信息附加到模型上
|
|
168
|
-
enhancedModel._detectedProvider = detectedProvider;
|
|
169
|
-
|
|
170
135
|
return enhancedModel;
|
|
171
136
|
});
|
|
172
137
|
|
|
173
|
-
|
|
174
|
-
const processedModels = await processMultiProviderModelList(enrichedModelList, 'newapi');
|
|
175
|
-
|
|
176
|
-
// 清理临时字段
|
|
177
|
-
return processedModels.map((model: any) => {
|
|
178
|
-
if (model._detectedProvider) {
|
|
179
|
-
delete model._detectedProvider;
|
|
180
|
-
}
|
|
181
|
-
return model;
|
|
182
|
-
});
|
|
138
|
+
return processMultiProviderModelList(enrichedModelList, 'newapi');
|
|
183
139
|
},
|
|
184
140
|
routers: (options) => {
|
|
185
141
|
const userBaseURL = options.baseURL?.replace(/\/v\d+[a-z]*\/?$/, '') || '';
|
|
@@ -215,16 +171,6 @@ export const LobeNewAPIAI = createRouterRuntime({
|
|
|
215
171
|
baseURL: urlJoin(userBaseURL, '/v1'),
|
|
216
172
|
},
|
|
217
173
|
},
|
|
218
|
-
{
|
|
219
|
-
apiType: 'qwen',
|
|
220
|
-
models: LOBE_DEFAULT_MODEL_LIST.map((m) => m.id).filter(
|
|
221
|
-
(id) => detectModelProvider(id) === 'qwen',
|
|
222
|
-
),
|
|
223
|
-
options: {
|
|
224
|
-
...options,
|
|
225
|
-
baseURL: urlJoin(userBaseURL, '/v1'),
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
174
|
{
|
|
229
175
|
apiType: 'openai',
|
|
230
176
|
options: {
|
|
@@ -1,17 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { useChatStore } from '@/store/chat';
|
|
4
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
|
5
|
-
|
|
6
|
-
import InboxWelcome from './InboxWelcome';
|
|
7
|
-
import WelcomeMessage from './WelcomeMessage';
|
|
8
|
-
|
|
9
|
-
const WelcomeChatItem = memo(() => {
|
|
10
|
-
const showInboxWelcome = useChatStore(chatSelectors.showInboxWelcome);
|
|
11
|
-
|
|
12
|
-
if (showInboxWelcome) return <InboxWelcome />;
|
|
13
|
-
|
|
14
|
-
return <WelcomeMessage />;
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
export default WelcomeChatItem;
|
|
1
|
+
export { default } from './WelcomeMessage';
|
package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatMinimap/index.tsx
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Icon } from '@lobehub/ui';
|
|
4
4
|
import { Tooltip } from 'antd';
|
|
5
5
|
import { createStyles, useTheme } from 'antd-style';
|
|
6
|
+
import debug from 'debug';
|
|
6
7
|
import { ChevronDown, ChevronUp } from 'lucide-react';
|
|
7
8
|
import { memo, useCallback, useMemo, useState, useSyncExternalStore } from 'react';
|
|
8
9
|
import { useTranslation } from 'react-i18next';
|
|
@@ -17,10 +18,12 @@ import {
|
|
|
17
18
|
import { useChatStore } from '@/store/chat';
|
|
18
19
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
19
20
|
|
|
21
|
+
const log = debug('lobe-react:chat-minimap');
|
|
22
|
+
|
|
20
23
|
const MIN_WIDTH = 16;
|
|
21
24
|
const MAX_WIDTH = 30;
|
|
22
25
|
const MAX_CONTENT_LENGTH = 320;
|
|
23
|
-
const MIN_MESSAGES =
|
|
26
|
+
const MIN_MESSAGES = 4;
|
|
24
27
|
|
|
25
28
|
const useStyles = createStyles(({ css, token }) => ({
|
|
26
29
|
arrow: css`
|
|
@@ -219,8 +222,8 @@ const ChatMinimap = () => {
|
|
|
219
222
|
const activeIndicatorPosition = useMemo(() => {
|
|
220
223
|
if (activeIndex === null) return null;
|
|
221
224
|
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
log('> activeIndex', activeIndex);
|
|
226
|
+
log('> indicatorIndexMap', indicatorIndexMap);
|
|
224
227
|
|
|
225
228
|
return indicatorIndexMap.get(activeIndex) ?? null;
|
|
226
229
|
}, [activeIndex, indicatorIndexMap]);
|
|
@@ -246,7 +249,7 @@ const ChatMinimap = () => {
|
|
|
246
249
|
let targetPosition: number;
|
|
247
250
|
|
|
248
251
|
if (activeIndicatorPosition !== null) {
|
|
249
|
-
|
|
252
|
+
log('activeIndicatorPosition', activeIndicatorPosition);
|
|
250
253
|
// We're on an indicator, move to prev/next
|
|
251
254
|
const delta = direction === 'prev' ? -1 : 1;
|
|
252
255
|
targetPosition = Math.min(
|
package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/index.tsx
CHANGED
|
@@ -31,22 +31,21 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
|
|
|
31
31
|
const [active] = useSessionStore((s) => [s.activeId === id]);
|
|
32
32
|
const [loading] = useChatStore((s) => [chatSelectors.isAIGenerating(s) && id === s.activeId]);
|
|
33
33
|
|
|
34
|
-
const [pin, title,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
34
|
+
const [pin, title, avatar, avatarBackground, updateAt, model, group] = useSessionStore((s) => {
|
|
35
|
+
const session = sessionSelectors.getSessionById(id)(s);
|
|
36
|
+
const meta = session.meta;
|
|
37
|
+
|
|
38
|
+
return [
|
|
39
|
+
sessionHelpers.getSessionPinned(session),
|
|
40
|
+
sessionMetaSelectors.getTitle(meta),
|
|
41
|
+
sessionMetaSelectors.getAvatar(meta),
|
|
42
|
+
meta.backgroundColor,
|
|
43
|
+
session?.updatedAt,
|
|
44
|
+
session.model,
|
|
45
|
+
session?.group,
|
|
46
|
+
// sessionMetaSelectors.getDescription(meta),
|
|
47
|
+
];
|
|
48
|
+
});
|
|
50
49
|
|
|
51
50
|
const showModel = model !== defaultModel;
|
|
52
51
|
|
|
@@ -99,7 +98,7 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
|
|
|
99
98
|
avatar={avatar}
|
|
100
99
|
avatarBackground={avatarBackground}
|
|
101
100
|
date={updateAt?.valueOf()}
|
|
102
|
-
description={description}
|
|
101
|
+
// description={description}
|
|
103
102
|
draggable={isDesktop}
|
|
104
103
|
key={id}
|
|
105
104
|
loading={loading}
|
package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/ListItem/index.tsx
CHANGED
|
@@ -12,7 +12,7 @@ const useStyles = createStyles(({ css, token }) => {
|
|
|
12
12
|
container: css`
|
|
13
13
|
position: relative;
|
|
14
14
|
margin-block: 2px;
|
|
15
|
-
padding-inline:
|
|
15
|
+
padding-inline: 12px 16px;
|
|
16
16
|
border-radius: ${token.borderRadius}px;
|
|
17
17
|
`,
|
|
18
18
|
mobile: css`
|
|
@@ -40,7 +40,7 @@ const ListItem = memo<ListItemProps & { avatar: string; avatarBackground?: strin
|
|
|
40
40
|
avatar={avatar}
|
|
41
41
|
background={avatarBackground}
|
|
42
42
|
shape="circle"
|
|
43
|
-
size={
|
|
43
|
+
size={32}
|
|
44
44
|
/>
|
|
45
45
|
),
|
|
46
46
|
[isHovering, avatar, avatarBackground],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { Block, Grid, GridProps, Text } from '@lobehub/ui';
|
|
3
|
+
import { Block, Grid, GridProps, Select, Text } from '@lobehub/ui';
|
|
4
4
|
import { useTheme } from 'antd-style';
|
|
5
5
|
import { ReactNode, memo } from 'react';
|
|
6
6
|
import { Center } from 'react-layout-kit';
|
|
@@ -13,6 +13,19 @@ export interface SizeSelectProps extends Omit<GridProps, 'children' | 'onChange'
|
|
|
13
13
|
value?: 'auto' | string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Check if a size value can be parsed as valid aspect ratio
|
|
18
|
+
*/
|
|
19
|
+
const canParseAsRatio = (value: string): boolean => {
|
|
20
|
+
if (value === 'auto') return true;
|
|
21
|
+
|
|
22
|
+
const parts = value.split('x');
|
|
23
|
+
if (parts.length !== 2) return false;
|
|
24
|
+
|
|
25
|
+
const [width, height] = parts.map(Number);
|
|
26
|
+
return !isNaN(width) && !isNaN(height) && width > 0 && height > 0;
|
|
27
|
+
};
|
|
28
|
+
|
|
16
29
|
const SizeSelect = memo<SizeSelectProps>(({ options, onChange, value, defaultValue, ...rest }) => {
|
|
17
30
|
const theme = useTheme();
|
|
18
31
|
const [active, setActive] = useMergeState('auto', {
|
|
@@ -20,6 +33,16 @@ const SizeSelect = memo<SizeSelectProps>(({ options, onChange, value, defaultVal
|
|
|
20
33
|
onChange,
|
|
21
34
|
value,
|
|
22
35
|
});
|
|
36
|
+
|
|
37
|
+
// Check if all options can be parsed as valid ratios
|
|
38
|
+
const hasInvalidRatio = options?.some((item) => !canParseAsRatio(item.value));
|
|
39
|
+
|
|
40
|
+
// If any option cannot be parsed as ratio, fallback to regular Select
|
|
41
|
+
if (hasInvalidRatio) {
|
|
42
|
+
return (
|
|
43
|
+
<Select onChange={onChange} options={options} style={{ width: '100%' }} value={active} />
|
|
44
|
+
);
|
|
45
|
+
}
|
|
23
46
|
return (
|
|
24
47
|
<Block padding={4} variant={'filled'} {...rest}>
|
|
25
48
|
<Grid gap={4} maxItemWidth={72} rows={16}>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
|
1
2
|
import { createStyles } from 'antd-style';
|
|
3
|
+
import { ChevronRight } from 'lucide-react';
|
|
2
4
|
import { ReactNode, memo } from 'react';
|
|
3
5
|
import { Flexbox } from 'react-layout-kit';
|
|
4
6
|
|
|
5
|
-
import Loader from '@/components/CircleLoader';
|
|
6
7
|
import { useChatStore } from '@/store/chat';
|
|
7
8
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
8
9
|
import { shinyTextStylish } from '@/styles/loading';
|
|
@@ -32,21 +33,18 @@ interface BuiltinPluginTitleProps {
|
|
|
32
33
|
toolCallId: string;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
const BuiltinPluginTitle = memo<BuiltinPluginTitleProps>(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
},
|
|
50
|
-
);
|
|
36
|
+
const BuiltinPluginTitle = memo<BuiltinPluginTitleProps>(({ messageId, index, apiName, title }) => {
|
|
37
|
+
const { styles } = useStyles();
|
|
38
|
+
|
|
39
|
+
const isLoading = useChatStore(chatSelectors.isInToolsCalling(messageId, index));
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Flexbox align={'center'} className={isLoading ? styles.shinyText : ''} gap={4} horizontal>
|
|
43
|
+
<div>{title}</div>
|
|
44
|
+
<Icon icon={ChevronRight} />
|
|
45
|
+
<span className={styles.apiName}>{apiName}</span>
|
|
46
|
+
</Flexbox>
|
|
47
|
+
);
|
|
48
|
+
});
|
|
51
49
|
|
|
52
50
|
export default BuiltinPluginTitle;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { Icon } from '@lobehub/ui';
|
|
2
2
|
import { createStyles } from 'antd-style';
|
|
3
3
|
import isEqual from 'fast-deep-equal';
|
|
4
|
-
import {
|
|
4
|
+
import { ChevronRight } from 'lucide-react';
|
|
5
5
|
import { memo, useMemo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
9
|
-
import Loader from '@/components/CircleLoader';
|
|
10
|
-
import PluginAvatar from '@/features/PluginAvatar';
|
|
11
9
|
import { useChatStore } from '@/store/chat';
|
|
12
10
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
13
11
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
@@ -60,13 +58,13 @@ const ToolTitle = memo<ToolTitleProps>(({ identifier, messageId, index, apiName,
|
|
|
60
58
|
() => [
|
|
61
59
|
{
|
|
62
60
|
apiName: t(`search.apiName.${apiName}`, apiName),
|
|
63
|
-
icon: <Icon icon={Globe} size={13} />,
|
|
61
|
+
// icon: <Icon icon={Globe} size={13} />,
|
|
64
62
|
id: WebBrowsingManifest.identifier,
|
|
65
63
|
title: t('search.title'),
|
|
66
64
|
},
|
|
67
65
|
{
|
|
68
66
|
apiName: t(`localSystem.apiName.${apiName}`, apiName),
|
|
69
|
-
icon: <Icon icon={Laptop} size={13} />,
|
|
67
|
+
// icon: <Icon icon={Laptop} size={13} />,
|
|
70
68
|
id: LocalSystemManifest.identifier,
|
|
71
69
|
title: t('localSystem.title'),
|
|
72
70
|
},
|
|
@@ -92,8 +90,8 @@ const ToolTitle = memo<ToolTitleProps>(({ identifier, messageId, index, apiName,
|
|
|
92
90
|
|
|
93
91
|
return (
|
|
94
92
|
<Flexbox align={'center'} className={isLoading ? styles.shinyText : ''} gap={6} horizontal>
|
|
95
|
-
{
|
|
96
|
-
<
|
|
93
|
+
<div>{pluginTitle}</div> <Icon icon={ChevronRight} />
|
|
94
|
+
<span className={styles.apiName}>{apiName}</span>
|
|
97
95
|
</Flexbox>
|
|
98
96
|
);
|
|
99
97
|
});
|
|
@@ -116,14 +116,7 @@ const Arguments = memo<ArgumentsProps>(({ arguments: args = '', shine, actions }
|
|
|
116
116
|
</Flexbox>
|
|
117
117
|
)}
|
|
118
118
|
{args.length > 100 ? (
|
|
119
|
-
<
|
|
120
|
-
language={'json'}
|
|
121
|
-
showLanguage={false}
|
|
122
|
-
style={{ padding: 8 }}
|
|
123
|
-
variant={'borderless'}
|
|
124
|
-
>
|
|
125
|
-
{JSON.stringify(displayArgs, null, 2)}
|
|
126
|
-
</Highlighter>
|
|
119
|
+
<pre style={{ padding: 8 }}>{JSON.stringify(displayArgs, null, 2)}</pre>
|
|
127
120
|
) : (
|
|
128
121
|
Object.entries(displayArgs).map(([key, value]) => {
|
|
129
122
|
return (
|
|
@@ -4,8 +4,8 @@ export default {
|
|
|
4
4
|
},
|
|
5
5
|
agentDefaultMessage:
|
|
6
6
|
'你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置]({{url}}) 完善我的信息。',
|
|
7
|
-
agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}
|
|
8
|
-
agentDefaultMessageWithoutEdit: '你好,我是 **{{name}}
|
|
7
|
+
agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,有什么我可以帮忙的吗?',
|
|
8
|
+
agentDefaultMessageWithoutEdit: '你好,我是 **{{name}}**,有什么我可以帮忙的吗?',
|
|
9
9
|
agents: '助手',
|
|
10
10
|
artifact: {
|
|
11
11
|
generating: '生成中',
|
|
@@ -3,22 +3,9 @@ import createDebug from 'debug';
|
|
|
3
3
|
|
|
4
4
|
import { appEnv } from '@/envs/app';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import { EdgeConfigData, EdgeConfigKeys } from './types';
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
/**
|
|
10
|
-
* Assistant whitelist
|
|
11
|
-
*/
|
|
12
|
-
AssistantBlacklist: 'assistant_blacklist',
|
|
13
|
-
/**
|
|
14
|
-
* Assistant whitelist
|
|
15
|
-
*/
|
|
16
|
-
AssistantWhitelist: 'assistant_whitelist',
|
|
17
|
-
/**
|
|
18
|
-
* Feature flags configuration
|
|
19
|
-
*/
|
|
20
|
-
FeatureFlags: 'feature_flags',
|
|
21
|
-
};
|
|
8
|
+
const debug = createDebug('lobe-server:edge-config');
|
|
22
9
|
|
|
23
10
|
export class EdgeConfig {
|
|
24
11
|
get client(): EdgeConfigClient {
|
|
@@ -38,29 +25,24 @@ export class EdgeConfig {
|
|
|
38
25
|
return isEnabled;
|
|
39
26
|
}
|
|
40
27
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
EdgeConfigKeys.AssistantWhitelist,
|
|
45
|
-
EdgeConfigKeys.AssistantBlacklist,
|
|
46
|
-
]);
|
|
28
|
+
private async getValue<K extends EdgeConfigKeys>(key: K) {
|
|
29
|
+
return this.client.get<EdgeConfigData[K]>(key);
|
|
30
|
+
}
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
};
|
|
32
|
+
private async getValues<const K extends EdgeConfigKeys>(keys: K[]) {
|
|
33
|
+
return this.client.getAll<Pick<EdgeConfigData, K>>(keys);
|
|
34
|
+
}
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
36
|
+
getAgentRestrictions = async () => {
|
|
37
|
+
const { assistant_blacklist: blacklist, assistant_whitelist: whitelist } = await this.getValues(
|
|
38
|
+
['assistant_blacklist', 'assistant_whitelist'],
|
|
39
|
+
);
|
|
40
|
+
return { blacklist, whitelist };
|
|
57
41
|
};
|
|
58
42
|
|
|
59
43
|
getFeatureFlags = async () => {
|
|
60
|
-
const featureFlags = await this.
|
|
44
|
+
const featureFlags = await this.getValue('feature_flags');
|
|
61
45
|
debug('Feature flags retrieved: %O', featureFlags);
|
|
62
|
-
return featureFlags
|
|
46
|
+
return featureFlags;
|
|
63
47
|
};
|
|
64
48
|
}
|
|
65
|
-
|
|
66
|
-
export { EdgeConfigKeys };
|
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
* EdgeConfig 完整配置类型
|
|
5
5
|
*/
|
|
6
6
|
export interface EdgeConfigData {
|
|
7
|
+
/**
|
|
8
|
+
* Assistant blacklist
|
|
9
|
+
*/
|
|
7
10
|
assistant_blacklist?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Assistant whitelist
|
|
13
|
+
*/
|
|
8
14
|
assistant_whitelist?: string[];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Feature flags configuration
|
|
18
|
+
*/
|
|
19
|
+
feature_flags?: Record<string, boolean | string[]>;
|
|
9
20
|
}
|
|
21
|
+
|
|
22
|
+
export type EdgeConfigKeys = keyof EdgeConfigData;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export interface ModelTokensUsage {
|
|
2
|
-
acceptedPredictionTokens?: number;
|
|
3
|
-
inputAudioTokens?: number;
|
|
4
|
-
inputCacheMissTokens?: number;
|
|
5
|
-
inputCachedTokens?: number;
|
|
6
|
-
/**
|
|
7
|
-
* currently only pplx has citation_tokens
|
|
8
|
-
*/
|
|
9
|
-
inputCitationTokens?: number;
|
|
10
|
-
/**
|
|
11
|
-
* user prompt image
|
|
12
|
-
*/
|
|
13
|
-
inputImageTokens?: number;
|
|
14
|
-
/**
|
|
15
|
-
* user prompt input
|
|
16
|
-
*/
|
|
17
|
-
inputTextTokens?: number;
|
|
18
|
-
inputWriteCacheTokens?: number;
|
|
19
|
-
outputAudioTokens?: number;
|
|
20
|
-
outputImageTokens?: number;
|
|
21
|
-
outputReasoningTokens?: number;
|
|
22
|
-
outputTextTokens?: number;
|
|
23
|
-
rejectedPredictionTokens?: number;
|
|
24
|
-
totalInputTokens?: number;
|
|
25
|
-
totalOutputTokens?: number;
|
|
26
|
-
totalTokens?: number;
|
|
27
|
-
}
|