omp packages

pi-dynamic-models0.2.0

Discover models from OpenAI-compatible endpoints and register them dynamically in Pi

apetersson Published 17 days ago MIT ~427 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-dynamic-models

Pi extension that discovers models from OpenAI-compatible endpoints and registers them as Pi providers dynamically.

Instead of maintaining a static ~/.pi/agent/models.json, you keep a small endpoint list in ~/.pi/agent/dynamic-models.json and let the extension refresh provider/model registration automatically.

Getting started

pi install npm:pi-dynamic-models

Run /reload if Pi is already running, then /dynamic-models-config and choose Add endpoint. Enter a name and the endpoint's OpenAI-compatible base URL, then choose authentication if needed. Models and advertised parameters are discovered immediately; there is no model list to maintain.

The command creates ~/.pi/agent/dynamic-models.json automatically. You can also create or edit this file manually, then run /dynamic-models-reload.

Minimal config example:

{
  "endpoints": [
    {
      "name": "my-provider",
      "baseUrl": "http://localhost:8000/v1"
    }
  ]
}

If your endpoint requires bearer auth, the smallest useful version is:

{
  "endpoints": [
    {
      "name": "my-provider",
      "baseUrl": "http://localhost:8000/v1",
      "apiKey": "env:MY_PROVIDER_API_KEY",
      "authHeader": true
    }
  ]
}

Features

  • discovers models from OpenAI-compatible GET /v1/models endpoints
  • registers one Pi provider per configured endpoint with pi.registerProvider()
  • removes providers that disappear from config on the next refresh
  • filters out embedding models by default
  • supports provider-level defaults and per-model overrides
  • supports auth via bearer token, custom headers, env vars, and shell commands
  • exposes commands for reload and status
  • logs refresh activity to ~/.pi/agent/dynamic-models.log
  • supports verbose debug logging with PI_DYNAMIC_MODELS_DEBUG=1

Commands

  • /dynamic-models-config
    • add, edit, or remove endpoints interactively and refresh discovery immediately
  • /dynamic-models-reload
    • reloads endpoints from config and re-registers providers
  • /dynamic-models-status
    • shows all currently discovered providers and models, including known metadata

How it works

At startup and on session_start, the extension:

  1. reads ~/.pi/agent/dynamic-models.json
  2. fetches each endpoint's model list
  3. normalizes the returned model metadata
  4. applies defaults and per-model overrides
  5. registers a Pi provider for that endpoint

If an endpoint is removed from config, its provider is unregistered on the next refresh.

Installation

Install from npm:

pi install npm:pi-dynamic-models

Alternatively, install directly from GitHub:

pi install git:github.com/apetersson/pi-dynamic-models

For local development:

pi install /absolute/path/to/pi-dynamic-models

Run /reload in Pi after installing or changing the extension. Requires Node.js 22.19.0 or newer and pi 1.x (@earendil-works/pi-coding-agent). Validated against pi 1.0.0.

To try the extension without installing it, run from this checkout:

pi -e ./src/index.ts

Manage endpoints in Pi

Run /dynamic-models-config in an interactive Pi session:

  • Add endpoint asks for a unique provider name, base URL (for example http://localhost:8000/v1), and optional bearer authentication using an environment variable.
  • Edit endpoint lets you change its name, base URL, custom models URL, authentication, API, or enabled state. Existing custom headers, filters, defaults, and model overrides are preserved.
  • Remove endpoint asks for confirmation, saves the change, and unregisters the provider.

Changes are saved to the configured JSON path and discovery runs immediately. Cancel a dialog to leave the file unchanged. If discovery fails, the endpoint remains saved so you can correct it or retry with /dynamic-models-reload.

Model IDs, context windows, output limits, input modalities, reasoning support, pricing, and compatibility flags are read from the model-list response when available. Missing values use defaults (128,000 context tokens, 16,384 output tokens, text input, no reasoning, and zero reported cost); these are fallback settings, not measured capabilities. The extension does not probe context limits or send test completions. Capability flags are read in either shape an endpoint may use: a map of booleans ({ "vision": true }) or a list of enabled names (["chat", "vision"]). Use the JSON configuration for custom headers, filters, and model overrides.

New endpoints use the OpenAI chat completions API. For a Responses endpoint, change API to openai-responses. Authentication environment variables must be available to the running Pi process.

Configuration

Default config path:

~/.pi/agent/dynamic-models.json

Override it with:

export PI_DYNAMIC_MODELS_CONFIG=/path/to/dynamic-models.json

Top-level shape

{
  "endpoints": []
}

Endpoint fields

Each endpoint supports:

  • name: provider name as shown in Pi
  • baseUrl: base API URL, usually ending in /v1
  • modelsUrl: optional full URL for model discovery
  • modelsPath: optional path appended to baseUrl, default: models
  • api: Pi provider API type, default: openai-completions
    • allowed values:
      • openai-completions
      • openai-responses
  • apiKey: optional auth value
    • literal string: "abc123"
    • env var: "env:MY_API_KEY"
    • shell command: "!security find-generic-password -ws my-key"
  • authHeader: when true, sends Authorization: Bearer <apiKey>
  • headers: additional request headers using the same value formats as apiKey
  • timeoutMs: request timeout for model discovery
  • enabled: enable/disable endpoint
  • includeEmbeddings: include embedding models, default false
  • includePatterns: only include matching model IDs, glob syntax
  • excludePatterns: exclude matching model IDs, glob syntax
  • defaults: fallback metadata for discovered models
  • modelOverrides: exact model-id overrides

defaults and modelOverrides

Supported fields:

  • name
  • reasoning
  • input
  • contextWindow
  • maxTokens
  • cost
  • compat
  • headers

modelOverrides also supports:

  • enabled

Example config

{
  "endpoints": [
    {
      "name": "EXAMPLE_SERVER",
      "baseUrl": "http://EXAMPLE_SERVER:8000/v1",
      "apiKey": "env:EXAMPLE_SERVER_API_KEY",
      "authHeader": true,
      "defaults": {
        "reasoning": true,
        "input": ["text"],
        "contextWindow": 262144,
        "maxTokens": 32768,
        "compat": {
          "supportsDeveloperRole": false,
          "supportsReasoningEffort": false,
          "thinkingFormat": "qwen-chat-template"
        }
      },
      "excludePatterns": ["text-embedding-*", "*embedding*", "*embed*"],
      "modelOverrides": {
        "Qwen3.5-122B-A10B-5bit": {
          "name": "Qwen3.5 122B A10B 5bit",
          "maxTokens": 65536
        }
      }
    }
  ]
}

A more minimal example is also available in:

  • dynamic-models.example.json

Authentication

Standard bearer auth

If your endpoint expects:

Authorization: Bearer <token>

use:

{
  "apiKey": "env:EXAMPLE_SERVER_API_KEY",
  "authHeader": true
}

Custom header auth

If your endpoint expects something like x-api-key:

{
  "authHeader": false,
  "headers": {
    "x-api-key": "env:EXAMPLE_SERVER_API_KEY"
  }
}

Shell-command-backed secrets

{
  "apiKey": "!security find-generic-password -ws EXAMPLE_SERVER_API_KEY",
  "authHeader": true
}

Model normalization

Many OpenAI-compatible /v1/models endpoints only return a model id and very little metadata.

This extension tries to infer or normalize from several common field names, including:

  • model id/name
  • context window (including top-level context_length and nested top_provider.context_length)
  • max output tokens (including nested top_provider.max_completion_tokens)
  • reasoning support
  • input modalities
  • cost/pricing
  • compat flags

When an endpoint does not return enough metadata, defaults and modelOverrides fill the gap.

Status output

/dynamic-models-status shows:

  • config path
  • loaded providers
  • per-provider metadata such as base URL, models URL, API type, authHeader
  • every discovered model
  • known metadata for each model
  • skipped providers
  • errors from the last refresh

Logging

Log file:

~/.pi/agent/dynamic-models.log

The extension appends:

  • refresh summaries
  • discovery errors

Enable verbose console debugging with:

export PI_DYNAMIC_MODELS_DEBUG=1

This adds debug output for:

  • refresh start/finish
  • endpoint discovery attempts
  • model counts
  • error context

Notes

  • embedding models are excluded by default because Pi expects chat/tool-capable models
  • the extension refreshes on startup and on session_start
  • disappearing endpoints are unregistered automatically

Development

Install dependencies:

npm install

Run TypeScript checks and tests:

npm run verify

Coverage:

npm run test:coverage

Publishing

From a clean checkout with dependencies installed:

npm ci
npm run verify
npm publish --dry-run
npm publish

Publishing runs TypeScript checks and tests automatically. The npm package contains the TypeScript extension, README, example configuration, and license. Pi loads the source directly; no build step is required. For subsequent releases, bump the version before publishing.

Repository structure

  • src/index.ts: extension implementation
  • dynamic-models.example.json: minimal example config
  • test/: tests
  • package.json: extension package metadata and scripts

License

MIT