{"_id":"@booplex/bpx-endpoints","_rev":"3-5ca39f596f58d3ae83afadd50022ebbb","name":"@booplex/bpx-endpoints","dist-tags":{"latest":"0.3.1"},"versions":{"0.2.0":{"name":"@booplex/bpx-endpoints","version":"0.2.0","keywords":["pi-package","pi-extension","bpx","endpoints","models.dev"],"author":{"name":"gabelul"},"_id":"@booplex/bpx-endpoints@0.2.0","maintainers":[{"name":"gabelu","email":"gabi.florea@gmail.com"}],"homepage":"https://github.com/gabelul/bpx-mono/tree/main/packages/bpx-endpoints#readme","bugs":{"url":"https://github.com/gabelul/bpx-mono/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"a10a7a701fb6c7450d01ea90397d339b53bacd02","tarball":"https://registry.npmjs.org/@booplex/bpx-endpoints/-/bpx-endpoints-0.2.0.tgz","fileCount":23,"integrity":"sha512-Q5YS41ubIah0pg16ZY23UGpRoxtTai/TCc37ocQocsD1bNxm+imsW0fuNBCcqWR7mUMgpWnZI6wzWBatuiPOaQ==","signatures":[{"sig":"MEUCIFMEAUt2sMVD9OLzo5BC/dBL+qGbd6tnpSLDAXfxC3CRAiEAzU71F0/i9kbVy4pPjzi5a7PodtlAihw/IxMBVJbjLEc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":242691},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"612b860c987ae5f56670c1d92987362e8e116562","scripts":{"test":"vitest run"},"_npmUser":{"name":"gabelu","email":"gabi.florea@gmail.com"},"repository":{"url":"git+https://github.com/gabelul/bpx-mono.git","type":"git","directory":"packages/bpx-endpoints"},"_npmVersion":"10.9.4","description":"Pi extension. Manage model endpoints — discovery, metadata sources, generated config, and a Pi-native TUI — through one /endpoints command.","directories":{},"_nodeVersion":"22.22.1","dependencies":{"@juicesharp/rpiv-config":"^1.20.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typebox":"*","@earendil-works/pi-ai":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/bpx-endpoints_0.2.0_1788612765782_0.18171810423060264","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@booplex/bpx-endpoints","version":"0.3.0","keywords":["pi-package","pi-extension","bpx","endpoints","models.dev"],"author":{"name":"gabelul"},"_id":"@booplex/bpx-endpoints@0.3.0","maintainers":[{"name":"gabelu","email":"gabi.florea@gmail.com"}],"homepage":"https://github.com/gabelul/bpx-mono/tree/main/packages/bpx-endpoints#readme","bugs":{"url":"https://github.com/gabelul/bpx-mono/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"43347175ba32a1b80638fb8c0af7498dd2e513da","tarball":"https://registry.npmjs.org/@booplex/bpx-endpoints/-/bpx-endpoints-0.3.0.tgz","fileCount":23,"integrity":"sha512-uqAd2cVJMCO9IEb6L58jxfwYrg/FKYWwcod2Z0Kl5q9UdJzvmDNx+CpGHDLzziSrIhg8MNCqX34h2D46jqnRMw==","signatures":[{"sig":"MEUCIQDMEyU31zQtAOOIFi7VyJGsBf0CRbuALimwpXfMMAcSnAIgSC8cKame1/RRPU/xHEbNNODkDahHvBIlomIN6FG06PY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCID1RQoeWsq7mgJSdZw4fGlCjj3WwGI8itTVybUxQyEBHAiEA3i4EOthhDtvYGc4lzOtgmf8bsomAMXfEuAbHHT4Td3M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@booplex%2fbpx-endpoints@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":267024},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"b2cb3f219c43854d371559ec01d1c1b44588b666","scripts":{"test":"vitest run"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0106c3c-ecbf-4098-94fa-23b8165997bd"}},"repository":{"url":"git+https://github.com/gabelul/bpx-mono.git","type":"git","directory":"packages/bpx-endpoints"},"_npmVersion":"11.19.0","description":"Pi extension. Manage model endpoints — discovery, metadata sources, generated config, and a Pi-native TUI — through one /endpoints command.","directories":{},"_nodeVersion":"24.21.0","dependencies":{"@juicesharp/rpiv-config":"^1.20.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typebox":"*","@earendil-works/pi-ai":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/bpx-endpoints_0.3.0_1790330641254_0.12090023273515338","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"pi":{"extensions":["./index.ts"]},"_id":"@booplex/bpx-endpoints@0.3.1","bugs":{"url":"https://github.com/gabelul/bpx-mono/issues"},"dist":{"shasum":"0f58ff98cffd0598911e67173bc52df5a174110a","tarball":"https://registry.npmjs.org/@booplex/bpx-endpoints/-/bpx-endpoints-0.3.1.tgz","fileCount":23,"integrity":"sha512-/1iLB+49CXgysVloYX4zK5SKaoptLQvpfJ0eiYUMfmo7m/Kgw+bOuNIqsRrHxqBouMgjIDpw9SVJOy+RW+8X4A==","signatures":[{"sig":"MEYCIQCKM/2JG7G8eAKH5gbfyX00sSueskW8/fl+0R19mtDKTAIhAMkH0A2kyk4B8hGXUzYEuxjPf8TaEC5Cxf2lobUOzHxH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDozlZ04WwBiYWd/sc8Ta0RGPDf7NnLfFDYDof9PgjWKAIhAP7hzlfar3v70S68VaCLWfYbR4Dqigeuf118CI1SPvhz"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@booplex%2fbpx-endpoints@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":267555},"name":"@booplex/bpx-endpoints","type":"module","author":{"name":"gabelul"},"engines":{"node":">=22.19.0"},"gitHead":"c482d6cc678be159f5d95bcc94e57e3386a5f0f4","scripts":{"test":"vitest run"},"version":"0.3.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0106c3c-ecbf-4098-94fa-23b8165997bd"}},"homepage":"https://github.com/gabelul/bpx-mono/tree/main/packages/bpx-endpoints#readme","keywords":["pi-package","pi-extension","bpx","endpoints","models.dev"],"repository":{"url":"git+https://github.com/gabelul/bpx-mono.git","type":"git","directory":"packages/bpx-endpoints"},"_npmVersion":"11.19.0","description":"Pi extension. Manage model endpoints — discovery, metadata sources, generated config, and a Pi-native TUI — through one /endpoints command.","directories":{},"maintainers":[{"name":"gabelu","email":"gabi.florea@gmail.com"}],"_nodeVersion":"24.21.0","dependencies":{"@juicesharp/rpiv-config":"^1.20.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typebox":"*","@earendil-works/pi-ai":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bpx-endpoints_0.3.1_1790333133455_0.04734472169754378"}}},"time":{"created":"2026-09-05T12:52:45.521Z","modified":"2026-09-25T10:45:33.969Z","0.2.0":"2026-09-05T12:52:45.906Z","0.3.0":"2026-09-25T10:04:01.357Z","0.3.1":"2026-09-25T10:45:33.591Z"},"bugs":{"url":"https://github.com/gabelul/bpx-mono/issues"},"author":{"name":"gabelul"},"homepage":"https://github.com/gabelul/bpx-mono/tree/main/packages/bpx-endpoints#readme","keywords":["pi-package","pi-extension","bpx","endpoints","models.dev"],"repository":{"url":"git+https://github.com/gabelul/bpx-mono.git","type":"git","directory":"packages/bpx-endpoints"},"description":"Pi extension. Manage model endpoints — discovery, metadata sources, generated config, and a Pi-native TUI — through one /endpoints command.","maintainers":[{"name":"gabelu","email":"gabi.florea@gmail.com"}],"readme":"# bpx-endpoints — every model endpoint, one command | pi extension\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/gabelul/bpx-mono/main/packages/bpx-endpoints/.github/assets/hero.png\" alt=\"A small clay robot at a workshop desk, plugged by a thick braided cable into a patch panel of colorful endpoint cables and three tiny homelab machines\" width=\"100%\">\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@booplex/bpx-endpoints\"><img src=\"https://img.shields.io/npm/v/@booplex/bpx-endpoints?color=a855f7&labelColor=1a1a2e&logo=npm&logoColor=white\" alt=\"npm version\"></a>\n  <a href=\"https://www.npmjs.com/package/@booplex/bpx-endpoints\"><img src=\"https://img.shields.io/npm/dm/@booplex/bpx-endpoints?color=2dd4bf&labelColor=1a1a2e\" alt=\"npm downloads\"></a>\n  <a href=\"https://github.com/gabelul/bpx-mono/actions/workflows/ci.yml\"><img src=\"https://img.shields.io/github/actions/workflow/status/gabelul/bpx-mono/ci.yml?branch=main&label=CI&labelColor=1a1a2e&color=a855f7\" alt=\"CI\"></a>\n</p>\n\npi ships with presets for the big hosted providers, and that's fine until your models live somewhere pi has never heard of. A load balancer in front of your model accounts. The vLLM box under the desk. A regional gateway with its own key dance. The stock answer is hand-editing `~/.pi/agent/models.json`, then hand-updating it every time the endpoint's model list changes — which is exactly the kind of chore I build tools to kill.\n\n`bpx-endpoints` puts all of it behind one command: `/endpoints`. Point an endpoint at pi and it discovers the model list, pulls parameter metadata from pi's registry plus [models.dev](https://models.dev), generates the config, and registers the endpoint into your live session. One pi-native panel holds the model-by-model knobs; refresh and doctor keep it honest over time.\n\nWorks in [pi](https://pi.dev) (the coding agent, v0.80+).\n\n## What it's for\n\npi's built-in presets already cover the known providers with correct base URLs and metadata, so this extension doesn't duplicate a preset catalog. It covers everything the presets don't:\n\n- OpenAI-compatible proxies and load balancers\n- Self-hosted endpoints (LM Studio, Ollama, vLLM)\n- Regional gateways\n- Any deployment where you supply the base URL, protocol, and key yourself\n\n## Install\n\n```bash\npi install npm:@booplex/bpx-endpoints\n```\n\n## Quick start\n\n1. Run `/endpoints` and press `a` to add an endpoint.\n2. Fill in the form: an id, the base URL (`http://localhost:11434/v1` for a local Ollama, say), the API protocol, and the key — or Authentication None for open local endpoints.\n3. Choose how models are discovered: the endpoint's own `/models` list (default) or manual ids. Press `ctrl+t` to test the connection, `ctrl+s` to save.\n\nThat's it. The models register into your running pi session immediately — no restart, no hand-written JSON. From the manager you can refresh (`r`), edit, clone (`y`), delete (`x`), and drill into per-model settings.\n\n## Commands\n\n```text\n/endpoints                 Open the Endpoint Manager\n/endpoints add             Add an endpoint through interactive prompts\n/endpoints settings        Edit extension settings (same picker as /consult)\n/endpoints status          Print a config / cache / generated read-out\n/endpoints list            List endpoints\n/endpoints refresh         Refresh all enabled endpoints\n/endpoints refresh <id>    Refresh a single endpoint\n/endpoints test <id> [model]   Send a test message (streams, reports latency)\n/endpoints test --all          Batch-test all enabled endpoints (one confirm)\n/endpoints probe-reasoning [id]  Probe accepted reasoning_effort values\n/endpoints doctor          Diagnose config / cache / generated / custom state\n/endpoints export [path]   Write masked effective generated + custom config\n/endpoints open            Show the config file + state directory paths\n```\n\nThe manager is the primary interface; the subcommands are shortcuts for scripting and recovery. It renders as a framed, solid panel centered at 104 columns — filled with your theme's card background, selected rows highlighted — so it reads as a dialog instead of more chat text. Model management, refresh, and completion happen inside the same panel session; the advanced override layer is one keystroke away.\n\n## Discovery, metadata, and refresh\n\nDiscovery runs in two modes: the endpoint's own model list (`discovery.mode: \"endpoint\"` + `modelsPath`) or manual entry (`discovery.mode: \"manual\"` + `modelIds`). A few things worth knowing about how discovery behaves:\n\n- **Full URL override**: `discovery.modelsUrl` bypasses baseUrl + path entirely — for endpoints like Ollama whose chat API lives at `.../v1` but model list at `http://host:11434/api/tags`.\n- **Path probing** (`discovery.probe: true`): when the configured URL 404s or returns something unexpected, bpx-endpoints tries the common variants (`/models`, `/v1/models`, `/api/tags`, `/api/models`) at the origin. Never on auth failures — 401/403 are reported, not guessed around. The resolved URL is cached per profile.\n- **Response shapes**: bare arrays, `data[]`, `models[]`, `data.models[]` nesting, and object-keyed maps all parse. Duplicate ids drop, id-less entries skip — both counted in warnings you'll see in doctor.\n- **Retries**: transient network errors, 429 (honoring `Retry-After`), and 5xx retry with backoff. Auth failures don't.\n- **Parameter sources** come from pi's built-in metadata plus a [models.dev](https://models.dev) sync cached locally (24h TTL, offline fallback), so refresh works when you're offline. Fuzzy matches surface as warnings; you can pick a different source per model from the manager.\n- **Inclusion policy** is include-all with exclusions by default, or `includeOnly` with an explicit list.\n\n## Reasoning efforts\n\nOpenAI-compatible endpoints reject unknown `reasoning_effort` values, and pi's thinking levels (`low` through `xhigh`) don't map onto every server's schema. So bpx-endpoints never copies a metadata source's `thinkingLevelMap` verbatim; it always emits a complete map:\n\n- **Unknown endpoint** → a canonical `low`/`medium`/`high` map that no pi level can leak through.\n- **Live probe** (`discovery.reasoningProbe: true`, or `ctrl+r` in the models view) → tiny 1-token requests per candidate value (`low`/`medium`/`high`/`xhigh`/`minimal`/`none`, max 3 models per refresh) record which values the endpoint actually accepts, and the map picks the nearest accepted value for every pi level. Evidence caches per model — one model's result is never reused for its siblings.\n- **Error mining** → when a probe or test message 400s with an effort-specific rejection that *declares* its supported set (\"Supported types are xhigh (default), medium, and low\"), the declared values are mined and unioned into the map. A failed test message that teaches the profile something updates the map immediately.\n- **Manual override** (`reasoningEfforts: [\"low\", \"medium\"]`) → wins over probe results.\n- An endpoint that accepts *no* effort value registers its reasoning models as non-reasoning, with a doctor note pointing at the pi-native alternative (`compat.supportsReasoningEffort: false` + a `thinkingFormat`).\n\nWhen the endpoint accepts `none`, pi's `off` level maps to it — a real zero-thinking setting, not \"think a little\".\n\nPrecedence, explicit: your authored `thinkingLevelMap` (models.custom.json override) always wins. Complete maps pass through untouched; partial maps keep their authored entries — `null` values included, which pi hides from the level picker — and only missing keys are filled from the best evidence available. Then manual `reasoningEfforts`, then per-model probe evidence, then canonical.\n\n## Keys, headers, and baseUrl references\n\nEndpoints authenticate with `apiKey` (sent as `Authorization: Bearer ...`) unless you choose None and provide auth through custom headers. Secrets don't have to be literals in the config:\n\n- `$VAR` and `${VAR}` expand from the environment; `!command` runs a shell command and uses its stdout. Header values and `apiKey` accept both; `baseUrl` accepts them too, including mid-URL: `\"baseUrl\": \"http://${MY_HOST}:8080/v1\"`.\n- Expansion happens at use time — discovery, tests, and registration — so config files keep the reference and nothing resolved lands on disk. An unset variable fails fast with the profile id in the message. `!command` must be the whole value.\n- A profile setting both `apiKey` and a custom `Authorization` header gets a doctor warning: pi appends the bearer token last, so it would silently win.\n\n## Configuration\n\nManaged config lives in a single flat file at `~/.pi/agent/bpx-endpoints.json` (the pi-native path, beside pi's own state) — TypeBox-schema validated, fail-soft on load, crash-resistant on save. Derived state lives under `~/.pi/agent/bpx-endpoints/`:\n\n| File | Purpose |\n| --- | --- |\n| `bpx-endpoints.json` | Managed user intent: endpoint profiles + settings |\n| `cache.json` | Discovered models, metadata candidates, per-profile test health |\n| `models.generated.json` | Generated pi `models.json`-shaped config |\n| `models.custom.json` | Unrestricted override layer, merged after the generated config |\n| `models.dev.json` | Local models.dev catalog cache |\n\nThe config directory is created `0700`; extension-owned JSON files are written `0600`. The extension never writes to pi's native `~/.pi/agent/models.json` — that file stays yours.\n\nOn first run, existing state migrates automatically (from `bpx-endpoints/config.json` or the legacy `~/.pi/agent/custom-provider/` directory), so existing endpoints survive the switch. Startup never touches the network; it merges and registers locally. Caches older than the stale threshold (default 7 days, `settings.staleReminderDays`) trigger a gentle reminder and a doctor warning.\n\n## Error handling\n\n| Situation | Behavior |\n| --- | --- |\n| Missing `models.generated.json` | Normal onboarding; no endpoints registered |\n| Invalid `models.generated.json` | Registration skipped, but `/endpoints`, refresh, doctor, and recovery still work |\n| Invalid `models.custom.json` | Ignored with a warning; generated endpoints still register |\n| Invalid `bpx-endpoints.json` | Already-generated endpoints still register, but edit/refresh enter recovery until fixed; `/endpoints settings` refuses to open over a broken file rather than overwrite it |\n| Unresolved API protocol | The affected endpoint is invalid — not generated, not registered, no silent fallback |\n\n## Development\n\n```bash\ngit clone https://github.com/gabelul/bpx-mono\ncd bpx-mono\nnpm install\nnpm run check   # typecheck + tests, monorepo-wide\n```\n\nIssues and PRs at [gabelul/bpx-mono](https://github.com/gabelul/bpx-mono/issues).\n","readmeFilename":"README.md"}