npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-custom-openai-providers

v0.2.1

Published

Maintain multiple OpenAI-compatible providers in pi with /custom-providers; switch between them with /model.

Readme

pi-custom-openai-providers

Maintain multiple OpenAI-compatible providers in pi and switch between them with /model.

License: MIT pi

Features

  • One command for everything/custom-providers with add / list / edit / remove subcommands
  • Switch with /model — each provider registers as custom-<name> and appears in pi's model picker
  • Persistent storage in pi's official path~/.pi/agent/models.json (pi's own models.json schema, written mode 0600)
  • Full models.md schemaheaders / compat / thinkingLevelMap / cost.tiers / modelOverrides / input modes (text / image) / custom api etc. all supported
  • Editor for the full specadd <name> --raw / edit <name> --raw opens $VISUAL / $EDITOR (falls back to vi) so you can edit the complete provider JSON including fields the 3-prompt flow doesn't expose
  • Auto-migration — the legacy <cwd>/.pi/custom-providers.json (multi-provider) and <cwd>/.pi/custom-openai.json (single-provider) are detected on first load, copied into ~/.pi/agent/models.json, then deleted
  • Env-var seedCUSTOM_OPENAI_* env vars create a custom-default provider when no providers are configured anywhere (CI / scripting friendly)
  • Zero runtime dependencies — pure TypeScript loaded by pi's jiti; only node:fs / node:path / node:os / node:child_process

Installation

⚠ Install in exactly one location. Installing both globally (~/.pi/agent/extensions/) and project-locally (.pi/extensions/) — or installing via pi install while a symlink / dev copy already exists — causes pi to load the extension twice. pi then adds a :1 suffix to the command's invocation name, so Tab autocomplete inserts /custom-providers:1 instead of /custom-providers . The extension detects this at load time, logs a warning to the terminal, and skips the duplicate command registration, but the cleanest fix is to remove one installation.

One-shot install (recommended)

# From GitHub
pi install github:playmaker/pi-custom-openai-providers

# Or from npm
pi install npm:pi-custom-openai-providers

Manual install (project-local)

git clone https://github.com/playmaker/pi-custom-openai-providers
cd <your-project>
ln -s "$(pwd)/../pi-custom-openai-providers" .pi/extensions/pi-custom-openai-providers

Manual install (global)

git clone https://github.com/playmaker/pi-custom-openai-providers ~/.pi/agent/extensions/pi-custom-openai-providers

Quick try (no install)

pi -e /path/to/pi-custom-openai-providers/src/index.ts

Usage

Add a provider

/custom-providers add deepseek
  Base URL: https://api.deepseek.com/v1
  API key: sk-...
  Model id: deepseek-chat

<name> is a short identifier without whitespace. It becomes part of the provider id custom-<name> shown in /model.

List configured providers

/custom-providers

Shows a persistent widget above the editor listing all configured providers with their endpoints and models. Stays visible until the next command or model change.

Edit a provider

/custom-providers edit deepseek
  Base URL [https://api.deepseek.com/v1]:
  API key (leave blank to keep current ending in xxxx):
  Model id [deepseek-chat]:

Empty input keeps the current value. Pressing Esc on any prompt cancels the edit and emits Edit cancelled. (nothing is saved or re-registered). Pressing Enter through all three prompts with no changes emits No changes for "<name>". and skips the save + re-register. Any actual change emits Updated custom provider "<name>".

Add or edit via the editor (full schema)

The 3-prompt flow only edits baseUrl / apiKey / the first model's id. For everything else in pi's models.md schema (headers / compat / thinkingLevelMap / cost.tiers / modelOverrides / image input / custom api per model / multiple models / ...), pass --raw and the extension opens $VISUAL / $EDITOR (falls back to vi) with the full provider JSON:

/custom-providers add my-openrouter --raw
/custom-providers edit my-openrouter --raw

The editor temp file is created with mode 0600 and cleaned up on exit. The extension validates the JSON before writing: it must be parseable, have a non-empty baseUrl, and at least one models entry with a non-empty id. Each model gets api: "openai-completions" injected if missing.

Honored environment variables for the editor (in order):

  1. $VISUAL
  2. $EDITOR
  3. vi (fallback if neither is set)

If the editor is not found, you get Editor "..." not found. Set $VISUAL or $EDITOR to a valid editor path. instead of a silent failure. If the file's contents are unchanged after you exit, the edit is a no-op and the disk state is preserved.

Remove a provider

/custom-providers remove deepseek

Switch providers

After configuring, use /model and pick custom-<name>/<modelId>:

/model
> custom-openrouter / anthropic/claude-sonnet-4.5

Tab completion

The /custom-providers command surfaces its subcommand shape through pi's autocomplete:

  • Typing /custom-providers shows the dropdown with [list | add <name> | edit <name> | remove <name>] — <description>.
  • Typing /custom-providers (with a trailing space) lists the four subcommands; keep typing to filter (e.g. aadd).
  • After /custom-providers edit or /custom-providers remove , existing provider names are offered for tab completion, filtered as you type.

Configuration

Storage

~/.pi/agent/models.json (mode 0600) — pi's official model.json schema. The extension adds a key per provider under the top-level providers object, prefixed with custom- to avoid clashing with built-ins (e.g. custom-my-qianwen).

Full ProviderEntry shape (every field from models.md is supported):

{
  "providers": {
    "custom-my-qianwen": {
      "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
      "apiKey": "$DASHSCOPE_KEY",
      "headers": {
        "x-portkey-api-key": "$PORTKEY_KEY"
      },
      "compat": {
        "supportsDeveloperRole": false,
        "supportsReasoningEffort": false
      },
      "models": [
        {
          "id": "qwen3-max",
          "name": "Qwen3 Max",
          "input": ["text"],
          "reasoning": true,
          "contextWindow": 262144,
          "maxTokens": 8192,
          "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
        }
      ]
    }
  }
}

You can also edit ~/.pi/agent/models.json directly with any text editor — the extension is just a convenience layer on top of pi's own config. Add the path to your global gitignore (or HOME-level) if you don't want it in version control:

.pi/agent/models.json

Environment variable seed

If no providers are configured anywhere and these are set on startup, a custom-default provider is created and persisted to ~/.pi/agent/models.json:

| Variable | Example | |----------|---------| | CUSTOM_OPENAI_BASE_URL | https://api.deepseek.com/v1 | | CUSTOM_OPENAI_API_KEY | sk-... | | CUSTOM_OPENAI_MODEL | deepseek-chat |

Legacy migration

The earlier single-provider .pi/custom-openai.json is auto-migrated as a default provider on first load; the old file is deleted.

Examples

DeepSeek

/custom-providers add deepseek
  Base URL: https://api.deepseek.com/v1
  API key: sk-...
  Model id: deepseek-chat

OpenRouter (route to any upstream model)

/custom-providers add openrouter
  Base URL: https://openrouter.ai/api/v1
  API key: sk-or-...
  Model id: anthropic/claude-sonnet-4.5

Local llama.cpp / Ollama OpenAI-compat mode

/custom-providers add local-llama
  Base URL: http://localhost:8080/v1
  API key: local
  Model id: llama-3.1-70b

Multiple endpoints side-by-side

/custom-providers
  Custom providers (3):
    custom-deepseek    https://api.deepseek.com/v1     model=deepseek-chat
    custom-openrouter  https://openrouter.ai/api/v1    model=anthropic/claude-sonnet-4.5
    custom-local-llama http://localhost:8080/v1        model=llama-3.1-70b

/model   # pick custom-openrouter / anthropic/claude-sonnet-4.5

Compatibility

  • pi ≥ 0.83 — uses registerProvider, registerCommand, setWidget, unregisterProvider
  • Node.js ≥ 20 — uses node:fs, node:path
  • Any endpoint speaking the OpenAI Chat Completions protocol: DeepSeek, OpenRouter, OpenAI, Azure OpenAI gateways, llama.cpp server, vLLM, Ollama's OpenAI-compat mode, custom corporate gateways, etc.

If your endpoint speaks a different protocol, adjust api: "openai-completions" in src/index.ts to the appropriate value (see pi docs for the full list).

Project layout

pi-custom-openai-providers/
├── src/
│   └── index.ts        # extension entry — exported default function(pi)
├── package.json        # pi.extensions → "./src/index.ts"
├── README.md
├── README_zh.md
├── LICENSE
└── .gitignore

This follows the official pi extension convention (pi.extensions in package.json pointing at the entry file). No build step — pi loads src/index.ts directly via jiti.

Development

git clone https://github.com/playmaker/pi-custom-openai-providers
cd pi-custom-openai-providers

There is no build step and no runtime npm dependency. To test against your local pi:

# Symlink into pi's global extensions directory
ln -s "$(pwd)" ~/.pi/agent/extensions/pi-custom-openai-providers

# Or load directly via -e flag
pi -e "$(pwd)/src/index.ts"

Run pi and try /custom-providers add test to exercise the flow.

Contributing

Issues and pull requests welcome at https://github.com/playmaker/pi-custom-openai-providers.

License

MIT © 2026 Zongchenghao

Acknowledgements

中文文档