@gtrabanco/pi-nan-provider 0.10.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/AGENTS.md +78 -12
- package/README.es.md +59 -9
- package/README.md +59 -9
- package/package.json +5 -5
- package/scripts/generate-models.ts +15 -12
- package/scripts/models.generated.ts +7 -2
- package/src/commands.ts +6 -4
- package/src/context-overflow-classifier.ts +114 -23
- package/src/fetch-models.ts +219 -18
- package/src/images.ts +408 -0
- package/src/index.ts +5 -2
- package/src/provider-factory.ts +102 -30
package/AGENTS.md
CHANGED
|
@@ -65,13 +65,15 @@ factory in `src/provider-factory.ts`. A second provider-specific file is a smell
|
|
|
65
65
|
refactor back to the factory and add a config entry in `src/providers.ts` instead.
|
|
66
66
|
The `factory is shared` test in `test/provider-factory.test.ts` guards this contract.
|
|
67
67
|
|
|
68
|
-
## Version policy (strict semver)
|
|
68
|
+
## Version policy (strict semver, pi-aligned scheme)
|
|
69
69
|
|
|
70
70
|
Every PR that changes code MUST bump `package.json` version in the same PR; CI publishes only when the version differs from npm.
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
- **
|
|
72
|
+
Since 1.0.0 the package version **aligns its MAJOR.MINOR with the pi release line the release is verified against** (pi 1.0.0 → package `1.0.x`; when pi ships 1.1.0, the next package release takes `1.1.0` even if it only carries fixes). The version marks the verified baseline, not the full support range — the npm `peerDependencies` range stays independent and usually wider.
|
|
73
|
+
|
|
74
|
+
- **PATCH** (`1.0.z`): bug fixes, docs, comment-only changes, catalog regeneration with identical values — the usual release cadence between pi minor releases.
|
|
75
|
+
- **MINOR** (`1.x.0`): reserved for tracking pi's minor releases (and may carry new features — new provider entries, new MCP tools, new env vars/config options).
|
|
76
|
+
- **MAJOR** (`x.0.0`): breaking changes, and re-alignment if pi ever ships a new major.
|
|
75
77
|
- Never reuse a published version; never publish with failing tests (CI gates publish on tests + typecheck).
|
|
76
78
|
- The npm registry is the source of truth for "published"; `.github/workflows/publish.yml` compares `package.json` against `npm view` and publishes only on difference.
|
|
77
79
|
|
|
@@ -198,9 +200,16 @@ Every PR that changes code MUST bump `package.json` version in the same PR; CI p
|
|
|
198
200
|
entry) so the id is never emitted twice.
|
|
199
201
|
Non-chat endpoints: qwen3-embedding, rerank, kokoro (TTS), whisper (STT),
|
|
200
202
|
flux-2-klein and qwen-image-2.1 (images) — MCP-bridge territory, not chat
|
|
201
|
-
catalog models
|
|
202
|
-
`
|
|
203
|
-
|
|
203
|
+
catalog models. The classification is now applied at RUNTIME too:
|
|
204
|
+
`NON_CHAT_MODEL_IDS` is exported from `src/fetch-models.ts` (single source
|
|
205
|
+
of truth: id → provenance reason), imported by `scripts/generate-models.ts`
|
|
206
|
+
(one definition, no duplicate), enforced by `mergeLiveWithGenerated` (those
|
|
207
|
+
ids land in the `nonChat` bucket and never enter the registry), and filtered
|
|
208
|
+
defensively by `baselineModels`. The generator excluded `qwen-image-2.1` via
|
|
209
|
+
this constant before (it also sits on models.dev with `limit.output: 0`,
|
|
210
|
+
excluded instead of being flagged "needs manual verification" forever); all
|
|
211
|
+
six ids are now under the same guard so they can never be emitted as chat
|
|
212
|
+
models or registered at runtime.
|
|
204
213
|
- NaN can close an SSE stream **before** `finish_reason`. The catalog sets
|
|
205
214
|
`supportsFinishReason: true` so pi-ai raises the retryable
|
|
206
215
|
`Stream ended without finish_reason` (pi-ai's `RETRYABLE_PROVIDER_ERROR_PATTERN`
|
|
@@ -240,23 +249,32 @@ Every PR that changes code MUST bump `package.json` version in the same PR; CI p
|
|
|
240
249
|
- Since 0.10.0, this package uses native MCP via `pi.registerMcpServer()`.
|
|
241
250
|
Both servers are session-scoped, visible in `/mcp` with source "extension".
|
|
242
251
|
Server names and tool IDs:
|
|
243
|
-
- `nan-search` → tools: `
|
|
252
|
+
- `nan-search` → tools: `mcp__nan_search__web_search`
|
|
244
253
|
(official remote, HTTP, `Authorization: Bearer <key>` header)
|
|
245
|
-
- `nan-media` → tools: `
|
|
246
|
-
(community stdio, `npx -y nan-mcp-server@1.1.2`, 120s timeout)
|
|
254
|
+
- `nan-media` → tools: `mcp__nan_media__generate_image/edit_image/text_to_speech/list_voices/speech_to_text/list_models/embed_text/rerank_documents`
|
|
255
|
+
(community stdio, `npx -y nan-mcp-server@1.1.2`, 120s timeout; 8 tools as of 1.1.2)
|
|
247
256
|
- `exposure: "direct"` on both — tools are declared to the model.
|
|
248
257
|
- User `mcp.json` entries with the same name take precedence.
|
|
249
258
|
- `/nan-mcp enable/disable` calls `pi.registerMcpServer()` / `pi.unregisterMcpServer()` directly.
|
|
250
259
|
- Missing `NAN_API_KEY` at load: web-search server NOT registered (console.warn).
|
|
251
260
|
NaN integration facts remain:
|
|
261
|
+
- pi >=0.99.2 sanitizes MCP tool/namespace names by replacing every character except
|
|
262
|
+
`[A-Za-z0-9_]` with `"_"` (0.99.0–0.99.1 kept `-`). So `mcp__nan-search__web_search`
|
|
263
|
+
became `mcp__nan_search__web_search` and `mcp__nan-media__*` became
|
|
264
|
+
`mcp__nan_media__*`. Server names differing only in `-`/`_` now collide
|
|
265
|
+
(`nan-search` and `nan-media` do not collide, they differ in more than one character).
|
|
266
|
+
- pi 0.99.2+/1.0 accept `McpServerConfig.description` (system-prompt listing plus
|
|
267
|
+
tool-search ranking); `validateMcpServerConfig` in 0.99.0–0.99.1 ignores unknown
|
|
268
|
+
keys, so passing `description` stays compatible.
|
|
252
269
|
- NaN's official remote MCP server: `https://api.nan.builders/mcp` (host
|
|
253
270
|
root, NOT /v1; JSON-RPC 2.0 over streamable HTTP, stateless; same `sk-`
|
|
254
271
|
key, shared rate limit/quota). Spec: https://nan.builders/openapi.json
|
|
255
272
|
(tag "MCP"). Currently exposes `web_search`.
|
|
256
273
|
- Community `nan-mcp-server` (https://github.com/luciferfran/nan-mcp-server):
|
|
257
274
|
stdio MCP server, version-pinned via NAN_MEDIA_MCP_VERSION (default 1.1.2)
|
|
258
|
-
or full command override via NAN_MEDIA_MCP_COMMAND. Tools: generate_image,
|
|
259
|
-
edit_image, text_to_speech, list_voices, speech_to_text
|
|
275
|
+
or full command override via NAN_MEDIA_MCP_COMMAND. Tools (1.1.2): generate_image,
|
|
276
|
+
edit_image, text_to_speech, list_voices, speech_to_text, list_models, embed_text,
|
|
277
|
+
rerank_documents.
|
|
260
278
|
- Automated check (scripts/check-nan-mcp-server.ts) compares the npm registry
|
|
261
279
|
against the pin weekly and files a `dependencies` issue when a newer release
|
|
262
280
|
exists, with a breaking/safe verdict from the live server tool surface.
|
|
@@ -275,3 +293,51 @@ Every PR that changes code MUST bump `package.json` version in the same PR; CI p
|
|
|
275
293
|
`mcp_servers_change` so pi's report stays silent, and warns once per session;
|
|
276
294
|
`/nan-mcp enable` persists the toggle without registering. Regression tests:
|
|
277
295
|
`test/mcp-host-connector.test.ts`.
|
|
296
|
+
- **pi 1.0.0 / pi-ai 1.0.0 compat** (verified 2026-10-01): the peer range is now
|
|
297
|
+
`">=0.99.0 <2"` (widened from `">=0.99.0 <1"`); the pi-ai 1.0.0 index/compat/types
|
|
298
|
+
type surfaces are identical to 0.99.1 (the release only adds a `./models` subpath,
|
|
299
|
+
Anthropic federation env consts, and a z.ai CN overflow pattern); the package's
|
|
300
|
+
tests and typecheck pass against 1.0.0 unchanged.
|
|
301
|
+
- **Native image models** (verified 2026-10-01): pi 1.0 lets a provider register
|
|
302
|
+
`ImageModel` entries (`type: "image"`) plus a `Provider.images` implementation map
|
|
303
|
+
keyed by a custom `ImageApi` id (`"nan-images"`); codemode reaches them with
|
|
304
|
+
`models.generateImages()` / `getModelOfType("image", provider, id)`, extensions with
|
|
305
|
+
`ctx.modelRegistry.generateImages()`. pi-ai never applies `filterModels` to
|
|
306
|
+
non-chat models, so image availability is not tier-filtered by the live `/models`
|
|
307
|
+
list — the 403 at call time is the tier signal. NaN endpoints and quotas are
|
|
308
|
+
documented in the package's image-model notes.
|
|
309
|
+
- **Cold-cache 524 wedge: measured practical ceiling + two-threshold classifier**
|
|
310
|
+
(issue #18, measured 2026-10-01 with direct cold curl probes, no pi in the
|
|
311
|
+
loop): api.nan.builders sits behind Cloudflare with a 120 s Proxy Read
|
|
312
|
+
Timeout. A COLD prompt of 208,036 tokens (~960 KB body) answered in 12.9 s;
|
|
313
|
+
~220k and ~286k tokens returned HTTP 524 `origin_response_timeout` at ~126 s
|
|
314
|
+
(JSON body or Cloudflare HTML page). Warm (cached) requests of the same size
|
|
315
|
+
answer in ~10 s. pi-ai (0.99.x–1.0.0) lists "524" in
|
|
316
|
+
`RETRYABLE_PROVIDER_ERROR_PATTERN` (retrying an identical cold payload always
|
|
317
|
+
fails) and `isContextOverflow()` matches nothing → the session wedges.
|
|
318
|
+
`src/context-overflow-classifier.ts` therefore has TWO independent
|
|
319
|
+
thresholds: the 400 branch (issue #3) keys on the model's `contextWindow`;
|
|
320
|
+
the 524 branch keys on `NAN_COLD_CACHE_CEILING_TOKENS` = 200,000 ONLY
|
|
321
|
+
(conservative midpoint below the last-working 208k measurement) — the
|
|
322
|
+
declared catalog windows are NOT reduced. A 524 below the ceiling stays a
|
|
323
|
+
transient retryable error. Compaction is a single pass with no hard-truncation
|
|
324
|
+
fallback in pi, so the rewrite rescues sessions that one compaction can bring
|
|
325
|
+
under the ceiling; far-over sessions still wedge (same limit as the #3 path).
|
|
326
|
+
- **Stale persisted catalog shadowing (issue #19, verified on pi-ai/pi 1.0.0):**
|
|
327
|
+
pi-ai's `createProvider`-built `refreshModels` restores
|
|
328
|
+
`context.stored.models` VERBATIM in the cache-only phase
|
|
329
|
+
(`dynamicModels = restored`, a closure variable unreachable from outside) and
|
|
330
|
+
`currentModels()` lets a dynamic entry REPLACE the static baseline entry with
|
|
331
|
+
the same id+type — so a `models-store.json` entry written by an older package
|
|
332
|
+
version (e.g. without `thinkingLevelMap`) shadows the newer generated
|
|
333
|
+
capability data whenever its `checkedAt` is fresh; `ModelsStoreEntry` has no
|
|
334
|
+
version/staleness signal. pi's `ModelsImpl` resolves models exclusively via
|
|
335
|
+
the provider object's `getModels()`/`getAllModels()`. Fix: `src/provider-factory.ts`
|
|
336
|
+
wraps both accessors (`withStaleCatalogOverlay`) to apply generated-catalog
|
|
337
|
+
capability data at READ time (chat ids from the generated catalog, image ids
|
|
338
|
+
from `baselineImageModels`) — the store decides which ids exist, the
|
|
339
|
+
generated catalog decides capability data; uncatalogued ids (live-only
|
|
340
|
+
`glm5.3`, ghosts) pass through untouched. `refreshModels` is NOT overridden:
|
|
341
|
+
the network phase already persists correct merged data. Option (a) of the
|
|
342
|
+
reporter (version-stamping persisted entries) is NOT implementable
|
|
343
|
+
provider-side: the store write path belongs to pi-ai.
|
package/README.es.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @gtrabanco/pi-nan-provider
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://github.com/gtrabanco/pi-nan-provider/releases)
|
|
5
5
|
|
|
6
6
|
[NaN Builders](https://nan.builders) model provider + MCP nativo para [pi](https://github.com/earendil-works/pi).
|
|
7
7
|
|
|
@@ -41,6 +41,8 @@ El proveedor utiliza un **catálogo de modelos de dos capas** para garantizar la
|
|
|
41
41
|
> [!IMPORTANT]
|
|
42
42
|
> **Detección de Tier**: La lista en vivo es la autoridad. Si tu clave tiene acceso premium, esos modelos aparecerán automáticamente; de lo contrario, se filtran.
|
|
43
43
|
|
|
44
|
+
Los ids no-chat que devuelve `/models` en vivo (embedding, rerank, TTS, STT, imagen) **no se registran** como modelos de chat — la clasificación es el único `NON_CHAT_MODEL_IDS` exportado desde `src/fetch-models.ts` (la misma fuente que usa el generador en build-time). La fusión salta sus marcadores y los coloca en un bucket observable `nonChat`; `baselineModels` también los filtra como capa defensiva. Esto evita que el selector de chat de pi ofrezca endpoints que no pueden servir chat (las peticiones devolverían 404).
|
|
45
|
+
|
|
44
46
|
El registro es síncrono a propósito: el catálogo de fallback está disponible al instante, y el runtime de Models de pi dirige el refresco en vivo (refresco de red en el arranque interactivo y periódico, solo caché en el registro), persistiendo el overlay entre ejecuciones.
|
|
45
47
|
|
|
46
48
|
### 🧠 Seguridad al cambiar de modelo (guard de razonamiento cross-model)
|
|
@@ -99,10 +101,13 @@ Consigue una clave en la [plataforma NaN](https://cloud.nan.builders/r/7GK06FX8)
|
|
|
99
101
|
|
|
100
102
|
## 🔌 MCP nativo
|
|
101
103
|
|
|
102
|
-
Dado que [pi 0.99.0 incluye un cliente MCP integrado](https://github.com/earendil-works/pi/blob/main/docs/usage.md), este paquete migra sus puentes a MCP nativo (requiere `pi >=0.99` —
|
|
104
|
+
Dado que [pi 0.99.0 incluye un cliente MCP integrado](https://github.com/earendil-works/pi/blob/main/docs/usage.md), este paquete migra sus puentes a MCP nativo (requiere `pi >=0.99, <2` — pi 0.99 hasta 1.0 son compatibles; el rango peer se amplió a `<2` en 0.11.0).
|
|
103
105
|
|
|
104
106
|
Ambos puentes están **activados por defecto** (por sesión, visibles en `/mcp`). Usa `/nan-mcp` para gestionarlos.
|
|
105
107
|
|
|
108
|
+
> [!TIP]
|
|
109
|
+
> ¿Prefieres configurar los servidores MCP de NaN tú mismo? Desde pi 0.99.2/1.0, un servidor MCP HTTP en el `mcp.json` global puede autenticarse con tu token de `/login nan` en vez de una clave copiada: `{ "auth": { "provider": "nan" } }` (solo en el `mcp.json` global; requiere `https`). El registro integrado de `nan-search` sigue usando `NAN_API_KEY`/la credencial almacenada.
|
|
110
|
+
|
|
106
111
|
### 🛠️ Comando de Gestión: `/nan-mcp`
|
|
107
112
|
|
|
108
113
|
| Comando | Efecto |
|
|
@@ -130,7 +135,7 @@ con un único aviso por sesión, mantiene los registros inactivos y deja que `/n
|
|
|
130
135
|
el toggle sin registrar un servidor que nunca podrá conectarse. Para tener MCP en la CLI, activa el
|
|
131
136
|
conector con `pi config` → Built-in extensions → `mcp`.
|
|
132
137
|
|
|
133
|
-
### Funciones de pi 0.99 y modelos NaN
|
|
138
|
+
### Funciones de pi 0.99-1.0 y modelos NaN
|
|
134
139
|
|
|
135
140
|
- **Modelos virtuales** — registra un router bajo `nan` (`pi.registerVirtualModel({ provider: "nan", ... })`);
|
|
136
141
|
enruta a los modelos físicos de NaN sin configuración por parte del proveedor. El guard de
|
|
@@ -143,12 +148,36 @@ conector con `pi config` → Built-in extensions → `mcp`.
|
|
|
143
148
|
endpoints de embedding/rerank/audio/imagen), así que este proveedor no registra modelos
|
|
144
149
|
`type: "classifier"`.
|
|
145
150
|
|
|
151
|
+
- **Modelos de imagen nativos de NaN** — flux-2-klein (text-to-image + image-to-image) y
|
|
152
|
+
qwen-image-2.1 (text-to-image) se registran como modelos de imagen de pi (`type: "image"`,
|
|
153
|
+
api `"nan-images"`). No aparecen en `/model`; se acceden desde codemode
|
|
154
|
+
con `models.generateImages(model, { input })` o desde extensiones con
|
|
155
|
+
`ctx.modelRegistry.generateImages()`:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
const painter = await models.getModelOfType("image", "nan", "flux-2-klein")
|
|
159
|
+
const result = await models.generateImages(painter, { input: [{ type: "text", text: "A red fox in the snow, watercolor" }] })
|
|
160
|
+
if (result.stopReason !== "stop") return result.errorMessage
|
|
161
|
+
for (const block of result.output) if (block.type === "image") image(block)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Ambos modelos necesitan el tier de membresía "inference" (403 de lo contrario); los endpoints
|
|
165
|
+
de imagen tienen su propio límite de tasa separado del chat (20 peticiones/min, 100
|
|
166
|
+
peticiones/mes compartido entre los dos modelos) y no consumen el presupuesto de tokens del
|
|
167
|
+
chat. [docs de NaN](https://nan.builders/docs/models) y [OpenAPI](https://nan.builders/openapi.json)
|
|
168
|
+
(comprobado 2026-10-01). El servidor MCP nan-media de la comunidad ya ofrece la misma
|
|
169
|
+
generación y edición como herramientas MCP, mientras que los modelos de imagen nativos permiten
|
|
170
|
+
que codemode y las extensiones los llamen directamente.
|
|
171
|
+
|
|
146
172
|
---
|
|
147
173
|
|
|
148
174
|
### 1. Servidor MCP oficial de NaN
|
|
149
175
|
*Puente oficial para herramientas remotas vía [https://api.nan.builders/mcp](https://nan.builders/docs/api).*
|
|
150
176
|
|
|
151
|
-
- **`
|
|
177
|
+
- **`mcp__nan_search__web_search(query, ...)`**: Realiza búsquedas web a través del gateway de NaN.
|
|
178
|
+
> pi 0.99.0–0.99.1 usaba la forma con guiones (`mcp__nan-search__web_search`); pi 0.99.2+ sanitiza
|
|
179
|
+
> los nombres de herramientas a solo `[A-Za-z0-9_]`, así que los guiones se convirtieron en
|
|
180
|
+
> guiones bajos. La forma con guiones bajos aplica desde 0.99.2 hasta pi 1.0.
|
|
152
181
|
|
|
153
182
|
### 2. Servidor MCP de Media (Comunidad)
|
|
154
183
|
*Conecta [`nan-mcp-server`](https://github.com/luciferfran/nan-mcp-server) mediante un cliente stdio local mínimo.*
|
|
@@ -158,11 +187,19 @@ conector con `pi config` → Built-in extensions → `mcp`.
|
|
|
158
187
|
|
|
159
188
|
| Herramienta | Propósito |
|
|
160
189
|
| :--- | :--- |
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
190
|
+
| `mcp__nan_media__generate_image` | Generación de imágenes (flux-2-klein) |
|
|
191
|
+
| `mcp__nan_media__edit_image` | Edición imagen→imagen (flux-2-klein) |
|
|
192
|
+
| `mcp__nan_media__text_to_speech` | Síntesis de audio (kokoro) |
|
|
193
|
+
| `mcp__nan_media__list_voices` | Listar voces disponibles |
|
|
194
|
+
| `mcp__nan_media__speech_to_text` | Transcripción de audio (whisper) |
|
|
195
|
+
| `mcp__nan_media__list_models` | Listar los ids de modelos que alcanza la key |
|
|
196
|
+
| `mcp__nan_media__embed_text` | Embeddings de texto (qwen3-embedding) |
|
|
197
|
+
| `mcp__nan_media__rerank_documents` | Reordenación de documentos (Qwen3-Reranker) |
|
|
198
|
+
|
|
199
|
+
> pi 0.99.0–0.99.1 usaba las formas con guiones (`mcp__nan-search__web_search`,
|
|
200
|
+
> `mcp__nan-media__*`); pi 0.99.2+ sanitiza los nombres de herramientas a solo
|
|
201
|
+
> `[A-Za-z0-9_]`, así que los guiones se convirtieron en guiones bajos. La forma
|
|
202
|
+
> con guiones bajos aplica desde 0.99.2 hasta pi 1.0.
|
|
166
203
|
|
|
167
204
|
#### 🔧 Configuración del Puente de Media
|
|
168
205
|
|
|
@@ -287,6 +324,8 @@ Los errores siguen siendo accionables: `401` → ejecuta `/login nan` o corrige
|
|
|
287
324
|
|
|
288
325
|
Catálogo base (verificado contra [docs de NaN](https://nan.builders/docs/models) y [OpenAPI](https://nan.builders/openapi.json)).
|
|
289
326
|
|
|
327
|
+
Modelos de chat:
|
|
328
|
+
|
|
290
329
|
| Modelo | Contexto | Máx. Salida | Entrada | Razonamiento |
|
|
291
330
|
| :--- | :--- | :--- | :--- | :---: |
|
|
292
331
|
| `qwen3.6` | 262,144 | 65,536 | texto, imagen | ✅ |
|
|
@@ -296,6 +335,17 @@ Catálogo base (verificado contra [docs de NaN](https://nan.builders/docs/models
|
|
|
296
335
|
| `glm5.3-flash` | 1,000,000 | 131,072 | texto, imagen | ✅ |
|
|
297
336
|
| `qwen3.8-flash` | 262,144 | 131,072 | texto, imagen | ✅ |
|
|
298
337
|
|
|
338
|
+
> [!NOTE]
|
|
339
|
+
> **Techo práctico con caché de prompt fría (issue #18).** Las ventanas de contexto de la tabla son las ventanas reales de los modelos, pero el borde de api.nan.builders (Cloudflare) aborta las respuestas que superan su Proxy Read Timeout de 120 s. Medido con peticiones frías directas (relleno único, sin caché de prompt; 2026-10-01): 208.036 tokens (~960 KB de cuerpo) respondió en 12,9 s mientras que ~220k y ~286k tokens devolvieron **HTTP 524 `origin_response_timeout`** a los ~126 s; los mismos tamaños con caché cálida responden en ~10 s. El techo práctico para peticiones frías queda por tanto muy por debajo de las ventanas declaradas. Desde 1.0.0 el provider reclasifica un 524 en una petición estimada por encima de 200.000 tokens (`NAN_COLD_CACHE_CEILING_TOKENS`) como desbordamiento de contexto para que pi compacte y reintente en vez de quedarse colgado; un 524 en una petición menor se deja intacto (timeout transitorio genuino).
|
|
340
|
+
|
|
341
|
+
Modelos de imagen no-chat (disponibles vía `models.generateImages()` /
|
|
342
|
+
`getModelOfType("image", …)`, no a través de `/model`):
|
|
343
|
+
|
|
344
|
+
| Modelo | Entrada | Propósito |
|
|
345
|
+
| :--- | :--- | :--- |
|
|
346
|
+
| `flux-2-klein` | texto, imagen | Text-to-image + image-to-image |
|
|
347
|
+
| `qwen-image-2.1` | texto | Text-to-image |
|
|
348
|
+
|
|
299
349
|
> [!NOTE]
|
|
300
350
|
> `mimo-v2.6-flash` está servido por NaN y desde el 2026-09-29 aparece también en models.dev (proveedor `nan`); la entrada manual que lo sostenía se conserva como fallback y su nota de procedencia sigue unida a la entrada generada.
|
|
301
351
|
>
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @gtrabanco/pi-nan-provider
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://github.com/gtrabanco/pi-nan-provider/releases)
|
|
5
5
|
|
|
6
6
|
[NaN Builders](https://nan.builders) model provider + native MCP servers for [pi](https://github.com/earendil-works/pi).
|
|
7
7
|
|
|
@@ -41,6 +41,8 @@ The provider uses a **two-layer model catalog** to ensure reliability:
|
|
|
41
41
|
> [!IMPORTANT]
|
|
42
42
|
> **Tier Detection**: The live list is authoritative. If your key has premium access, those models will appear automatically; otherwise, they are filtered out.
|
|
43
43
|
|
|
44
|
+
NaN's live `/models` also returns non-chat endpoint ids (embedding, rerank, TTS, STT, image). These are **not registered** as chat models — the classification is the single exported `NON_CHAT_MODEL_IDS` from `src/fetch-models.ts` (the same source used by the build-time generator). The merge skips their placeholders and places them in an observable `nonChat` bucket; `baselineModels` also filters them defensively. This prevents pi's chat picker from offering endpoints that cannot serve chat (requests would 404).
|
|
45
|
+
|
|
44
46
|
The registration is synchronous on purpose: the generated fallback catalog is available immediately, and pi's Models runtime drives the live refresh (network refresh at interactive startup and periodically, cache-only at registration), persisting the overlay between runs.
|
|
45
47
|
|
|
46
48
|
### 🧠 Model-switch safety (cross-model reasoning guard)
|
|
@@ -99,10 +101,13 @@ Get a key from the [NaN platform](https://cloud.nan.builders/r/7GK06FX8) (user s
|
|
|
99
101
|
|
|
100
102
|
## 🔌 Native MCP Servers
|
|
101
103
|
|
|
102
|
-
Since [pi 0.99.0 ships a built-in MCP client](https://github.com/earendil-works/pi/blob/main/docs/usage.md), this package migrates its bridges to native MCP (requires `pi >=0.99` —
|
|
104
|
+
Since [pi 0.99.0 ships a built-in MCP client](https://github.com/earendil-works/pi/blob/main/docs/usage.md), this package migrates its bridges to native MCP (requires `pi >=0.99, <2` — pi 0.99 through 1.0 are supported; the peer range was widened to `<2` in 0.11.0).
|
|
103
105
|
|
|
104
106
|
Both bridges are **enabled by default** (session-scoped, visible in `/mcp`). Use `/nan-mcp` to manage them.
|
|
105
107
|
|
|
108
|
+
> [!TIP]
|
|
109
|
+
> Prefer to configure NaN's MCP servers yourself? Since pi 0.99.2/1.0 an HTTP MCP server in the global `mcp.json` can authenticate with your `/login nan` token instead of a copied key: `{ "auth": { "provider": "nan" } }` (global `mcp.json` only; `https` required). The bundled `nan-search` registration keeps using `NAN_API_KEY`/the stored credential.
|
|
110
|
+
|
|
106
111
|
### 🛠️ Management Command: `/nan-mcp`
|
|
107
112
|
|
|
108
113
|
| Command | Effect |
|
|
@@ -129,7 +134,7 @@ per session, keeps the registrations idle, and lets `/nan-mcp enable` persist th
|
|
|
129
134
|
registering a server that can never connect. To get MCP in the CLI, enable the connector with
|
|
130
135
|
`pi config` → Built-in extensions → `mcp`.
|
|
131
136
|
|
|
132
|
-
### pi 0.99 features and NaN models
|
|
137
|
+
### pi 0.99-1.0 features and NaN models
|
|
133
138
|
|
|
134
139
|
- **Virtual models** — register a router under `nan` (`pi.registerVirtualModel({ provider: "nan", ... })`);
|
|
135
140
|
it routes to the physical NaN models with no provider-side configuration. The cross-model thinking
|
|
@@ -140,12 +145,36 @@ registering a server that can never connect. To get MCP in the CLI, enable the c
|
|
|
140
145
|
- **Classifier models** — not applicable: NaN exposes no classifier API (chat plus
|
|
141
146
|
embedding/rerank/audio/image endpoints only), so this provider registers no `type: "classifier"` models.
|
|
142
147
|
|
|
148
|
+
- **Native NaN image models** — flux-2-klein (text-to-image + image-to-image) and
|
|
149
|
+
qwen-image-2.1 (text-to-image) are registered as pi image models (`type: "image"`,
|
|
150
|
+
api `"nan-images"`). They do not appear in `/model`; they are reached through codemode
|
|
151
|
+
with `models.generateImages(model, { input })` or from extensions with
|
|
152
|
+
`ctx.modelRegistry.generateImages()`:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
const painter = await models.getModelOfType("image", "nan", "flux-2-klein")
|
|
156
|
+
const result = await models.generateImages(painter, { input: [{ type: "text", text: "A red fox in the snow, watercolor" }] })
|
|
157
|
+
if (result.stopReason !== "stop") return result.errorMessage
|
|
158
|
+
for (const block of result.output) if (block.type === "image") image(block)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Both models need the "inference" membership tier (403 otherwise); the image endpoints
|
|
162
|
+
are rate-limited separately from chat (20 requests/min, 100 requests/month shared
|
|
163
|
+
between the two models) and do not consume the chat token budget.
|
|
164
|
+
[NaN docs](https://nan.builders/docs/models) and [OpenAPI](https://nan.builders/openapi.json)
|
|
165
|
+
(checked 2026-10-01). The community nan-media MCP server already offers the same
|
|
166
|
+
generation and editing as MCP tools, while the native image models let codemode and
|
|
167
|
+
extensions call them directly.
|
|
168
|
+
|
|
143
169
|
---
|
|
144
170
|
|
|
145
171
|
### 1. Official NaN MCP Server
|
|
146
172
|
*Official remote MCP server registered natively via `pi.registerMcpServer()`.*
|
|
147
173
|
|
|
148
|
-
- **`
|
|
174
|
+
- **`mcp__nan_search__web_search(query, ...)`**: Performs web searches through NaN's gateway.
|
|
175
|
+
> pi 0.99.0–0.99.1 used the hyphenated form (`mcp__nan-search__web_search`); pi 0.99.2+ sanitizes
|
|
176
|
+
> tool names to `[A-Za-z0-9_]` only, so hyphens became underscores. The underscore form applies
|
|
177
|
+
> from 0.99.2 onward through pi 1.0.
|
|
149
178
|
|
|
150
179
|
### 2. Community Media MCP Server
|
|
151
180
|
*Bridges [`nan-mcp-server`](https://github.com/luciferfran/nan-mcp-server) via a minimal local stdio client.*
|
|
@@ -155,11 +184,19 @@ registering a server that can never connect. To get MCP in the CLI, enable the c
|
|
|
155
184
|
|
|
156
185
|
| Tool | Purpose |
|
|
157
186
|
| :--- | :--- |
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
187
|
+
| `mcp__nan_media__generate_image` | Image generation (flux-2-klein) |
|
|
188
|
+
| `mcp__nan_media__edit_image` | Image-to-image editing (flux-2-klein) |
|
|
189
|
+
| `mcp__nan_media__text_to_speech` | Audio synthesis (kokoro) |
|
|
190
|
+
| `mcp__nan_media__list_voices` | List available voices |
|
|
191
|
+
| `mcp__nan_media__speech_to_text` | Audio transcription (whisper) |
|
|
192
|
+
| `mcp__nan_media__list_models` | List the NaN model ids the key can reach |
|
|
193
|
+
| `mcp__nan_media__embed_text` | Text embeddings (qwen3-embedding) |
|
|
194
|
+
| `mcp__nan_media__rerank_documents` | Document reranking (Qwen3-Reranker) |
|
|
195
|
+
|
|
196
|
+
> pi 0.99.0–0.99.1 used the hyphenated forms (`mcp__nan-search__web_search`,
|
|
197
|
+
> `mcp__nan-media__*`); pi 0.99.2+ sanitizes tool names to `[A-Za-z0-9_]` only,
|
|
198
|
+
> so hyphens became underscores. The underscore form applies from 0.99.2 onward
|
|
199
|
+
> through pi 1.0.
|
|
163
200
|
|
|
164
201
|
#### 🔧 Media Bridge Configuration
|
|
165
202
|
|
|
@@ -284,6 +321,8 @@ Failures stay actionable: `401` → run `/login nan` or fix `NAN_API_KEY`, `404`
|
|
|
284
321
|
|
|
285
322
|
Baseline catalog (verified against [NaN docs](https://nan.builders/docs/models) and [OpenAPI](https://nan.builders/openapi.json)).
|
|
286
323
|
|
|
324
|
+
Chat models:
|
|
325
|
+
|
|
287
326
|
| Model | Context | Max Output | Input | Reasoning |
|
|
288
327
|
| :--- | :--- | :--- | :--- | :---: |
|
|
289
328
|
| `qwen3.6` | 262,144 | 65,536 | text, image | ✅ |
|
|
@@ -293,6 +332,17 @@ Baseline catalog (verified against [NaN docs](https://nan.builders/docs/models)
|
|
|
293
332
|
| `glm5.3-flash` | 1,000,000 | 131,072 | text, image | ✅ |
|
|
294
333
|
| `qwen3.8-flash` | 262,144 | 131,072 | text, image | ✅ |
|
|
295
334
|
|
|
335
|
+
> [!NOTE]
|
|
336
|
+
> **Cold prompt cache practical ceiling (issue #18).** The context windows above are the models' real windows, but the api.nan.builders edge (Cloudflare) aborts responses past its 120 s Proxy Read Timeout. Measured with direct cold requests (unique filler, no prompt cache; 2026-10-01): 208,036 tokens (~960 KB body) answered in 12.9 s while ~220k and ~286k tokens returned **HTTP 524 `origin_response_timeout`** at ~126 s; the same sizes with a warm prompt cache answer in ~10 s. The practical ceiling for cold requests is therefore well below the declared windows. Since 1.0.0 the provider reclassifies a 524 on an estimated over-200,000-token request (`NAN_COLD_CACHE_CEILING_TOKENS`) as a context overflow so pi compacts and retries instead of wedging; a 524 on a smaller request is left alone (genuine transient timeout).
|
|
337
|
+
|
|
338
|
+
Non-chat image models (available through `models.generateImages()` /
|
|
339
|
+
`getModelOfType("image", …)`, not through `/model`):
|
|
340
|
+
|
|
341
|
+
| Model | Input | Purpose |
|
|
342
|
+
| :--- | :--- | :--- |
|
|
343
|
+
| `flux-2-klein` | text, image | Text-to-image + image-to-image |
|
|
344
|
+
| `qwen-image-2.1` | text | Text-to-image |
|
|
345
|
+
|
|
296
346
|
> [!NOTE]
|
|
297
347
|
> `mimo-v2.6-flash` is served by NaN and has been listed by models.dev provider `nan` since 2026-09-29. Before that it entered the catalog through a manual-only entry; that entry is kept as a fallback (re-emitted automatically if models.dev drops the model again) and its provenance note stays attached to the generated entry.
|
|
298
348
|
>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtrabanco/pi-nan-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "NaN Builders (api.nan.builders) model provider for pi - OpenAI-compatible registration with a models.dev-generated fallback, tier-aware live catalog, and MCP bridges (official web search + optional community media server)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"check-pi-sdk-versions": "node scripts/check-pi-sdk-versions.mjs --report"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@earendil-works/pi-ai": ">=0.99.0 <
|
|
46
|
-
"@earendil-works/pi-coding-agent": ">=0.99.0 <
|
|
45
|
+
"@earendil-works/pi-ai": ">=0.99.0 <2",
|
|
46
|
+
"@earendil-works/pi-coding-agent": ">=0.99.0 <2"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@earendil-works/pi-ai": "0.
|
|
50
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
49
|
+
"@earendil-works/pi-ai": "1.0.0",
|
|
50
|
+
"@earendil-works/pi-coding-agent": "1.0.0",
|
|
51
51
|
"@types/bun": "1.4",
|
|
52
52
|
"typescript": "7"
|
|
53
53
|
},
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
* MANUAL_ONLY entry — or this script exits non-zero.
|
|
26
26
|
* - Any other models.dev entry missing `limit.context`/`limit.output` is
|
|
27
27
|
* skipped and flagged "needs manual verification" — never guessed. Entries
|
|
28
|
-
* that are not chat models are excluded via NON_CHAT_MODEL_IDS instead
|
|
28
|
+
* that are not chat models are excluded via NON_CHAT_MODEL_IDS instead
|
|
29
|
+
* (defined in `src/fetch-models.ts` and also enforced at runtime).
|
|
29
30
|
* - models.dev modalities are intersected with pi's supported input set
|
|
30
31
|
* ("text" | "image"); e.g. mimo-v2.6-flash's audio input is not
|
|
31
32
|
* representable in pi's Model type and is dropped from `input` (noted on
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
*/
|
|
34
35
|
|
|
35
36
|
import type { GeneratedModelEntry } from "../src/fetch-models.ts";
|
|
37
|
+
import { NON_CHAT_MODEL_IDS } from "../src/fetch-models.ts";
|
|
36
38
|
import type { ManualModelOverride } from "./manual-overrides.ts";
|
|
37
39
|
import {
|
|
38
40
|
MANUAL_OVERRIDES,
|
|
@@ -97,17 +99,10 @@ const PROVIDER_REMOVED_MODEL_IDS: Record<string, string> = {
|
|
|
97
99
|
"removed by NaN (checked 2026-09-29): zero mentions in https://nan.builders/docs/models and in the model param description of https://nan.builders/openapi.json, and models.dev provider nan dropped it as well — superseded by mimo-v2.6-flash; excluded so regeneration does not resurrect it",
|
|
98
100
|
};
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
* "needs manual verification" forever — that flag would suggest limits worth
|
|
105
|
-
* confirming for a model this package must not serve as chat.
|
|
106
|
-
*/
|
|
107
|
-
const NON_CHAT_MODEL_IDS: Record<string, string> = {
|
|
108
|
-
"qwen-image-2.1":
|
|
109
|
-
"image-generation model (text→image; output modality image) documented in https://nan.builders/docs/models and https://nan.builders/openapi.json (checked 2026-09-29) — not a chat model, out of the static chat catalog (models.dev reports limit.output 0)",
|
|
110
|
-
};
|
|
102
|
+
// NON_CHAT_MODEL_IDS (six non-chat endpoint ids) is imported from its single
|
|
103
|
+
// source of truth, `src/fetch-models.ts`, where the runtime live merge applies
|
|
104
|
+
// the same classification. Here it feeds convertModel's exclusion and the
|
|
105
|
+
// exclusion-note list in GENERATED_CATALOG_META.notes.
|
|
111
106
|
|
|
112
107
|
/**
|
|
113
108
|
* Premium/tier-gated models that models.dev documents but that are deliberately
|
|
@@ -346,6 +341,14 @@ async function main(): Promise<void> {
|
|
|
346
341
|
// so the manual data never disappears silently.
|
|
347
342
|
const entryById = new Map(entries.map((entry) => [entry.id, entry]));
|
|
348
343
|
for (const [modelId, detail] of Object.entries(MANUAL_ONLY_MODEL_IDS)) {
|
|
344
|
+
// Guard: a MANUAL_ONLY_MODEL_IDS entry must not be a non-chat id.
|
|
345
|
+
// (REQUIRED_MODEL_IDS can't land here: if a required id were non-chat,
|
|
346
|
+
// convertModel skips it and the existing missing-required fail already
|
|
347
|
+
// fires — but this guard is explicit for MANUAL_ONLY.)
|
|
348
|
+
const nonChatReason = NON_CHAT_MODEL_IDS[modelId];
|
|
349
|
+
if (nonChatReason) {
|
|
350
|
+
fail(`MANUAL_ONLY_MODEL_IDS id "${modelId}" is classified as non-chat (${nonChatReason}) — this is a contradictory repo configuration`);
|
|
351
|
+
}
|
|
349
352
|
const existing = entryById.get(modelId);
|
|
350
353
|
if (existing) {
|
|
351
354
|
const note = `manual-only: "${modelId}" skipped: models.dev provider "${SOURCE_PROVIDER_ID}" now lists it, so the manual-only entry is not emitted and the models.dev values are used (${detail})`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This file is auto-generated by scripts/generate-models.ts
|
|
2
2
|
// Do not edit manually — run `bun run generate-models` to update.
|
|
3
3
|
//
|
|
4
|
-
// Source: https://models.dev/api.json (provider "nan"), fetched 2026-10-
|
|
4
|
+
// Source: https://models.dev/api.json (provider "nan"), fetched 2026-10-02T00:02:21.641Z
|
|
5
5
|
// Provenance: every contextWindow/maxTokens/input/cost value traces to
|
|
6
6
|
// models.dev or to the per-entry notes below. Nothing is invented; entries
|
|
7
7
|
// models.dev documents incompletely are omitted and flagged instead.
|
|
@@ -455,7 +455,7 @@ export const NAN_GENERATED_MODELS: readonly GeneratedModelEntry[] = [
|
|
|
455
455
|
export const GENERATED_CATALOG_META = {
|
|
456
456
|
source: "https://models.dev/api.json",
|
|
457
457
|
modelsDevProvider: "nan",
|
|
458
|
-
fetchedAt: "2026-10-
|
|
458
|
+
fetchedAt: "2026-10-02T00:02:21.641Z",
|
|
459
459
|
modelCount: 6,
|
|
460
460
|
models: ["deepseek-v4-flash","gemma4","glm5.3-flash","mimo-v2.6-flash","qwen3.6","qwen3.8-flash"],
|
|
461
461
|
notes: [
|
|
@@ -463,6 +463,11 @@ export const GENERATED_CATALOG_META = {
|
|
|
463
463
|
"live-only: \"glm5.3\" kept out of the static catalog (premium-tier model (models.dev now documents it with 1M context / 131,072 max output; NaN docs https://nan.builders/docs/models + https://nan.builders/openapi.json, checked 2026-09-13) kept live-only so a non-premium key never sees a model it cannot call when the live /models fetch is unavailable; premium keys still get it via the /models refresh with conservative placeholder limits)",
|
|
464
464
|
"provider-removed: \"glm5.2\" excluded from the catalog (removed by NaN (2026-09-05); absent from the official chat model list in https://nan.builders/openapi.json and https://nan.builders/docs/models (checked 2026-09-07) while models.dev provider nan still listed it — excluded so regeneration does not resurrect it)",
|
|
465
465
|
"provider-removed: \"mimo-v2.5\" excluded from the catalog (removed by NaN (checked 2026-09-29): zero mentions in https://nan.builders/docs/models and in the model param description of https://nan.builders/openapi.json, and models.dev provider nan dropped it as well — superseded by mimo-v2.6-flash; excluded so regeneration does not resurrect it)",
|
|
466
|
+
"non-chat: \"qwen3-embedding\" excluded from the chat catalog (embedding endpoint (https://nan.builders/docs/models, checked 2026-10-01) — not a chat model)",
|
|
467
|
+
"non-chat: \"rerank\" excluded from the chat catalog (rerank endpoint (https://nan.builders/docs/models, checked 2026-10-01) — not a chat model)",
|
|
468
|
+
"non-chat: \"kokoro\" excluded from the chat catalog (text-to-speech (TTS) endpoint (https://nan.builders/docs/models, checked 2026-10-01) — not a chat model)",
|
|
469
|
+
"non-chat: \"whisper\" excluded from the chat catalog (speech-to-text (STT) endpoint (https://nan.builders/docs/models, checked 2026-10-01) — not a chat model)",
|
|
470
|
+
"non-chat: \"flux-2-klein\" excluded from the chat catalog (image generation endpoint (https://nan.builders/docs/models, checked 2026-10-01) — not a chat model)",
|
|
466
471
|
"compat matches the maintainer's working ~/.pi/agent/models.json LiteLLM config for api.nan.builders (2026-09-04): supportsDeveloperRole false, supportsReasoningEffort true, maxTokensField max_tokens. NaN's docs example sets only supportsDeveloperRole: true and is not battle-tested. supportsFinishReason true (2026-09-13, issue #2): the LiteLLM gateway intermittently closes SSE streams before emitting finish_reason; with true pi-ai raises 'Stream ended without finish_reason', which matches pi-ai's retryable-provider pattern ('ended without') and is retried automatically, whereas false silently synthesized stop/toolUse and stalled the turn mid-answer. supportsUsageInStreaming true (2026-09-16, issue #7): NaN's published schema is silent about stream_options, but the live gateway honors it — two identical streaming calls per model, differing only in stream_options: { include_usage: true }, returned 0 usage chunks without it and exactly 1 with it (prompt/completion/reasoning/cached token counts) on deepseek-v4-flash, glm5.3-flash, qwen3.6, mimo-v2.5 and gemma4, and a real pi session then recorded token counts where it recorded zeros. pi-ai only sends stream_options when this is not false, and the sanitizer forwards it when the model declares true, so chat models opt in by default and usage is reported (issue #4). A model that does not report streaming usage can still opt out per model with a models.json compat override (supportsUsageInStreaming: false); the sanitizer then strips stream_options and the payload stays strict.",
|
|
467
472
|
"input includes image: NaN serves the Vision-Exp variant ('takes images as input', https://nan.builders/docs/models; the image_url content-parts in https://nan.builders/openapi.json list deepseek-v4-flash among the vision models). models.dev provider nan also lists text+image now (DeepSeek V4.1 Flash entry, checked 2026-09-13; its 2026-09-07 snapshot listed text only), so this override is kept as a pin for the vision capability rather than as a divergence. reasoning_effort_values=[\"none\"] (issue #16, measured 2026-09-27 against live gateway, repro included in the issue): only \"none\" deterministically disables reasoning (0 reasoning tokens, answer produced). Every other value leaves 13-14K reasoning tokens and causes runaway reasoning (finish_reason:\"length\" with ZERO answer text). The catalog declares only [\"none\"] because the remaining values are useless noise. thinkingLevelMap { off: \"none\" } (issue #16, measured 2026-09-27): when pi maps reasoning:\"off\" to reasoningEffort:undefined, the thinkingLevelMap.off=\"none\" supplies the effort so the gateway receives reasoning_effort:\"none\" and does NOT enter runaway reasoning mode.",
|
|
468
473
|
"thinkingLevelMap { off: \"none\" } (issue #16): NaN docs state that with no reasoning_effort parameter gemma4 defaults to reasoning ON (16,384-token budget), while `none`/`minimal` skip reasoning entirely (https://nan.builders/docs/models#controlling-reasoning, checked 2026-10-01). pi maps reasoning:\"off\" to reasoningEffort:undefined, so without this map `thinking: off` sent no parameter and the model reasoned anyway; the map sends reasoning_effort:\"none\" and actually disables reasoning.",
|
package/src/commands.ts
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* package registers:
|
|
4
4
|
*
|
|
5
5
|
* - `nan-search` — the official NaN remote MCP server (api.nan.builders/mcp),
|
|
6
|
-
* exposing `
|
|
6
|
+
* exposing `mcp__nan_search__web_search` (pi >=0.99.2). Default: enabled.
|
|
7
|
+
* (pi 0.99.0–0.99.1 used the hyphenated form `mcp__nan-search__web_search`.)
|
|
7
8
|
* - `nan-media` — the community stdio media server (flux-2-klein / kokoro /
|
|
8
|
-
* whisper), exposing `
|
|
9
|
+
* whisper), exposing `mcp__nan_media__generate_image` etc. Default: enabled.
|
|
10
|
+
* (pi 0.99.0–0.99.1 used the hyphenated form `mcp__nan-media__*`.)
|
|
9
11
|
*
|
|
10
12
|
* Both are session-scoped native servers (visible in /mcp, source "extension").
|
|
11
13
|
* /nan-mcp enables/disables them via pi.registerMcpServer / pi.unregisterMcpServer,
|
|
@@ -74,8 +76,8 @@ function serverName(bridge: BridgeKey): string {
|
|
|
74
76
|
/** Describe the bridge in the status message. */
|
|
75
77
|
function bridgeDescription(bridge: BridgeKey): string {
|
|
76
78
|
return bridge === "webSearch"
|
|
77
|
-
? "web-search bridge (official NaN MCP →
|
|
78
|
-
: "nan-mcp-server bridge (community media MCP →
|
|
79
|
+
? "web-search bridge (official NaN MCP → mcp__nan_search__web_search)"
|
|
80
|
+
: "nan-mcp-server bridge (community media MCP → mcp__nan_media__generate_image/edit_image/text_to_speech/list_voices/speech_to_text)";
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
/** Check if a native server of this name is currently registered. */
|