larkin 0.2.87 → 0.2.88
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.
|
@@ -65,20 +65,30 @@ function validatePiBaseUrl(raw) {
|
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
67
|
* 查询 OpenAI 兼容 provider 的 /models 列表(setup 时校验 --model 是否真实可用)。
|
|
68
|
-
*
|
|
68
|
+
* 网络超时/不可达返回 null(不阻塞 setup——运行时对账会严格兜底);
|
|
69
|
+
* 列表拿到但模型不在其中时抛错。
|
|
69
70
|
*/
|
|
70
71
|
async function listProviderModels(baseUrl, apiKey, fetchImpl = fetch) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
try {
|
|
73
|
+
const url = `${validatePiBaseUrl(baseUrl)}/models`;
|
|
74
|
+
const response = await fetchImpl(url, {
|
|
75
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
76
|
+
signal: AbortSignal.timeout(30_000),
|
|
77
|
+
});
|
|
78
|
+
if (!response.ok)
|
|
79
|
+
throw new Error(`provider /models 查询失败:HTTP ${response.status}`);
|
|
80
|
+
const payload = await response.json();
|
|
81
|
+
if (!payload || !Array.isArray(payload.data))
|
|
82
|
+
throw new Error("provider /models 响应格式非法");
|
|
83
|
+
return payload.data.map((entry) => String(entry.id ?? "")).filter(Boolean);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError"
|
|
87
|
+
|| /fetch failed|network|ETIMEDOUT|ECONNREFUSED/i.test(error.message))) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
function resolveBuiltinPiProviderSetupSelection(input) {
|
|
84
94
|
if (input.distribution !== "builtin")
|
|
@@ -51,20 +51,30 @@ export function validatePiBaseUrl(raw) {
|
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* 查询 OpenAI 兼容 provider 的 /models 列表(setup 时校验 --model 是否真实可用)。
|
|
54
|
-
*
|
|
54
|
+
* 网络超时/不可达返回 null(不阻塞 setup——运行时对账会严格兜底);
|
|
55
|
+
* 列表拿到但模型不在其中时抛错。
|
|
55
56
|
*/
|
|
56
57
|
export async function listProviderModels(baseUrl, apiKey, fetchImpl = fetch) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
try {
|
|
59
|
+
const url = `${validatePiBaseUrl(baseUrl)}/models`;
|
|
60
|
+
const response = await fetchImpl(url, {
|
|
61
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
62
|
+
signal: AbortSignal.timeout(30_000),
|
|
63
|
+
});
|
|
64
|
+
if (!response.ok)
|
|
65
|
+
throw new Error(`provider /models 查询失败:HTTP ${response.status}`);
|
|
66
|
+
const payload = await response.json();
|
|
67
|
+
if (!payload || !Array.isArray(payload.data))
|
|
68
|
+
throw new Error("provider /models 响应格式非法");
|
|
69
|
+
return payload.data.map((entry) => String(entry.id ?? "")).filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError"
|
|
73
|
+
|| /fetch failed|network|ETIMEDOUT|ECONNREFUSED/i.test(error.message))) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
68
78
|
}
|
|
69
79
|
export function resolveBuiltinPiProviderSetupSelection(input) {
|
|
70
80
|
if (input.distribution !== "builtin")
|
|
@@ -612,11 +612,17 @@ export async function main() {
|
|
|
612
612
|
};
|
|
613
613
|
if (setupModel && raw.baseUrl) {
|
|
614
614
|
// Owner 决策:模型名必须来自 provider 的权威可用列表,输错即报错,不做运行时猜测。
|
|
615
|
+
// 网络超时/不可达时不阻塞 setup(null),运行时对账会严格兜底。
|
|
615
616
|
const availableIds = await listProviderModels(raw.baseUrl, setupApiKey);
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
617
|
+
if (availableIds !== null) {
|
|
618
|
+
const matched = availableIds.some((id) => id === setupModel || id.endsWith(`/${setupModel}`));
|
|
619
|
+
if (!matched) {
|
|
620
|
+
const preview = availableIds.slice(0, 12).join(", ") + (availableIds.length > 12 ? ", …" : "");
|
|
621
|
+
throw new Error(`未知模型 ${setupModel};provider 可用模型:[${preview || "无"}]`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
say("[setup] 网络暂不可达,跳过 /models 预校验;运行时将对模型严格对账");
|
|
620
626
|
}
|
|
621
627
|
}
|
|
622
628
|
stageBuiltinPiProvider(CFG_DIR, id, { ...raw, apiKey: setupApiKey });
|