@lobehub/chat 1.124.0 → 1.124.2
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/.env.example +5 -0
- package/.github/scripts/pr-comment.js +11 -2
- package/.github/workflows/desktop-pr-build.yml +86 -12
- package/.github/workflows/release-desktop-beta.yml +91 -20
- package/CHANGELOG.md +58 -0
- package/Dockerfile +2 -0
- package/Dockerfile.database +2 -0
- package/Dockerfile.pglite +2 -0
- package/apps/desktop/electron-builder.js +8 -4
- package/changelog/v1.json +21 -0
- package/docs/self-hosting/environment-variables/model-provider.mdx +18 -0
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +20 -0
- package/locales/ar/chat.json +2 -0
- package/locales/bg-BG/chat.json +2 -0
- package/locales/de-DE/chat.json +2 -0
- package/locales/en-US/chat.json +2 -0
- package/locales/es-ES/chat.json +2 -0
- package/locales/fa-IR/chat.json +2 -0
- package/locales/fr-FR/chat.json +2 -0
- package/locales/it-IT/chat.json +2 -0
- package/locales/ja-JP/chat.json +2 -0
- package/locales/ko-KR/chat.json +2 -0
- package/locales/nl-NL/chat.json +2 -0
- package/locales/pl-PL/chat.json +2 -0
- package/locales/pt-BR/chat.json +2 -0
- package/locales/ru-RU/chat.json +2 -0
- package/locales/tr-TR/chat.json +2 -0
- package/locales/vi-VN/chat.json +2 -0
- package/locales/zh-CN/chat.json +2 -0
- package/locales/zh-CN/modelProvider.json +1 -1
- package/locales/zh-TW/chat.json +2 -0
- package/package.json +1 -1
- package/packages/const/src/hotkeys.ts +1 -1
- package/packages/const/src/index.ts +1 -0
- package/packages/const/src/settings/hotkey.ts +3 -2
- package/packages/const/src/trace.ts +1 -1
- package/packages/const/src/user.ts +1 -2
- package/packages/database/src/client/db.test.ts +19 -13
- package/packages/electron-server-ipc/src/ipcClient.test.ts +783 -1
- package/packages/file-loaders/src/loadFile.test.ts +61 -0
- package/packages/file-loaders/src/utils/isTextReadableFile.test.ts +43 -0
- package/packages/file-loaders/src/utils/parser-utils.test.ts +155 -0
- package/packages/model-bank/src/aiModels/aihubmix.ts +38 -4
- package/packages/model-bank/src/aiModels/groq.ts +26 -8
- package/packages/model-bank/src/aiModels/hunyuan.ts +3 -3
- package/packages/model-bank/src/aiModels/modelscope.ts +13 -2
- package/packages/model-bank/src/aiModels/moonshot.ts +25 -5
- package/packages/model-bank/src/aiModels/novita.ts +40 -9
- package/packages/model-bank/src/aiModels/openrouter.ts +0 -13
- package/packages/model-bank/src/aiModels/qwen.ts +62 -1
- package/packages/model-bank/src/aiModels/siliconcloud.ts +20 -0
- package/packages/model-bank/src/aiModels/volcengine.ts +141 -15
- package/packages/model-runtime/package.json +2 -1
- package/packages/model-runtime/src/ai21/index.test.ts +2 -2
- package/packages/model-runtime/src/ai360/index.test.ts +2 -2
- package/packages/model-runtime/src/akashchat/index.test.ts +19 -0
- package/packages/model-runtime/src/anthropic/index.test.ts +1 -2
- package/packages/model-runtime/src/baichuan/index.test.ts +1 -2
- package/packages/model-runtime/src/bedrock/index.test.ts +1 -2
- package/packages/model-runtime/src/bfl/createImage.test.ts +1 -2
- package/packages/model-runtime/src/bfl/index.test.ts +1 -2
- package/packages/model-runtime/src/cloudflare/index.test.ts +1 -2
- package/packages/model-runtime/src/cohere/index.test.ts +19 -0
- package/packages/model-runtime/src/deepseek/index.test.ts +2 -2
- package/packages/model-runtime/src/fireworksai/index.test.ts +2 -2
- package/packages/model-runtime/src/giteeai/index.test.ts +2 -2
- package/packages/model-runtime/src/github/index.test.ts +2 -2
- package/packages/model-runtime/src/google/createImage.test.ts +1 -2
- package/packages/model-runtime/src/google/index.test.ts +1 -1
- package/packages/model-runtime/src/groq/index.test.ts +2 -3
- package/packages/model-runtime/src/huggingface/index.test.ts +40 -0
- package/packages/model-runtime/src/hunyuan/index.test.ts +2 -3
- package/packages/model-runtime/src/internlm/index.test.ts +2 -2
- package/packages/model-runtime/src/jina/index.test.ts +19 -0
- package/packages/model-runtime/src/lmstudio/index.test.ts +2 -2
- package/packages/model-runtime/src/minimax/index.test.ts +19 -0
- package/packages/model-runtime/src/mistral/index.test.ts +2 -3
- package/packages/model-runtime/src/modelscope/index.test.ts +19 -0
- package/packages/model-runtime/src/moonshot/index.test.ts +1 -2
- package/packages/model-runtime/src/nebius/index.test.ts +19 -0
- package/packages/model-runtime/src/newapi/index.test.ts +49 -42
- package/packages/model-runtime/src/newapi/index.ts +124 -143
- package/packages/model-runtime/src/novita/index.test.ts +3 -4
- package/packages/model-runtime/src/nvidia/index.test.ts +19 -0
- package/packages/model-runtime/src/openrouter/index.test.ts +2 -3
- package/packages/model-runtime/src/perplexity/index.test.ts +2 -3
- package/packages/model-runtime/src/ppio/index.test.ts +3 -4
- package/packages/model-runtime/src/qwen/index.test.ts +2 -2
- package/packages/model-runtime/src/sambanova/index.test.ts +19 -0
- package/packages/model-runtime/src/search1api/index.test.ts +19 -0
- package/packages/model-runtime/src/sensenova/index.test.ts +2 -2
- package/packages/model-runtime/src/spark/index.test.ts +2 -2
- package/packages/model-runtime/src/stepfun/index.test.ts +2 -2
- package/packages/model-runtime/src/taichu/index.test.ts +4 -5
- package/packages/model-runtime/src/tencentcloud/index.test.ts +1 -1
- package/packages/model-runtime/src/togetherai/index.test.ts +1 -2
- package/packages/model-runtime/src/upstage/index.test.ts +1 -2
- package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.test.ts +9 -7
- package/packages/model-runtime/src/utils/streams/anthropic.ts +2 -2
- package/packages/model-runtime/src/utils/streams/openai/openai.ts +20 -13
- package/packages/model-runtime/src/utils/streams/openai/responsesStream.test.ts +1 -2
- package/packages/model-runtime/src/utils/streams/openai/responsesStream.ts +2 -2
- package/packages/model-runtime/src/utils/streams/protocol.ts +2 -2
- package/packages/model-runtime/src/wenxin/index.test.ts +2 -3
- package/packages/model-runtime/src/xai/index.test.ts +2 -2
- package/packages/model-runtime/src/zeroone/index.test.ts +1 -2
- package/packages/model-runtime/src/zhipu/index.test.ts +2 -3
- package/packages/model-runtime/vitest.config.mts +0 -7
- package/packages/types/src/index.ts +2 -0
- package/packages/types/src/message/base.ts +1 -1
- package/packages/types/src/openai/chat.ts +2 -3
- package/packages/utils/package.json +2 -1
- package/packages/utils/src/_deprecated/parseModels.test.ts +1 -1
- package/packages/utils/src/_deprecated/parseModels.ts +1 -1
- package/packages/utils/src/client/topic.test.ts +1 -2
- package/packages/utils/src/client/topic.ts +1 -2
- package/packages/utils/src/electron/desktopRemoteRPCFetch.ts +1 -1
- package/packages/utils/src/fetch/fetchSSE.ts +7 -8
- package/packages/utils/src/fetch/parseError.ts +1 -3
- package/packages/utils/src/format.test.ts +1 -2
- package/packages/utils/src/index.ts +1 -0
- package/packages/utils/src/toolManifest.ts +1 -2
- package/packages/utils/src/trace.ts +1 -1
- package/packages/utils/vitest.config.mts +1 -1
- package/packages/web-crawler/src/__tests__/urlRules.test.ts +275 -0
- package/packages/web-crawler/src/crawImpl/__tests__/exa.test.ts +269 -0
- package/packages/web-crawler/src/crawImpl/__tests__/firecrawl.test.ts +284 -0
- package/packages/web-crawler/src/crawImpl/__tests__/naive.test.ts +234 -0
- package/packages/web-crawler/src/crawImpl/__tests__/tavily.test.ts +359 -0
- package/packages/web-crawler/src/utils/__tests__/errorType.test.ts +217 -0
- package/packages/web-crawler/vitest.config.mts +3 -0
- package/scripts/electronWorkflow/mergeMacReleaseFiles.ts +207 -0
- package/src/app/[variants]/(main)/settings/provider/(detail)/newapi/page.tsx +1 -1
- package/src/components/Thinking/index.tsx +2 -3
- package/src/config/llm.ts +8 -0
- package/src/features/ChatInput/Desktop/index.tsx +16 -4
- package/src/features/ChatInput/StoreUpdater.tsx +2 -0
- package/src/libs/traces/index.ts +1 -1
- package/src/locales/default/chat.ts +1 -0
- package/src/locales/default/modelProvider.ts +1 -1
- package/src/server/modules/ModelRuntime/trace.ts +1 -2
- package/src/store/chat/slices/aiChat/actions/__tests__/cancel-functionality.test.ts +107 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +352 -7
- package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +2 -1
- package/packages/model-runtime/src/openrouter/__snapshots__/index.test.ts.snap +0 -113
@@ -0,0 +1,207 @@
|
|
1
|
+
/* eslint-disable unicorn/no-process-exit, unicorn/prefer-top-level-await */
|
2
|
+
import fs from 'fs-extra';
|
3
|
+
import path from 'node:path';
|
4
|
+
import { parse, stringify } from 'yaml';
|
5
|
+
|
6
|
+
interface LatestMacYml {
|
7
|
+
files: Array<{
|
8
|
+
sha512: string;
|
9
|
+
size: number;
|
10
|
+
url: string;
|
11
|
+
}>;
|
12
|
+
path: string;
|
13
|
+
releaseDate: string;
|
14
|
+
sha512: string;
|
15
|
+
version: string;
|
16
|
+
}
|
17
|
+
|
18
|
+
// 配置
|
19
|
+
const RELEASE_TAG = process.env.RELEASE_TAG || process.argv[2];
|
20
|
+
const FILE_NAME = 'latest-mac.yml';
|
21
|
+
const RELEASE_DIR = path.resolve('release');
|
22
|
+
|
23
|
+
// 验证环境变量和输入
|
24
|
+
if (!RELEASE_TAG) {
|
25
|
+
console.error('❌ RELEASE_TAG environment variable or argument is required');
|
26
|
+
process.exit(1);
|
27
|
+
}
|
28
|
+
|
29
|
+
// 验证 release tag 格式
|
30
|
+
if (!/^v?\d+\.\d+\.\d+/.test(RELEASE_TAG)) {
|
31
|
+
console.error(`❌ Invalid RELEASE_TAG format: ${RELEASE_TAG}. Expected format: v1.2.3`);
|
32
|
+
process.exit(1);
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* 检测 latest-mac.yml 文件的平台类型
|
37
|
+
*/
|
38
|
+
function detectPlatform(yamlContent: LatestMacYml): 'intel' | 'arm' | 'both' | 'none' {
|
39
|
+
const hasIntel = yamlContent.files.some((file) => file.url.includes('-x64.dmg'));
|
40
|
+
const hasArm = yamlContent.files.some((file) => file.url.includes('-arm64.dmg'));
|
41
|
+
|
42
|
+
if (hasIntel && hasArm) return 'both';
|
43
|
+
if (hasIntel && !hasArm) return 'intel';
|
44
|
+
if (!hasIntel && hasArm) return 'arm';
|
45
|
+
return 'none';
|
46
|
+
}
|
47
|
+
|
48
|
+
/**
|
49
|
+
* 合并两个 latest-mac.yml 文件
|
50
|
+
* @param intelContent Intel 平台的 YAML 内容
|
51
|
+
* @param armContent ARM 平台的 YAML 内容
|
52
|
+
*/
|
53
|
+
function mergeYamlFiles(intelContent: LatestMacYml, armContent: LatestMacYml): string {
|
54
|
+
// 以 Intel 为基础(保持兼容性)
|
55
|
+
const merged: LatestMacYml = {
|
56
|
+
...intelContent,
|
57
|
+
files: [...intelContent.files, ...armContent.files],
|
58
|
+
};
|
59
|
+
|
60
|
+
// 使用 yaml 库生成,保持 sha512 在同一行
|
61
|
+
return stringify(merged, {
|
62
|
+
lineWidth: 0, // 不换行
|
63
|
+
});
|
64
|
+
}
|
65
|
+
|
66
|
+
// GitHub API functions removed since we're working with local files only
|
67
|
+
|
68
|
+
/**
|
69
|
+
* 读取本地文件
|
70
|
+
*/
|
71
|
+
function readLocalFile(filePath: string): string | null {
|
72
|
+
try {
|
73
|
+
if (fs.existsSync(filePath)) {
|
74
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
75
|
+
console.log(`✅ Read local file: ${filePath} (${content.length} chars)`);
|
76
|
+
return content;
|
77
|
+
}
|
78
|
+
console.log(`⚠️ Local file not found: ${filePath}`);
|
79
|
+
return null;
|
80
|
+
} catch (error) {
|
81
|
+
console.error(`❌ Error reading local file ${filePath}:`, error);
|
82
|
+
return null;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
/**
|
87
|
+
* 写入本地文件
|
88
|
+
*/
|
89
|
+
function writeLocalFile(filePath: string, content: string): void {
|
90
|
+
try {
|
91
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
92
|
+
console.log(`✅ Written local file: ${filePath} (${content.length} chars)`);
|
93
|
+
} catch (error) {
|
94
|
+
console.error(`❌ Error writing local file ${filePath}:`, error);
|
95
|
+
throw error;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* 主函数
|
101
|
+
*/
|
102
|
+
async function main(): Promise<void> {
|
103
|
+
try {
|
104
|
+
console.log(`🚀 Starting macOS Release file merge for ${RELEASE_TAG}`);
|
105
|
+
console.log(`📁 Working directory: ${RELEASE_DIR}`);
|
106
|
+
|
107
|
+
// 1. 检查 release 目录下的所有文件
|
108
|
+
const releaseFiles = fs.readdirSync(RELEASE_DIR);
|
109
|
+
console.log(`📂 Files in release directory: ${releaseFiles.join(', ')}`);
|
110
|
+
|
111
|
+
// 2. 查找所有 latest-mac*.yml 文件
|
112
|
+
const macYmlFiles = releaseFiles.filter(
|
113
|
+
(f) => f.startsWith('latest-mac') && f.endsWith('.yml'),
|
114
|
+
);
|
115
|
+
console.log(`🔍 Found macOS YAML files: ${macYmlFiles.join(', ')}`);
|
116
|
+
|
117
|
+
if (macYmlFiles.length === 0) {
|
118
|
+
console.log('⚠️ No macOS YAML files found, skipping merge');
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
|
122
|
+
// 3. 处理找到的文件,识别平台
|
123
|
+
const macFiles: Array<{
|
124
|
+
content: string;
|
125
|
+
filename: string;
|
126
|
+
platform: 'intel' | 'arm';
|
127
|
+
yaml: LatestMacYml;
|
128
|
+
}> = [];
|
129
|
+
|
130
|
+
for (const fileName of macYmlFiles) {
|
131
|
+
const filePath = path.join(RELEASE_DIR, fileName);
|
132
|
+
const content = readLocalFile(filePath);
|
133
|
+
|
134
|
+
if (!content) continue;
|
135
|
+
|
136
|
+
try {
|
137
|
+
const yamlContent = parse(content) as LatestMacYml;
|
138
|
+
const platform = detectPlatform(yamlContent);
|
139
|
+
|
140
|
+
if (platform === 'intel' || platform === 'arm') {
|
141
|
+
macFiles.push({ content, filename: fileName, platform, yaml: yamlContent });
|
142
|
+
console.log(`🔍 Detected ${platform} platform in ${fileName}`);
|
143
|
+
} else if (platform === 'both') {
|
144
|
+
console.log(`✅ Found already merged file: ${fileName}`);
|
145
|
+
// 如果已经是合并后的文件,直接复制为最终文件
|
146
|
+
writeLocalFile(path.join(RELEASE_DIR, FILE_NAME), content);
|
147
|
+
return;
|
148
|
+
} else {
|
149
|
+
console.log(`⚠️ Unknown platform type: ${platform} in ${fileName}`);
|
150
|
+
}
|
151
|
+
} catch (error) {
|
152
|
+
console.warn(`⚠️ Failed to parse ${fileName}:`, error);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
// 4. 检查是否有两个不同平台的文件
|
157
|
+
const intelFiles = macFiles.filter((f) => f.platform === 'intel');
|
158
|
+
const armFiles = macFiles.filter((f) => f.platform === 'arm');
|
159
|
+
|
160
|
+
if (intelFiles.length === 0 && armFiles.length === 0) {
|
161
|
+
console.log('⚠️ No valid platform files found');
|
162
|
+
return;
|
163
|
+
}
|
164
|
+
|
165
|
+
if (intelFiles.length === 0) {
|
166
|
+
console.log('⚠️ No Intel files found, using ARM only');
|
167
|
+
writeLocalFile(path.join(RELEASE_DIR, FILE_NAME), armFiles[0].content);
|
168
|
+
return;
|
169
|
+
}
|
170
|
+
|
171
|
+
if (armFiles.length === 0) {
|
172
|
+
console.log('⚠️ No ARM files found, using Intel only');
|
173
|
+
writeLocalFile(path.join(RELEASE_DIR, FILE_NAME), intelFiles[0].content);
|
174
|
+
return;
|
175
|
+
}
|
176
|
+
|
177
|
+
// 5. 合并 Intel 和 ARM 文件
|
178
|
+
const intelFile = intelFiles[0];
|
179
|
+
const armFile = armFiles[0];
|
180
|
+
|
181
|
+
console.log(`🔄 Merging ${intelFile.filename} (Intel) and ${armFile.filename} (ARM)...`);
|
182
|
+
const mergedContent = mergeYamlFiles(intelFile.yaml, armFile.yaml);
|
183
|
+
|
184
|
+
// 6. 保存合并后的文件
|
185
|
+
const mergedFilePath = path.join(RELEASE_DIR, FILE_NAME);
|
186
|
+
writeLocalFile(mergedFilePath, mergedContent);
|
187
|
+
|
188
|
+
// 7. 验证合并结果
|
189
|
+
const mergedYaml = parse(mergedContent) as LatestMacYml;
|
190
|
+
const finalPlatform = detectPlatform(mergedYaml);
|
191
|
+
|
192
|
+
if (finalPlatform === 'both') {
|
193
|
+
console.log('✅ Successfully merged both Intel and ARM platforms');
|
194
|
+
console.log(`📊 Final file contains ${mergedYaml.files.length} files`);
|
195
|
+
} else {
|
196
|
+
console.warn(`⚠️ Merge result unexpected: ${finalPlatform}`);
|
197
|
+
}
|
198
|
+
|
199
|
+
console.log('🎉 Merge complete!');
|
200
|
+
} catch (error) {
|
201
|
+
console.error('❌ Error during merge:', error);
|
202
|
+
process.exit(1);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
// 运行主函数
|
207
|
+
void main();
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { ChatCitationItem } from '@lobechat/types';
|
1
2
|
import { ActionIcon, CopyButton, Icon, Markdown, ScrollShadow } from '@lobehub/ui';
|
2
3
|
import { createStyles } from 'antd-style';
|
3
4
|
import { AnimatePresence, motion } from 'framer-motion';
|
@@ -7,8 +8,6 @@ import { CSSProperties, RefObject, memo, useEffect, useRef, useState } from 'rea
|
|
7
8
|
import { useTranslation } from 'react-i18next';
|
8
9
|
import { Flexbox } from 'react-layout-kit';
|
9
10
|
|
10
|
-
import { CitationItem } from '@/types/message';
|
11
|
-
|
12
11
|
const useStyles = createStyles(({ css, token }) => ({
|
13
12
|
container: css`
|
14
13
|
overflow: hidden;
|
@@ -74,7 +73,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
74
73
|
}));
|
75
74
|
|
76
75
|
interface ThinkingProps {
|
77
|
-
citations?:
|
76
|
+
citations?: ChatCitationItem[];
|
78
77
|
content?: string;
|
79
78
|
duration?: number;
|
80
79
|
style?: CSSProperties;
|
package/src/config/llm.ts
CHANGED
@@ -186,6 +186,10 @@ export const getLLMConfig = () => {
|
|
186
186
|
|
187
187
|
ENABLED_AIHUBMIX: z.boolean(),
|
188
188
|
AIHUBMIX_API_KEY: z.string().optional(),
|
189
|
+
|
190
|
+
ENABLED_NEWAPI: z.boolean(),
|
191
|
+
NEWAPI_API_KEY: z.string().optional(),
|
192
|
+
NEWAPI_PROXY_URL: z.string().optional(),
|
189
193
|
},
|
190
194
|
runtimeEnv: {
|
191
195
|
API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE,
|
@@ -368,6 +372,10 @@ export const getLLMConfig = () => {
|
|
368
372
|
ENABLED_AIHUBMIX: !!process.env.AIHUBMIX_API_KEY,
|
369
373
|
AIHUBMIX_API_KEY: process.env.AIHUBMIX_API_KEY,
|
370
374
|
|
375
|
+
ENABLED_NEWAPI: !!process.env.NEWAPI_API_KEY,
|
376
|
+
NEWAPI_API_KEY: process.env.NEWAPI_API_KEY,
|
377
|
+
NEWAPI_PROXY_URL: process.env.NEWAPI_PROXY_URL,
|
378
|
+
|
371
379
|
ENABLED_NEBIUS: !!process.env.NEBIUS_API_KEY,
|
372
380
|
NEBIUS_API_KEY: process.env.NEBIUS_API_KEY,
|
373
381
|
},
|
@@ -1,9 +1,11 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
3
|
import { ChatInput, ChatInputActionBar } from '@lobehub/editor/react';
|
4
|
+
import { Text } from '@lobehub/ui';
|
4
5
|
import { createStyles } from 'antd-style';
|
5
6
|
import { memo, useEffect } from 'react';
|
6
|
-
import {
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
7
9
|
|
8
10
|
import { useChatInputStore } from '@/features/ChatInput/store';
|
9
11
|
import { useChatStore } from '@/store/chat';
|
@@ -12,7 +14,6 @@ import { chatSelectors } from '@/store/chat/selectors';
|
|
12
14
|
import ActionBar from '../ActionBar';
|
13
15
|
import InputEditor from '../InputEditor';
|
14
16
|
import SendArea from '../SendArea';
|
15
|
-
import ShortcutHint from '../SendArea/ShortcutHint';
|
16
17
|
import TypoBar from '../TypoBar';
|
17
18
|
import FilePreview from './FilePreview';
|
18
19
|
|
@@ -28,6 +29,9 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
28
29
|
}
|
29
30
|
}
|
30
31
|
`,
|
32
|
+
footnote: css`
|
33
|
+
font-size: 10px;
|
34
|
+
`,
|
31
35
|
fullscreen: css`
|
32
36
|
position: absolute;
|
33
37
|
z-index: 100;
|
@@ -42,6 +46,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
42
46
|
}));
|
43
47
|
|
44
48
|
const DesktopChatInput = memo<{ showFootnote?: boolean }>(({ showFootnote }) => {
|
49
|
+
const { t } = useTranslation('chat');
|
45
50
|
const [slashMenuRef, expand, showTypoBar, editor, leftActions] = useChatInputStore((s) => [
|
46
51
|
s.slashMenuRef,
|
47
52
|
s.expand,
|
@@ -65,7 +70,8 @@ const DesktopChatInput = memo<{ showFootnote?: boolean }>(({ showFootnote }) =>
|
|
65
70
|
{!expand && fileNode}
|
66
71
|
<Flexbox
|
67
72
|
className={cx(styles.container, expand && styles.fullscreen)}
|
68
|
-
|
73
|
+
gap={8}
|
74
|
+
paddingBlock={showFootnote ? '0 8px' : '0 12px'}
|
69
75
|
paddingInline={12}
|
70
76
|
>
|
71
77
|
<ChatInput
|
@@ -85,7 +91,13 @@ const DesktopChatInput = memo<{ showFootnote?: boolean }>(({ showFootnote }) =>
|
|
85
91
|
{expand && fileNode}
|
86
92
|
<InputEditor />
|
87
93
|
</ChatInput>
|
88
|
-
{showFootnote && !expand &&
|
94
|
+
{showFootnote && !expand && (
|
95
|
+
<Center style={{ pointerEvents: 'none', zIndex: 100 }}>
|
96
|
+
<Text className={styles.footnote} type={'secondary'}>
|
97
|
+
{t('input.disclaimer')}
|
98
|
+
</Text>
|
99
|
+
</Center>
|
100
|
+
)}
|
89
101
|
</Flexbox>
|
90
102
|
</>
|
91
103
|
);
|
@@ -19,12 +19,14 @@ const StoreUpdater = memo<StoreUpdaterProps>(
|
|
19
19
|
rightActions,
|
20
20
|
onSend,
|
21
21
|
onMarkdownContentChange,
|
22
|
+
sendMenu,
|
22
23
|
}) => {
|
23
24
|
const storeApi = useStoreApi();
|
24
25
|
const useStoreUpdater = createStoreUpdater(storeApi);
|
25
26
|
const editor = useChatInputEditor();
|
26
27
|
|
27
28
|
useStoreUpdater('mobile', mobile);
|
29
|
+
useStoreUpdater('sendMenu', sendMenu);
|
28
30
|
useStoreUpdater('leftActions', leftActions);
|
29
31
|
useStoreUpdater('rightActions', rightActions);
|
30
32
|
|
package/src/libs/traces/index.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
+
import { CURRENT_VERSION } from '@lobechat/const';
|
1
2
|
import { Langfuse } from 'langfuse';
|
2
3
|
import { CreateLangfuseTraceBody } from 'langfuse-core';
|
3
4
|
|
4
|
-
import { CURRENT_VERSION } from '@/const/version';
|
5
5
|
import { getLangfuseConfig } from '@/envs/langfuse';
|
6
6
|
import { TraceEventClient } from '@/libs/traces/event';
|
7
7
|
|
@@ -1,9 +1,8 @@
|
|
1
|
+
import { INBOX_SESSION_ID, LOBE_CHAT_OBSERVATION_ID, LOBE_CHAT_TRACE_ID } from '@lobechat/const';
|
1
2
|
import { ChatStreamCallbacks, ChatStreamPayload } from '@lobechat/model-runtime';
|
2
3
|
import { TracePayload, TraceTagMap } from '@lobechat/types';
|
3
4
|
import { after } from 'next/server';
|
4
5
|
|
5
|
-
import { INBOX_SESSION_ID } from '@/const/session';
|
6
|
-
import { LOBE_CHAT_OBSERVATION_ID, LOBE_CHAT_TRACE_ID } from '@/const/trace';
|
7
6
|
import { TraceClient } from '@/libs/traces';
|
8
7
|
|
9
8
|
export interface AgentChatOptions {
|
@@ -0,0 +1,107 @@
|
|
1
|
+
import { act, renderHook } from '@testing-library/react';
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { useChatStore } from '../../../../store';
|
5
|
+
|
6
|
+
describe('Cancel send message functionality tests', () => {
|
7
|
+
describe('cancelSendMessageInServer', () => {
|
8
|
+
it('should be able to call cancel method normally', () => {
|
9
|
+
const { result } = renderHook(() => useChatStore());
|
10
|
+
|
11
|
+
// Initial state setup
|
12
|
+
act(() => {
|
13
|
+
useChatStore.setState({
|
14
|
+
activeId: 'session-1',
|
15
|
+
activeTopicId: 'topic-1',
|
16
|
+
mainSendMessageOperations: {},
|
17
|
+
});
|
18
|
+
});
|
19
|
+
|
20
|
+
// Test method exists
|
21
|
+
expect(typeof result.current.cancelSendMessageInServer).toBe('function');
|
22
|
+
|
23
|
+
// Test method can be called safely
|
24
|
+
expect(() => {
|
25
|
+
act(() => {
|
26
|
+
result.current.cancelSendMessageInServer();
|
27
|
+
});
|
28
|
+
}).not.toThrow();
|
29
|
+
});
|
30
|
+
|
31
|
+
it('should be able to call with specified topic ID', () => {
|
32
|
+
const { result } = renderHook(() => useChatStore());
|
33
|
+
|
34
|
+
act(() => {
|
35
|
+
useChatStore.setState({
|
36
|
+
activeId: 'session-1',
|
37
|
+
mainSendMessageOperations: {},
|
38
|
+
});
|
39
|
+
});
|
40
|
+
|
41
|
+
expect(() => {
|
42
|
+
act(() => {
|
43
|
+
result.current.cancelSendMessageInServer('topic-2');
|
44
|
+
});
|
45
|
+
}).not.toThrow();
|
46
|
+
});
|
47
|
+
});
|
48
|
+
|
49
|
+
describe('clearSendMessageError', () => {
|
50
|
+
it('should be able to call clear error method normally', () => {
|
51
|
+
const { result } = renderHook(() => useChatStore());
|
52
|
+
|
53
|
+
act(() => {
|
54
|
+
useChatStore.setState({
|
55
|
+
activeId: 'session-1',
|
56
|
+
activeTopicId: 'topic-1',
|
57
|
+
mainSendMessageOperations: {},
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
expect(typeof result.current.clearSendMessageError).toBe('function');
|
62
|
+
|
63
|
+
expect(() => {
|
64
|
+
act(() => {
|
65
|
+
result.current.clearSendMessageError();
|
66
|
+
});
|
67
|
+
}).not.toThrow();
|
68
|
+
});
|
69
|
+
});
|
70
|
+
|
71
|
+
describe('Internal methods', () => {
|
72
|
+
it('should have internal state management methods', () => {
|
73
|
+
const { result } = renderHook(() => useChatStore());
|
74
|
+
|
75
|
+
expect(typeof result.current.internal_toggleSendMessageOperation).toBe('function');
|
76
|
+
expect(typeof result.current.internal_updateSendMessageOperation).toBe('function');
|
77
|
+
});
|
78
|
+
|
79
|
+
it('internal_toggleSendMessageOperation should work normally', () => {
|
80
|
+
const { result } = renderHook(() => useChatStore());
|
81
|
+
|
82
|
+
act(() => {
|
83
|
+
useChatStore.setState({ mainSendMessageOperations: {} });
|
84
|
+
});
|
85
|
+
|
86
|
+
expect(() => {
|
87
|
+
act(() => {
|
88
|
+
const abortController = result.current.internal_toggleSendMessageOperation(
|
89
|
+
'test-key',
|
90
|
+
true,
|
91
|
+
);
|
92
|
+
expect(abortController).toBeInstanceOf(AbortController);
|
93
|
+
});
|
94
|
+
}).not.toThrow();
|
95
|
+
});
|
96
|
+
});
|
97
|
+
|
98
|
+
describe('State structure', () => {
|
99
|
+
it('should have mainSendMessageOperations state', () => {
|
100
|
+
const { result } = renderHook(() => useChatStore());
|
101
|
+
|
102
|
+
// Ensure state exists
|
103
|
+
expect(result.current.mainSendMessageOperations).toBeDefined();
|
104
|
+
expect(typeof result.current.mainSendMessageOperations).toBe('object');
|
105
|
+
});
|
106
|
+
});
|
107
|
+
});
|