@lobehub/chat 1.124.1 → 1.124.3
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/package.json +1 -1
- package/packages/const/package.json +3 -1
- package/packages/const/src/analytics.ts +1 -1
- package/packages/const/src/desktop.ts +3 -2
- package/packages/const/src/discover.ts +3 -2
- package/packages/const/src/guide.ts +2 -2
- package/packages/const/src/hotkeys.ts +1 -1
- package/packages/const/src/index.ts +2 -0
- package/packages/const/src/settings/common.ts +1 -1
- package/packages/const/src/settings/genUserLLMConfig.test.ts +1 -2
- package/packages/const/src/settings/genUserLLMConfig.ts +1 -2
- package/packages/const/src/settings/hotkey.ts +3 -2
- package/packages/const/src/settings/index.ts +1 -3
- package/packages/const/src/settings/knowledge.ts +1 -1
- package/packages/const/src/settings/llm.ts +2 -4
- package/packages/const/src/settings/systemAgent.ts +1 -5
- package/packages/const/src/settings/tts.ts +1 -1
- package/packages/const/src/trace.ts +1 -1
- package/packages/const/src/url.ts +2 -2
- 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-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/higress/index.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/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/discover/index.ts +0 -8
- package/packages/types/src/index.ts +4 -0
- package/packages/types/src/message/base.ts +1 -1
- package/packages/types/src/openai/chat.ts +2 -3
- package/packages/types/src/tool/index.ts +1 -0
- package/packages/types/src/tool/tool.ts +1 -1
- package/packages/types/src/user/settings/index.ts +1 -2
- 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 -2
- 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/src/app/(backend)/webapi/models/[provider]/pull/route.ts +0 -2
- package/src/app/(backend)/webapi/models/[provider]/route.ts +0 -2
- package/src/app/(backend)/webapi/text-to-image/[provider]/route.ts +0 -2
- package/src/app/(backend)/webapi/trace/route.ts +0 -2
- package/src/components/Thinking/index.tsx +2 -3
- package/src/features/ChatInput/StoreUpdater.tsx +2 -0
- package/src/libs/traces/index.ts +1 -1
- package/src/server/modules/ModelRuntime/trace.ts +1 -2
- package/packages/const/src/settings/sync.ts +0 -5
- package/packages/model-runtime/src/openrouter/__snapshots__/index.test.ts.snap +0 -113
@@ -0,0 +1,61 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import * as fsPromises from 'node:fs/promises';
|
3
|
+
import path from 'node:path';
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
5
|
+
|
6
|
+
import { loadFile } from './loadFile';
|
7
|
+
|
8
|
+
const fixtures = path.join(__dirname, '../test/fixtures');
|
9
|
+
const fp = (name: string) => path.join(fixtures, name);
|
10
|
+
|
11
|
+
describe('loadFile', () => {
|
12
|
+
it('loads text-like files via TextLoader and aggregates', async () => {
|
13
|
+
const file = fp('test.txt');
|
14
|
+
const doc = await loadFile(file);
|
15
|
+
expect(doc.fileType).toBe('txt');
|
16
|
+
expect(doc.filename).toBe('test.txt');
|
17
|
+
expect(doc.source).toBe(file);
|
18
|
+
expect(doc.content).toContain('This is line 1.');
|
19
|
+
expect(doc.pages?.[0].metadata.lineNumberStart).toBe(1);
|
20
|
+
expect(doc.totalCharCount).toBeGreaterThan(0);
|
21
|
+
expect(doc.totalLineCount).toBeGreaterThan(0);
|
22
|
+
});
|
23
|
+
|
24
|
+
it('loads pdf files via PdfLoader and aggregates', async () => {
|
25
|
+
const file = fp('test.pdf');
|
26
|
+
const doc = await loadFile(file);
|
27
|
+
expect(doc.fileType).toBe('pdf');
|
28
|
+
expect(doc.filename).toBe('test.pdf');
|
29
|
+
expect(doc.source).toBe(file);
|
30
|
+
expect(doc.content).toContain('123');
|
31
|
+
expect(doc.pages && doc.pages.length).toBeGreaterThan(0);
|
32
|
+
});
|
33
|
+
|
34
|
+
it('returns error page when fs.stat fails', async () => {
|
35
|
+
const doc = await loadFile('/not/exists.xyz');
|
36
|
+
expect(doc.pages).toHaveLength(1);
|
37
|
+
expect(doc.pages?.[0].metadata.error).toContain('Failed to access file stats:');
|
38
|
+
expect(doc.metadata.error).toContain('Failed to access file stats:');
|
39
|
+
});
|
40
|
+
|
41
|
+
it('falls back to TextLoader for unsupported type and warns', async () => {
|
42
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
43
|
+
const doc = await loadFile(fp('test.epub')); // epub is unsupported in current mapping
|
44
|
+
expect(warn).toHaveBeenCalled();
|
45
|
+
expect(doc.content.length).toBeGreaterThanOrEqual(0);
|
46
|
+
warn.mockRestore();
|
47
|
+
});
|
48
|
+
|
49
|
+
it('allows overriding metadata via second parameter', async () => {
|
50
|
+
const file = fp('test.txt');
|
51
|
+
const override = {
|
52
|
+
source: 's3://bucket/key',
|
53
|
+
filename: 'override.txt',
|
54
|
+
fileType: 'custom',
|
55
|
+
};
|
56
|
+
const doc = await loadFile(file, override);
|
57
|
+
expect(doc.source).toBe('s3://bucket/key');
|
58
|
+
expect(doc.filename).toBe('override.txt');
|
59
|
+
expect(doc.fileType).toBe('custom');
|
60
|
+
});
|
61
|
+
});
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
2
|
+
|
3
|
+
import { isTextReadableFile } from './isTextReadableFile';
|
4
|
+
|
5
|
+
describe('isTextReadableFile', () => {
|
6
|
+
it('should return true for common text-readable types', () => {
|
7
|
+
const positives = [
|
8
|
+
'txt',
|
9
|
+
'md',
|
10
|
+
'mdx',
|
11
|
+
'json',
|
12
|
+
'yaml',
|
13
|
+
'yml',
|
14
|
+
'csv',
|
15
|
+
'html',
|
16
|
+
'css',
|
17
|
+
'js',
|
18
|
+
'ts',
|
19
|
+
'py',
|
20
|
+
'log',
|
21
|
+
'sql',
|
22
|
+
'patch',
|
23
|
+
'diff',
|
24
|
+
];
|
25
|
+
|
26
|
+
for (const ext of positives) {
|
27
|
+
expect(isTextReadableFile(ext)).toBe(true);
|
28
|
+
}
|
29
|
+
});
|
30
|
+
|
31
|
+
it('should be case-insensitive', () => {
|
32
|
+
expect(isTextReadableFile('Md')).toBe(true);
|
33
|
+
expect(isTextReadableFile('JSON')).toBe(true);
|
34
|
+
expect(isTextReadableFile('YML')).toBe(true);
|
35
|
+
});
|
36
|
+
|
37
|
+
it('should return false for non text-readable or binary types', () => {
|
38
|
+
const negatives = ['pdf', 'docx', 'xlsx', 'pptx', 'png', 'jpg', 'gif'];
|
39
|
+
for (const ext of negatives) {
|
40
|
+
expect(isTextReadableFile(ext)).toBe(false);
|
41
|
+
}
|
42
|
+
});
|
43
|
+
});
|
@@ -0,0 +1,155 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { type ExtractedFile, extractFiles, parseString } from './parser-utils';
|
5
|
+
|
6
|
+
describe('parser-utils', () => {
|
7
|
+
describe('parseString', () => {
|
8
|
+
it('should parse valid XML string into XMLDocument', () => {
|
9
|
+
const xml = '<root><item id="1">hello</item></root>';
|
10
|
+
const doc = parseString(xml);
|
11
|
+
|
12
|
+
// The parsed document should contain the root and item node
|
13
|
+
const root = (doc as any).getElementsByTagName('root')[0];
|
14
|
+
expect(root).toBeDefined();
|
15
|
+
const item = (doc as any).getElementsByTagName('item')[0];
|
16
|
+
expect(item).toBeDefined();
|
17
|
+
expect(item.getAttribute('id')).toBe('1');
|
18
|
+
expect(item.textContent).toBe('hello');
|
19
|
+
});
|
20
|
+
});
|
21
|
+
|
22
|
+
describe('extractFiles', () => {
|
23
|
+
beforeEach(() => {
|
24
|
+
vi.resetModules();
|
25
|
+
});
|
26
|
+
|
27
|
+
it('should reject on invalid input type', async () => {
|
28
|
+
// @ts-expect-error intentional wrong type
|
29
|
+
await expect(extractFiles(123, () => true)).rejects.toThrow(
|
30
|
+
'[OfficeParser]: Invalid input type',
|
31
|
+
);
|
32
|
+
});
|
33
|
+
|
34
|
+
it('should read entries via yauzl.fromBuffer and filter matches', async () => {
|
35
|
+
// Arrange: build a fake zipfile object with two file entries and one directory
|
36
|
+
const entryHandlers: Record<string, (cb: () => void) => void> = {};
|
37
|
+
const listeners: Record<string, Function[]> = { entry: [], end: [], error: [] };
|
38
|
+
let idx = 0;
|
39
|
+
const sequence = [
|
40
|
+
{ fileName: 'folder/' },
|
41
|
+
{ fileName: 'keep.txt' },
|
42
|
+
{ fileName: 'skip.bin' },
|
43
|
+
];
|
44
|
+
|
45
|
+
const emit = (name: string, payload?: any) =>
|
46
|
+
(listeners[name] || []).forEach((fn) => fn(payload));
|
47
|
+
|
48
|
+
const fakeZipfile = {
|
49
|
+
readEntry: vi.fn().mockImplementation(() => {
|
50
|
+
queueMicrotask(() => {
|
51
|
+
if (idx < sequence.length) {
|
52
|
+
const entry = sequence[idx++];
|
53
|
+
emit('entry', entry as any);
|
54
|
+
} else {
|
55
|
+
emit('end');
|
56
|
+
}
|
57
|
+
});
|
58
|
+
}),
|
59
|
+
openReadStream: vi.fn((entry: any, cb: (err: any, stream?: any) => void) => {
|
60
|
+
if (entry.fileName === 'keep.txt') {
|
61
|
+
// Provide a minimal readable stream compatible with concat-stream
|
62
|
+
const chunks: any[] = [];
|
63
|
+
const stream = {
|
64
|
+
pipe(destination: any) {
|
65
|
+
// emulate piping to concat-stream writable
|
66
|
+
if (typeof destination.end === 'function') {
|
67
|
+
destination.end(Buffer.from('hello world'));
|
68
|
+
}
|
69
|
+
return destination;
|
70
|
+
},
|
71
|
+
on: vi.fn(),
|
72
|
+
};
|
73
|
+
cb(null, stream);
|
74
|
+
} else if (entry.fileName === 'skip.bin') {
|
75
|
+
// This entry should be skipped by filter, so not invoked
|
76
|
+
cb(null, undefined as any);
|
77
|
+
}
|
78
|
+
}),
|
79
|
+
on: vi.fn((evt: string, handler: Function) => {
|
80
|
+
listeners[evt] = listeners[evt] || [];
|
81
|
+
listeners[evt].push(handler);
|
82
|
+
}),
|
83
|
+
close: vi.fn(),
|
84
|
+
} as any;
|
85
|
+
|
86
|
+
// Mock yauzl.fromBuffer to pass back our fake zipfile
|
87
|
+
vi.doMock('yauzl', () => ({
|
88
|
+
default: {
|
89
|
+
fromBuffer: (_buf: Buffer, _opts: any, cb: (err: any, zf?: any) => void) =>
|
90
|
+
cb(null, fakeZipfile),
|
91
|
+
open: vi.fn(),
|
92
|
+
},
|
93
|
+
}));
|
94
|
+
|
95
|
+
// Re-import module to use mocked yauzl
|
96
|
+
const { extractFiles: mockedExtractFiles } = await import('./parser-utils');
|
97
|
+
|
98
|
+
const files: ExtractedFile[] = await mockedExtractFiles(Buffer.from('zip'), (name) =>
|
99
|
+
name.endsWith('.txt'),
|
100
|
+
);
|
101
|
+
expect(files).toEqual([{ path: 'keep.txt', content: 'hello world' }]);
|
102
|
+
});
|
103
|
+
|
104
|
+
it('should open zip by file path when input is string', async () => {
|
105
|
+
const listeners: Record<string, Function[]> = { entry: [], end: [], error: [] };
|
106
|
+
let idx = 0;
|
107
|
+
const entries = [{ fileName: 'keep.txt' }];
|
108
|
+
const emit2 = (name: string, payload?: any) =>
|
109
|
+
(listeners[name] || []).forEach((fn) => fn(payload));
|
110
|
+
|
111
|
+
const fakeZipfile = {
|
112
|
+
readEntry: vi.fn().mockImplementation(() => {
|
113
|
+
queueMicrotask(() => {
|
114
|
+
if (idx < entries.length) {
|
115
|
+
const entry = entries[idx++];
|
116
|
+
emit2('entry', entry as any);
|
117
|
+
} else {
|
118
|
+
emit2('end');
|
119
|
+
}
|
120
|
+
});
|
121
|
+
}),
|
122
|
+
openReadStream: vi.fn((entry: any, cb: (err: any, stream?: any) => void) => {
|
123
|
+
const stream = {
|
124
|
+
pipe(destination: any) {
|
125
|
+
if (typeof destination.end === 'function') {
|
126
|
+
destination.end(Buffer.from('A'));
|
127
|
+
}
|
128
|
+
return destination;
|
129
|
+
},
|
130
|
+
on: vi.fn(),
|
131
|
+
};
|
132
|
+
cb(null, stream);
|
133
|
+
}),
|
134
|
+
on: vi.fn((evt: string, handler: Function) => {
|
135
|
+
listeners[evt] = listeners[evt] || [];
|
136
|
+
listeners[evt].push(handler);
|
137
|
+
}),
|
138
|
+
close: vi.fn(),
|
139
|
+
} as any;
|
140
|
+
|
141
|
+
vi.doMock('yauzl', () => ({
|
142
|
+
default: {
|
143
|
+
fromBuffer: vi.fn(),
|
144
|
+
open: (_path: string, _opts: any, cb: (err: any, zf?: any) => void) =>
|
145
|
+
cb(null, fakeZipfile),
|
146
|
+
},
|
147
|
+
}));
|
148
|
+
|
149
|
+
const { extractFiles: mockedExtractFiles } = await import('./parser-utils');
|
150
|
+
|
151
|
+
const files = await mockedExtractFiles('/tmp/file.zip', (name) => name === 'keep.txt');
|
152
|
+
expect(files).toEqual([{ path: 'keep.txt', content: 'A' }]);
|
153
|
+
});
|
154
|
+
});
|
155
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeAi21AI } from './index';
|
6
6
|
|
7
7
|
testProvider({
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeAi360AI } from './index';
|
6
6
|
|
7
7
|
testProvider({
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
3
|
+
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
|
+
import { LobeAkashChatAI } from './index';
|
6
|
+
|
7
|
+
const provider = ModelProvider.AkashChat;
|
8
|
+
const defaultBaseURL = 'https://chatapi.akash.network/api/v1';
|
9
|
+
|
10
|
+
testProvider({
|
11
|
+
Runtime: LobeAkashChatAI,
|
12
|
+
provider,
|
13
|
+
defaultBaseURL,
|
14
|
+
chatDebugEnv: 'DEBUG_AKASH_CHAT_COMPLETION',
|
15
|
+
chatModel: 'llama-3.1-8b-instruct',
|
16
|
+
test: {
|
17
|
+
skipAPICall: true,
|
18
|
+
},
|
19
|
+
});
|
@@ -1,8 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
+
import { ChatCompletionTool, ChatStreamPayload } from '@lobechat/model-runtime';
|
2
3
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import { ChatCompletionTool, ChatStreamPayload } from '@/libs/model-runtime';
|
5
|
-
|
6
5
|
import * as anthropicHelpers from '../utils/anthropicHelpers';
|
7
6
|
import * as debugStreamModule from '../utils/debugStream';
|
8
7
|
import { LobeAnthropicAI } from './index';
|
@@ -1,8 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
+
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@lobechat/model-runtime';
|
2
3
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@/libs/model-runtime';
|
5
|
-
|
6
5
|
import { testProvider } from '../providerTestUtils';
|
7
6
|
import { LobeBaichuanAI } from './index';
|
8
7
|
|
@@ -1,9 +1,8 @@
|
|
1
1
|
// @vitest-environment node
|
2
2
|
import { InvokeModelWithResponseStreamCommand } from '@aws-sdk/client-bedrock-runtime';
|
3
|
+
import { AgentRuntimeErrorType, ModelProvider } from '@lobechat/model-runtime';
|
3
4
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
4
5
|
|
5
|
-
import { AgentRuntimeErrorType, ModelProvider } from '@/libs/model-runtime';
|
6
|
-
|
7
6
|
import * as debugStreamModule from '../utils/debugStream';
|
8
7
|
import { LobeBedrockAI } from './index';
|
9
8
|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
3
|
|
4
|
-
import { CreateImagePayload } from '
|
5
|
-
|
4
|
+
import { CreateImagePayload } from '../types/image';
|
6
5
|
import { createBflImage } from './createImage';
|
7
6
|
import { BflStatusResponse } from './types';
|
8
7
|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
3
|
|
4
|
-
import { CreateImagePayload } from '
|
5
|
-
|
4
|
+
import { CreateImagePayload } from '../types/image';
|
6
5
|
import { LobeBflAI } from './index';
|
7
6
|
|
8
7
|
// Mock the createBflImage function
|
@@ -1,8 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
+
import { ChatCompletionTool } from '@lobechat/model-runtime';
|
2
3
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import { ChatCompletionTool } from '@/libs/model-runtime';
|
5
|
-
|
6
5
|
import * as debugStreamModule from '../utils/debugStream';
|
7
6
|
import { LobeCloudflareAI } from './index';
|
8
7
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
3
|
+
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
|
+
import { LobeCohereAI } from './index';
|
6
|
+
|
7
|
+
const provider = ModelProvider.Cohere;
|
8
|
+
const defaultBaseURL = 'https://api.cohere.ai/compatibility/v1';
|
9
|
+
|
10
|
+
testProvider({
|
11
|
+
Runtime: LobeCohereAI,
|
12
|
+
provider,
|
13
|
+
defaultBaseURL,
|
14
|
+
chatDebugEnv: 'DEBUG_COHERE_CHAT_COMPLETION',
|
15
|
+
chatModel: 'command-r7b',
|
16
|
+
test: {
|
17
|
+
skipAPICall: true,
|
18
|
+
},
|
19
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeDeepSeekAI } from './index';
|
6
6
|
|
7
7
|
const provider = ModelProvider.DeepSeek;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeFireworksAI } from './index';
|
6
6
|
|
7
7
|
const provider = ModelProvider.FireworksAI;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeGiteeAI } from './index';
|
6
6
|
|
7
7
|
testProvider({
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeGithubAI } from './index';
|
6
6
|
|
7
7
|
testProvider({
|
@@ -2,8 +2,7 @@
|
|
2
2
|
import { GoogleGenAI } from '@google/genai';
|
3
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
4
4
|
|
5
|
-
import { CreateImagePayload } from '
|
6
|
-
|
5
|
+
import { CreateImagePayload } from '../types/image';
|
7
6
|
import * as imageToBase64Module from '../utils/imageToBase64';
|
8
7
|
import { createGoogleImage } from './createImage';
|
9
8
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
// @vitest-environment edge-runtime
|
2
2
|
import { GenerateContentResponse, Tool } from '@google/genai';
|
3
|
+
import { OpenAIChatMessage } from '@lobechat/model-runtime';
|
3
4
|
import OpenAI from 'openai';
|
4
5
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
5
6
|
|
6
|
-
import { OpenAIChatMessage } from '@/libs/model-runtime';
|
7
7
|
import { ChatStreamPayload } from '@/types/openai/chat';
|
8
8
|
|
9
9
|
import * as debugStreamModule from '../utils/debugStream';
|
@@ -1,9 +1,8 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
+
import { LobeOpenAICompatibleRuntime } from '@lobechat/model-runtime';
|
2
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import {
|
5
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
6
|
-
|
5
|
+
import { testProvider } from '../providerTestUtils';
|
7
6
|
import { LobeGroq } from './index';
|
8
7
|
|
9
8
|
testProvider({
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
import type { ChatModelCard } from '@/types/llm';
|
1
|
+
import type { ChatModelCard } from '@lobechat/types';
|
2
|
+
import uniqueId from 'lodash-es/uniqueId';
|
4
3
|
|
5
4
|
import { ModelProvider } from '../types';
|
6
5
|
import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
|
@@ -0,0 +1,40 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
4
|
+
|
5
|
+
import { LobeHuggingFaceAI } from './index';
|
6
|
+
|
7
|
+
describe('LobeHuggingFaceAI', () => {
|
8
|
+
let instance: any;
|
9
|
+
|
10
|
+
beforeEach(() => {
|
11
|
+
instance = new LobeHuggingFaceAI({ apiKey: 'test' });
|
12
|
+
|
13
|
+
const mockAsyncIterable = {
|
14
|
+
async *[Symbol.asyncIterator]() {
|
15
|
+
yield { choices: [] } as any;
|
16
|
+
},
|
17
|
+
} as any;
|
18
|
+
|
19
|
+
// mock custom client's chatCompletionStream
|
20
|
+
instance['client'] = {
|
21
|
+
chatCompletionStream: vi.fn().mockReturnValue(mockAsyncIterable),
|
22
|
+
} as any;
|
23
|
+
});
|
24
|
+
|
25
|
+
it('should initialize and return StreamingTextResponse on chat', async () => {
|
26
|
+
const res = await instance.chat({
|
27
|
+
messages: [{ role: 'user', content: 'hello' }],
|
28
|
+
model: 'meta-llama/Meta-Llama-3.1-8B-Instruct',
|
29
|
+
temperature: 0,
|
30
|
+
stream: true,
|
31
|
+
});
|
32
|
+
|
33
|
+
expect(res).toBeInstanceOf(Response);
|
34
|
+
});
|
35
|
+
|
36
|
+
it('should set provider id properly', async () => {
|
37
|
+
// provider id 用于错误封装等,这里验证暴露 id 一致
|
38
|
+
expect(ModelProvider.HuggingFace).toBe('huggingface');
|
39
|
+
});
|
40
|
+
});
|
@@ -1,9 +1,8 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
+
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@lobechat/model-runtime';
|
2
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import {
|
5
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
6
|
-
|
5
|
+
import { testProvider } from '../providerTestUtils';
|
7
6
|
import { LobeHunyuanAI } from './index';
|
8
7
|
|
9
8
|
testProvider({
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeInternLMAI } from './index';
|
6
6
|
|
7
7
|
testProvider({
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
3
|
+
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
|
+
import { LobeJinaAI } from './index';
|
6
|
+
|
7
|
+
const provider = ModelProvider.Jina;
|
8
|
+
const defaultBaseURL = 'https://deepsearch.jina.ai/v1';
|
9
|
+
|
10
|
+
testProvider({
|
11
|
+
Runtime: LobeJinaAI,
|
12
|
+
provider,
|
13
|
+
defaultBaseURL,
|
14
|
+
chatDebugEnv: 'DEBUG_JINA_CHAT_COMPLETION',
|
15
|
+
chatModel: 'jina-embeddings-v3',
|
16
|
+
test: {
|
17
|
+
skipAPICall: true,
|
18
|
+
},
|
19
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import { ModelProvider } from '
|
3
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
4
3
|
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
5
|
import { LobeLMStudioAI } from './index';
|
6
6
|
|
7
7
|
const provider = ModelProvider.LMStudio;
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
3
|
+
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
|
+
import { LobeMinimaxAI } from './index';
|
6
|
+
|
7
|
+
const provider = ModelProvider.Minimax;
|
8
|
+
const defaultBaseURL = 'https://api.minimax.chat/v1';
|
9
|
+
|
10
|
+
testProvider({
|
11
|
+
Runtime: LobeMinimaxAI,
|
12
|
+
provider,
|
13
|
+
defaultBaseURL,
|
14
|
+
chatDebugEnv: 'DEBUG_MINIMAX_CHAT_COMPLETION',
|
15
|
+
chatModel: 'abab6.5s-chat',
|
16
|
+
test: {
|
17
|
+
skipAPICall: true,
|
18
|
+
},
|
19
|
+
});
|
@@ -1,9 +1,8 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
+
import { LobeOpenAICompatibleRuntime } from '@lobechat/model-runtime';
|
2
3
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import {
|
5
|
-
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
|
6
|
-
|
5
|
+
import { testProvider } from '../providerTestUtils';
|
7
6
|
import { LobeMistralAI } from './index';
|
8
7
|
|
9
8
|
testProvider({
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { ModelProvider } from '@lobechat/model-runtime';
|
3
|
+
|
4
|
+
import { testProvider } from '../providerTestUtils';
|
5
|
+
import { LobeModelScopeAI } from './index';
|
6
|
+
|
7
|
+
const provider = ModelProvider.ModelScope;
|
8
|
+
const defaultBaseURL = 'https://api-inference.modelscope.cn/v1';
|
9
|
+
|
10
|
+
testProvider({
|
11
|
+
Runtime: LobeModelScopeAI,
|
12
|
+
provider,
|
13
|
+
defaultBaseURL,
|
14
|
+
chatDebugEnv: 'DEBUG_MODELSCOPE_CHAT_COMPLETION',
|
15
|
+
chatModel: 'qwen2-7b-instruct',
|
16
|
+
test: {
|
17
|
+
skipAPICall: true,
|
18
|
+
},
|
19
|
+
});
|