@gtrabanco/pi-nan-provider 0.2.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/AGENTS.md +84 -0
- package/CLAUDE.md +1 -0
- package/CONTRIBUTING.md +48 -0
- package/LICENSE +21 -0
- package/README.es.md +144 -0
- package/README.md +144 -0
- package/package.json +59 -0
- package/scripts/generate-models.ts +239 -0
- package/scripts/models.generated.ts +440 -0
- package/src/fetch-models.ts +254 -0
- package/src/index.ts +96 -0
- package/src/mcp/nan-media.ts +199 -0
- package/src/mcp/nan-search.ts +220 -0
- package/src/mcp/stdio-client.ts +222 -0
- package/src/provider-factory.ts +96 -0
- package/src/providers.ts +34 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# AGENTS.md — rules for any agent working on this repo
|
|
2
|
+
|
|
3
|
+
## The One Rule
|
|
4
|
+
|
|
5
|
+
You must understand and be able to explain any code you write. If you cannot explain
|
|
6
|
+
why a line exists, delete it or learn why before shipping. (Mirrors pi's own
|
|
7
|
+
CONTRIBUTING "One Rule" — we apply it to ourselves too.)
|
|
8
|
+
|
|
9
|
+
## No fabricated model metadata
|
|
10
|
+
|
|
11
|
+
Every context-window, max-token, modality, cost, and compat value must trace to a
|
|
12
|
+
source:
|
|
13
|
+
|
|
14
|
+
- **models.dev** (provider `nan` in `https://models.dev/api.json`) — the default
|
|
15
|
+
source, pulled by `scripts/generate-models.ts`; or
|
|
16
|
+
- **an explicit manual note** recorded on the generated entry
|
|
17
|
+
(`notes` in `scripts/models.generated.ts`) stating where the value was confirmed
|
|
18
|
+
(URL + date).
|
|
19
|
+
|
|
20
|
+
Never guess limits. If a model is missing from models.dev or has incomplete limits,
|
|
21
|
+
the generator omits it and flags it (`needs manual verification`); do not invent
|
|
22
|
+
numbers to fill the gap. The same applies to auth mechanics: only documented pi
|
|
23
|
+
behavior (`docs/custom-provider.md` shipped with pi) — no invented flows.
|
|
24
|
+
|
|
25
|
+
## Verify before done
|
|
26
|
+
|
|
27
|
+
Run both before considering any task done:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bun test # all tests must pass
|
|
31
|
+
bun run typecheck # typecheck must be clean (bunx resolves tsc; bun publish lifecycle lacks node_modules/.bin on PATH)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Regenerate the catalog after touching `scripts/generate-models.ts`:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bun run generate-models
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## One shared implementation for all providers
|
|
41
|
+
|
|
42
|
+
`nan` (and any future provider, e.g. `helmcode`) must stay behind the single shared
|
|
43
|
+
factory in `src/provider-factory.ts`. A second provider-specific file is a smell:
|
|
44
|
+
refactor back to the factory and add a config entry in `src/providers.ts` instead.
|
|
45
|
+
The `factory is shared` test in `test/provider-factory.test.ts` guards this contract.
|
|
46
|
+
|
|
47
|
+
## Version policy (strict semver)
|
|
48
|
+
|
|
49
|
+
Every PR that changes code MUST bump `package.json` version in the same PR; CI publishes only when the version differs from npm.
|
|
50
|
+
|
|
51
|
+
- **PATCH** (`0.1.z`): bug fixes, docs, comment-only changes, catalog regeneration with identical values.
|
|
52
|
+
- **MINOR** (`0.x.0`): new features — new provider entries, new MCP tools, new env vars/config options, and (while `0.x`) breaking changes, each breaking change called out explicitly in the PR/changelog.
|
|
53
|
+
- **MAJOR** (`x.0.0`): breaking changes once `1.0.0` is reached.
|
|
54
|
+
- Never reuse a published version; never publish with failing tests (CI gates publish on tests + typecheck).
|
|
55
|
+
- 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.
|
|
56
|
+
|
|
57
|
+
## Verified API facts (do not re-derive from stale docs)
|
|
58
|
+
|
|
59
|
+
- pi 0.84.4: `openAICompletionsApi` is **not** exported from the `@earendil-works/pi-ai`
|
|
60
|
+
root (the `custom-provider.md` snippet is stale). Import it from
|
|
61
|
+
`@earendil-works/pi-ai/api/openai-completions.lazy`.
|
|
62
|
+
- `createProvider` and `envApiKeyAuth(name, envVars)` are on the pi-ai root.
|
|
63
|
+
`envApiKeyAuth` implements exactly: stored credential key wins → first set env
|
|
64
|
+
var → unconfigured; `login()` prompts with `{ type: "secret" }`.
|
|
65
|
+
- `pi.registerProvider(provider)` accepts a complete pi-ai `Provider`; pi's Models
|
|
66
|
+
runtime then drives `fetchModels` refreshes (network refresh at interactive
|
|
67
|
+
startup and periodically, cache-only at registration) and persists the overlay.
|
|
68
|
+
A `fetchModels` rejection never blocks startup.
|
|
69
|
+
- models.json overrides compose **above** registered native providers.
|
|
70
|
+
- Relative imports inside this package use `.ts` extensions (pi's official
|
|
71
|
+
extension examples do the same; pi transpiles extension sources).
|
|
72
|
+
- pi intentionally has NO built-in MCP client (docs/usage.md). MCP integration
|
|
73
|
+
happens by bridging servers into pi custom tools via `pi.registerTool()`:
|
|
74
|
+
- NaN's official remote MCP server: `https://api.nan.builders/mcp` (host
|
|
75
|
+
root, NOT /v1; JSON-RPC 2.0 over streamable HTTP, stateless; same `sk-`
|
|
76
|
+
key, shared rate limit/quota). Spec: https://nan.builders/openapi.json
|
|
77
|
+
(tag "MCP"). Currently exposes `web_search` (same args as POST /v1/search);
|
|
78
|
+
"growing registry" — use tools/list to discover.
|
|
79
|
+
- Community `nan-mcp-server` (https://github.com/luciferfran/nan-mcp-server):
|
|
80
|
+
stdio MCP server, spawned per tool call (lazy), opt-in NAN_MEDIA_MCP=1,
|
|
81
|
+
version-pinned via NAN_MEDIA_MCP_VERSION (default 1.0.7) or a full command
|
|
82
|
+
override via NAN_MEDIA_MCP_COMMAND. Tools: generate_image, edit_image,
|
|
83
|
+
text_to_speech, list_voices, speech_to_text, embed, rerank, list_models
|
|
84
|
+
(we bridge the audio/image/transcription scope).
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Contributing to @gtrabanco/pi-nan-provider
|
|
2
|
+
|
|
3
|
+
Thanks for contributing! Read [`AGENTS.md`](AGENTS.md) first — it contains the binding rules for this repo (the One Rule, no fabricated model metadata, one shared provider implementation, verified pi API facts, and the versioning policy). This document covers the mechanics.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install
|
|
9
|
+
bun test # all tests must pass
|
|
10
|
+
bun run typecheck # typecheck must be clean (bunx-resolved tsc)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The upstream contracts this package must follow live in pi's own docs (`docs/custom-provider.md`, `docs/packages.md` shipped with `@earendil-works/pi-coding-agent`) and in NaN's OpenAPI spec (`https://nan.builders/openapi.json`). Verify API surfaces against the installed `@earendil-works/pi-ai`/`pi-coding-agent` versions — doc snippets can be stale (see `AGENTS.md` for known corrections).
|
|
14
|
+
|
|
15
|
+
## Making changes
|
|
16
|
+
|
|
17
|
+
1. **Write/adjust tests first** for the behavior you are adding or fixing. Every source file has a matching test file — keep that true.
|
|
18
|
+
2. Implement the change; keep `nan` (and any future provider) behind the single shared factory in `src/provider-factory.ts`. A second provider-specific file is a smell.
|
|
19
|
+
3. Run the full gate before considering any task done:
|
|
20
|
+
```bash
|
|
21
|
+
bun test && bun run typecheck
|
|
22
|
+
```
|
|
23
|
+
4. If you touched `scripts/generate-models.ts` or catalog-related logic, regenerate and commit the catalog:
|
|
24
|
+
```bash
|
|
25
|
+
bun run generate-models
|
|
26
|
+
```
|
|
27
|
+
5. Never fabricate model metadata. Every context-window/max-token/modality/cost/compat value must trace to models.dev or an explicit `notes` entry stating where it was confirmed (URL + date).
|
|
28
|
+
|
|
29
|
+
## Versioning and releases (strict semver)
|
|
30
|
+
|
|
31
|
+
Every PR that changes code **must** bump `package.json`'s version in the same PR; CI only publishes when the version changed. The policy lives in `AGENTS.md`; the short version:
|
|
32
|
+
|
|
33
|
+
| Change | Bump |
|
|
34
|
+
|---|---|
|
|
35
|
+
| Docs, comments, catalog regeneration with identical values | PATCH |
|
|
36
|
+
| New feature (new provider, new MCP tool, new env var, new config option) | MINOR |
|
|
37
|
+
| Breaking change (renamed config, changed env var semantics, removed model/field/behavior) | MINOR while `0.x` (announced in the PR), MAJOR from `1.0.0` |
|
|
38
|
+
| Fixes | PATCH |
|
|
39
|
+
|
|
40
|
+
## Pull requests
|
|
41
|
+
|
|
42
|
+
- One logical change per PR; include tests and the version bump.
|
|
43
|
+
- CI (`publish.yml`) runs on merges to `main` touching `src/**`, `scripts/**`, `test/**`, or `package.json`: it regenerates the catalog, runs tests + typecheck, and publishes **only if the version differs from npm**. Docs-only merges never publish.
|
|
44
|
+
- Set the `NPM_TOKEN` repository secret before the first release (npm automation token with publish rights for `@gtrabanco`).
|
|
45
|
+
|
|
46
|
+
## Reporting issues
|
|
47
|
+
|
|
48
|
+
Include: pi version (`pi --version`), the extension version, what you expected vs what happened, and — for model data issues — the exact value in question plus its source. Model-data corrections should come with a source link so they can be encoded as provenance notes.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gtrabanco
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.es.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# @gtrabanco/pi-nan-provider
|
|
2
|
+
|
|
3
|
+
Proveedor de modelos de [NaN Builders](https://nan.builders) + puentes MCP para [pi](https://github.com/earendil-works/pi). Registra el proveedor `nan` vía `pi.registerProvider()` usando la API OpenAI-compatible de NaN (`https://api.nan.builders/v1`, LiteLLM por debajo), y conecta las herramientas MCP de NaN en pi con `pi.registerTool()`.
|
|
4
|
+
|
|
5
|
+
**Documentación en español** (este archivo) · [Documentation in English](README.md)
|
|
6
|
+
|
|
7
|
+
Consigue tu API key de NaN (enlace de referidos): **<https://cloud.nan.builders/r/7GK06FX8>**
|
|
8
|
+
|
|
9
|
+
## Cómo funciona
|
|
10
|
+
|
|
11
|
+
Catálogo de modelos de dos capas, nunca una sola:
|
|
12
|
+
|
|
13
|
+
1. **Fallback generado** (`scripts/models.generated.ts`, versionado): se genera en build desde [models.dev](https://models.dev) (proveedor `nan`). Es la configuración *servida* por NaN — si el modelo subyacente soporta 2M de contexto pero NaN lo sirve a 1M, el catálogo dice lo que tu clave obtiene, no el máximo teórico del modelo. Cada valor traza a su fuente, y la entrada cruda completa de models.dev se conserva por modelo (`extras`) para no perder ninguna propiedad documentada. Nada se inventa: las entradas incompletas en models.dev se omiten y se marcan.
|
|
14
|
+
2. **Fetch en vivo de `/models`**: el endpoint de NaN solo devuelve los `id` de los modelos, así que se usa para confirmar qué IDs puede llamar tu clave. Los IDs en vivo se combinan con los datos de capacidades generados; un ID en vivo sin datos generados se conserva con límites conservadores de ejemplo (nunca capacidades fabricadas). Ante timeout (~3s), fallo de red, error de auth o respuesta inutilizable, se usa el catálogo generado y el arranque nunca se bloquea.
|
|
15
|
+
|
|
16
|
+
**Detección de tier:** con clave configurada, la lista en vivo de `/models` es la autoridad — lista exactamente los modelos que tu membresía de NaN puede llamar, y los modelos ausentes se filtran del conjunto disponible (`filterModels`). Eso incluye los modelos con tier: un modelo de tier premium simplemente no aparece si tu clave no lo tiene. Sin clave (o si falla el fetch), se muestra el catálogo generado completo.
|
|
17
|
+
|
|
18
|
+
El registro es síncrono a propósito: el catálogo generado 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.
|
|
19
|
+
|
|
20
|
+
## Instalación
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pi install npm:@gtrabanco/pi-nan-provider
|
|
24
|
+
# o, desde git:
|
|
25
|
+
pi install git:github.com/gtrabanco/pi-nan-provider
|
|
26
|
+
# o, para probarlo sin instalar:
|
|
27
|
+
pi -e npm:@gtrabanco/pi-nan-provider
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Después reinicia pi (o `/reload`). Verifica con:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pi --list-models nan
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Autenticación
|
|
37
|
+
|
|
38
|
+
`resolve()` comprueba primero la credencial almacenada y después recurre a la variable de entorno correspondiente — la misma precedencia que usan los proveedores nativos de pi. No hace falta ningún prompt si la env var está configurada. Las claves nunca se hardcodean ni se loguean.
|
|
39
|
+
|
|
40
|
+
**Opción 1 — variable de entorno (rápida):** con el paquete instalado basta con exportar la clave para tener NaN configurado:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export NAN_API_KEY="sk-tu-clave-aqui"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Opción 2 — `/login` (persistente):** ejecuta `/login nan` en pi y pega tu clave; se guarda en `~/.pi/agent/auth.json`.
|
|
47
|
+
|
|
48
|
+
**Opción 3 — `~/.pi/agent/auth.json` directamente:**
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"nan": { "type": "api_key", "key": "sk-tu-clave-aqui" }
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Consigue una clave en la [plataforma NaN](https://cloud.nan.builders/r/7GK06FX8) (ajustes de usuario → API Keys; enlace de referidos). La clave es personal e intransferible.
|
|
57
|
+
|
|
58
|
+
## Puentes MCP
|
|
59
|
+
|
|
60
|
+
pi no incluye cliente MCP a propósito ("It intentionally does not include built-in MCP" — `docs/usage.md` de pi). Este paquete conecta servidores MCP dentro de pi como herramientas nativas personalizadas, de modo que el LLM las llama como cualquier herramienta integrada.
|
|
61
|
+
|
|
62
|
+
### 1. Servidor MCP oficial de NaN (activo por defecto)
|
|
63
|
+
|
|
64
|
+
El servidor MCP remoto oficial de NaN ([`https://api.nan.builders/mcp`](https://nan.builders/docs/api), JSON-RPC 2.0 sobre HTTP, misma clave `sk-`, mismo límite de tasa/cuota/concurrencia que la API REST) se conecta como:
|
|
65
|
+
|
|
66
|
+
- **`nan_web_search(query, count?, freshness?, fetch_content?)`** — búsqueda web vía NaN. Registrado por defecto siempre que pi soporte `registerTool`; desactívalo con `NAN_MCP_TOOLS=0`.
|
|
67
|
+
|
|
68
|
+
El servidor es un registro en crecimiento (descubrible con `tools/list`); este paquete conecta por ahora la herramienta documentada `web_search` y mantiene un helper genérico `callNanMcpTool()` para herramientas futuras.
|
|
69
|
+
|
|
70
|
+
### 2. Servidor MCP de media de la comunidad (opcional, perezoso)
|
|
71
|
+
|
|
72
|
+
[`nan-mcp-server`](https://github.com/luciferfran/nan-mcp-server) es un servidor MCP stdio que expone las herramientas de media de NaN: generación/edición de imágenes (flux-2-klein), TTS (kokoro) y STT (whisper). Como pi no tiene cliente MCP, este paquete lo conecta como herramientas de pi mediante un cliente MCP stdio mínimo:
|
|
73
|
+
|
|
74
|
+
- **Desactivado por defecto** — actívalo con `NAN_MEDIA_MCP=1`.
|
|
75
|
+
- **Perezoso (lazy)**: el proceso del servidor MCP se lanza *por cada llamada* y se termina justo después. No arranca ni conecta nada a menos que se invoque realmente generación de audio/imagen/transcripción.
|
|
76
|
+
- **Configuración**: `NAN_API_KEY` se reenvía automáticamente (la misma clave del proveedor); los ficheros generados van a `~/nan-mcp-output/` (por defecto del servidor, configurable con `NAN_OUTPUT_DIR`).
|
|
77
|
+
|
|
78
|
+
| Herramienta | Propósito |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `nan_generate_image(prompt, size?, n?, seed?, guidance?, outputName?)` | Generar una imagen (flux-2-klein) |
|
|
81
|
+
| `nan_edit_image(prompt, images, size?, n?, seed?, guidance?, outputName?)` | Editar una imagen imagen→imagen (flux-2-klein) |
|
|
82
|
+
| `nan_text_to_speech(text, voice?, format?, speed?, outputName?)` | Sintetizar audio (kokoro) |
|
|
83
|
+
| `nan_list_voices()` | Listar voces kokoro por idioma |
|
|
84
|
+
| `nan_speech_to_text(file, language?, verbose?)` | Transcribir audio (whisper) |
|
|
85
|
+
|
|
86
|
+
Variables de entorno:
|
|
87
|
+
|
|
88
|
+
| Variable | Por defecto | Significado |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `NAN_MEDIA_MCP` | off | `1`/`true`/`on` activa las herramientas de media |
|
|
91
|
+
| `NAN_MEDIA_MCP_VERSION` | `1.0.7` | Versión del servidor fijada para `npx -y nan-mcp-server@<v>` (recomendación de supply-chain del propio proyecto) |
|
|
92
|
+
| `NAN_MEDIA_MCP_COMMAND` | — | Comando personalizado completo, p. ej. `bunx nan-mcp-server@1.0.7` |
|
|
93
|
+
| `NAN_MEDIA_MCP_TIMEOUT_MS` | `120000` | Timeout por llamada; el proceso se mata al expirar |
|
|
94
|
+
| `NAN_MCP_TOOLS` | — | `0`/`false`/`off` desactiva el puente `nan_web_search` oficial |
|
|
95
|
+
|
|
96
|
+
## Modelos
|
|
97
|
+
|
|
98
|
+
Catálogo base (de models.dev, proveedor `nan`, obtenido 2026-09-04 — límites *servidos* por NaN, no máximos teóricos):
|
|
99
|
+
|
|
100
|
+
| Modelo | Contexto | Máx. salida | Entrada | Razonamiento |
|
|
101
|
+
|---|---|---|---|---|
|
|
102
|
+
| `qwen3.6` | 262,144 | 65,536 | texto, imagen | sí |
|
|
103
|
+
| `gemma4` | 262,144 | 32,768 | texto, imagen | sí |
|
|
104
|
+
| `deepseek-v4-flash` | 1,000,000 | 384,000 | texto, imagen | sí |
|
|
105
|
+
| `mimo-v2.5` | 1,048,576 | 131,072 | texto, imagen | sí |
|
|
106
|
+
| `glm5.2` | 500,000 | 131,072 | texto | sí |
|
|
107
|
+
| `glm5.3-flash` | 1,000,000 | 131,072 | texto, imagen | sí |
|
|
108
|
+
| `qwen3.8-flash` | 262,144 | 131,072 | texto, imagen | sí |
|
|
109
|
+
|
|
110
|
+
Notas (grabadas por entrada en `scripts/models.generated.ts`):
|
|
111
|
+
|
|
112
|
+
- `deepseek-v4-flash` incluye entrada de imagen porque NaN sirve la variante Vision-Exp ([docs de NaN](https://nan.builders/docs/models)); models.dev la lista como solo texto.
|
|
113
|
+
- `mimo-v2.5` es omnimodal (texto/imagen/audio) en NaN, pero el tipo de modelo de pi solo representa entrada texto/imagen, así que el audio se omite en `input`.
|
|
114
|
+
- NaN factura por cuota de membresía, que models.dev reporta como coste cero por token — el coste mostrado por pi será $0.
|
|
115
|
+
- Compat (`supportsDeveloperRole: false`, `supportsReasoningEffort: true`, `supportsUsageInStreaming: true`, `maxTokensField: "max_tokens"`) coincide con la config LiteLLM probada en batalla que este paquete reemplaza; el ejemplo de los docs de NaN (`supportsDeveloperRole: true`) no está probado.
|
|
116
|
+
- **Tier/cuota**: qué modelos puedes llamar lo decide tu membresía de NaN. Con clave, el fetch en vivo refleja exactamente eso (ver *Cómo funciona* — detección de tier). El GLM 5.3 de tier premium no está en el proveedor `nan` de models.dev; solo está `glm5.3-flash`.
|
|
117
|
+
|
|
118
|
+
### Relación con `~/.pi/agent/models.json`
|
|
119
|
+
|
|
120
|
+
Este paquete reemplaza el bloque `nan` manual de `~/.pi/agent/models.json` (el [ejemplo pi](https://nan.builders/docs/examples) de los docs de NaN). Si conservas ese bloque, ten en cuenta que **models.json se compone por encima de los proveedores registrados** — el fichero estático gana sobre este paquete. Elimina la entrada `nan` de `models.json` (conserva `defaultProvider`/`defaultModel` en `settings.json` si los usas) para usar el catálogo en vivo de este paquete. Los topes de salida por petición pueden seguir configurándose ahí o vía `params` del modelo.
|
|
121
|
+
|
|
122
|
+
## Compatibilidad con versiones de pi
|
|
123
|
+
|
|
124
|
+
Verificado contra pi **0.84.4** y la línea 0.85 (`registerProvider(provider)`, `registerProvider(name, config)`, `registerTool` y `modelRegistry.getApiKeyForProvider` presentes en ambas). La extensión degrada con elegancia entre versiones:
|
|
125
|
+
|
|
126
|
+
- **Ruta nativa (pi ≥ 0.84)**: Provider completo con auth credencial-almacenada-primero-then-env, overlay de catálogo en vivo y filtrado por tier.
|
|
127
|
+
- **Fallback legacy**: si el overload nativo de Provider es rechazado, el registro cae a la forma legacy documentada `(name, config)` con el mismo catálogo generado y auth por env `$NAN_API_KEY` (la auth por credencial almacenada es una limitación del camino legacy, no un cambio silencioso).
|
|
128
|
+
- **Puentes MCP**: se omiten por completo en runtimes sin `registerTool`; los proveedores se registran igualmente.
|
|
129
|
+
- `peerDependencies` es `>=0.84.4` sin límite superior.
|
|
130
|
+
|
|
131
|
+
## helmcode
|
|
132
|
+
|
|
133
|
+
La fábrica compartida (`src/provider-factory.ts`) es agnóstica del proveedor, pero `helmcode` **no está registrado**: no existe una URL base ni fuente de capacidades confirmadas (ausente de models.dev y de los docs de NaN), y este repo no fabrica datos de proveedores. Cuando se confirme un endpoint, registrarlo es una entrada en `src/providers.ts` más datos de catálogo — sin una segunda implementación. Un test de contrato (`factory is shared`) ya ejercita un segundo proveedor por el mismo camino de código.
|
|
134
|
+
|
|
135
|
+
## Desarrollo
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bun install
|
|
139
|
+
bun run generate-models # regenerar el catálogo fallback desde models.dev (pre-publish)
|
|
140
|
+
bun test # tests unitarios + integración (fetch, auth, puentes MCP, compat)
|
|
141
|
+
bun run typecheck # typecheck vía bunx (tsc local, se autoinstala si falta)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`prepublishOnly` ejecuta generación + tests + typecheck. El typecheck resuelve `tsc` vía `bunx` porque `bun publish` ejecuta los scripts de ciclo de vida sin `node_modules/.bin` en el PATH (un `tsc` pelado falla ahí con exit 127). Las releases siguen semver estricto (ver `AGENTS.md`); CI publica cuando un merge a main cambia código y la versión. Ver `CONTRIBUTING.md` para el flujo completo de contribución.
|
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# @gtrabanco/pi-nan-provider
|
|
2
|
+
|
|
3
|
+
[NaN Builders](https://nan.builders) model provider + MCP bridges for [pi](https://github.com/earendil-works/pi). Registers the `nan` provider via `pi.registerProvider()` using NaN's OpenAI-compatible API (`https://api.nan.builders/v1`, LiteLLM behind it), and bridges NaN's MCP tools into pi with `pi.registerTool()`.
|
|
4
|
+
|
|
5
|
+
**Docs in English** (this file) · [Documentación en español](README.es.md)
|
|
6
|
+
|
|
7
|
+
Get your NaN API key (referral link): **<https://cloud.nan.builders/r/7GK06FX8>**
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
Two-layer model catalog, never either alone:
|
|
12
|
+
|
|
13
|
+
1. **Generated fallback** (`scripts/models.generated.ts`, committed): pulled at build time from [models.dev](https://models.dev) (provider `nan`). This is NaN's *served* configuration — if the underlying model can do 2M context but NaN serves it at 1M, the catalog says what your key gets, not the raw model maximum. Every value traces to its source, and the full raw models.dev entry is preserved per model (`extras`) so no documented property is lost. Nothing is invented: entries models.dev documents incompletely are omitted and flagged.
|
|
14
|
+
2. **Live `/models` fetch** at runtime: NaN's endpoint returns only model `id`s, so it is used to confirm which IDs your key can actually call. Live IDs are merged with the generated capability data; a live ID without generated data is kept with conservative placeholder limits (never fabricated capabilities). On timeout (~3s), network failure, auth error, or an unusable response, the generated catalog is used and startup is never blocked.
|
|
15
|
+
|
|
16
|
+
**Tier detection:** with a key configured, the live `/models` list is authoritative — it lists exactly the models your NaN membership can call, and models absent from it are filtered out of the available set (`filterModels`). That includes tier-gated models: a premium-tier model simply does not appear unless your key has the tier. Without a key (or if the fetch fails), the full generated catalog is shown.
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pi install npm:@gtrabanco/pi-nan-provider
|
|
24
|
+
# or, from git:
|
|
25
|
+
pi install git:github.com/gtrabanco/pi-nan-provider
|
|
26
|
+
# or, to try it without installing:
|
|
27
|
+
pi -e npm:@gtrabanco/pi-nan-provider
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then restart pi (or `/reload`). Verify with:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pi --list-models nan
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Authentication
|
|
37
|
+
|
|
38
|
+
`resolve()` checks the stored credential first, then falls back to the matching env var — the same precedence pi's built-in providers use. No prompt is needed when the env var is set. Keys are never hardcoded or logged.
|
|
39
|
+
|
|
40
|
+
**Option 1 — env var (quick):** having the package installed is enough; just export the key and NaN is configured:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export NAN_API_KEY="sk-your-key-here"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Option 2 — `/login` (persistent):** run `/login nan` in pi and paste your key; it is stored in `~/.pi/agent/auth.json`.
|
|
47
|
+
|
|
48
|
+
**Option 3 — `~/.pi/agent/auth.json` directly:**
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"nan": { "type": "api_key", "key": "sk-your-key-here" }
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Get a key from the [NaN platform](https://cloud.nan.builders/r/7GK06FX8) (user settings → API Keys; referral link). The key is personal and non-transferable.
|
|
57
|
+
|
|
58
|
+
## MCP bridges
|
|
59
|
+
|
|
60
|
+
pi intentionally ships without an MCP client ("It intentionally does not include built-in MCP" — pi's `docs/usage.md`). This package bridges MCP servers into pi as native custom tools, so the LLM calls them like any built-in tool.
|
|
61
|
+
|
|
62
|
+
### 1. Official NaN MCP server (on by default)
|
|
63
|
+
|
|
64
|
+
NaN's official remote MCP server ([`https://api.nan.builders/mcp`](https://nan.builders/docs/api), JSON-RPC 2.0 over HTTP, same `sk-` key, same rate limit/quota/concurrency as the REST API) is bridged as:
|
|
65
|
+
|
|
66
|
+
- **`nan_web_search(query, count?, freshness?, fetch_content?)`** — web search through NaN. Registered by default whenever pi supports `registerTool`; disable with `NAN_MCP_TOOLS=0`.
|
|
67
|
+
|
|
68
|
+
The server is a growing registry (discover with `tools/list`); this package currently bridges the documented `web_search` tool and keeps a generic `callNanMcpTool()` helper for future tools.
|
|
69
|
+
|
|
70
|
+
### 2. Community media MCP server (opt-in, lazy)
|
|
71
|
+
|
|
72
|
+
[`nan-mcp-server`](https://github.com/luciferfran/nan-mcp-server) is a stdio MCP server exposing NaN's media tools: image generation/editing (flux-2-klein), TTS (kokoro), and STT (whisper). Because pi has no MCP client, this package bridges it as pi tools via a minimal built-in MCP stdio client:
|
|
73
|
+
|
|
74
|
+
- **Off by default** — enable with `NAN_MEDIA_MCP=1`.
|
|
75
|
+
- **Lazy**: the MCP server process is spawned *per tool call* and terminated immediately after. Nothing starts, connects, or costs anything unless audio/image/transcription is actually invoked.
|
|
76
|
+
- **Config**: `NAN_API_KEY` is forwarded automatically (same key as the provider); generated files land in `~/nan-mcp-output/` (the server's default, override with `NAN_OUTPUT_DIR`).
|
|
77
|
+
|
|
78
|
+
| Tool | Purpose |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `nan_generate_image(prompt, size?, n?, seed?, guidance?, outputName?)` | Generate an image (flux-2-klein) |
|
|
81
|
+
| `nan_edit_image(prompt, images, size?, n?, seed?, guidance?, outputName?)` | Edit an image image→image (flux-2-klein) |
|
|
82
|
+
| `nan_text_to_speech(text, voice?, format?, speed?, outputName?)` | Synthesize audio (kokoro) |
|
|
83
|
+
| `nan_list_voices()` | List kokoro voices by language |
|
|
84
|
+
| `nan_speech_to_text(file, language?, verbose?)` | Transcribe audio (whisper) |
|
|
85
|
+
|
|
86
|
+
Environment variables:
|
|
87
|
+
|
|
88
|
+
| Variable | Default | Meaning |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `NAN_MEDIA_MCP` | off | `1`/`true`/`on` enables the media tools |
|
|
91
|
+
| `NAN_MEDIA_MCP_VERSION` | `1.0.7` | Pinned server version for `npx -y nan-mcp-server@<v>` (upstream's own supply-chain recommendation) |
|
|
92
|
+
| `NAN_MEDIA_MCP_COMMAND` | — | Full custom command, e.g. `bunx nan-mcp-server@1.0.7` |
|
|
93
|
+
| `NAN_MEDIA_MCP_TIMEOUT_MS` | `120000` | Per-call timeout; the process is killed after it |
|
|
94
|
+
| `NAN_MCP_TOOLS` | — | `0`/`false`/`off` disables the official `nan_web_search` bridge |
|
|
95
|
+
|
|
96
|
+
## Models
|
|
97
|
+
|
|
98
|
+
Baseline catalog (from models.dev, provider `nan`, fetched 2026-09-04 — NaN's *served* limits, not raw model maxima):
|
|
99
|
+
|
|
100
|
+
| Model | Context | Max output | Input | Reasoning |
|
|
101
|
+
|---|---|---|---|---|
|
|
102
|
+
| `qwen3.6` | 262,144 | 65,536 | text, image | yes |
|
|
103
|
+
| `gemma4` | 262,144 | 32,768 | text, image | yes |
|
|
104
|
+
| `deepseek-v4-flash` | 1,000,000 | 384,000 | text, image | yes |
|
|
105
|
+
| `mimo-v2.5` | 1,048,576 | 131,072 | text, image | yes |
|
|
106
|
+
| `glm5.2` | 500,000 | 131,072 | text | yes |
|
|
107
|
+
| `glm5.3-flash` | 1,000,000 | 131,072 | text, image | yes |
|
|
108
|
+
| `qwen3.8-flash` | 262,144 | 131,072 | text, image | yes |
|
|
109
|
+
|
|
110
|
+
Notes (recorded per entry in `scripts/models.generated.ts`):
|
|
111
|
+
|
|
112
|
+
- `deepseek-v4-flash` includes image input because NaN serves the Vision-Exp variant ([NaN docs](https://nan.builders/docs/models)); models.dev lists text only.
|
|
113
|
+
- `mimo-v2.5` is omnimodal (text/image/audio) on NaN, but pi's model type only represents text/image input, so audio is dropped from `input`.
|
|
114
|
+
- NaN bills via membership quota, which models.dev reports as zero per-token cost — pi's cost display will read $0.
|
|
115
|
+
- Compat (`supportsDeveloperRole: false`, `supportsReasoningEffort: true`, `supportsUsageInStreaming: true`, `maxTokensField: "max_tokens"`) matches the battle-tested LiteLLM config this package replaces; NaN's docs example (`supportsDeveloperRole: true`) is not battle-tested.
|
|
116
|
+
- **Tier/quota**: which models you can call is decided by your NaN membership. With a key, the live fetch reflects exactly that (see *How it works* — tier detection). The premium-tier GLM 5.3 is not in the models.dev `nan` provider at all; only `glm5.3-flash` is.
|
|
117
|
+
|
|
118
|
+
### Relationship to `~/.pi/agent/models.json`
|
|
119
|
+
|
|
120
|
+
This package replaces the hand-written `nan` block in `~/.pi/agent/models.json` (the NaN docs [pi example](https://nan.builders/docs/examples)). If you keep that block, be aware that **models.json overrides compose above registered providers** — the static file wins over this package. Remove the `nan` entry from `models.json` (keep `defaultProvider`/`defaultModel` in `settings.json` if you use them) to use the live catalog from this package. Per-request output caps can still be set there or via model `params`.
|
|
121
|
+
|
|
122
|
+
## pi version compatibility
|
|
123
|
+
|
|
124
|
+
Verified against pi **0.84.4** and the 0.85 line (`registerProvider(provider)`, `registerProvider(name, config)`, `registerTool`, and `modelRegistry.getApiKeyForProvider` all present in both). The extension degrades gracefully across versions:
|
|
125
|
+
|
|
126
|
+
- **Native path (pi ≥ 0.84)**: full Provider with stored-credential-then-env auth, live catalog overlay, and tier filtering.
|
|
127
|
+
- **Legacy fallback**: if the native Provider overload is rejected, registration falls back to the documented legacy `(name, config)` form with the same generated catalog and `$NAN_API_KEY` env auth (stored-credential auth is a limitation of the legacy path, not a silent behavior change).
|
|
128
|
+
- **MCP bridges**: skipped entirely on runtimes without `registerTool`; providers still register.
|
|
129
|
+
- `peerDependencies` is `>=0.84.4` with no upper bound.
|
|
130
|
+
|
|
131
|
+
## helmcode
|
|
132
|
+
|
|
133
|
+
The shared factory (`src/provider-factory.ts`) is provider-agnostic, but `helmcode` is **not registered**: no confirmed base URL or capability source exists for it (absent from models.dev and NaN's docs), and this repo does not fabricate provider data. When an endpoint is confirmed, registering it is one entry in `src/providers.ts` plus catalog data — no second implementation. A contract test (`factory is shared`) already exercises a second provider through the same code path.
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bun install
|
|
139
|
+
bun run generate-models # regenerate the fallback catalog from models.dev (pre-publish)
|
|
140
|
+
bun test # unit + integration tests (fetch, auth, MCP bridges, compat)
|
|
141
|
+
bun run typecheck # typecheck via bunx (local tsc, auto-installs if missing)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`prepublishOnly` runs generation + tests + typecheck. Typecheck resolves `tsc` via `bunx` because `bun publish` runs lifecycle scripts without `node_modules/.bin` on PATH (a bare `tsc` fails there with exit 127). Releases follow strict semver (see `AGENTS.md`); CI publishes when a merge to main changes code and the version. See `CONTRIBUTING.md` for the full contribution flow.
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gtrabanco/pi-nan-provider",
|
|
3
|
+
"version": "0.2.1",
|
|
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
|
+
"keywords": [
|
|
6
|
+
"pi",
|
|
7
|
+
"pi-package",
|
|
8
|
+
"pi-extension",
|
|
9
|
+
"pi-coding-agent",
|
|
10
|
+
"ai",
|
|
11
|
+
"ai-provider",
|
|
12
|
+
"nan",
|
|
13
|
+
"nan-builders",
|
|
14
|
+
"openai-compatible",
|
|
15
|
+
"litellm"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./src/index.ts",
|
|
19
|
+
"pi": {
|
|
20
|
+
"extensions": [
|
|
21
|
+
"./src/index.ts"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"src/",
|
|
26
|
+
"scripts/",
|
|
27
|
+
"README.md",
|
|
28
|
+
"README.es.md",
|
|
29
|
+
"CONTRIBUTING.md",
|
|
30
|
+
"AGENTS.md",
|
|
31
|
+
"CLAUDE.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"generate-models": "bun run scripts/generate-models.ts",
|
|
36
|
+
"prepublishOnly": "bun run generate-models && bun test && bun run typecheck",
|
|
37
|
+
"test": "bun test",
|
|
38
|
+
"typecheck": "bunx tsc --noEmit"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@earendil-works/pi-ai": ">=0.84.4 <1",
|
|
42
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4 <1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@earendil-works/pi-ai": "0.84.4",
|
|
46
|
+
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
47
|
+
"@types/bun": "latest",
|
|
48
|
+
"typescript": "^5.9.2"
|
|
49
|
+
},
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/gtrabanco/pi-nan-provider.git"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/gtrabanco/pi-nan-provider/issues"
|
|
57
|
+
},
|
|
58
|
+
"homepage": "https://github.com/gtrabanco/pi-nan-provider#readme"
|
|
59
|
+
}
|