@esuyo/pi-esuyo-custom-provider

Register custom OpenAI-compatible providers in Pi.dev via JSON config

Packages

Package details

extension

Install @esuyo/pi-esuyo-custom-provider from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@esuyo/pi-esuyo-custom-provider
Package
@esuyo/pi-esuyo-custom-provider
Version
1.0.11
Published
Sep 4, 2026
Downloads
487/mo · 192/wk
Author
migsperez
License
MIT
Types
extension
Size
32.2 KB
Dependencies
0 dependencies · 0 peers
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@esuyo/pi-esuyo-custom-provider

Add any OpenAI-compatible provider to Pi.dev — local models, corporate proxies, or custom API gateways. Configure everything in a single JSON file, no coding required.

Installation

pi install npm:@esuyo/pi-esuyo-custom-provider

Quick start

Create ~/.pi/agent/custom-providers.json:

{
  "providers": [
    {
      "name": "ollama",
      "label": "Ollama Local",
      "baseUrl": "http://localhost:11434/v1",
      "apiKey": "ollama",
      "fetchModels": true
    }
  ]
}

Run /reload in Pi (or restart it), then open the model picker with /model — your provider's models will appear in the list.

Configuration

Provider fields

Field Required Description
name Provider ID used in /model (e.g. my-gateway).
label Display name shown in the UI. Defaults to name.
baseUrl OpenAI-compatible API endpoint (e.g. http://localhost:11434/v1).
apiKey API key. Supports env vars ($MY_KEY / ${MY_KEY}) and shell commands (!command).
fetchModels Auto-discover models from {baseUrl}/models. Default: false.
models Static model definitions (merged with discovered models when fetchModels: true).
contextWindow Provider-level default context window (tokens). Applied to every model unless the model defines its own.
maxTokens Provider-level default max output tokens. Applied to every model unless the model defines its own.
headers Extra HTTP headers sent with every request.
sendSessionHeaders Send per-conversation x-opencode-session / x-opencode-client headers (see below). Default: false.
compat Provider compatibility flags (see below).

API key resolution

Same syntax as Pi's models.json:

Syntax Description
$ENV_VAR / ${ENV_VAR} Read from environment variable
!command Execute shell command, stdout is the value
$$ Literal $
$! Literal !
Plain string Used as-is

Model fields

Field Default Description
id Model identifier sent to the API (required).
name id Human-readable label.
reasoning false Supports extended thinking.
input ["text"] Input types: ["text"] or ["text", "image"].
contextWindow Max context window in tokens. Falls back to the provider-level contextWindow, otherwise Pi.dev decides.
maxTokens Max output tokens. Falls back to the provider-level maxTokens, otherwise Pi.dev decides.
cost all zeros Per-million-token rates { input, output, cacheRead, cacheWrite }.

Session headers

Pi only sends x-opencode-session for its built-in opencode providers. If your gateway needs the current conversation id, opt in per provider:

{
  "providers": [
    {
      "name": "gateway",
      "baseUrl": "https://gateway.corp.com/v1",
      "apiKey": "$GATEWAY_API_KEY",
      "sendSessionHeaders": true
    }
  ]
}

With sendSessionHeaders: true, every request for that provider gets x-opencode-session: <live session id> (read fresh per request, so it survives new/resume/fork) and x-opencode-client: pi when not already set. Auth headers are never touched. Providers without the flag are unchanged.

Alternatively, map the session id to any header with $PI_SESSION_ID (or ${PI_SESSION_ID}) in headers — presence of the variable is its own opt-in, independent of the flag. The extension (not Pi) owns this placeholder:

{
  "providers": [
    {
      "name": "gateway",
      "baseUrl": "https://gateway.corp.com/v1",
      "apiKey": "$GATEWAY_API_KEY",
      "headers": { "x-opencode-session": "$PI_SESSION_ID" }
    }
  ]
}

Headers containing $PI_SESSION_ID are stripped before pi.registerProvider is called and never reach Pi core — Pi resolves every provider header as an env-var template and would otherwise throw Failed to resolve provider "<id>" header "<key>" from environment variable: PI_SESSION_ID (surfaced as API key auth failed). The extension holds these templates back and substitutes the live session id per request in the before_provider_headers hook (overwriting unconditionally).

The value is substituted per request with the live session id. With no live session the header is deleted (null), never sent literally. Authorization is never touched.

Compatibility flags

Flag When to use
supportsDeveloperRole: false Servers that don't understand the developer role (Ollama, vLLM).
supportsReasoningEffort: false Servers that don't support reasoning_effort.
supportsUsageInStreaming: false Servers lacking streaming usage support.
maxTokensField: "max_tokens" Use max_tokens instead of max_completion_tokens.
requiresToolResultName: true When tool results need a name field.

Examples

Local model server (Ollama, vLLM, LM Studio)

{
  "providers": [
    {
      "name": "local",
      "baseUrl": "http://localhost:11434/v1",
      "apiKey": "ollama",
      "fetchModels": true,
      "compat": {
        "supportsDeveloperRole": false,
        "supportsReasoningEffort": false
      }
    }
  ]
}

API gateway with static models

{
  "providers": [
    {
      "name": "gateway",
      "label": "Corporate AI Gateway",
      "baseUrl": "https://gateway.corp.com/v1",
      "apiKey": "$GATEWAY_API_KEY",
      "models": [
        {
          "id": "gpt-4o",
          "input": ["text", "image"],
          "contextWindow": 128000,
          "maxTokens": 16384,
          "cost": { "input": 2.5, "output": 10, "cacheRead": 0.5, "cacheWrite": 1.25 }
        }
      ],
      "headers": {
        "X-Corp-Auth": "$CORP_AUTH_TOKEN"
      }
    }
  ]
}

Multiple providers

{
  "providers": [
    {
      "name": "local",
      "baseUrl": "http://localhost:11434/v1",
      "apiKey": "ollama",
      "fetchModels": true
    },
    {
      "name": "proxy",
      "baseUrl": "https://my-proxy.example.com/v1",
      "apiKey": "$PROXY_KEY",
      "models": [
        { "id": "claude-sonnet-4", "input": ["text", "image"], "contextWindow": 200000 }
      ]
    }
  ]
}

Environment variables

Variable Default Description
PI_CUSTOM_PROVIDERS_CONFIG ~/.pi/agent/custom-providers.json Custom path to the config file.

Updating

pi update npm:@esuyo/pi-esuyo-custom-provider

Or run /reload after updating the config file — no reinstall needed for config changes.