pi-models-discovery 1.0.0 → 1.1.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 CHANGED
@@ -15,7 +15,7 @@ pi install npm:pi-models-discovery
15
15
  ### Option 1: interactive configuration inside pi (recommended)
16
16
 
17
17
  ```
18
- /model-discovery
18
+ /config:model-discovery
19
19
  ```
20
20
 
21
21
  Interactively add / remove / rediscover providers: enter id, baseUrl, api type, apiKey (optional), display name (optional). Changes are written to models.json and take effect **immediately** (no /reload required). A backup is written to `models.json.discovery-bak` before each write.
@@ -42,12 +42,12 @@ Add `"discoverModels": true` to a provider in `~/.pi/agent/models.json`:
42
42
 
43
43
  `baseUrl` and `api` are required; `apiKey` is optional (omit for unauthenticated services). Multiple providers sharing the same `baseUrl+apiKey` reuse a single `/models` request.
44
44
 
45
- Hand edits require `/reload` to take effect; changes made through `/model-discovery` apply immediately.
45
+ Hand edits require `/reload` to take effect; changes made through `/config:model-discovery` apply immediately.
46
46
 
47
47
  ## Refreshing the cache
48
48
 
49
49
  ```
50
- /model-discovery-refresh
50
+ /config:model-discovery-refresh
51
51
  ```
52
52
 
53
53
  Forces a rediscovery of every discovery provider and updates the local cache, notifying the result for each provider.
@@ -55,12 +55,14 @@ Forces a rediscovery of every discovery provider and updates the local cache, no
55
55
  ## Behavior
56
56
 
57
57
  - **Startup (cache-first)**: when the cache hits, models are registered directly from the persisted list with zero network requests. The cache lives at `~/.pi/agent/extensions/pi-models-discovery/cache.json`. The cache is invalidated automatically when the provider configuration fingerprint (baseUrl+api+apiKey+headers+compat) changes, triggering a fresh network discovery.
58
- - **Online refresh**: `/model-discovery-refresh`, or the `refreshModels` hook triggered when opening `/model`, rediscovers online and updates the cache.
58
+ - **Online refresh**: `/config:model-discovery-refresh`, or the `refreshModels` hook triggered when opening `/model`, rediscovers online and updates the cache.
59
59
  - **Offline / fetch failure**: handwritten `models` in models.json (if any) are kept as a fallback, and an explicit warning is surfaced via in-session notify — never a silent degradation. One provider failing does not affect the others.
60
60
  - **apiKey resolution** (discovery request only): supports literals and `$ENV_VAR` / `${ENV_VAR}` interpolation; `!command` values skip discovery with an explicit warning (chat requests are still resolved by pi itself and are unaffected).
61
61
  - Default parameters for discovered models: `reasoning: true`, `input: ["text", "image"]`, zero cost, `contextWindow` 1M, `maxTokens` 64K, `compat.supportsDeveloperRole: false`. Provider-level `compat` is merged into every discovered model.
62
62
  - Model metadata may carry `name` / `context_window` (or `contextWindow`) / `max_tokens` (or `maxTokens`); defaults are used when absent.
63
63
 
64
+ The old `/model-discovery`, `/model-discovery-refresh`, `/pi-model-discovery`, and `/pi-model-discovery-refresh` names remain available as compatibility aliases.
65
+
64
66
  ## Uninstall
65
67
 
66
68
  ```bash
package/README.zh-CN.md CHANGED
@@ -15,7 +15,7 @@ pi install npm:pi-models-discovery
15
15
  ### 方式一:pi 终端内交互配置(推荐)
16
16
 
17
17
  ```
18
- /model-discovery
18
+ /config:model-discovery
19
19
  ```
20
20
 
21
21
  交互式添加 / 删除 / 重新发现 provider:输入 id、baseUrl、api 类型、apiKey(可留空)、显示名(可留空),确认后写入 models.json 并**立即生效**(无需 /reload)。写入前自动备份到 `models.json.discovery-bak`。
@@ -42,12 +42,12 @@ pi install npm:pi-models-discovery
42
42
 
43
43
  `baseUrl` 和 `api` 必填;`apiKey` 可选(无鉴权服务可省略)。同一 `baseUrl+apiKey` 的多个 provider 共享一次 `/models` 请求。
44
44
 
45
- 手编方式修改配置后需 `/reload` 生效;`/model-discovery` 命令的修改立即生效。
45
+ 手编方式修改配置后需 `/reload` 生效;`/config:model-discovery` 命令的修改立即生效。
46
46
 
47
47
  ## 刷新缓存
48
48
 
49
49
  ```
50
- /model-discovery-refresh
50
+ /config:model-discovery-refresh
51
51
  ```
52
52
 
53
53
  强制重新拉取所有发现 provider 的模型列表并更新本地缓存,逐个 notify 结果。
@@ -55,12 +55,14 @@ pi install npm:pi-models-discovery
55
55
  ## 行为
56
56
 
57
57
  - **启动(缓存优先)**:缓存命中时直接用持久化的模型列表注册,零网络请求;缓存文件位于 `~/.pi/agent/extensions/pi-models-discovery/cache.json`。provider 配置指纹(baseUrl+api+apiKey+headers+compat)变化时缓存自动失效,重新走网络发现。
58
- - **在线刷新**:`/model-discovery-refresh` 或 `/model` 打开时触发的 `refreshModels` 在线重新发现,并同步更新缓存。
58
+ - **在线刷新**:`/config:model-discovery-refresh` 或 `/model` 打开时触发的 `refreshModels` 在线重新发现,并同步更新缓存。
59
59
  - **离线 / 拉取失败**:保留 models.json 里手写的 `models`(如有,作为回退),并通过会话内 notify 显式警告,不静默降级;单个 provider 失败不影响其他 provider。
60
60
  - **apiKey 解析**(仅发现请求):支持字面量与 `$ENV_VAR` / `${ENV_VAR}` 插值;`!command` 形式跳过发现并显式警告(聊天请求仍由 pi 自身解析执行,不受影响)。
61
61
  - 发现的模型默认参数:`reasoning: true`、`input: ["text", "image"]`、cost 全 0、`contextWindow` 1M、`maxTokens` 64K、`compat.supportsDeveloperRole: false`;provider 级 `compat` 会合并进每个发现的模型。
62
62
  - 模型元数据可携带 `name` / `context_window`(或 `contextWindow`)/ `max_tokens`(或 `maxTokens`),缺失时用默认值。
63
63
 
64
+ 旧的 `/model-discovery`、`/model-discovery-refresh`、`/pi-model-discovery` 和 `/pi-model-discovery-refresh` 名称仍作为兼容别名保留。
65
+
64
66
  ## 卸载
65
67
 
66
68
  ```bash
package/SKILL.md ADDED
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: configure-pi-models-discovery
3
+ description: "配置与排查 models.json 的动态模型发现、缓存刷新、鉴权和离线回退。Use when adding discoverModels providers or refreshing model catalogs."
4
+ ---
5
+
6
+ # 配置 pi-models-discovery
7
+
8
+ ## 诊断
9
+
10
+ 读取实际 Pi agent 目录中的:
11
+
12
+ - `models.json`:provider 配置;
13
+ - `extensions/pi-models-discovery/cache.json`:启动缓存;
14
+ - `models.json.discovery-bak`:交互配置写回前的备份。
15
+
16
+ 只处理带 `discoverModels: true` 的 provider。确认 `baseUrl`、`api`、可选 `apiKey`、headers/compat 以及服务的 `GET {baseUrl}/models` 响应。
17
+
18
+ ## 修改
19
+
20
+ 优先使用 `/config:model-discovery` 添加、删除或重新发现 provider;命令会备份并格式化重写 `models.json`,注释与原排版不会保留。手工修改时,provider 至少提供 `baseUrl`、`api`、`discoverModels: true`;修改后需要 `/reload`。
21
+
22
+ `apiKey` 可用字面量、`$ENV_VAR` 或 `${ENV_VAR}`;`!command` 不用于发现请求,会被跳过并警告。不要把密钥写入 Skill、仓库或回复。
23
+
24
+ ## 验证
25
+
26
+ - `/config:model-discovery-refresh` 强制联网刷新并更新缓存;旧命令名仅为兼容别名。
27
+ - 打开 `/model` 也会触发在线刷新。
28
+ - 逐个 provider 报告成功或失败。失败时可保留 `models.json` 中手写的 `models` 作为显式离线回退,但不能把缓存或静态模型冒充本次发现成功。
@@ -8,8 +8,8 @@
8
8
  "en-US": "Force rediscovery of all model-discovery providers and update the local cache (startup uses the cache and performs no network requests by default)"
9
9
  },
10
10
  "refreshEmpty": {
11
- "zh-CN": "models.json 中没有标记 discoverModels 的 provider,可用 /model-discovery 添加",
12
- "en-US": "No provider in models.json is marked with discoverModels; add one with /model-discovery"
11
+ "zh-CN": "models.json 中没有标记 discoverModels 的 provider,可用 /config:model-discovery 添加",
12
+ "en-US": "No provider in models.json is marked with discoverModels; add one with /config:model-discovery"
13
13
  },
14
14
  "refreshDone": {
15
15
  "zh-CN": "模型刷新完成:{ok}/{total} 个 provider 成功",
@@ -148,8 +148,8 @@
148
148
  "en-US": "{id}: discovered and registered {count} models; they are available in /model"
149
149
  },
150
150
  "firstFailed": {
151
- "zh-CN": "{id}: 配置已保存,但首次发现失败;服务恢复后可在 /model-discovery 中重新发现",
152
- "en-US": "{id}: configuration saved, but initial discovery failed; rediscover with /model-discovery after the service recovers"
151
+ "zh-CN": "{id}: 配置已保存,但首次发现失败;服务恢复后可在 /config:model-discovery 中重新发现",
152
+ "en-US": "{id}: configuration saved, but initial discovery failed; rediscover with /config:model-discovery after the service recovers"
153
153
  },
154
154
  "rediscover": {
155
155
  "zh-CN": "🔄 重新发现模型",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-models-discovery",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Pi extension: discover models from {baseUrl}/models for providers marked with discoverModels in models.json",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -12,7 +12,8 @@
12
12
  "src",
13
13
  "locales",
14
14
  "README.md",
15
- "README.zh-CN.md"
15
+ "README.zh-CN.md",
16
+ "SKILL.md"
16
17
  ],
17
18
  "scripts": {
18
19
  "test": "tsx --test tests/catalog.test.ts",
@@ -22,7 +23,11 @@
22
23
  },
23
24
  "pi": {
24
25
  "extensions": [
25
- "./index.ts"
26
+ "./index.ts",
27
+ "../pi-extensions-i18n/index.ts"
28
+ ],
29
+ "skills": [
30
+ "./SKILL.md"
26
31
  ]
27
32
  },
28
33
  "engines": {
@@ -49,14 +54,15 @@
49
54
  ],
50
55
  "peerDependencies": {
51
56
  "@earendil-works/pi-ai": ">=0.80.0 <0.81.0",
52
- "@earendil-works/pi-coding-agent": ">=0.80.0 <0.81.0",
53
- "pi-extensions-i18n": "^0.3.0"
57
+ "@earendil-works/pi-coding-agent": ">=0.80.0 <0.81.0"
58
+ },
59
+ "dependencies": {
60
+ "pi-extensions-i18n": "^0.4.0"
54
61
  },
55
62
  "devDependencies": {
56
63
  "@earendil-works/pi-ai": "0.80.10",
57
64
  "@earendil-works/pi-coding-agent": "0.80.10",
58
65
  "@types/node": "24.12.4",
59
- "pi-extensions-i18n": "^0.3.0",
60
66
  "tsx": "4.23.1",
61
67
  "typescript": "5.9.3"
62
68
  }
package/src/index.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * GET {baseUrl}/models 自动发现模型并注册,无需手写 models 数组。
6
6
  *
7
7
  * 配置方式(二选一):
8
- * 1. pi 终端内执行 /model-discovery,交互式添加/删除/重新发现 provider(推荐);
8
+ * 1. pi 终端内执行 /config:model-discovery,交互式添加/删除/重新发现 provider(推荐);
9
9
  * 2. 直接编辑 ~/.pi/agent/models.json:
10
10
  * {
11
11
  * "providers": {
@@ -23,7 +23,7 @@
23
23
  * - 首次发现成功后,模型列表持久化到 ~/.pi/agent/extensions/pi-models-discovery/cache.json;
24
24
  * 之后每次启动直接读缓存注册,不请求网络。配置指纹
25
25
  * (baseUrl+api+apiKey+headers+compat)变化时缓存自动失效,重新走网络发现。
26
- * - /model-discovery-refresh 强制重新拉取所有发现 provider 并更新缓存;
26
+ * - /config:model-discovery-refresh 强制重新拉取所有发现 provider 并更新缓存;
27
27
  * /model 打开时触发的在线 refreshModels 同样走网络并同步更新缓存。
28
28
  * - baseUrl / api 由扩展显式转发(pi 的 extension 组合层要求),
29
29
  * apiKey / name / headers / compat 不写回注册配置,由 pi 的 models.json 层回落生效。
@@ -37,7 +37,7 @@
37
37
  * 以免空列表清掉 models.json 手写 models。
38
38
  * - 发现请求的 apiKey 解析仅支持字面量与 $ENV_VAR/${ENV_VAR} 插值;
39
39
  * "!command" 形式的 apiKey 跳过发现(显式警告),pi 发起聊天请求时仍由 pi 自身解析。
40
- * - /model-discovery 命令对 models.json 的修改立即生效(registerProvider 运行时可直接调用);
40
+ * - /config:model-discovery 命令对 models.json 的修改立即生效(registerProvider 运行时可直接调用);
41
41
  * 直接手编 models.json 后需 /reload 扩展生效。
42
42
  * - 本插件不使用 console.*:所有用户可见消息走 ctx.ui.notify;
43
43
  * 加载期(无 ctx)产生的消息收集到 pendingNotices,session_start 时统一 flush。
@@ -417,7 +417,7 @@ function validateEntry(entry: DiscoveryProviderEntry, notices: Notice[]): entry
417
417
 
418
418
  /**
419
419
  * 对单个 provider 执行模型发现并注册(成功带 models,失败保留手写回退)。
420
- * 启动期缓存未命中时与 /model-discovery、/model-discovery-refresh 命令共用;
420
+ * 启动期缓存未命中时与 /config:model-discovery、/config:model-discovery-refresh 命令共用;
421
421
  * 运行期调用立即生效,无需 /reload。
422
422
  * 成功时持久化模型缓存;返回发现的模型列表(失败为 null),消息写入 notices。
423
423
  * 注意:本函数不再主动输出“发现成功”信息;调用方按需自行 notify,
@@ -476,9 +476,9 @@ function registerFromCache(
476
476
  });
477
477
  }
478
478
 
479
- /** /model-discovery 交互式配置命令 */
479
+ /** /config:model-discovery 交互式配置命令;旧名称保留为兼容别名。 */
480
480
  function registerDiscoveryCommand(pi: ExtensionAPI, fetchCache: FetchCache) {
481
- pi.registerCommand("model-discovery", {
481
+ const command = {
482
482
  description: i18n.t("commandDescription"),
483
483
  handler: async (_args, ctx) => {
484
484
  if (!ctx.hasUI) return;
@@ -512,12 +512,15 @@ function registerDiscoveryCommand(pi: ExtensionAPI, fetchCache: FetchCache) {
512
512
  }
513
513
  }
514
514
  },
515
- });
515
+ };
516
+ for (const name of ["config:model-discovery", "model-discovery", "pi-model-discovery"] as const) {
517
+ pi.registerCommand(name, command);
518
+ }
516
519
  }
517
520
 
518
- /** /model-discovery-refresh 强制刷新命令:绕过启动缓存,重拉所有发现 provider 并更新持久化缓存 */
521
+ /** /config:model-discovery-refresh 强制刷新命令;旧名称保留为兼容别名。 */
519
522
  function registerRefreshCommand(pi: ExtensionAPI) {
520
- pi.registerCommand("model-discovery-refresh", {
523
+ const command = {
521
524
  description: i18n.t("refreshDescription"),
522
525
  handler: async (_args, ctx) => {
523
526
  if (!ctx.hasUI) return;
@@ -551,7 +554,10 @@ function registerRefreshCommand(pi: ExtensionAPI) {
551
554
  ok === providers.length ? "info" : "warning",
552
555
  );
553
556
  },
554
- });
557
+ };
558
+ for (const name of ["config:model-discovery-refresh", "model-discovery-refresh", "pi-model-discovery-refresh"] as const) {
559
+ pi.registerCommand(name, command);
560
+ }
555
561
  }
556
562
 
557
563
  type CommandCtx = Parameters<Parameters<ExtensionAPI["registerCommand"]>[1]["handler"]>[1];
@@ -561,7 +567,7 @@ function flushNotices(ctx: CommandCtx, notices: Notice[]): void {
561
567
  for (const notice of notices) ctx.ui.notify(notice.message, notice.level);
562
568
  }
563
569
 
564
- /** /model-discovery 添加 provider 交互流程 */
570
+ /** /config:model-discovery 添加 provider 交互流程 */
565
571
  async function addProviderFlow(pi: ExtensionAPI, ctx: CommandCtx, data: Record<string, unknown>, fetchCache: FetchCache) {
566
572
  const existingIds = new Set(Object.keys((data.providers ?? {}) as Record<string, unknown>));
567
573
  const id = (await ctx.ui.input(i18n.t("providerId")))?.trim();
@@ -617,7 +623,7 @@ async function addProviderFlow(pi: ExtensionAPI, ctx: CommandCtx, data: Record<s
617
623
  }
618
624
  }
619
625
 
620
- /** /model-discovery 管理 provider(重新发现/删除)交互流程 */
626
+ /** /config:model-discovery 管理 provider(重新发现/删除)交互流程 */
621
627
  async function manageProviderFlow(
622
628
  pi: ExtensionAPI,
623
629
  ctx: CommandCtx,