custom-provider-pi 0.1.3 → 0.1.4
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 +10 -4
- package/custom-provider.ts +26 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -217,13 +217,19 @@ pi install local:/path/to/custom-provider
|
|
|
217
217
|
|
|
218
218
|
### 多模态(图片输入)
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
默认 `input: ["text"]`(纯文本)。pi 会自动识别已知的多模态模型并开启图片输入:
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
1. **OpenRouter 目录**:`architecture.input_modalities` 含 `image` 时自动标记
|
|
223
|
+
2. **内置模式匹配**:`gpt-4o` / `claude-*` / `gemini-*` / `grok-4+` / `glm-4v` / `qwen-vl` / `minimax-m*` 及 ID 含 `vision` 的模型
|
|
224
|
+
3. **显式覆盖**:模型对象写 `input: ["text", "image"]` 或 `["text"]`
|
|
225
|
+
|
|
226
|
+
**为什么默认不开**:向不支持图片的模型发图会收到上游 404(如 deepseek-v4-flash-0731 非 vision 版)。未知模型保守处理为纯文本;已知视觉模型自动开启,无需手动配置。
|
|
227
|
+
|
|
228
|
+
**强制指定**:
|
|
223
229
|
|
|
224
230
|
```bash
|
|
225
|
-
/custom-provider add
|
|
226
|
-
--overrides '{"mymodel":{"input":["text"]}}'
|
|
231
|
+
/custom-provider add my --base-url ... \
|
|
232
|
+
--overrides '{"mymodel":{"input":["text","image"]}}'
|
|
227
233
|
```
|
|
228
234
|
|
|
229
235
|
### 上下文窗口与规格推断
|
package/custom-provider.ts
CHANGED
|
@@ -233,7 +233,7 @@ async function refreshRemoteSpecs(): Promise<void> {
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
// 查询模型规格:远程实时表 → 本地已知预设 → undefined
|
|
236
|
-
function lookupModelSpec(modelId: string): { contextWindow: number; maxTokens: number } | undefined {
|
|
236
|
+
function lookupModelSpec(modelId: string): { contextWindow: number; maxTokens: number; vision?: boolean } | undefined {
|
|
237
237
|
if (remoteSpecStore && remoteSpecStore.size > 0) {
|
|
238
238
|
// 候选链逐形态命中:deepseek-v4-flash-free → deepseek-v4-flash → deepseek-v4 …
|
|
239
239
|
for (const candidate of normalizeModelIdCandidates(modelId)) {
|
|
@@ -416,16 +416,17 @@ function stripBasePath(baseUrl: string): string {
|
|
|
416
416
|
function normalizeBaseUrl(baseUrl: string, api: string): string {
|
|
417
417
|
const root = stripBasePath(baseUrl);
|
|
418
418
|
|
|
419
|
+
// 已经包含版本号后缀(/v1、/v4、/v1beta 等)或特殊版本路径段 → 不再追加
|
|
420
|
+
// 覆盖智谱 /api/paas/v4、Google /v1beta 等风格
|
|
421
|
+
if (/\/v\d+(?:beta)?(?:\/|$)/i.test(root)) return root;
|
|
422
|
+
|
|
419
423
|
switch (api) {
|
|
420
424
|
case "openai-completions":
|
|
421
425
|
case "openai-responses":
|
|
422
426
|
case "anthropic-messages":
|
|
423
|
-
// OpenAI/Anthropic 兼容协议要求 /v1 前缀;只在"不以 /v1 结尾"时补,
|
|
424
|
-
// 避免路径中段含 /v1/ 的历史误判
|
|
425
427
|
return /\/v1$/i.test(root) ? root : `${root}/v1`;
|
|
426
428
|
|
|
427
429
|
case "google-generative-ai":
|
|
428
|
-
// Google Generative AI 需要 /v1beta 或 /v1 前缀
|
|
429
430
|
if (!/(\/v1|\/v1beta)(\/|$)/i.test(root)) return `${root}/v1`;
|
|
430
431
|
return root;
|
|
431
432
|
|
|
@@ -562,12 +563,19 @@ async function fetchModels(
|
|
|
562
563
|
headers?: Record<string, string>
|
|
563
564
|
): Promise<string[]> {
|
|
564
565
|
const cleanBase = stripBasePath(baseUrl);
|
|
565
|
-
|
|
566
|
+
// 已包含版本段(/v1、/v4、/api/paas/v4)则不追加 /v1
|
|
567
|
+
const hasVersion = /\/v\d+(?:beta)?(?:\/|$)/i.test(cleanBase);
|
|
568
|
+
const v1Base = hasVersion ? cleanBase : `${cleanBase}/v1`;
|
|
566
569
|
|
|
567
|
-
//
|
|
570
|
+
// 尝试多种端点路径
|
|
568
571
|
const endpoints = api === "google-generative-ai"
|
|
569
572
|
? [`${v1Base}/models`]
|
|
570
|
-
: [
|
|
573
|
+
: [
|
|
574
|
+
`${v1Base}/models`, // 标准 /v1/models
|
|
575
|
+
`${cleanBase}/models`, // 已含版本或原始路径
|
|
576
|
+
`${cleanBase}/v4/models`, // 智谱 /api/paas/v4 后追加
|
|
577
|
+
`${cleanBase}/api/models`,
|
|
578
|
+
];
|
|
571
579
|
|
|
572
580
|
// 按协议组装认证头:anthropic 用 x-api-key,google 用 x-goog-api-key,其余 Bearer
|
|
573
581
|
const requestHeaders: Record<string, string> = { ...resolveHeaders(headers) };
|
|
@@ -667,10 +675,11 @@ async function probeEndpoint(
|
|
|
667
675
|
const base = url.replace(/\/+$/, "");
|
|
668
676
|
const resolvedKey = apiKey ? resolveValue(apiKey) : "";
|
|
669
677
|
|
|
670
|
-
// 按常见端点路径尝试(OpenAI 兼容最多,其次 Anthropic)
|
|
678
|
+
// 按常见端点路径尝试(OpenAI 兼容最多,其次 Anthropic/Google)
|
|
671
679
|
const attempts = [
|
|
672
680
|
{ ep: `${base}/v1/models`, api: "openai-completions" },
|
|
673
681
|
{ ep: `${base}/models`, api: "openai-completions" },
|
|
682
|
+
{ ep: `${base}/v4/models`, api: "openai-completions" }, // 智谱风格 /api/paas/v4
|
|
674
683
|
{ ep: `${base}/v1/models`, api: "anthropic-messages", useXApiKey: true },
|
|
675
684
|
];
|
|
676
685
|
|
|
@@ -1162,7 +1171,7 @@ export default function customProviderExtension(pi: ExtensionAPI) {
|
|
|
1162
1171
|
);
|
|
1163
1172
|
if (!addMode) return;
|
|
1164
1173
|
|
|
1165
|
-
// ================= 简单添加路径(
|
|
1174
|
+
// ================= 简单添加路径(4 步完成)=================
|
|
1166
1175
|
if (addMode.startsWith("简单")) {
|
|
1167
1176
|
// 1. URL
|
|
1168
1177
|
const simpleUrl = await ctx.ui.input(
|
|
@@ -1171,9 +1180,15 @@ export default function customProviderExtension(pi: ExtensionAPI) {
|
|
|
1171
1180
|
);
|
|
1172
1181
|
if (!simpleUrl) return;
|
|
1173
1182
|
|
|
1174
|
-
// 2.
|
|
1183
|
+
// 2. API Key(留空 = local 无认证)
|
|
1184
|
+
const simpleKeyInput = await ctx.ui.input(
|
|
1185
|
+
"API Key(留空 = 无认证本地服务,支持 $ENV 环境变量)",
|
|
1186
|
+
"$DEEPSEEK_API_KEY"
|
|
1187
|
+
);
|
|
1188
|
+
const simpleApiKey = simpleKeyInput?.trim() || "local";
|
|
1189
|
+
|
|
1190
|
+
// 3. 探测
|
|
1175
1191
|
ctx.ui.notify("正在探测端点…", "info");
|
|
1176
|
-
let simpleApiKey = "local";
|
|
1177
1192
|
const probeResult = await probeEndpoint(simpleUrl, simpleApiKey);
|
|
1178
1193
|
|
|
1179
1194
|
let simpleModels: (string | IModel)[] = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "custom-provider-pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "pi 扩展:统一管理第三方模型 Provider。子命令体系 /custom-provider add|remove|refresh|list|test|config|enable|disable|prune,支持交互向导、flags/JSON 非交互添加、双协议混用(OpenAI + Anthropic)、模型关键字过滤与修剪",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|