@fanchaozz/provider-manager 0.2.2 → 1.0.0
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 +257 -244
- package/README_EN.md +12 -0
- package/components.ts +192 -40
- package/forms.ts +700 -542
- package/package.json +47 -47
- package/sync.ts +3 -1
- package/ui.ts +20 -10
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fanchaozz/provider-manager",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A pi extension that manages custom providers and models in ~/.pi/agent/models.json via a TUI dashboard, /providers slash command, and remote model sync.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "index.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"*.ts",
|
|
9
|
-
"README.md",
|
|
10
|
-
"README_EN.md"
|
|
11
|
-
],
|
|
12
|
-
"keywords": [
|
|
13
|
-
"pi-package",
|
|
14
|
-
"pi-extension",
|
|
15
|
-
"provider",
|
|
16
|
-
"model",
|
|
17
|
-
"ai"
|
|
18
|
-
],
|
|
19
|
-
"pi": {
|
|
20
|
-
"extensions": [
|
|
21
|
-
"./"
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
"license": "MIT",
|
|
25
|
-
"author": "fanchaozz <fanchaozz@users.noreply.github.com>",
|
|
26
|
-
"homepage": "https://github.com/fanchaozz/provider-manager#readme",
|
|
27
|
-
"repository": {
|
|
28
|
-
"type": "git",
|
|
29
|
-
"url": "git+https://github.com/fanchaozz/provider-manager.git"
|
|
30
|
-
},
|
|
31
|
-
"bugs": {
|
|
32
|
-
"url": "https://github.com/fanchaozz/provider-manager/issues"
|
|
33
|
-
},
|
|
34
|
-
"engines": {
|
|
35
|
-
"node": ">=20"
|
|
36
|
-
},
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"test": "for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done",
|
|
42
|
-
"ci:test": "npm install --no-save @earendil-works/pi-coding-agent && for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done"
|
|
43
|
-
},
|
|
44
|
-
"publishConfig": {
|
|
45
|
-
"access": "public"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@fanchaozz/provider-manager",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A pi extension that manages custom providers and models in ~/.pi/agent/models.json via a TUI dashboard, /providers slash command, and remote model sync.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"*.ts",
|
|
9
|
+
"README.md",
|
|
10
|
+
"README_EN.md"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"pi-package",
|
|
14
|
+
"pi-extension",
|
|
15
|
+
"provider",
|
|
16
|
+
"model",
|
|
17
|
+
"ai"
|
|
18
|
+
],
|
|
19
|
+
"pi": {
|
|
20
|
+
"extensions": [
|
|
21
|
+
"./"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "fanchaozz <fanchaozz@users.noreply.github.com>",
|
|
26
|
+
"homepage": "https://github.com/fanchaozz/provider-manager#readme",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/fanchaozz/provider-manager.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/fanchaozz/provider-manager/issues"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"test": "for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done",
|
|
42
|
+
"ci:test": "npm install --no-save @earendil-works/pi-coding-agent && for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/sync.ts
CHANGED
|
@@ -80,7 +80,8 @@ export function inferInput(id: string): ("text" | "image")[] {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/** 把 FetchedModel 变成 ModelConfig。缺省值以 DEFAULT_MODEL_CONFIG 为准(reasoning=yes / input=[text,image] / ctx/max / thinkingLevelMap.medium=medium),
|
|
83
|
-
* 启发式仅在缺省为 no 时下调(比如「明显不是 reasoning」)。可选 3 个参传入覆盖上下文窗口 / max / defaults。
|
|
83
|
+
* 启发式仅在缺省为 no 时下调(比如「明显不是 reasoning」)。可选 3 个参传入覆盖上下文窗口 / max / defaults。
|
|
84
|
+
* compat 同步拷默认(用户模板里已带 supportsDeveloperRole=false,新增 model 不应丢这项) */
|
|
84
85
|
export function inferModel(id: string, fetched: FetchedModel, overrides?: { contextWindow?: number; maxTokens?: number; defaults?: typeof DEFAULT_MODEL_CONFIG }): ModelConfig {
|
|
85
86
|
const cfg = overrides?.defaults ?? DEFAULT_MODEL_CONFIG;
|
|
86
87
|
const heuristicReasoning = inferReasoning(id);
|
|
@@ -95,6 +96,7 @@ export function inferModel(id: string, fetched: FetchedModel, overrides?: { cont
|
|
|
95
96
|
contextWindow: overrides?.contextWindow ?? cfg.contextWindow,
|
|
96
97
|
maxTokens: overrides?.maxTokens ?? cfg.maxTokens,
|
|
97
98
|
thinkingLevelMap: { ...cfg.thinkingLevelMap },
|
|
99
|
+
compat: cfg.compat ? { ...cfg.compat } : undefined,
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
102
|
|
package/ui.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { readFileSync, existsSync } from "node:fs";
|
|
|
12
12
|
import { readModelsJson, getModelsJsonPath, maskApiKey, type ModelsJson, type ProviderConfig, type ModelConfig } from "./store.ts";
|
|
13
13
|
import {
|
|
14
14
|
addProviderFlow,
|
|
15
|
+
addModelFlow,
|
|
15
16
|
editProviderFlow,
|
|
16
17
|
deleteProviderFlow,
|
|
17
18
|
editModelFlow,
|
|
@@ -291,6 +292,19 @@ class Dashboard {
|
|
|
291
292
|
this.invalidate();
|
|
292
293
|
return;
|
|
293
294
|
}
|
|
295
|
+
// 空列表下"新增 provider"是唯一可执行动作,必须在导航块之前判定。
|
|
296
|
+
// 否则 n 会落到 else if 链外的 if (items.length === 0) 分支被吞掉。
|
|
297
|
+
if (data === "n") {
|
|
298
|
+
if (this.pane === "provider") {
|
|
299
|
+
void this.runForm(addProviderFlow);
|
|
300
|
+
} else {
|
|
301
|
+
// model 面板 n → 调用 addModelFlow(sync 拉不到时使用模板新增)
|
|
302
|
+
const sel = this.providers[this.providerIndex];
|
|
303
|
+
if (sel) void this.runForm(addModelFlow, sel.id);
|
|
304
|
+
else this.ctx.ui.notify("No provider selected", "warning");
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
294
308
|
// 导航(循环:第 1 个按 ↑ 跳最后,最后按 ↓ 跳第 1 个)
|
|
295
309
|
const items = this.pane === "provider" ? this.providers : (this.providers[this.providerIndex]?.models ?? []);
|
|
296
310
|
if (items.length === 0) {
|
|
@@ -313,13 +327,6 @@ class Dashboard {
|
|
|
313
327
|
const m = prov?.models[this.modelIndex];
|
|
314
328
|
if (prov && m) void this.runForm(editModelFlow, prov.id, m.id);
|
|
315
329
|
}
|
|
316
|
-
} else if (data === "n") {
|
|
317
|
-
// n: 新增 provider。仅 provider 面板支持;model 面板的 n 跳到 sync 提示。
|
|
318
|
-
if (this.pane === "provider") {
|
|
319
|
-
void this.runForm(addProviderFlow);
|
|
320
|
-
} else {
|
|
321
|
-
this.ctx.ui.notify("model 不能直接新增,请用 sync(按 y)", "info");
|
|
322
|
-
}
|
|
323
330
|
} else if (data === "d") {
|
|
324
331
|
const prov = this.providers[this.providerIndex];
|
|
325
332
|
if (this.pane === "provider" && prov) {
|
|
@@ -478,10 +485,13 @@ class Dashboard {
|
|
|
478
485
|
lines.push(th.fg("borderMuted", "─".repeat(width)));
|
|
479
486
|
if (this.help) {
|
|
480
487
|
lines.push(...this.renderHelp(width, th));
|
|
488
|
+
} else if (this.providers.length === 0) {
|
|
489
|
+
// 空态:导航/编辑/同步/删除 均无意义,只保留有效动作
|
|
490
|
+
lines.push(th.fg("dim", " n add first provider · ? help · q close"));
|
|
481
491
|
} else {
|
|
482
492
|
const parts = ["↑↓/jk nav", "←→ pane"];
|
|
483
493
|
if (this.pane === "provider") parts.push("n new", "Enter edit", "y sync");
|
|
484
|
-
else parts.push("Enter edit", "y sync", "t test", "T test-all");
|
|
494
|
+
else parts.push("n new", "Enter edit", "y sync", "t test", "T test-all");
|
|
485
495
|
parts.push("d del", "? help", "q close");
|
|
486
496
|
lines.push(th.fg("dim", " " + parts.join(" · ")));
|
|
487
497
|
}
|
|
@@ -692,9 +702,9 @@ class Dashboard {
|
|
|
692
702
|
];
|
|
693
703
|
// 按面板增补特有项
|
|
694
704
|
if (this.pane === "provider") {
|
|
695
|
-
lines.splice(5, 0, " n new provider (
|
|
705
|
+
lines.splice(5, 0, " n new provider (model 仍走 sync)");
|
|
696
706
|
} else {
|
|
697
|
-
lines.splice(5, 0, " t / T test current model / test all in provider");
|
|
707
|
+
lines.splice(5, 0, " n new model manually (sync 拉不到时;走 defaultModel 模板)", " t / T test current model / test all in provider");
|
|
698
708
|
}
|
|
699
709
|
lines.push("", th.fg("dim", " y sync"));
|
|
700
710
|
return lines.map((l) => truncateToWidth(l, width));
|