Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ NextCoWork brings agent-driven development to the desktop: multiple workspaces s
- **Plugins** — a manifest-driven plugin system with per-call capability gates. Plugins can contribute commands, menus, keybindings, custom editors, views, web apps, agent tools and bundled skills.
- **Native experience** — light/dark themes, accent colors, motion-level control, auto-update, and full Simplified Chinese / English localization.

## API Route setup

In the model settings provider catalog, add **API Route**, save your API key, then fetch and import models. The preset uses the OpenAI Chat Completions endpoint at `https://global.api-route.com/v1`. Available models depend on your key's group and permissions; use the exact IDs returned by the catalog (for example `gpt-6.1-sol`) without adding a vendor prefix. See the [API Route quickstart](https://www.api-route.com/docs/quickstart) for key setup.

## Download

Installers are published for:
Expand Down
4 changes: 4 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ NextCoWork 把 Agent 驱动的开发带到桌面端:多工作区并排开、
- **插件系统** —— 清单驱动、逐调用能力门控。插件可贡献命令、菜单、快捷键、自定义编辑器、视图、Web 应用、Agent 工具和捆绑技能。
- **原生体验** —— 深浅主题、强调色、动效档位、自动更新,简体中文 / English 完整双语言。

## 配置 API Route

在模型设置的服务商目录中添加 **API Route**,保存 API Key 后拉取并导入模型。预设使用 OpenAI Chat Completions 协议,地址为 `https://global.api-route.com/v1`。可用模型取决于密钥的分组与权限;请直接使用列表返回的完整 ID(例如 `gpt-6.1-sol`),无需添加厂商前缀。密钥配置可参考 [API Route 快速开始](https://www.api-route.com/docs/quickstart)。

## 下载

安装包发布平台:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import { resolveBrand, type Brand } from '../../../../components/brand/brands'

/**
* `null` = 我们**故意**不给它图标,退回首字母。
* 五家都是 lobehub 根本没收字形的(逐个在 `@lobehub/icons-static-svg/icons/`
* 下找过):Requesty、Opper、OhMyGPT、LocalAI,以及 llama.cpp —— 最后这个是 ggerganov 的
* 六家都是 lobehub 根本没收字形的(逐个在 `@lobehub/icons-static-svg/icons/`
* 下找过):Requesty、Opper、API Route、OhMyGPT、LocalAI,以及 llama.cpp —— 最后这个是 ggerganov 的
* 独立项目,不是 Meta 的东西。
*
* ★ 编一个「差不多的」图标比没有图标更糟:用户看见 Meta 的 ∞ 会以为
Expand Down Expand Up @@ -84,6 +84,7 @@ const EXPECTED: Readonly<Record<string, Brand | null>> = {
openrouter: 'openrouter',
requesty: null,
opper: null,
'api-route': null,
siliconflow: 'siliconcloud',
'siliconflow-intl': 'siliconcloud',
together: 'together',
Expand Down Expand Up @@ -126,10 +127,10 @@ describe('内置预设的品牌图标', () => {
* 「null 只有这么几家」:某天规则表改窄了让一堆家一起掉进 null,
* 这里会红,而界面上只会安静地多出几个字母。
*/
it('没有图标的就是这五家,不多不少', () => {
it('没有图标的就是这六家,不多不少', () => {
const blank = PROVIDER_PRESETS.filter((p) => resolveBrand(p.name, p.id) === null).map(
(p) => p.id
)
expect(blank).toEqual(['requesty', 'opper', 'ohmygpt', 'llamacpp', 'localai'])
expect(blank).toEqual(['requesty', 'opper', 'api-route', 'ohmygpt', 'llamacpp', 'localai'])
})
})
52 changes: 52 additions & 0 deletions src/shared/domain/__tests__/api-route-preset.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, expect, it } from 'vitest'
import { modelListRequest, parseModelList } from '../../../main/kernel/upstream/model-list'
import {
importRows,
modelListAvailability
} from '../../../renderer/src/settings/pages/model/import-models'
import {
isPresetAdded,
providerFromPreset,
seedModelsForPreset
} from '../../../renderer/src/settings/pages/model/provider-edit'
import { previewUrl } from '../baseurl'
import { findPreset } from '../presets'

describe('API Route preset setup', () => {
it('creates a provider record that can be saved and recognized as already added', () => {
const preset = findPreset('api-route')!
const provider = providerFromPreset(preset)!
expect(provider.protocol).toBe('openai-chat')
expect(provider.baseUrl).toBe('https://global.api-route.com/v1')
expect(provider.credentialRef).toBe('provider:api-route')
expect(isPresetAdded(preset, [provider])).toBe(true)
expect(previewUrl(provider.baseUrl, provider.protocol)).toBe(
'https://global.api-route.com/v1/chat/completions'
)
})

it('requires a key for discovery and avoids seeding a stale fallback catalog', () => {
const preset = findPreset('api-route')!
const provider = providerFromPreset(preset)!
expect(modelListAvailability(provider)).toEqual({
hint: null,
needsKey: true
})
expect(seedModelsForPreset(preset, provider.protocol)).toEqual([])
expect(modelListRequest(provider.protocol, provider.baseUrl, 'test-key')).toEqual({
url: 'https://global.api-route.com/v1/models',
headers: { accept: 'application/json', authorization: 'Bearer test-key' }
})
})

it('preserves unprefixed upstream model IDs through discovery and import rows', () => {
const fetched = parseModelList('openai-chat', {
data: [{ id: 'gpt-6.1-sol' }, { id: 'claude-fable-5-1' }]
})
expect(importRows(fetched, []).map((row) => row.id)).toEqual([
'gpt-6.1-sol',
'claude-fable-5-1'
])
expect(findPreset('api-route')?.recommended).toBeUndefined()
})
})
13 changes: 13 additions & 0 deletions src/shared/domain/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,19 @@ export const PROVIDER_PRESETS: readonly ProviderPreset[] = [
'模型列表要先填 key 才能拉。服务托管在欧盟(AWS 斯德哥尔摩)。',
verification: 'probed'
},
{
id: 'api-route',
name: 'API Route',
category: 'aggregator',
endpoints: [oa('https://global.api-route.com/v1', true)],
docsUrl: 'https://www.api-route.com/docs/quickstart',
apiKeyUrl: 'https://www.api-route.com/api-keys',
suggestedModels: ['gpt-6.1-sol'],
notes:
'模型列表需要 API Key,可用模型取决于密钥的分组与权限。' +
'使用模型列表返回的完整 ID(如 gpt-6.1-sol),无需添加厂商前缀。',
verification: 'probed'
},
{
id: 'siliconflow',
name: '硅基流动(国内)',
Expand Down
Loading