yingclaw 1.7.0 → 1.7.2
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/README.md +1 -2
- package/bin/cli.js +10 -15
- package/lib/config.js +39 -0
- package/package.json +1 -1
package/README.md
CHANGED
package/bin/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
saveConfig,
|
|
8
8
|
writeEnvToZshrc,
|
|
9
9
|
fetchModels,
|
|
10
|
+
fetchModelsFromBaseUrl,
|
|
10
11
|
resetConfig,
|
|
11
12
|
validateConfig,
|
|
12
13
|
resolveFastModel,
|
|
@@ -137,22 +138,16 @@ async function configureCustomProvider({ chalk, ora, existingConfig }) {
|
|
|
137
138
|
}).then(v => v.trim());
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
const modelsUrl = await input({
|
|
141
|
-
message: chalk.cyan('Models URL(可选,留空则手动输入模型)'),
|
|
142
|
-
default: existingConfig?.provider === 'custom' ? existingConfig.modelsUrl : undefined,
|
|
143
|
-
validate: (v) => !v.trim() || isValidUrl(v.trim()) ? true : '请输入有效 URL,或留空',
|
|
144
|
-
}).then(v => v.trim());
|
|
145
|
-
|
|
146
141
|
let modelChoices = [];
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
142
|
+
let modelsUrl;
|
|
143
|
+
const fetchSpinner = ora('正在自动获取可用模型...').start();
|
|
144
|
+
const onlineResult = await fetchModelsFromBaseUrl('custom', apiKey, baseUrl);
|
|
145
|
+
if (onlineResult) {
|
|
146
|
+
modelsUrl = onlineResult.modelsUrl;
|
|
147
|
+
fetchSpinner.succeed(chalk.green(`已获取 ${onlineResult.models.length} 个可用模型`));
|
|
148
|
+
modelChoices = onlineResult.models.map(id => ({ name: id, value: id }));
|
|
149
|
+
} else {
|
|
150
|
+
fetchSpinner.warn(chalk.yellow('无法自动获取模型列表,改为手动输入模型'));
|
|
156
151
|
}
|
|
157
152
|
|
|
158
153
|
let model;
|
package/lib/config.js
CHANGED
|
@@ -80,6 +80,43 @@ function parseModelIdsResponse(providerKey, data) {
|
|
|
80
80
|
return normalizeModelIds(providerKey, ids);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function buildModelUrlCandidates(baseUrl) {
|
|
84
|
+
let url;
|
|
85
|
+
try { url = new URL(baseUrl); } catch { return []; }
|
|
86
|
+
|
|
87
|
+
const pathname = url.pathname.replace(/\/+$/, '');
|
|
88
|
+
const candidates = [];
|
|
89
|
+
const add = (pathPart) => {
|
|
90
|
+
const normalized = pathPart.startsWith('/') ? pathPart : `/${pathPart}`;
|
|
91
|
+
candidates.push(`${url.origin}${normalized}`);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
add(`${pathname}/v1/models`);
|
|
95
|
+
|
|
96
|
+
if (pathname.endsWith('/anthropic')) {
|
|
97
|
+
const withoutAnthropic = pathname.slice(0, -'/anthropic'.length);
|
|
98
|
+
add(`${withoutAnthropic}/v1/models`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
add('/v1/models');
|
|
102
|
+
|
|
103
|
+
return [...new Set(candidates)];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function fetchModelsFromBaseUrl(providerKey, apiKey, baseUrl, fetcher = fetchModels) {
|
|
107
|
+
const effectiveProviderKey = providerKey === 'custom'
|
|
108
|
+
? providerKeyFromBaseUrl(baseUrl) || providerKey
|
|
109
|
+
: providerKey;
|
|
110
|
+
|
|
111
|
+
for (const modelsUrl of buildModelUrlCandidates(baseUrl)) {
|
|
112
|
+
const models = await fetcher(effectiveProviderKey, apiKey, modelsUrl);
|
|
113
|
+
if (models && models.length > 0) {
|
|
114
|
+
return { modelsUrl, models: normalizeModelIds(effectiveProviderKey, models) };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
83
120
|
// 联网拉取厂商支持的模型列表,失败返回 null
|
|
84
121
|
function fetchModels(providerKey, apiKey, modelsUrlOverride) {
|
|
85
122
|
return new Promise((resolve) => {
|
|
@@ -267,6 +304,8 @@ module.exports = {
|
|
|
267
304
|
validateConfig,
|
|
268
305
|
normalizeModelIds,
|
|
269
306
|
parseModelIdsResponse,
|
|
307
|
+
buildModelUrlCandidates,
|
|
308
|
+
fetchModelsFromBaseUrl,
|
|
270
309
|
resolveFastModel,
|
|
271
310
|
providerKeyFromBaseUrl,
|
|
272
311
|
buildClaudeEnv,
|