bingocode 1.0.14 → 1.0.15
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/LICENSE +29 -38
- package/package.json +3 -3
- package/src/cli/ProviderPanel.tsx +725 -725
- package/src/server/config/providerPresets.ts +93 -93
- package/src/server/config/providers.yaml +145 -145
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
// Provider presets — loaded from providers.yaml at startup
|
|
2
|
-
// Original work inspired by cc-switch (https://github.com/farion1231/cc-switch) by Jason Young, MIT License
|
|
3
|
-
|
|
4
|
-
//@C:ID=M.PP.providerPresets;K=M;V=2.0;P=Import dependencies;D=API;M=Providers;S=ModelConfiguration
|
|
5
|
-
import { readFileSync } from 'fs'
|
|
6
|
-
import { fileURLToPath } from 'url'
|
|
7
|
-
import { parse } from 'yaml'
|
|
8
|
-
import path from 'path'
|
|
9
|
-
import type { ApiFormat } from '../types/provider.js'
|
|
10
|
-
|
|
11
|
-
//@C:ID=T.PP.ModelMapping;K=T;V=1.0;P=Define model type mappings;D=API;M=Providers;S=ModelConfiguration
|
|
12
|
-
export type ModelMapping = {
|
|
13
|
-
main: string
|
|
14
|
-
haiku: string
|
|
15
|
-
sonnet: string
|
|
16
|
-
opus: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
//@C:ID=T.PP.ProviderField;K=T;V=1.0;P=Define per-provider field descriptor;D=API;M=Providers;S=ModelConfiguration
|
|
20
|
-
export type ProviderField = {
|
|
21
|
-
/** Field key: 'name' | 'apiKey' | 'baseUrl' map to top-level fields; others go into extra.<key> */
|
|
22
|
-
key: string
|
|
23
|
-
/** Human-readable label shown in the CLI form */
|
|
24
|
-
label: string
|
|
25
|
-
required?: boolean
|
|
26
|
-
/** If true, input is masked in the terminal */
|
|
27
|
-
secret?: boolean
|
|
28
|
-
placeholder?: string
|
|
29
|
-
/** Default value pre-filled in the form */
|
|
30
|
-
default?: string
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
//@C:ID=T.PP.ProviderPreset;K=T;V=2.0;P=Define provider preset structure;D=API;M=Providers;S=ModelConfiguration
|
|
34
|
-
export type ProviderPreset = {
|
|
35
|
-
id: string
|
|
36
|
-
name: string
|
|
37
|
-
baseUrl: string
|
|
38
|
-
apiFormat: ApiFormat
|
|
39
|
-
defaultModels: ModelMapping
|
|
40
|
-
needsApiKey: boolean
|
|
41
|
-
websiteUrl: string
|
|
42
|
-
/** Ordered list of fields to render when adding a new provider from this preset */
|
|
43
|
-
fields: ProviderField[]
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
//@C:ID=D.PP.PROVIDER_PRESETS;K=D;V=2.0;P=Load provider presets from yaml;D=API;M=Providers;S=ModelConfiguration
|
|
47
|
-
function loadPresetsFromYaml(): ProviderPreset[] {
|
|
48
|
-
try {
|
|
49
|
-
const yamlPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'providers.yaml')
|
|
50
|
-
const raw = parse(readFileSync(yamlPath, 'utf-8')) as { presets?: ProviderPreset[] }
|
|
51
|
-
const presets = raw?.presets
|
|
52
|
-
if (!Array.isArray(presets) || presets.length === 0) {
|
|
53
|
-
throw new Error('providers.yaml missing presets array')
|
|
54
|
-
}
|
|
55
|
-
// Ensure fields is always an array
|
|
56
|
-
return presets.map(p => ({ ...p, fields: Array.isArray(p.fields) ? p.fields : [] }))
|
|
57
|
-
} catch (err) {
|
|
58
|
-
console.error('[providerPresets] Failed to load providers.yaml, falling back to defaults:', err)
|
|
59
|
-
// Minimal fallback so the server can still start
|
|
60
|
-
return [
|
|
61
|
-
{
|
|
62
|
-
id: 'official',
|
|
63
|
-
name: 'Claude Official',
|
|
64
|
-
baseUrl: '',
|
|
65
|
-
apiFormat: 'anthropic',
|
|
66
|
-
defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
|
|
67
|
-
needsApiKey: false,
|
|
68
|
-
websiteUrl: 'https://www.anthropic.com/claude-code',
|
|
69
|
-
fields: [{ key: 'name', label: 'Provider 昵称', required: true }],
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
id: 'custom',
|
|
73
|
-
name: 'Custom',
|
|
74
|
-
baseUrl: '',
|
|
75
|
-
apiFormat: 'anthropic',
|
|
76
|
-
defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
|
|
77
|
-
needsApiKey: true,
|
|
78
|
-
websiteUrl: '',
|
|
79
|
-
fields: [
|
|
80
|
-
{ key: 'name', label: 'Provider 昵称', required: true },
|
|
81
|
-
{ key: 'baseUrl', label: 'Base URL', required: true },
|
|
82
|
-
{ key: 'apiKey', label: 'API Key', required: false, secret: true },
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
|
-
]
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export const PROVIDER_PRESETS: ProviderPreset[] = loadPresetsFromYaml()
|
|
90
|
-
|
|
91
|
-
export async function loadProviderPresets(): Promise<ProviderPreset[]> {
|
|
92
|
-
return PROVIDER_PRESETS
|
|
93
|
-
}
|
|
1
|
+
// Provider presets — loaded from providers.yaml at startup
|
|
2
|
+
// Original work inspired by cc-switch (https://github.com/farion1231/cc-switch) by Jason Young, MIT License
|
|
3
|
+
|
|
4
|
+
//@C:ID=M.PP.providerPresets;K=M;V=2.0;P=Import dependencies;D=API;M=Providers;S=ModelConfiguration
|
|
5
|
+
import { readFileSync } from 'fs'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
import { parse } from 'yaml'
|
|
8
|
+
import path from 'path'
|
|
9
|
+
import type { ApiFormat } from '../types/provider.js'
|
|
10
|
+
|
|
11
|
+
//@C:ID=T.PP.ModelMapping;K=T;V=1.0;P=Define model type mappings;D=API;M=Providers;S=ModelConfiguration
|
|
12
|
+
export type ModelMapping = {
|
|
13
|
+
main: string
|
|
14
|
+
haiku: string
|
|
15
|
+
sonnet: string
|
|
16
|
+
opus: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//@C:ID=T.PP.ProviderField;K=T;V=1.0;P=Define per-provider field descriptor;D=API;M=Providers;S=ModelConfiguration
|
|
20
|
+
export type ProviderField = {
|
|
21
|
+
/** Field key: 'name' | 'apiKey' | 'baseUrl' map to top-level fields; others go into extra.<key> */
|
|
22
|
+
key: string
|
|
23
|
+
/** Human-readable label shown in the CLI form */
|
|
24
|
+
label: string
|
|
25
|
+
required?: boolean
|
|
26
|
+
/** If true, input is masked in the terminal */
|
|
27
|
+
secret?: boolean
|
|
28
|
+
placeholder?: string
|
|
29
|
+
/** Default value pre-filled in the form */
|
|
30
|
+
default?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//@C:ID=T.PP.ProviderPreset;K=T;V=2.0;P=Define provider preset structure;D=API;M=Providers;S=ModelConfiguration
|
|
34
|
+
export type ProviderPreset = {
|
|
35
|
+
id: string
|
|
36
|
+
name: string
|
|
37
|
+
baseUrl: string
|
|
38
|
+
apiFormat: ApiFormat
|
|
39
|
+
defaultModels: ModelMapping
|
|
40
|
+
needsApiKey: boolean
|
|
41
|
+
websiteUrl: string
|
|
42
|
+
/** Ordered list of fields to render when adding a new provider from this preset */
|
|
43
|
+
fields: ProviderField[]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//@C:ID=D.PP.PROVIDER_PRESETS;K=D;V=2.0;P=Load provider presets from yaml;D=API;M=Providers;S=ModelConfiguration
|
|
47
|
+
function loadPresetsFromYaml(): ProviderPreset[] {
|
|
48
|
+
try {
|
|
49
|
+
const yamlPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'providers.yaml')
|
|
50
|
+
const raw = parse(readFileSync(yamlPath, 'utf-8')) as { presets?: ProviderPreset[] }
|
|
51
|
+
const presets = raw?.presets
|
|
52
|
+
if (!Array.isArray(presets) || presets.length === 0) {
|
|
53
|
+
throw new Error('providers.yaml missing presets array')
|
|
54
|
+
}
|
|
55
|
+
// Ensure fields is always an array
|
|
56
|
+
return presets.map(p => ({ ...p, fields: Array.isArray(p.fields) ? p.fields : [] }))
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error('[providerPresets] Failed to load providers.yaml, falling back to defaults:', err)
|
|
59
|
+
// Minimal fallback so the server can still start
|
|
60
|
+
return [
|
|
61
|
+
{
|
|
62
|
+
id: 'official',
|
|
63
|
+
name: 'Claude Official',
|
|
64
|
+
baseUrl: '',
|
|
65
|
+
apiFormat: 'anthropic',
|
|
66
|
+
defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
|
|
67
|
+
needsApiKey: false,
|
|
68
|
+
websiteUrl: 'https://www.anthropic.com/claude-code',
|
|
69
|
+
fields: [{ key: 'name', label: 'Provider 昵称', required: true }],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'custom',
|
|
73
|
+
name: 'Custom',
|
|
74
|
+
baseUrl: '',
|
|
75
|
+
apiFormat: 'anthropic',
|
|
76
|
+
defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
|
|
77
|
+
needsApiKey: true,
|
|
78
|
+
websiteUrl: '',
|
|
79
|
+
fields: [
|
|
80
|
+
{ key: 'name', label: 'Provider 昵称', required: true },
|
|
81
|
+
{ key: 'baseUrl', label: 'Base URL', required: true },
|
|
82
|
+
{ key: 'apiKey', label: 'API Key', required: false, secret: true },
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const PROVIDER_PRESETS: ProviderPreset[] = loadPresetsFromYaml()
|
|
90
|
+
|
|
91
|
+
export async function loadProviderPresets(): Promise<ProviderPreset[]> {
|
|
92
|
+
return PROVIDER_PRESETS
|
|
93
|
+
}
|
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
|
|
3
|
-
# Provider 预设配置
|
|
4
|
-
# fields 数组声明新增时需填写的字段
|
|
5
|
-
# key: 'name' | 'apiKey' | 'baseUrl' 直接映射到顶层字段,其余存入 extra.<key>
|
|
6
|
-
# secret: true 时前端使用密码掩码显示
|
|
7
|
-
|
|
8
|
-
presets:
|
|
9
|
-
- id: official
|
|
10
|
-
name: Claude Official
|
|
11
|
-
baseUrl: ''
|
|
12
|
-
apiFormat: anthropic
|
|
13
|
-
needsApiKey: false
|
|
14
|
-
websiteUrl: https://www.anthropic.com/claude-code
|
|
15
|
-
defaultModels:
|
|
16
|
-
main: ''
|
|
17
|
-
haiku: ''
|
|
18
|
-
sonnet: ''
|
|
19
|
-
opus: ''
|
|
20
|
-
fields:
|
|
21
|
-
- key: name
|
|
22
|
-
label: Provider 昵称
|
|
23
|
-
required: true
|
|
24
|
-
secret: false
|
|
25
|
-
placeholder: 'e.g. Claude Official'
|
|
26
|
-
|
|
27
|
-
- id: deepseek
|
|
28
|
-
name: DeepSeek
|
|
29
|
-
baseUrl: https://api.deepseek.com/anthropic
|
|
30
|
-
apiFormat: anthropic
|
|
31
|
-
needsApiKey: true
|
|
32
|
-
websiteUrl: https://platform.deepseek.com
|
|
33
|
-
defaultModels:
|
|
34
|
-
main: DeepSeek-V3.2
|
|
35
|
-
haiku: DeepSeek-V3.2
|
|
36
|
-
sonnet: DeepSeek-V3.2
|
|
37
|
-
opus: DeepSeek-V3.2
|
|
38
|
-
fields:
|
|
39
|
-
- key: name
|
|
40
|
-
label: Provider 昵称
|
|
41
|
-
required: true
|
|
42
|
-
secret: false
|
|
43
|
-
placeholder: 'e.g. My DeepSeek'
|
|
44
|
-
- key: apiKey
|
|
45
|
-
label: API Key
|
|
46
|
-
required: true
|
|
47
|
-
secret: true
|
|
48
|
-
placeholder: 'sk-...'
|
|
49
|
-
|
|
50
|
-
- id: zhipuglm
|
|
51
|
-
name: Zhipu GLM
|
|
52
|
-
baseUrl: https://open.bigmodel.cn/api/anthropic
|
|
53
|
-
apiFormat: anthropic
|
|
54
|
-
needsApiKey: true
|
|
55
|
-
websiteUrl: https://open.bigmodel.cn
|
|
56
|
-
defaultModels:
|
|
57
|
-
main: glm-5
|
|
58
|
-
haiku: glm-5
|
|
59
|
-
sonnet: glm-5
|
|
60
|
-
opus: glm-5
|
|
61
|
-
fields:
|
|
62
|
-
- key: name
|
|
63
|
-
label: Provider 昵称
|
|
64
|
-
required: true
|
|
65
|
-
secret: false
|
|
66
|
-
placeholder: 'e.g. My GLM'
|
|
67
|
-
- key: apiKey
|
|
68
|
-
label: API Key
|
|
69
|
-
required: true
|
|
70
|
-
secret: true
|
|
71
|
-
placeholder: '智谱 API Key'
|
|
72
|
-
|
|
73
|
-
- id: kimi
|
|
74
|
-
name: Kimi
|
|
75
|
-
baseUrl: https://api.moonshot.cn/anthropic
|
|
76
|
-
apiFormat: anthropic
|
|
77
|
-
needsApiKey: true
|
|
78
|
-
websiteUrl: https://platform.moonshot.cn
|
|
79
|
-
defaultModels:
|
|
80
|
-
main: kimi-k2.5
|
|
81
|
-
haiku: kimi-k2.5
|
|
82
|
-
sonnet: kimi-k2.5
|
|
83
|
-
opus: kimi-k2.5
|
|
84
|
-
fields:
|
|
85
|
-
- key: name
|
|
86
|
-
label: Provider 昵称
|
|
87
|
-
required: true
|
|
88
|
-
secret: false
|
|
89
|
-
placeholder: 'e.g. My Kimi'
|
|
90
|
-
- key: apiKey
|
|
91
|
-
label: API Key
|
|
92
|
-
required: true
|
|
93
|
-
secret: true
|
|
94
|
-
placeholder: 'Moonshot API Key'
|
|
95
|
-
|
|
96
|
-
- id: minimax
|
|
97
|
-
name: MiniMax
|
|
98
|
-
baseUrl: https://api.minimaxi.com/anthropic
|
|
99
|
-
apiFormat: anthropic
|
|
100
|
-
needsApiKey: true
|
|
101
|
-
websiteUrl: https://platform.minimaxi.com
|
|
102
|
-
defaultModels:
|
|
103
|
-
main: MiniMax-M2.7
|
|
104
|
-
haiku: MiniMax-M2.7
|
|
105
|
-
sonnet: MiniMax-M2.7
|
|
106
|
-
opus: MiniMax-M2.7
|
|
107
|
-
fields:
|
|
108
|
-
- key: name
|
|
109
|
-
label: Provider 昵称
|
|
110
|
-
required: true
|
|
111
|
-
secret: false
|
|
112
|
-
placeholder: 'e.g. My MiniMax'
|
|
113
|
-
- key: apiKey
|
|
114
|
-
label: API Key
|
|
115
|
-
required: true
|
|
116
|
-
secret: true
|
|
117
|
-
placeholder: 'MiniMax API Key'
|
|
118
|
-
|
|
119
|
-
- id: custom
|
|
120
|
-
name: Custom
|
|
121
|
-
baseUrl: ''
|
|
122
|
-
apiFormat:
|
|
123
|
-
needsApiKey: true
|
|
124
|
-
websiteUrl: ''
|
|
125
|
-
defaultModels:
|
|
126
|
-
main: ''
|
|
127
|
-
haiku: ''
|
|
128
|
-
sonnet: ''
|
|
129
|
-
opus: ''
|
|
130
|
-
fields:
|
|
131
|
-
- key: name
|
|
132
|
-
label: Provider 昵称
|
|
133
|
-
required: true
|
|
134
|
-
secret: false
|
|
135
|
-
placeholder: 'e.g. My Custom Provider'
|
|
136
|
-
- key: baseUrl
|
|
137
|
-
label: Base URL
|
|
138
|
-
required: true
|
|
139
|
-
secret: false
|
|
140
|
-
placeholder: 'https://your-api-endpoint.com/
|
|
141
|
-
- key: apiKey
|
|
142
|
-
label: API Key
|
|
143
|
-
required: false
|
|
144
|
-
secret: true
|
|
145
|
-
placeholder: '(可选)API Key'
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
# Provider 预设配置
|
|
4
|
+
# fields 数组声明新增时需填写的字段
|
|
5
|
+
# key: 'name' | 'apiKey' | 'baseUrl' 直接映射到顶层字段,其余存入 extra.<key>
|
|
6
|
+
# secret: true 时前端使用密码掩码显示
|
|
7
|
+
|
|
8
|
+
presets:
|
|
9
|
+
- id: official
|
|
10
|
+
name: Claude Official
|
|
11
|
+
baseUrl: ''
|
|
12
|
+
apiFormat: anthropic
|
|
13
|
+
needsApiKey: false
|
|
14
|
+
websiteUrl: https://www.anthropic.com/claude-code
|
|
15
|
+
defaultModels:
|
|
16
|
+
main: ''
|
|
17
|
+
haiku: ''
|
|
18
|
+
sonnet: ''
|
|
19
|
+
opus: ''
|
|
20
|
+
fields:
|
|
21
|
+
- key: name
|
|
22
|
+
label: Provider 昵称
|
|
23
|
+
required: true
|
|
24
|
+
secret: false
|
|
25
|
+
placeholder: 'e.g. Claude Official'
|
|
26
|
+
|
|
27
|
+
- id: deepseek
|
|
28
|
+
name: DeepSeek
|
|
29
|
+
baseUrl: https://api.deepseek.com/anthropic
|
|
30
|
+
apiFormat: anthropic
|
|
31
|
+
needsApiKey: true
|
|
32
|
+
websiteUrl: https://platform.deepseek.com
|
|
33
|
+
defaultModels:
|
|
34
|
+
main: DeepSeek-V3.2
|
|
35
|
+
haiku: DeepSeek-V3.2
|
|
36
|
+
sonnet: DeepSeek-V3.2
|
|
37
|
+
opus: DeepSeek-V3.2
|
|
38
|
+
fields:
|
|
39
|
+
- key: name
|
|
40
|
+
label: Provider 昵称
|
|
41
|
+
required: true
|
|
42
|
+
secret: false
|
|
43
|
+
placeholder: 'e.g. My DeepSeek'
|
|
44
|
+
- key: apiKey
|
|
45
|
+
label: API Key
|
|
46
|
+
required: true
|
|
47
|
+
secret: true
|
|
48
|
+
placeholder: 'sk-...'
|
|
49
|
+
|
|
50
|
+
- id: zhipuglm
|
|
51
|
+
name: Zhipu GLM
|
|
52
|
+
baseUrl: https://open.bigmodel.cn/api/anthropic
|
|
53
|
+
apiFormat: anthropic
|
|
54
|
+
needsApiKey: true
|
|
55
|
+
websiteUrl: https://open.bigmodel.cn
|
|
56
|
+
defaultModels:
|
|
57
|
+
main: glm-5
|
|
58
|
+
haiku: glm-5
|
|
59
|
+
sonnet: glm-5
|
|
60
|
+
opus: glm-5
|
|
61
|
+
fields:
|
|
62
|
+
- key: name
|
|
63
|
+
label: Provider 昵称
|
|
64
|
+
required: true
|
|
65
|
+
secret: false
|
|
66
|
+
placeholder: 'e.g. My GLM'
|
|
67
|
+
- key: apiKey
|
|
68
|
+
label: API Key
|
|
69
|
+
required: true
|
|
70
|
+
secret: true
|
|
71
|
+
placeholder: '智谱 API Key'
|
|
72
|
+
|
|
73
|
+
- id: kimi
|
|
74
|
+
name: Kimi
|
|
75
|
+
baseUrl: https://api.moonshot.cn/anthropic
|
|
76
|
+
apiFormat: anthropic
|
|
77
|
+
needsApiKey: true
|
|
78
|
+
websiteUrl: https://platform.moonshot.cn
|
|
79
|
+
defaultModels:
|
|
80
|
+
main: kimi-k2.5
|
|
81
|
+
haiku: kimi-k2.5
|
|
82
|
+
sonnet: kimi-k2.5
|
|
83
|
+
opus: kimi-k2.5
|
|
84
|
+
fields:
|
|
85
|
+
- key: name
|
|
86
|
+
label: Provider 昵称
|
|
87
|
+
required: true
|
|
88
|
+
secret: false
|
|
89
|
+
placeholder: 'e.g. My Kimi'
|
|
90
|
+
- key: apiKey
|
|
91
|
+
label: API Key
|
|
92
|
+
required: true
|
|
93
|
+
secret: true
|
|
94
|
+
placeholder: 'Moonshot API Key'
|
|
95
|
+
|
|
96
|
+
- id: minimax
|
|
97
|
+
name: MiniMax
|
|
98
|
+
baseUrl: https://api.minimaxi.com/anthropic
|
|
99
|
+
apiFormat: anthropic
|
|
100
|
+
needsApiKey: true
|
|
101
|
+
websiteUrl: https://platform.minimaxi.com
|
|
102
|
+
defaultModels:
|
|
103
|
+
main: MiniMax-M2.7
|
|
104
|
+
haiku: MiniMax-M2.7
|
|
105
|
+
sonnet: MiniMax-M2.7
|
|
106
|
+
opus: MiniMax-M2.7
|
|
107
|
+
fields:
|
|
108
|
+
- key: name
|
|
109
|
+
label: Provider 昵称
|
|
110
|
+
required: true
|
|
111
|
+
secret: false
|
|
112
|
+
placeholder: 'e.g. My MiniMax'
|
|
113
|
+
- key: apiKey
|
|
114
|
+
label: API Key
|
|
115
|
+
required: true
|
|
116
|
+
secret: true
|
|
117
|
+
placeholder: 'MiniMax API Key'
|
|
118
|
+
|
|
119
|
+
- id: custom
|
|
120
|
+
name: Custom
|
|
121
|
+
baseUrl: ''
|
|
122
|
+
apiFormat: openai_chat
|
|
123
|
+
needsApiKey: true
|
|
124
|
+
websiteUrl: ''
|
|
125
|
+
defaultModels:
|
|
126
|
+
main: ''
|
|
127
|
+
haiku: ''
|
|
128
|
+
sonnet: ''
|
|
129
|
+
opus: ''
|
|
130
|
+
fields:
|
|
131
|
+
- key: name
|
|
132
|
+
label: Provider 昵称
|
|
133
|
+
required: true
|
|
134
|
+
secret: false
|
|
135
|
+
placeholder: 'e.g. My Custom Provider'
|
|
136
|
+
- key: baseUrl
|
|
137
|
+
label: Base URL
|
|
138
|
+
required: true
|
|
139
|
+
secret: false
|
|
140
|
+
placeholder: 'https://your-api-endpoint.com/v1'
|
|
141
|
+
- key: apiKey
|
|
142
|
+
label: API Key
|
|
143
|
+
required: false
|
|
144
|
+
secret: true
|
|
145
|
+
placeholder: '(可选)API Key'
|