@lobehub/lobehub 2.1.15 → 2.1.17
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/v2.json +14 -0
- package/locales/en-US/setting.json +3 -0
- package/locales/zh-CN/setting.json +3 -0
- package/package.json +1 -1
- package/packages/model-bank/src/aiModels/lobehub/chat/moonshot.ts +29 -0
- package/packages/model-bank/src/modelProviders/moonshot.ts +3 -4
- package/packages/model-runtime/src/core/RouterRuntime/baseRuntimeMap.ts +0 -2
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.test.ts +91 -0
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +21 -9
- package/packages/model-runtime/src/core/RouterRuntime/index.ts +1 -1
- package/packages/model-runtime/src/{providers/anthropic → core/anthropicCompatibleFactory}/generateObject.ts +1 -1
- package/packages/model-runtime/src/core/anthropicCompatibleFactory/index.ts +626 -0
- package/packages/model-runtime/src/providers/anthropic/index.test.ts +110 -103
- package/packages/model-runtime/src/providers/anthropic/index.ts +12 -281
- package/packages/model-runtime/src/providers/bedrock/index.ts +2 -2
- package/packages/model-runtime/src/providers/moonshot/index.test.ts +294 -328
- package/packages/model-runtime/src/providers/moonshot/index.ts +225 -79
- package/src/app/[variants]/(main)/agent/profile/features/Header/AgentPublishButton/PublishButton.tsx +52 -8
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx +52 -8
- package/src/locales/default/setting.ts +3 -0
- /package/packages/model-runtime/src/{providers/anthropic → core/anthropicCompatibleFactory}/generateObject.test.ts +0 -0
- /package/packages/model-runtime/src/{providers/anthropic → core/anthropicCompatibleFactory}/handleAnthropicError.ts +0 -0
- /package/packages/model-runtime/src/{providers/anthropic → core/anthropicCompatibleFactory}/resolveCacheTTL.ts +0 -0
- /package/packages/model-runtime/src/{providers/anthropic → core/anthropicCompatibleFactory}/resolveMaxTokens.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 2.1.17](https://github.com/lobehub/lobe-chat/compare/v2.1.16...v2.1.17)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-02-04**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **model-runtime**: Extract Anthropic factory and convert Moonshot to RouterRuntime.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **model-runtime**: Extract Anthropic factory and convert Moonshot to RouterRuntime, closes [#12109](https://github.com/lobehub/lobe-chat/issues/12109) ([71064fd](https://github.com/lobehub/lobe-chat/commit/71064fd))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 2.1.16](https://github.com/lobehub/lobe-chat/compare/v2.1.15...v2.1.16)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2026-02-04**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **misc**: Add the preview publish to market button preview check.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **misc**: Add the preview publish to market button preview check, closes [#12105](https://github.com/lobehub/lobe-chat/issues/12105) ([28887c7](https://github.com/lobehub/lobe-chat/commit/28887c7))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 2.1.15](https://github.com/lobehub/lobe-chat/compare/v2.1.14...v2.1.15)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2026-02-04**</sup>
|
package/changelog/v2.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {},
|
|
4
|
+
"date": "2026-02-04",
|
|
5
|
+
"version": "2.1.17"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"children": {
|
|
9
|
+
"fixes": [
|
|
10
|
+
"Add the preview publish to market button preview check."
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"date": "2026-02-04",
|
|
14
|
+
"version": "2.1.16"
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"children": {
|
|
4
18
|
"fixes": [
|
|
@@ -268,6 +268,9 @@
|
|
|
268
268
|
"marketPublish.upload.button": "Publish New Version",
|
|
269
269
|
"marketPublish.upload.tooltip": "Publish a new version to Agent Community",
|
|
270
270
|
"marketPublish.uploadGroup.tooltip": "Publish a new version to Group Community",
|
|
271
|
+
"marketPublish.validation.confirmPublish": "Are you sure you want to publish to the market?",
|
|
272
|
+
"marketPublish.validation.emptyName": "Cannot publish: Name is required",
|
|
273
|
+
"marketPublish.validation.emptySystemRole": "Cannot publish: System Role is required",
|
|
271
274
|
"memory.enabled.desc": "Allow LobeHub to extract preferences and info from conversations and use them later. You can view, edit, or clear memory anytime.",
|
|
272
275
|
"memory.enabled.title": "Enable Memory",
|
|
273
276
|
"memory.title": "Memory Settings",
|
|
@@ -268,6 +268,9 @@
|
|
|
268
268
|
"marketPublish.upload.button": "发布新版本",
|
|
269
269
|
"marketPublish.upload.tooltip": "发布新版本到助理社区",
|
|
270
270
|
"marketPublish.uploadGroup.tooltip": "向群组社区发布新版本",
|
|
271
|
+
"marketPublish.validation.confirmPublish": "确定要发布到市场吗?",
|
|
272
|
+
"marketPublish.validation.emptyName": "无法发布:名称不能为空",
|
|
273
|
+
"marketPublish.validation.emptySystemRole": "无法发布:系统角色不能为空",
|
|
271
274
|
"memory.enabled.desc": "允许 LobeHub 从对话中提取偏好和信息,并在之后使用。您可以随时查看、编辑或清除记忆内容。",
|
|
272
275
|
"memory.enabled.title": "启用记忆功能",
|
|
273
276
|
"memory.title": "记忆设置",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.17",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import { AIChatModelCard } from '../../../types/aiModel';
|
|
2
2
|
|
|
3
3
|
export const moonshotChatModels: AIChatModelCard[] = [
|
|
4
|
+
{
|
|
5
|
+
abilities: {
|
|
6
|
+
functionCall: true,
|
|
7
|
+
reasoning: true,
|
|
8
|
+
search: true,
|
|
9
|
+
structuredOutput: true,
|
|
10
|
+
vision: true,
|
|
11
|
+
},
|
|
12
|
+
contextWindowTokens: 262_144,
|
|
13
|
+
description:
|
|
14
|
+
'Kimi K2.5 is Kimi\'s most versatile model to date, featuring a native multimodal architecture that supports both vision and text inputs, "thinking" and "non-thinking" modes, and both conversational and agent tasks.',
|
|
15
|
+
displayName: 'Kimi K2.5',
|
|
16
|
+
enabled: true,
|
|
17
|
+
id: 'kimi-k2.5',
|
|
18
|
+
maxOutput: 32_768,
|
|
19
|
+
pricing: {
|
|
20
|
+
units: [
|
|
21
|
+
{ name: 'textInput', rate: 0.6, strategy: 'fixed', unit: 'millionTokens' },
|
|
22
|
+
{ name: 'textInput_cacheRead', rate: 0.1, strategy: 'fixed', unit: 'millionTokens' },
|
|
23
|
+
{ name: 'textOutput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
releasedAt: '2026-01-27',
|
|
27
|
+
settings: {
|
|
28
|
+
extendParams: ['enableReasoning'],
|
|
29
|
+
searchImpl: 'params',
|
|
30
|
+
},
|
|
31
|
+
type: 'chat',
|
|
32
|
+
},
|
|
4
33
|
{
|
|
5
34
|
abilities: {
|
|
6
35
|
functionCall: true,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type ModelProviderCard } from '@/types/llm';
|
|
2
2
|
|
|
3
|
-
// ref: https://platform.moonshot.cn/docs/intro#model-list
|
|
4
3
|
const Moonshot: ModelProviderCard = {
|
|
5
4
|
chatModels: [],
|
|
6
5
|
checkModel: 'kimi-latest',
|
|
@@ -8,12 +7,12 @@ const Moonshot: ModelProviderCard = {
|
|
|
8
7
|
'Moonshot, from Moonshot AI (Beijing Moonshot Technology), offers multiple NLP models for use cases like content creation, research, recommendations, and medical analysis, with strong long-context and complex generation support.',
|
|
9
8
|
id: 'moonshot',
|
|
10
9
|
modelList: { showModelFetcher: true },
|
|
11
|
-
modelsUrl: 'https://platform.moonshot.
|
|
10
|
+
modelsUrl: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
12
11
|
name: 'Moonshot',
|
|
13
12
|
settings: {
|
|
14
13
|
disableBrowserRequest: true, // CORS error
|
|
15
14
|
proxyUrl: {
|
|
16
|
-
placeholder: 'https://api.moonshot.
|
|
15
|
+
placeholder: 'https://api.moonshot.ai/v1',
|
|
17
16
|
},
|
|
18
17
|
responseAnimation: {
|
|
19
18
|
speed: 2,
|
|
@@ -22,7 +21,7 @@ const Moonshot: ModelProviderCard = {
|
|
|
22
21
|
sdkType: 'openai',
|
|
23
22
|
showModelFetcher: true,
|
|
24
23
|
},
|
|
25
|
-
url: 'https://www.moonshot.
|
|
24
|
+
url: 'https://www.moonshot.ai/',
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
export default Moonshot;
|
|
@@ -6,7 +6,6 @@ import { LobeDeepSeekAI } from '../../providers/deepseek';
|
|
|
6
6
|
import { LobeFalAI } from '../../providers/fal';
|
|
7
7
|
import { LobeGoogleAI } from '../../providers/google';
|
|
8
8
|
import { LobeMinimaxAI } from '../../providers/minimax';
|
|
9
|
-
import { LobeMoonshotAI } from '../../providers/moonshot';
|
|
10
9
|
import { LobeOpenAI } from '../../providers/openai';
|
|
11
10
|
import { LobeQwenAI } from '../../providers/qwen';
|
|
12
11
|
import { LobeVertexAI } from '../../providers/vertexai';
|
|
@@ -21,7 +20,6 @@ export const baseRuntimeMap = {
|
|
|
21
20
|
fal: LobeFalAI,
|
|
22
21
|
google: LobeGoogleAI,
|
|
23
22
|
minimax: LobeMinimaxAI,
|
|
24
|
-
moonshot: LobeMoonshotAI,
|
|
25
23
|
openai: LobeOpenAI,
|
|
26
24
|
qwen: LobeQwenAI,
|
|
27
25
|
vertexai: LobeVertexAI,
|
|
@@ -452,6 +452,97 @@ describe('createRouterRuntime', () => {
|
|
|
452
452
|
});
|
|
453
453
|
|
|
454
454
|
describe('router matching', () => {
|
|
455
|
+
describe('baseURLPattern matching', () => {
|
|
456
|
+
it('should match router by baseURLPattern (RegExp)', async () => {
|
|
457
|
+
const mockChatOpenAI = vi.fn().mockResolvedValue('openai-response');
|
|
458
|
+
const mockChatAnthropic = vi.fn().mockResolvedValue('anthropic-response');
|
|
459
|
+
|
|
460
|
+
class OpenAIRuntime implements LobeRuntimeAI {
|
|
461
|
+
chat = mockChatOpenAI;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
class AnthropicRuntime implements LobeRuntimeAI {
|
|
465
|
+
chat = mockChatAnthropic;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const Runtime = createRouterRuntime({
|
|
469
|
+
id: 'test-runtime',
|
|
470
|
+
routers: [
|
|
471
|
+
{
|
|
472
|
+
apiType: 'anthropic',
|
|
473
|
+
baseURLPattern: /\/anthropic\/?$/,
|
|
474
|
+
options: { apiKey: 'anthropic-key' },
|
|
475
|
+
runtime: AnthropicRuntime as any,
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
apiType: 'openai',
|
|
479
|
+
options: { apiKey: 'openai-key' },
|
|
480
|
+
runtime: OpenAIRuntime as any,
|
|
481
|
+
},
|
|
482
|
+
],
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
const runtime = new Runtime({
|
|
486
|
+
apiKey: 'test',
|
|
487
|
+
baseURL: 'https://api.example.com/anthropic',
|
|
488
|
+
});
|
|
489
|
+
const result = await runtime.chat({
|
|
490
|
+
model: 'test-model',
|
|
491
|
+
messages: [],
|
|
492
|
+
temperature: 0.7,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
expect(result).toBe('anthropic-response');
|
|
496
|
+
expect(mockChatAnthropic).toHaveBeenCalled();
|
|
497
|
+
expect(mockChatOpenAI).not.toHaveBeenCalled();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('should prioritize baseURLPattern over models matching', async () => {
|
|
501
|
+
const mockChatOpenAI = vi.fn().mockResolvedValue('openai-response');
|
|
502
|
+
const mockChatAnthropic = vi.fn().mockResolvedValue('anthropic-response');
|
|
503
|
+
|
|
504
|
+
class OpenAIRuntime implements LobeRuntimeAI {
|
|
505
|
+
chat = mockChatOpenAI;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
class AnthropicRuntime implements LobeRuntimeAI {
|
|
509
|
+
chat = mockChatAnthropic;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const Runtime = createRouterRuntime({
|
|
513
|
+
id: 'test-runtime',
|
|
514
|
+
routers: [
|
|
515
|
+
{
|
|
516
|
+
apiType: 'anthropic',
|
|
517
|
+
baseURLPattern: /\/anthropic\/?$/,
|
|
518
|
+
options: { apiKey: 'anthropic-key' },
|
|
519
|
+
runtime: AnthropicRuntime as any,
|
|
520
|
+
models: ['claude-3'],
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
apiType: 'openai',
|
|
524
|
+
options: { apiKey: 'openai-key' },
|
|
525
|
+
runtime: OpenAIRuntime as any,
|
|
526
|
+
models: ['gpt-4', 'test-model'], // includes test-model
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Even though 'test-model' matches OpenAI router, baseURLPattern should win
|
|
532
|
+
const runtime = new Runtime({
|
|
533
|
+
apiKey: 'test',
|
|
534
|
+
baseURL: 'https://api.example.com/anthropic',
|
|
535
|
+
});
|
|
536
|
+
const result = await runtime.chat({
|
|
537
|
+
model: 'test-model',
|
|
538
|
+
messages: [],
|
|
539
|
+
temperature: 0.7,
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
expect(result).toBe('anthropic-response');
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
455
546
|
it('should fallback to last router when model does not match any', async () => {
|
|
456
547
|
const mockChatFirst = vi.fn().mockResolvedValue('first-response');
|
|
457
548
|
const mockChatLast = vi.fn().mockResolvedValue('last-response');
|
|
@@ -58,10 +58,11 @@ interface RouterOptionItem extends ProviderIniOptions {
|
|
|
58
58
|
|
|
59
59
|
type RouterOptions = RouterOptionItem | RouterOptionItem[];
|
|
60
60
|
|
|
61
|
-
export type RuntimeClass =
|
|
61
|
+
export type RuntimeClass = new (options?: any) => LobeRuntimeAI;
|
|
62
62
|
|
|
63
63
|
interface RouterInstance {
|
|
64
64
|
apiType: keyof typeof baseRuntimeMap;
|
|
65
|
+
baseURLPattern?: RegExp;
|
|
65
66
|
models?: string[];
|
|
66
67
|
options: RouterOptions;
|
|
67
68
|
runtime?: RuntimeClass;
|
|
@@ -177,14 +178,25 @@ export const createRouterRuntime = ({
|
|
|
177
178
|
|
|
178
179
|
private async resolveMatchedRouter(model: string): Promise<RouterInstance> {
|
|
179
180
|
const resolvedRouters = await this.resolveRouters(model);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
181
|
+
const baseURL = this._options.baseURL;
|
|
182
|
+
|
|
183
|
+
// Priority 1: Match by baseURLPattern (RegExp only)
|
|
184
|
+
if (baseURL) {
|
|
185
|
+
const baseURLMatch = resolvedRouters.find((router) => router.baseURLPattern?.test(baseURL));
|
|
186
|
+
if (baseURLMatch) return baseURLMatch;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Priority 2: Match by models
|
|
190
|
+
const modelMatch = resolvedRouters.find((router) => {
|
|
191
|
+
if (router.models && router.models.length > 0) {
|
|
192
|
+
return router.models.includes(model);
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
});
|
|
196
|
+
if (modelMatch) return modelMatch;
|
|
197
|
+
|
|
198
|
+
// Fallback: Use the last router
|
|
199
|
+
return resolvedRouters.at(-1)!;
|
|
188
200
|
}
|
|
189
201
|
|
|
190
202
|
private normalizeRouterOptions(router: RouterInstance): RouterOptionItem[] {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import debug from 'debug';
|
|
3
3
|
|
|
4
|
-
import { buildAnthropicMessages, buildAnthropicTools } from '
|
|
4
|
+
import { buildAnthropicMessages, buildAnthropicTools } from '../contextBuilders/anthropic';
|
|
5
5
|
import { GenerateObjectOptions, GenerateObjectPayload } from '../../types';
|
|
6
6
|
|
|
7
7
|
const log = debug('lobe-model-runtime:anthropic:generate-object');
|