pi-models-discovery 1.6.0 → 1.6.1

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
@@ -77,21 +77,28 @@ Forces a rediscovery of every discovery provider and updates the local cache, no
77
77
  - **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.
78
78
  - **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).
79
79
  - 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.
80
- - Discovered models declare `thinkingLevelMap: { xhigh: "xhigh", max: "max" }`, so `xhigh` and `max` appear in `/thinking`; the standard levels stay omitted and keep pi's provider default mapping. `/models` cannot report per-model thinking capability, so this is a blanket default for every discovered model: when a provider rejects those levels, override it per model through `modelOverrides` in models.json (set `xhigh` / `max` to `null` to hide them), or declare the model yourself in a handwritten `models` entry.
80
+ - Discovered models default `thinkingLevelMap.xhigh` / `max` to `null`; extra tiers are no longer assumed to work on every backend. Standard tiers keep Pi's default mapping. Opt in with provider-level `compat.thinkingLevelMap` when the service supports extra tiers, or set any unsupported tier to `null`.
81
+ - For non-reasoning models, set provider-level `compat.reasoning: false` so `/thinking` offers only `off`. `reasoning` and `thinkingLevelMap` are extracted to the model's top level; other `compat` fields (such as `supportsReasoningEffort` and `thinkingFormat`) are forwarded normally. Mixed-model gateways can use `modelOverrides` by model.id. Existing caches apply the current thinking configuration at startup without a network refresh.
82
+
83
+ Example for a local non-reasoning service. To enable verified extra tiers instead, use `"thinkingLevelMap": { "xhigh": "xhigh", "max": "max" }` and remove `"reasoning": false`.
81
84
 
82
85
  ```json
83
86
  {
84
87
  "providers": {
85
- "llm-proxy": {
88
+ "local": {
89
+ "baseUrl": "http://127.0.0.1:8000/v1",
90
+ "api": "openai-completions",
86
91
  "discoverModels": true,
87
- "modelOverrides": {
88
- "some-model": { "thinkingLevelMap": { "xhigh": null, "max": null } }
92
+ "compat": {
93
+ "reasoning": false,
94
+ "supportsReasoningEffort": false,
95
+ "thinkingLevelMap": { "xhigh": null, "max": null }
89
96
  }
90
97
  }
91
98
  }
92
99
  }
93
100
  ```
94
- - Model metadata may carry `name` / `context_window` (or `contextWindow`) / `max_tokens` (or `maxTokens`); defaults are used when absent.
101
+ - Model metadata may carry `name` / `context_window` (or `contextWindow`, or vLLM's `max_model_len`) / `max_tokens` (or `maxTokens`); defaults are used when absent.
95
102
 
96
103
  The old `/model-discovery`, `/model-discovery-refresh`, `/pi-model-discovery`, and `/pi-model-discovery-refresh` names remain available as compatibility aliases.
97
104
 
package/README.zh-CN.md CHANGED
@@ -77,21 +77,28 @@ pi install npm:pi-models-discovery
77
77
  - **离线 / 拉取失败**:保留 models.json 里手写的 `models`(如有,作为回退),并通过会话内 notify 显式警告,不静默降级;单个 provider 失败不影响其他 provider。
78
78
  - **apiKey 解析**(仅发现请求):支持字面量与 `$ENV_VAR` / `${ENV_VAR}` 插值;`!command` 形式跳过发现并显式警告(聊天请求仍由 pi 自身解析执行,不受影响)。
79
79
  - 发现的模型默认参数:`reasoning: true`、`input: ["text", "image"]`、cost 全 0、`contextWindow` 1M、`maxTokens` 64K、`compat.supportsDeveloperRole: false`;provider 级 `compat` 会合并进每个发现的模型。
80
- - 发现的模型声明 `thinkingLevelMap: { xhigh: "xhigh", max: "max" }`,让 `xhigh` / `max` 出现在 `/thinking`;标准档位保持缺省,仍由 pi 的 provider 默认映射决定。`/models` 无法逐个模型返回思考能力,所以这是对所有发现模型一刀切的默认值:某个 provider 拒绝这些档位时,在 models.json 的 `modelOverrides` 里按 model.id 覆盖(把 `xhigh` / `max` 置 `null` 可隐藏),或改用手写 `models` 条目自行声明。
80
+ - 发现的模型默认将 `thinkingLevelMap.xhigh` / `max` 设为 `null`,不再假定所有后端支持这些额外档位。标准档位仍沿用 Pi 默认映射。若服务支持额外档位,可在 provider 的 `compat.thinkingLevelMap` 中显式开启,也可将任一不支持的档位置为 `null`。
81
+ - 非推理模型可设置 provider 的 `compat.reasoning: false`,让 `/thinking` 只提供 `off`。`reasoning` 和 `thinkingLevelMap` 会提取到模型顶层,其余 `compat` 字段(如 `supportsReasoningEffort`、`thinkingFormat`)正常转发。混合模型网关可用 `modelOverrides` 按 model.id 覆盖。旧缓存会在启动时应用当前推理配置,无需联网刷新。
82
+
83
+ 下面是本地非推理服务的配置;若要开启已确认支持的额外档位,改用 `"thinkingLevelMap": { "xhigh": "xhigh", "max": "max" }` 并移除 `"reasoning": false`。
81
84
 
82
85
  ```json
83
86
  {
84
87
  "providers": {
85
- "llm-proxy": {
88
+ "local": {
89
+ "baseUrl": "http://127.0.0.1:8000/v1",
90
+ "api": "openai-completions",
86
91
  "discoverModels": true,
87
- "modelOverrides": {
88
- "some-model": { "thinkingLevelMap": { "xhigh": null, "max": null } }
92
+ "compat": {
93
+ "reasoning": false,
94
+ "supportsReasoningEffort": false,
95
+ "thinkingLevelMap": { "xhigh": null, "max": null }
89
96
  }
90
97
  }
91
98
  }
92
99
  }
93
100
  ```
94
- - 模型元数据可携带 `name` / `context_window`(或 `contextWindow`)/ `max_tokens`(或 `maxTokens`),缺失时用默认值。
101
+ - 模型元数据可携带 `name` / `context_window`(或 `contextWindow`,或 vLLM 的 `max_model_len`)/ `max_tokens`(或 `maxTokens`),缺失时用默认值。
95
102
 
96
103
  旧的 `/model-discovery`、`/model-discovery-refresh`、`/pi-model-discovery` 和 `/pi-model-discovery-refresh` 名称仍作为兼容别名保留。
97
104
 
package/SKILL.md CHANGED
@@ -23,7 +23,7 @@ description: "配置与排查 models.json 的动态模型发现、缓存刷新
23
23
 
24
24
  ## 思考等级
25
25
 
26
- 发现的模型默认声明 `thinkingLevelMap: { xhigh: "xhigh", max: "max" }`(对所有模型一刀切)。若某个模型不认 `xhigh` / `max`,用 models.json 的 `modelOverrides` 按 model.id 把它们置 `null`。
26
+ 发现的模型默认隐藏 `xhigh` / `max`(映射为 `null`),标准档位沿用 Pi 默认映射。provider 的 `compat.thinkingLevelMap` 可显式开启支持的档位或将不支持的档位置 `null`;非推理服务用 `compat.reasoning: false` 关闭推理,必要时配合 `compat.supportsReasoningEffort: false`。这两个扩展配置字段会提取到模型顶层,其余 compat 正常转发。逐模型差异用 `modelOverrides` 按 model.id 覆盖。旧缓存启动时会应用当前配置,无需联网刷新。
27
27
 
28
28
  ## 验证
29
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-models-discovery",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
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",
package/src/index.ts CHANGED
@@ -35,9 +35,8 @@
35
35
  * - 注册 refreshModels:打开 /model 触发在线刷新时重新发现;
36
36
  * 离线初始化(allowNetwork=false)返回上次成功列表(含缓存),尚无成功记录时抛错,
37
37
  * 以免空列表清掉 models.json 手写 models。
38
- * - 发现模型默认声明 thinkingLevelMap { xhigh: "xhigh", max: "max" },让 xhigh/max 出现在
39
- * /thinking;标准档位缺省沿用 pi 的 provider 默认映射。这是对所有发现模型一刀切的默认值,
40
- * 上游不认这些值时用 models.json 的 provider.modelOverrides 按 model.id 覆盖。
38
+ * - 发现模型默认隐藏 xhigh/max;provider.compat.thinkingLevelMap 可显式开启或覆盖档位,
39
+ * provider.compat.reasoning 可关闭推理;逐模型差异用 provider.modelOverrides 覆盖。
41
40
  * - 发现请求的 apiKey 解析仅支持字面量与 $ENV_VAR/${ENV_VAR} 插值;
42
41
  * "!command" 形式的 apiKey 跳过发现(显式警告),pi 发起聊天请求时仍由 pi 自身解析。
43
42
  * - /config:model-discovery 命令对 models.json 的修改立即生效(registerProvider 运行时可直接调用);
@@ -96,6 +95,8 @@ interface ModelsResponse {
96
95
  name?: string;
97
96
  context_window?: number;
98
97
  contextWindow?: number;
98
+ /** vLLM reports the served context window here. */
99
+ max_model_len?: number;
99
100
  max_tokens?: number;
100
101
  maxTokens?: number;
101
102
  }>;
@@ -298,6 +299,21 @@ function resolveEnvValue(raw: string): { value: string | null; error: string | n
298
299
  return { value, error: null };
299
300
  }
300
301
 
302
+ /** 扩展专用的推理默认值从 compat 提取,不作为请求兼容字段转发。 */
303
+ function modelThinking(providerCompat: Record<string, unknown> | undefined) {
304
+ const { reasoning, thinkingLevelMap, ...compat } = providerCompat ?? {};
305
+ return {
306
+ reasoning: typeof reasoning === "boolean" ? reasoning : true,
307
+ thinkingLevelMap: {
308
+ xhigh: null,
309
+ max: null,
310
+ ...(thinkingLevelMap && typeof thinkingLevelMap === "object" && !Array.isArray(thinkingLevelMap)
311
+ ? thinkingLevelMap as ProviderModelConfig["thinkingLevelMap"] : {}),
312
+ },
313
+ compat: { supportsDeveloperRole: false, ...compat },
314
+ };
315
+ }
316
+
301
317
  export function buildModel(
302
318
  id: string,
303
319
  name: string | undefined,
@@ -308,18 +324,11 @@ export function buildModel(
308
324
  return {
309
325
  id,
310
326
  name: name ?? id,
311
- reasoning: true,
312
- // xhigh/max 必须给非 null 值才会出现在 /thinking(缺省键等同不支持);
313
- // 标准档位保持缺省,仍走 pi 的 provider 默认映射,语义不变。
314
- thinkingLevelMap: { xhigh: "xhigh", max: "max" },
327
+ ...modelThinking(providerCompat),
315
328
  input: ["text", "image"],
316
329
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
317
330
  contextWindow: contextWindow ?? 1_000_000,
318
331
  maxTokens: maxTokens ?? 65_536,
319
- compat: {
320
- supportsDeveloperRole: false,
321
- ...providerCompat,
322
- },
323
332
  };
324
333
  }
325
334
 
@@ -375,7 +384,7 @@ async function fetchModels(
375
384
  buildModel(
376
385
  m.id,
377
386
  m.name,
378
- m.context_window ?? m.contextWindow,
387
+ m.context_window ?? m.contextWindow ?? m.max_model_len,
379
388
  m.max_tokens ?? m.maxTokens,
380
389
  entry.compat,
381
390
  ),
@@ -486,6 +495,8 @@ function registerFromCache(
486
495
  notices: Notice[],
487
496
  ): void {
488
497
  if (!validateEntry(entry, notices)) return;
498
+ // 旧缓存含硬编码的 xhigh/max,启动时按当前 provider 配置重建,保持离线可用。
499
+ models = models.map((model) => ({ ...model, ...modelThinking(entry.compat) }));
489
500
  const state: LastModelsState = { lastModels: models };
490
501
  const refreshModels = createRefreshModels(entry, notices, state);
491
502
  pi.registerProvider(entry.id, {