@lobehub/chat 1.111.10 → 1.111.12

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.
Files changed (59) hide show
  1. package/.github/workflows/claude-code-review.yml +12 -12
  2. package/.github/workflows/claude.yml +9 -9
  3. package/.vscode/extensions.json +13 -0
  4. package/.vscode/settings.json +89 -0
  5. package/CHANGELOG.md +42 -0
  6. package/CLAUDE.md +117 -0
  7. package/changelog/v1.json +14 -0
  8. package/docs/development/state-management/state-management-intro.mdx +2 -2
  9. package/docs/development/state-management/state-management-intro.zh-CN.mdx +2 -2
  10. package/package.json +1 -1
  11. package/packages/model-runtime/src/RouterRuntime/createRuntime.ts +9 -1
  12. package/packages/model-runtime/src/ai302/index.ts +1 -1
  13. package/packages/model-runtime/src/aihubmix/index.ts +28 -71
  14. package/packages/model-runtime/src/anthropic/index.ts +6 -26
  15. package/packages/model-runtime/src/giteeai/index.ts +2 -37
  16. package/packages/model-runtime/src/github/index.ts +33 -44
  17. package/packages/model-runtime/src/modelscope/index.ts +2 -38
  18. package/packages/model-runtime/src/moonshot/index.ts +2 -36
  19. package/packages/model-runtime/src/novita/__snapshots__/index.test.ts.snap +40 -22
  20. package/packages/model-runtime/src/novita/index.ts +1 -32
  21. package/packages/model-runtime/src/nvidia/index.ts +1 -1
  22. package/packages/model-runtime/src/openai/__snapshots__/index.test.ts.snap +63 -7
  23. package/packages/model-runtime/src/openai/index.ts +1 -1
  24. package/packages/model-runtime/src/openrouter/__snapshots__/index.test.ts.snap +6 -21
  25. package/packages/model-runtime/src/openrouter/index.ts +29 -37
  26. package/packages/model-runtime/src/qiniu/index.ts +3 -27
  27. package/packages/model-runtime/src/qwen/index.ts +1 -1
  28. package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
  29. package/packages/model-runtime/src/utils/modelParse.test.ts +6 -6
  30. package/packages/model-runtime/src/utils/modelParse.ts +238 -40
  31. package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.test.ts +18 -0
  32. package/packages/model-runtime/src/utils/streams/openai/openai.ts +12 -0
  33. package/packages/model-runtime/src/v0/index.ts +2 -2
  34. package/packages/model-runtime/src/volcengine/index.ts +1 -1
  35. package/packages/model-runtime/src/xai/index.ts +2 -24
  36. package/packages/model-runtime/src/zhipu/index.ts +1 -1
  37. package/src/config/aiModels/aihubmix.ts +1 -9
  38. package/src/config/aiModels/anthropic.ts +24 -4
  39. package/src/config/aiModels/fal.ts +20 -3
  40. package/src/config/aiModels/google.ts +60 -6
  41. package/src/config/aiModels/groq.ts +4 -21
  42. package/src/config/aiModels/hunyuan.ts +1 -1
  43. package/src/config/aiModels/mistral.ts +22 -5
  44. package/src/config/aiModels/moonshot.ts +20 -0
  45. package/src/config/aiModels/openai.ts +0 -45
  46. package/src/config/aiModels/qwen.ts +113 -3
  47. package/src/config/aiModels/sensenova.ts +6 -6
  48. package/src/config/aiModels/siliconcloud.ts +80 -0
  49. package/src/config/aiModels/stepfun.ts +38 -4
  50. package/src/config/aiModels/zhipu.ts +33 -8
  51. package/src/config/modelProviders/aihubmix.ts +1 -1
  52. package/src/config/modelProviders/mistral.ts +1 -0
  53. package/src/config/modelProviders/openai.ts +1 -1
  54. package/src/config/modelProviders/qwen.ts +1 -1
  55. package/src/config/modelProviders/v0.ts +1 -0
  56. package/src/config/modelProviders/volcengine.ts +1 -0
  57. package/src/server/routers/async/image.ts +1 -0
  58. package/src/services/file/_deprecated.ts +1 -1
  59. package/src/store/file/slices/upload/action.ts +1 -1
@@ -17,14 +17,14 @@ jobs:
17
17
  # github.event.pull_request.user.login == 'external-contributor' ||
18
18
  # github.event.pull_request.user.login == 'new-developer' ||
19
19
  # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
20
-
20
+
21
21
  runs-on: ubuntu-latest
22
22
  permissions:
23
23
  contents: read
24
24
  pull-requests: read
25
25
  issues: read
26
26
  id-token: write
27
-
27
+
28
28
  steps:
29
29
  - name: Checkout repository
30
30
  uses: actions/checkout@v4
@@ -38,8 +38,9 @@ jobs:
38
38
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
39
39
 
40
40
  # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
41
- # model: "claude-opus-4-20250514"
42
-
41
+ model: 'claude-opus-4-1-20250805'
42
+ allowed_bots: 'bot'
43
+
43
44
  # Direct prompt for automated review (no @claude mention needed)
44
45
  direct_prompt: |
45
46
  Please review this pull request and provide feedback on:
@@ -48,12 +49,12 @@ jobs:
48
49
  - Performance considerations
49
50
  - Security concerns
50
51
  - Test coverage
51
-
52
+
52
53
  Be constructive and helpful in your feedback.
53
54
 
54
55
  # Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
55
56
  # use_sticky_comment: true
56
-
57
+
57
58
  # Optional: Customize review based on file types
58
59
  # direct_prompt: |
59
60
  # Review this PR focusing on:
@@ -61,18 +62,17 @@ jobs:
61
62
  # - For API endpoints: Security, input validation, and error handling
62
63
  # - For React components: Performance, accessibility, and best practices
63
64
  # - For tests: Coverage, edge cases, and test quality
64
-
65
+
65
66
  # Optional: Different prompts for different authors
66
67
  # direct_prompt: |
67
- # ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' &&
68
+ # ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' &&
68
69
  # 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' ||
69
70
  # 'Please provide a thorough code review focusing on our coding standards and best practices.' }}
70
-
71
+
71
72
  # Optional: Add specific tools for running tests or linting
72
- # allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
73
-
73
+ allowed_tools: 'Bash(bun run:*),Bash(pnpm run:*),Bash(npm run:*),Bash(npx vitest:*),Bash(rg:*),Bash(find:*),Bash(sed:*),Bash(grep:*),Bash(awk:*),Bash(wc:*),Bash(xargs:*)'
74
+
74
75
  # Optional: Skip review for certain conditions
75
76
  # if: |
76
77
  # !contains(github.event.pull_request.title, '[skip-review]') &&
77
78
  # !contains(github.event.pull_request.title, '[WIP]')
78
-
@@ -39,26 +39,26 @@ jobs:
39
39
  # This is an optional setting that allows Claude to read CI results on PRs
40
40
  additional_permissions: |
41
41
  actions: read
42
-
42
+
43
43
  # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
44
- # model: "claude-opus-4-20250514"
45
-
44
+ model: 'claude-opus-4-1-20250805'
45
+ allowed_bots: 'bot'
46
+
46
47
  # Optional: Customize the trigger phrase (default: @claude)
47
48
  # trigger_phrase: "/claude"
48
-
49
+
49
50
  # Optional: Trigger when specific user is assigned to an issue
50
51
  # assignee_trigger: "claude-bot"
51
-
52
+
52
53
  # Optional: Allow Claude to run specific commands
53
- # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
54
-
54
+ allowed_tools: 'Bash(bun run:*),Bash(pnpm run:*),Bash(npm run:*),Bash(npx vitest:*),Bash(rg:*),Bash(find:*),Bash(sed:*),Bash(grep:*),Bash(awk:*),Bash(wc:*),Bash(xargs:*)'
55
+
55
56
  # Optional: Add custom instructions for Claude to customize its behavior for your project
56
57
  # custom_instructions: |
57
58
  # Follow our coding standards
58
59
  # Ensure all new code has tests
59
60
  # Use TypeScript for new files
60
-
61
+
61
62
  # Optional: Custom environment variables for Claude
62
63
  # claude_env: |
63
64
  # NODE_ENV: test
64
-
@@ -0,0 +1,13 @@
1
+ {
2
+ "recommendations": [
3
+ "Anthropic.claude-code",
4
+ "dbaeumer.vscode-eslint",
5
+ "jrr997.antd-docs",
6
+ "seatonjiang.gitmoji-vscode",
7
+ "styled-components.vscode-styled-components",
8
+ "stylelint.vscode-stylelint",
9
+ "unifiedjs.vscode-mdx",
10
+ "unifiedjs.vscode-remark",
11
+ "vitest.explorer",
12
+ ]
13
+ }
@@ -0,0 +1,89 @@
1
+ {
2
+ "npm.packageManager": "pnpm",
3
+ // don't show errors, but fix when save and git pre commit
4
+ "eslint.rules.customizations": [
5
+ { "rule": "import/order", "severity": "off" },
6
+ { "rule": "prettier/prettier", "severity": "off" },
7
+ { "rule": "react/jsx-sort-props", "severity": "off" },
8
+ { "rule": "sort-keys-fix/sort-keys-fix", "severity": "off" },
9
+ { "rule": "typescript-sort-keys/interface", "severity": "off" }
10
+ ],
11
+ "stylelint.validate": [
12
+ "css",
13
+ "postcss",
14
+ // make stylelint work with tsx antd-style css template string
15
+ "typescriptreact"
16
+ ],
17
+ "search.exclude": {
18
+ "**/node_modules": true,
19
+ // useless to search this big folder
20
+ "locales": true
21
+ },
22
+ "vitest.maximumConfigs": 6,
23
+ "workbench.editor.customLabels.patterns": {
24
+ "**/app/**/[[]*[]]/[[]*[]]/page.tsx": "${dirname(2)}/${dirname(1)}/${dirname} • page component",
25
+ "**/app/**/[[]*[]]/page.tsx": "${dirname(1)}/${dirname} • page component",
26
+ "**/app/**/page.tsx": "${dirname} • page component",
27
+
28
+ "**/app/**/[[]*[]]/[[]*[]]/layout.tsx": "${dirname(2)}/${dirname(1)}/${dirname} • page layout",
29
+ "**/app/**/[[]*[]]/layout.tsx": "${dirname(1)}/${dirname} • page layout",
30
+ "**/app/**/layout.tsx": "${dirname} • page layout",
31
+
32
+ "**/app/**/[[]*[]]/[[]*[]]/default.tsx": "${dirname(2)}/${dirname(1)}/${dirname} • slot default",
33
+ "**/app/**/[[]*[]]/default.tsx": "${dirname(1)}/${dirname} • slot default",
34
+ "**/app/**/default.tsx": "${dirname} • slot default",
35
+
36
+ "**/app/**/[[]*[]]/[[]*[]]/error.tsx": "${dirname(2)}/${dirname(1)}/${dirname} • error component",
37
+ "**/app/**/[[]*[]]/error.tsx": "${dirname(1)}/${dirname} • error component",
38
+ "**/app/**/error.tsx": "${dirname} • error component",
39
+
40
+ "**/app/**/[[]*[]]/[[]*[]]/loading.tsx": "${dirname(2)}/${dirname(1)}/${dirname} • loading component",
41
+ "**/app/**/[[]*[]]/loading.tsx": "${dirname(1)}/${dirname} • loading component",
42
+ "**/app/**/loading.tsx": "${dirname} • loading component",
43
+
44
+ "**/src/**/route.ts": "${dirname(1)}/${dirname} • route",
45
+ "**/src/**/index.tsx": "${dirname} • component",
46
+
47
+ "**/src/database/repositories/*/index.ts": "${dirname} • db repository",
48
+ "**/src/database/models/*.ts": "${filename} • db model",
49
+ "**/src/database/schemas/*.ts": "${filename} • db schema",
50
+
51
+ "**/src/services/*.ts": "${filename} • service",
52
+ "**/src/services/*/client.ts": "${dirname} • client service",
53
+ "**/src/services/*/server.ts": "${dirname} • server service",
54
+
55
+ "**/src/store/*/action.ts": "${dirname} • action",
56
+ "**/src/store/*/slices/*/action.ts": "${dirname(2)}/${dirname} • action",
57
+ "**/src/store/*/slices/*/actions/*.ts": "${dirname(1)}/${dirname}/${filename} • action",
58
+
59
+ "**/src/store/*/initialState.ts": "${dirname} • state",
60
+ "**/src/store/*/slices/*/initialState.ts": "${dirname(2)}/${dirname} • state",
61
+
62
+ "**/src/store/*/selectors.ts": "${dirname} • selectors",
63
+ "**/src/store/*/slices/*/selectors.ts": "${dirname(2)}/${dirname} • selectors",
64
+
65
+ "**/src/store/*/reducer.ts": "${dirname} • reducer",
66
+ "**/src/store/*/slices/*/reducer.ts": "${dirname(2)}/${dirname} • reducer",
67
+
68
+ "**/src/config/modelProviders/*.ts": "${filename} • provider",
69
+ "**/src/config/aiModels/*.ts": "${filename} • model",
70
+ "**/src/config/paramsSchemas/*/*.json": "${dirname(1)}/${filename} • params",
71
+ "**/src/libs/model-runtime/*/index.ts": "${dirname} • runtime",
72
+
73
+ "**/src/server/services/*/index.ts": "${dirname} • server/service",
74
+ "**/src/server/routers/lambda/*.ts": "${filename} • lambda",
75
+ "**/src/server/routers/async/*.ts": "${filename} • async",
76
+ "**/src/server/routers/edge/*.ts": "${filename} • edge",
77
+
78
+ "**/src/locales/default/*.ts": "${filename} • locale",
79
+ },
80
+ "eslint.validate": [
81
+ "javascript",
82
+ "javascriptreact",
83
+ "typescript",
84
+ "typescriptreact",
85
+ "markdown",
86
+ // support mdx
87
+ "mdx"
88
+ ]
89
+ }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,48 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.111.12](https://github.com/lobehub/lobe-chat/compare/v1.111.11...v1.111.12)
6
+
7
+ <sup>Released on **2025-08-14**</sup>
8
+
9
+ <br/>
10
+
11
+ <details>
12
+ <summary><kbd>Improvements and Fixes</kbd></summary>
13
+
14
+ </details>
15
+
16
+ <div align="right">
17
+
18
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
19
+
20
+ </div>
21
+
22
+ ### [Version 1.111.11](https://github.com/lobehub/lobe-chat/compare/v1.111.10...v1.111.11)
23
+
24
+ <sup>Released on **2025-08-13**</sup>
25
+
26
+ #### 💄 Styles
27
+
28
+ - **misc**: Update Mistral AI models & Optimize many model providers fetching.
29
+
30
+ <br/>
31
+
32
+ <details>
33
+ <summary><kbd>Improvements and Fixes</kbd></summary>
34
+
35
+ #### Styles
36
+
37
+ - **misc**: Update Mistral AI models & Optimize many model providers fetching, closes [#8644](https://github.com/lobehub/lobe-chat/issues/8644) ([1d466e5](https://github.com/lobehub/lobe-chat/commit/1d466e5))
38
+
39
+ </details>
40
+
41
+ <div align="right">
42
+
43
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
44
+
45
+ </div>
46
+
5
47
  ### [Version 1.111.10](https://github.com/lobehub/lobe-chat/compare/v1.111.9...v1.111.10)
6
48
 
7
49
  <sup>Released on **2025-08-12**</sup>
package/CLAUDE.md ADDED
@@ -0,0 +1,117 @@
1
+ # CLAUDE.md
2
+
3
+ This document serves as a shared guideline for all team members when using Claude Code in this repository.
4
+
5
+ ## Suggestions
6
+
7
+ - When searching the project source code, it is recommended to exclude: `src/database/migrations/meta`, `**/*.test.*`, `**/__snapshots__`, `**/fixtures`
8
+ - Please store all temporary scripts (such as migration and refactoring scripts) in the `docs/.local/` directory; the contents of this folder will not be committed.
9
+
10
+ ## Technologies Stack
11
+
12
+ read @.cursor/rules/project-introduce.mdc for more details.
13
+
14
+ ### Directory Structure
15
+
16
+ ```plaintext
17
+ src/
18
+ ├── app/ # Next.js App Router
19
+ ├── features/ # Feature-based UI components
20
+ ├── store/ # Zustand state stores
21
+ ├── services/ # Client services (tRPC/Model calls)
22
+ ├── server/ # Server-side (tRPC routers, services)
23
+ ├── database/ # Schemas, models, repositories
24
+ ├── libs/ # External library integrations
25
+ ```
26
+
27
+ ### Data Flow
28
+
29
+ - **Client DB Version**: UI → Zustand → Service → Model → PGLite
30
+ - **Server DB Version**: UI → Zustand → Service → tRPC → Repository/Model → PostgreSQL
31
+
32
+ ## Development
33
+
34
+ ### Git Workflow
35
+
36
+ - use rebase for git pull.
37
+ - git commit message should prefix with gitmoji.
38
+ - git branch name format example: tj/feat/feature-name
39
+ - use .github/PULL_REQUEST_TEMPLATE.md to generate pull request description
40
+
41
+ ### Package Management
42
+
43
+ this is a monorepo project and we use `pnpm` as package manager
44
+
45
+ ### TypeScript Code Style Guide
46
+
47
+ see @.cursor/rules/typescript.mdc
48
+
49
+ ### Modify Code Rules
50
+
51
+ - **Code Language**:
52
+ - For files with existing Chinese comments: Continue using Chinese to maintain consistency
53
+ - For new files or files without Chinese comments: MUST use American English.
54
+ - eg: new react tsx file and new test file
55
+ - Conservative for existing code, modern approaches for new features
56
+
57
+ ### Testing
58
+
59
+ Testing work follows the Rule-Aware Task Execution system above.
60
+
61
+ - **Required Rule**: `testing-guide/testing-guide.mdc`
62
+ - **Command**: `npx vitest run --config vitest.config.ts '[file-path-pattern]'`, wrapped in single quotes to avoid shell expansion
63
+
64
+ **Important**:
65
+
66
+ - Never run `bun run test` etc to run tests, this will run all tests and cost about 10mins
67
+ - If try to fix the same test twice, but still failed, stop and ask for help.
68
+
69
+ ### Typecheck
70
+
71
+ - use `bun run type-check` to check type errors.
72
+
73
+ ### Internationalization
74
+
75
+ - **Keys**: Add to `src/locales/default/namespace.ts`
76
+ - **Dev**: Translate at least `zh-CN` files for preview
77
+ - **Structure**: Hierarchical nested objects, not flat keys
78
+ - **Script**: DON'T run `pnpm i18n` (user/CI handles it)
79
+
80
+ ## Rules Index
81
+
82
+ Some useful rules of this project. Read them when needed.
83
+
84
+ **IMPORTANT**: All rule files referenced in this document are located in the `.cursor/rules/` directory. Throughout this document, rule files are referenced by their filename only for brevity.
85
+
86
+ ### 📋 Complete Rule Files
87
+
88
+ **Core Development**
89
+
90
+ - `backend-architecture.mdc` - Three-layer architecture, data flow
91
+ - `react-component.mdc` - antd-style, Lobe UI usage
92
+ - `drizzle-schema-style-guide.mdc` - Schema naming, patterns
93
+ - `define-database-model.mdc` - Model templates, CRUD patterns
94
+
95
+ **State & UI**
96
+
97
+ - `zustand-slice-organization.mdc` - Store organization
98
+ - `zustand-action-patterns.mdc` - Action patterns
99
+ - `packages/react-layout-kit.mdc` - Layout components usage
100
+
101
+ **Testing & Quality**
102
+
103
+ - `testing-guide/testing-guide.mdc` - Test strategy, mock patterns
104
+ - `code-review.mdc` - Review process and standards
105
+
106
+ **Desktop (Electron)**
107
+
108
+ - `desktop-feature-implementation.mdc` - Main/renderer process patterns
109
+ - `desktop-local-tools-implement.mdc` - Tool integration workflow
110
+ - `desktop-menu-configuration.mdc` - App menu, context menu, tray menu
111
+ - `desktop-window-management.mdc` - Window creation, state management, multi-window
112
+ - `desktop-controller-tests.mdc` - Controller unit testing guide
113
+
114
+ **Development Tools**
115
+
116
+ - `i18n.mdc` - Internationalization workflow
117
+ - `debug.mdc` - Debugging strategies
package/changelog/v1.json CHANGED
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "children": {},
4
+ "date": "2025-08-14",
5
+ "version": "1.111.12"
6
+ },
7
+ {
8
+ "children": {
9
+ "improvements": [
10
+ "Update Mistral AI models & Optimize many model providers fetching."
11
+ ]
12
+ },
13
+ "date": "2025-08-13",
14
+ "version": "1.111.11"
15
+ },
2
16
  {
3
17
  "children": {
4
18
  "improvements": [
@@ -1,5 +1,3 @@
1
- {/* eslint-disable no-irregular-whitespace */}
2
-
3
1
  # Best Practices for State Management
4
2
 
5
3
  LobeChat differs from traditional CRUD web applications in that it involves a large amount of rich interactive capabilities. Therefore, it is crucial to design a data flow architecture that is easy to develop and maintain. This document will introduce the best practices for data flow management in LobeChat.
@@ -111,6 +109,8 @@ Based on the provided directory structure of LobeChat SessionStore, we can updat
111
109
 
112
110
  In the LobeChat application, session management is a complex functional module, so we use the Slice pattern to organize the data flow. Below is the directory structure of LobeChat SessionStore, where each directory and file has its specific purpose:
113
111
 
112
+ {/* eslint-disable no-irregular-whitespace */}
113
+
114
114
  ```bash
115
115
  src/store/session
116
116
  ├── helpers.ts # Helper functions
@@ -1,5 +1,3 @@
1
- {/* eslint-disable no-irregular-whitespace */}
2
-
3
1
  # 状态管理最佳实践
4
2
 
5
3
  LobeChat 不同于传统 CRUD 的网页,存在大量的富交互能力,如何设计一个易于开发与易于维护的数据流架构非常重要。本篇文档将介绍 LobeChat 中的数据流管理最佳实践。
@@ -111,6 +109,8 @@ LobeChat SessionStore
111
109
 
112
110
  在 LobeChat 应用中,由于会话管理是一个复杂的功能模块,因此我们采用了 [slice 模式](https://github.com/pmndrs/zustand/blob/main/docs/guides/slices-pattern.md) 来组织数据流。下面是 LobeChat SessionStore 的目录结构,其中每个目录和文件都有其特定的用途:
113
111
 
112
+ {/* eslint-disable no-irregular-whitespace */}
113
+
114
114
  ```fish
115
115
  src/store/session
116
116
  ├── index.ts # SessionStore 的聚合导出文件
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.111.10",
3
+ "version": "1.111.12",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot 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",
@@ -114,6 +114,7 @@ export const createRouterRuntime = ({
114
114
  id,
115
115
  routers,
116
116
  apiKey: DEFAULT_API_LEY,
117
+ models,
117
118
  ...params
118
119
  }: CreateRouterRuntimeOptions) => {
119
120
  return class UniformRuntime implements LobeRuntimeAI {
@@ -201,7 +202,14 @@ export const createRouterRuntime = ({
201
202
  }
202
203
 
203
204
  async models() {
204
- return this._runtimes[0].runtime.models?.();
205
+ if (models && typeof models === 'function') {
206
+ // 如果是函数式配置,使用最后一个 runtime 的 client 调用函数
207
+ const lastRuntime = this._runtimes.at(-1)?.runtime;
208
+ if (lastRuntime && 'client' in lastRuntime) {
209
+ return await models({ client: (lastRuntime as any).client });
210
+ }
211
+ }
212
+ return this._runtimes.at(-1)?.runtime.models?.();
205
213
  }
206
214
 
207
215
  async embeddings(payload: EmbeddingsPayload, options?: EmbeddingsOptions) {
@@ -40,7 +40,7 @@ export const Lobe302AI = createOpenAICompatibleRuntime({
40
40
  const modelsPage = (await client.models.list()) as any;
41
41
  const modelList: Ai302ModelCard[] = modelsPage.data;
42
42
 
43
- return processMultiProviderModelList(modelList);
43
+ return processMultiProviderModelList(modelList, 'ai302');
44
44
  },
45
45
  provider: ModelProvider.Ai302,
46
46
  });
@@ -1,10 +1,12 @@
1
1
  import urlJoin from 'url-join';
2
2
 
3
- import AiHubMixModels from '@/config/aiModels/aihubmix';
4
- import type { ChatModelCard } from '@/types/llm';
3
+ import { LOBE_DEFAULT_MODEL_LIST } from '@/config/aiModels';
4
+ import { responsesAPIModels } from '@/const/models';
5
5
 
6
6
  import { createRouterRuntime } from '../RouterRuntime';
7
7
  import { ModelProvider } from '../types';
8
+ import { ChatStreamPayload } from '../types/chat';
9
+ import { detectModelProvider, processMultiProviderModelList } from '../utils/modelParse';
8
10
 
9
11
  export interface AiHubMixModelCard {
10
12
  created: number;
@@ -15,6 +17,17 @@ export interface AiHubMixModelCard {
15
17
 
16
18
  const baseURL = 'https://aihubmix.com';
17
19
 
20
+ const handlePayload = (payload: ChatStreamPayload) => {
21
+ if (
22
+ responsesAPIModels.has(payload.model) ||
23
+ payload.model.includes('gpt-') ||
24
+ /^o\d/.test(payload.model)
25
+ ) {
26
+ return { ...payload, apiMode: 'responses' } as any;
27
+ }
28
+ return payload as any;
29
+ };
30
+
18
31
  export const LobeAiHubMixAI = createRouterRuntime({
19
32
  debug: {
20
33
  chatCompletion: () => process.env.DEBUG_AIHUBMIX_CHAT_COMPLETION === '1',
@@ -24,68 +37,11 @@ export const LobeAiHubMixAI = createRouterRuntime({
24
37
  },
25
38
  id: ModelProvider.AiHubMix,
26
39
  models: async ({ client }) => {
27
- const functionCallKeywords = [
28
- 'gpt-4',
29
- 'gpt-3.5',
30
- 'claude',
31
- 'gemini',
32
- 'qwen',
33
- 'deepseek',
34
- 'llama',
35
- ];
36
-
37
- const visionKeywords = [
38
- 'gpt-4o',
39
- 'gpt-4-vision',
40
- 'claude-3',
41
- 'claude-4',
42
- 'gemini-pro-vision',
43
- 'qwen-vl',
44
- 'llava',
45
- ];
46
-
47
- const reasoningKeywords = [
48
- 'o1',
49
- 'deepseek-r1',
50
- 'qwq',
51
- 'claude-opus-4',
52
- 'claude-sonnet-4',
53
- 'claude-3-5-sonnet',
54
- 'claude-3-5-haiku',
55
- ];
56
-
57
40
  try {
58
41
  const modelsPage = (await client.models.list()) as any;
59
42
  const modelList: AiHubMixModelCard[] = modelsPage.data || [];
60
43
 
61
- return modelList
62
- .map((model) => {
63
- const knownModel = AiHubMixModels.find(
64
- (m) => model.id.toLowerCase() === m.id.toLowerCase(),
65
- );
66
-
67
- const modelId = model.id.toLowerCase();
68
-
69
- return {
70
- contextWindowTokens: knownModel?.contextWindowTokens ?? undefined,
71
- displayName: knownModel?.displayName ?? model.id,
72
- enabled: knownModel?.enabled || false,
73
- functionCall:
74
- functionCallKeywords.some((keyword) => modelId.includes(keyword)) ||
75
- knownModel?.abilities?.functionCall ||
76
- false,
77
- id: model.id,
78
- reasoning:
79
- reasoningKeywords.some((keyword) => modelId.includes(keyword)) ||
80
- knownModel?.abilities?.reasoning ||
81
- false,
82
- vision:
83
- visionKeywords.some((keyword) => modelId.includes(keyword)) ||
84
- knownModel?.abilities?.vision ||
85
- false,
86
- };
87
- })
88
- .filter(Boolean) as ChatModelCard[];
44
+ return await processMultiProviderModelList(modelList, 'aihubmix');
89
45
  } catch (error) {
90
46
  console.warn(
91
47
  'Failed to fetch AiHubMix models. Please ensure your AiHubMix API key is valid:',
@@ -97,25 +53,26 @@ export const LobeAiHubMixAI = createRouterRuntime({
97
53
  routers: [
98
54
  {
99
55
  apiType: 'anthropic',
100
- models: async () => {
101
- const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
102
- return LOBE_DEFAULT_MODEL_LIST.map((m) => m.id).filter(
103
- (id) => id.startsWith('claude') || id.startsWith('kimi-k2'),
104
- );
105
- },
56
+ models: LOBE_DEFAULT_MODEL_LIST.map((m) => m.id).filter(
57
+ (id) => detectModelProvider(id) === 'anthropic',
58
+ ),
106
59
  options: { baseURL },
107
60
  },
108
61
  {
109
62
  apiType: 'google',
110
- models: async () => {
111
- const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
112
- return LOBE_DEFAULT_MODEL_LIST.map((m) => m.id).filter((id) => id.startsWith('gemini'));
113
- },
63
+ models: LOBE_DEFAULT_MODEL_LIST.map((m) => m.id).filter(
64
+ (id) => detectModelProvider(id) === 'google',
65
+ ),
114
66
  options: { baseURL: urlJoin(baseURL, '/gemini') },
115
67
  },
116
68
  {
117
69
  apiType: 'openai',
118
- options: { baseURL: urlJoin(baseURL, '/v1') },
70
+ options: {
71
+ baseURL: urlJoin(baseURL, '/v1'),
72
+ chatCompletion: {
73
+ handlePayload,
74
+ },
75
+ },
119
76
  },
120
77
  ],
121
78
  });
@@ -1,7 +1,5 @@
1
1
  import Anthropic, { ClientOptions } from '@anthropic-ai/sdk';
2
2
 
3
- import type { ChatModelCard } from '@/types/llm';
4
-
5
3
  import { LobeRuntimeAI } from '../BaseAI';
6
4
  import { AgentRuntimeErrorType } from '../error';
7
5
  import {
@@ -17,8 +15,10 @@ import { desensitizeUrl } from '../utils/desensitizeUrl';
17
15
  import { StreamingResponse } from '../utils/response';
18
16
  import { AnthropicStream } from '../utils/streams';
19
17
  import { handleAnthropicError } from './handleAnthropicError';
18
+ import { processModelList, MODEL_LIST_CONFIGS } from '../utils/modelParse';
20
19
 
21
20
  export interface AnthropicModelCard {
21
+ created_at: string;
22
22
  display_name: string;
23
23
  id: string;
24
24
  }
@@ -218,8 +218,6 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
218
218
  }
219
219
 
220
220
  async models() {
221
- const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
222
-
223
221
  const url = `${this.baseURL}/v1/models`;
224
222
  const response = await fetch(url, {
225
223
  headers: {
@@ -232,30 +230,12 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
232
230
 
233
231
  const modelList: AnthropicModelCard[] = json['data'];
234
232
 
235
- return modelList
236
- .map((model) => {
237
- const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
238
- (m) => model.id.toLowerCase() === m.id.toLowerCase(),
239
- );
240
-
241
- return {
242
- contextWindowTokens: knownModel?.contextWindowTokens ?? undefined,
233
+ const standardModelList = modelList.map((model) => ({
234
+ created: model.created_at,
243
235
  displayName: model.display_name,
244
- enabled: knownModel?.enabled || false,
245
- functionCall:
246
- model.id.toLowerCase().includes('claude-3') ||
247
- knownModel?.abilities?.functionCall ||
248
- false,
249
236
  id: model.id,
250
- reasoning: knownModel?.abilities?.reasoning || false,
251
- vision:
252
- (model.id.toLowerCase().includes('claude-3') &&
253
- !model.id.toLowerCase().includes('claude-3-5-haiku')) ||
254
- knownModel?.abilities?.vision ||
255
- false,
256
- };
257
- })
258
- .filter(Boolean) as ChatModelCard[];
237
+ }));
238
+ return processModelList(standardModelList, MODEL_LIST_CONFIGS.anthropic, 'anthropic');
259
239
  }
260
240
 
261
241
  private handleError(error: any): ChatCompletionErrorPayload {