{"repo": "andrewhowdencom/pi.litellm", "files": {"README.md": {"947e19122fe21f5ebae2222e43df5de08897dcbe": {"t": 1785747240.013065, "n": 8028, "h": "5bd1ec8227810200", "c": "# pi.litellm\n\n[![CI](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nPi extension that adds [LiteLLM](https://docs.litellm.ai/docs/) as a first-class provider with **automatic model discovery**. Point it at your LiteLLM proxy and all configured models appear in Pi's `/model` selector — no manual enumeration required.\n\n## Installation\n\nInstall as a Pi package from git:\n\n```bash\npi install git:github.com/andrewhowdencom/pi.litellm\n```\n\n> The npm package name is `pi-litellm`.\n\nOr load temporarily for a single session:\n\n```bash\npi -e git:github.com/andrewhowdencom/pi.litellm\n```\n\n## Configuration\n\n### `settings.json`\n\nAdd the extension settings to your Pi `settings.json`. The extension reads from two locations, with project-local overriding global:\n\n**Global defaults** (`~/.pi/agent/settings.json`):\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://localhost:4000\",\n \"apiKey\": \"sk-...\"\n }\n}\n```\n\n**Project-local overrides** (`./.pi/settings.json`):\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://project-proxy:4000\"\n }\n}\n```\n\nThe extension normalizes the URL automatically (adds `/v1` if missing, strips trailing slashes).\n\nWhen `apiKey` is set, the extension sends `Authorization: Bearer ` with every request.\n\n### Optional per-model overrides (`./.pi/litellm.json`)\n\nCreate `.pi/litellm.json` in your project directory to override discovered metadata for specific models:\n\n```json\n{\n \"modelOverrides\": {\n \"gpt-4\": {\n \"contextWindow\": 8192,\n \"maxTokens\": 4096,\n \"cost\": {\n \"input\": 30,\n \"output\": 60\n }\n },\n \"claude-sonnet-4\": {\n \"reasoning\": true,\n \"input\": [\"text\", \"image\"]\n }\n }\n}\n```\n\nAvailable override fields:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Display name shown in Pi's model selector |\n| `reasoning` | `boolean` | Whether the model supports extended thinking |\n| `input` | `[\"text\"]` or `[\"text\", \"image\"]` | Supported input modalities |\n| `cost.input` | `number` | Input cost per million tokens ($) |\n| `cost.output` | `number` | Output cost per million tokens ($) |\n| `cost.cacheRead` | `number` | Cache read cost per million tokens ($) |\n| `cost.cacheWrite` | `number` | Cache write cost per million tokens ($) |\n| `contextWindow` | `number` | Maximum context window in tokens |\n| `maxTokens` | `number` | Maximum output tokens |\n\n## Usage\n\n### Interactive mode\n\nStart Pi and select a LiteLLM model with `/model` or `Ctrl+L`:\n\n```bash\npi\n```\n\nThen type `/model` and search for models prefixed with `litellm/`.\n\n### Print mode (one-shot)\n\n```bash\npi --provider litellm --model gpt-4 -p \"Summarize this codebase\"\n```\n\n### With API key\n\nEnsure `apiKey` is set in your `settings.json`, then:\n\n```bash\npi --provider litellm --model claude-sonnet-4 -p \"Refactor this function\"\n```\n\n## How autodiscovery works\n\nAt startup, the extension queries your LiteLLM proxy in two phases. `{baseUrl}` below refers to your `LITELLM_BASE_URL` after normalization — it always ends with `/v1`.\n\n1. **Authoritative list:** `GET {baseUrl}/models` — the OpenAI-compatible list endpoint. This is **key-scoped**: it returns exactly the model aliases your API key is entitled to call, with no duplicate per-deployment rows and no tag-gated entries you cannot reach. It defines *which* models appear in the picker.\n\n2. **Metadata enrichment:** `GET {baseUrl}/model/info` — LiteLLM's rich metadata endpoint. Its context windows, token limits, and per-token costs are merged onto the authoritative models (joined by `model_name`). This step is best-effort: if `/model/info` returns 404, errors, or is malformed, the extension keeps the key-scoped list and applies sensible defaults for the missing metadata.\n\n> Only models returned by `/models` are shown, so you never see a model your key cannot use. This avoids the \"not allowed access to model due to tags configuration\" error that occurs when a proxy fronts one alias with multiple tag-scoped deployments.\n\n### Sensible defaults\n\nWhen metadata is missing, the extension applies these defaults:\n\n| Field | Default | Rationale |\n|-------|---------|-----------|\n| `contextWindow` | `128000` | Common default for modern models |\n| `maxTokens` | `4096` | Conservative output limit |\n| `cost.*` | `0` | Unknown costs show as \"—\" in Pi UI |\n| `input` | `[\"text\"]` | Safe default; image support detected heuristically |\n| `reasoning` | `false` | Safe default; detected heuristically from model name |\n\n### Heuristic model classification\n\nWhen LiteLLM does not expose capability metadata, the extension guesses from the model ID:\n\n- **Vision support** (`input: [\"text\", \"image\"]`): triggered by IDs containing `vision`, `gpt-4o`, `claude-.*sonnet`, `gemini`, or `llava`.\n- **Reasoning support** (`reasoning: true`): triggered by IDs matching `o1`, `o3`, `reasoning`, `thinking`, `r1`, or `deepseek-r1`.\n\nThese are conservative defaults. Use `.pi/litellm.json` overrides to correct misclassified models.\n\n## Architecture\n\n```\nPi startup\n │\n ▼\nAsync extension factory loads\n │\n ├─► Read config (settings.json + optional .pi/litellm.json)\n │\n ├─► Fetch /models (authoritative, key-scoped list)\n │ └─► Defines which models are shown\n │\n ├─► Fetch /model/info (best-effort enrichment)\n │ └─► Merge costs, context windows, token limits by model_name\n │ └─► On failure: keep list, apply defaults for metadata\n │\n ├─► Map each model to Pi ProviderModelConfig\n │ └─► Apply defaults for missing fields\n │ └─► Apply user overrides from config file\n │\n └─► pi.registerProvider(\"litellm\", { ... })\n```\n\nThe extension uses Pi's built-in `openai-completions` streaming API — **no custom streaming logic** is required because LiteLLM is natively OpenAI-compatible.\n\n## Troubleshooting\n\n### `LiteLLM baseUrl is required`\n\nAdd the extension configuration to your Pi `settings.json`:\n\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://localhost:4000\"\n }\n}\n```\n\nPlace it in `~/.pi/agent/settings.json` for global defaults, or `./.pi/settings.json` for project-local configuration.\n\n### `No models discovered from LiteLLM proxy`\n\n- Verify your LiteLLM proxy is running and accessible at the configured `baseUrl`.\n- Check that the proxy has at least one model configured in its `config.yaml`.\n- If authentication is required, set `apiKey` in your `settings.json`.\n\n### Models appear with `contextWindow: 128000` and `cost: 0`\n\nYour LiteLLM proxy is not exposing the `/model/info` endpoint (common with older versions or minimal deployments), so metadata enrichment is skipped. The authoritative `/v1/models` list still populates the picker, but with default context windows and costs. Upgrade LiteLLM or add per-model overrides in `.pi/litellm.json`.\n\n### `Failed to fetch models from LiteLLM: ...`\n\n- Check network connectivity to the proxy.\n- Verify the base URL is correct (try `curl http://localhost:4000/v1/models`, adjusting for your proxy URL).\n- If using HTTPS with a self-signed certificate, ensure your Node.js environment trusts the certificate.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Type-check and test\nnpm run check\n\n# Type-check only\nnpm run build\n```\n\n## Requirements\n\n- [Pi](https://pi.dev) ≥ 0.72 (for `registerProvider` API)\n- [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) with at least `/v1/models` exposed\n- `/model/info` endpoint recommended for rich metadata enrichment (costs, context windows)\n- Peer dependencies (provided by Pi): `@mariozechner/pi-ai`, `@mariozechner/pi-coding-agent`, `typebox`\n\n## Support\n\nReport issues at [github.com/andrewhowdencom/pi.litellm/issues](https://github.com/andrewhowdencom/pi.litellm/issues).\n\n## License\n\nMIT\n"}, "8a62e1eeccefa11b2ea2ce81a5bcfe508ef385d3": {"t": 1785771640.6740165, "n": 8028, "h": "5bd1ec8227810200", "c": "# pi.litellm\n\n[![CI](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nPi extension that adds [LiteLLM](https://docs.litellm.ai/docs/) as a first-class provider with **automatic model discovery**. Point it at your LiteLLM proxy and all configured models appear in Pi's `/model` selector — no manual enumeration required.\n\n## Installation\n\nInstall as a Pi package from git:\n\n```bash\npi install git:github.com/andrewhowdencom/pi.litellm\n```\n\n> The npm package name is `pi-litellm`.\n\nOr load temporarily for a single session:\n\n```bash\npi -e git:github.com/andrewhowdencom/pi.litellm\n```\n\n## Configuration\n\n### `settings.json`\n\nAdd the extension settings to your Pi `settings.json`. The extension reads from two locations, with project-local overriding global:\n\n**Global defaults** (`~/.pi/agent/settings.json`):\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://localhost:4000\",\n \"apiKey\": \"sk-...\"\n }\n}\n```\n\n**Project-local overrides** (`./.pi/settings.json`):\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://project-proxy:4000\"\n }\n}\n```\n\nThe extension normalizes the URL automatically (adds `/v1` if missing, strips trailing slashes).\n\nWhen `apiKey` is set, the extension sends `Authorization: Bearer ` with every request.\n\n### Optional per-model overrides (`./.pi/litellm.json`)\n\nCreate `.pi/litellm.json` in your project directory to override discovered metadata for specific models:\n\n```json\n{\n \"modelOverrides\": {\n \"gpt-4\": {\n \"contextWindow\": 8192,\n \"maxTokens\": 4096,\n \"cost\": {\n \"input\": 30,\n \"output\": 60\n }\n },\n \"claude-sonnet-4\": {\n \"reasoning\": true,\n \"input\": [\"text\", \"image\"]\n }\n }\n}\n```\n\nAvailable override fields:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Display name shown in Pi's model selector |\n| `reasoning` | `boolean` | Whether the model supports extended thinking |\n| `input` | `[\"text\"]` or `[\"text\", \"image\"]` | Supported input modalities |\n| `cost.input` | `number` | Input cost per million tokens ($) |\n| `cost.output` | `number` | Output cost per million tokens ($) |\n| `cost.cacheRead` | `number` | Cache read cost per million tokens ($) |\n| `cost.cacheWrite` | `number` | Cache write cost per million tokens ($) |\n| `contextWindow` | `number` | Maximum context window in tokens |\n| `maxTokens` | `number` | Maximum output tokens |\n\n## Usage\n\n### Interactive mode\n\nStart Pi and select a LiteLLM model with `/model` or `Ctrl+L`:\n\n```bash\npi\n```\n\nThen type `/model` and search for models prefixed with `litellm/`.\n\n### Print mode (one-shot)\n\n```bash\npi --provider litellm --model gpt-4 -p \"Summarize this codebase\"\n```\n\n### With API key\n\nEnsure `apiKey` is set in your `settings.json`, then:\n\n```bash\npi --provider litellm --model claude-sonnet-4 -p \"Refactor this function\"\n```\n\n## How autodiscovery works\n\nAt startup, the extension queries your LiteLLM proxy in two phases. `{baseUrl}` below refers to your `LITELLM_BASE_URL` after normalization — it always ends with `/v1`.\n\n1. **Authoritative list:** `GET {baseUrl}/models` — the OpenAI-compatible list endpoint. This is **key-scoped**: it returns exactly the model aliases your API key is entitled to call, with no duplicate per-deployment rows and no tag-gated entries you cannot reach. It defines *which* models appear in the picker.\n\n2. **Metadata enrichment:** `GET {baseUrl}/model/info` — LiteLLM's rich metadata endpoint. Its context windows, token limits, and per-token costs are merged onto the authoritative models (joined by `model_name`). This step is best-effort: if `/model/info` returns 404, errors, or is malformed, the extension keeps the key-scoped list and applies sensible defaults for the missing metadata.\n\n> Only models returned by `/models` are shown, so you never see a model your key cannot use. This avoids the \"not allowed access to model due to tags configuration\" error that occurs when a proxy fronts one alias with multiple tag-scoped deployments.\n\n### Sensible defaults\n\nWhen metadata is missing, the extension applies these defaults:\n\n| Field | Default | Rationale |\n|-------|---------|-----------|\n| `contextWindow` | `128000` | Common default for modern models |\n| `maxTokens` | `4096` | Conservative output limit |\n| `cost.*` | `0` | Unknown costs show as \"—\" in Pi UI |\n| `input` | `[\"text\"]` | Safe default; image support detected heuristically |\n| `reasoning` | `false` | Safe default; detected heuristically from model name |\n\n### Heuristic model classification\n\nWhen LiteLLM does not expose capability metadata, the extension guesses from the model ID:\n\n- **Vision support** (`input: [\"text\", \"image\"]`): triggered by IDs containing `vision`, `gpt-4o`, `claude-.*sonnet`, `gemini`, or `llava`.\n- **Reasoning support** (`reasoning: true`): triggered by IDs matching `o1`, `o3`, `reasoning`, `thinking`, `r1`, or `deepseek-r1`.\n\nThese are conservative defaults. Use `.pi/litellm.json` overrides to correct misclassified models.\n\n## Architecture\n\n```\nPi startup\n │\n ▼\nAsync extension factory loads\n │\n ├─► Read config (settings.json + optional .pi/litellm.json)\n │\n ├─► Fetch /models (authoritative, key-scoped list)\n │ └─► Defines which models are shown\n │\n ├─► Fetch /model/info (best-effort enrichment)\n │ └─► Merge costs, context windows, token limits by model_name\n │ └─► On failure: keep list, apply defaults for metadata\n │\n ├─► Map each model to Pi ProviderModelConfig\n │ └─► Apply defaults for missing fields\n │ └─► Apply user overrides from config file\n │\n └─► pi.registerProvider(\"litellm\", { ... })\n```\n\nThe extension uses Pi's built-in `openai-completions` streaming API — **no custom streaming logic** is required because LiteLLM is natively OpenAI-compatible.\n\n## Troubleshooting\n\n### `LiteLLM baseUrl is required`\n\nAdd the extension configuration to your Pi `settings.json`:\n\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://localhost:4000\"\n }\n}\n```\n\nPlace it in `~/.pi/agent/settings.json` for global defaults, or `./.pi/settings.json` for project-local configuration.\n\n### `No models discovered from LiteLLM proxy`\n\n- Verify your LiteLLM proxy is running and accessible at the configured `baseUrl`.\n- Check that the proxy has at least one model configured in its `config.yaml`.\n- If authentication is required, set `apiKey` in your `settings.json`.\n\n### Models appear with `contextWindow: 128000` and `cost: 0`\n\nYour LiteLLM proxy is not exposing the `/model/info` endpoint (common with older versions or minimal deployments), so metadata enrichment is skipped. The authoritative `/v1/models` list still populates the picker, but with default context windows and costs. Upgrade LiteLLM or add per-model overrides in `.pi/litellm.json`.\n\n### `Failed to fetch models from LiteLLM: ...`\n\n- Check network connectivity to the proxy.\n- Verify the base URL is correct (try `curl http://localhost:4000/v1/models`, adjusting for your proxy URL).\n- If using HTTPS with a self-signed certificate, ensure your Node.js environment trusts the certificate.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Type-check and test\nnpm run check\n\n# Type-check only\nnpm run build\n```\n\n## Requirements\n\n- [Pi](https://pi.dev) ≥ 0.72 (for `registerProvider` API)\n- [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) with at least `/v1/models` exposed\n- `/model/info` endpoint recommended for rich metadata enrichment (costs, context windows)\n- Peer dependencies (provided by Pi): `@mariozechner/pi-ai`, `@mariozechner/pi-coding-agent`, `typebox`\n\n## Support\n\nReport issues at [github.com/andrewhowdencom/pi.litellm/issues](https://github.com/andrewhowdencom/pi.litellm/issues).\n\n## License\n\nMIT\n"}, "cf33edbaf8506af9b7c67548cab0328cadc7360e": {"t": 1785771641.9353456, "n": 7290, "h": "9cdb345f3c1fea12", "c": "# pi.litellm\n\n[![CI](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nPi extension that adds [LiteLLM](https://docs.litellm.ai/docs/) as a first-class provider with **automatic model discovery**. Point it at your LiteLLM proxy and all configured models appear in Pi's `/model` selector — no manual enumeration required.\n\n## Installation\n\nInstall as a Pi package from git:\n\n```bash\npi install git:github.com/andrewhowdencom/pi.litellm\n```\n\n> The npm package name is `pi-litellm`.\n\nOr load temporarily for a single session:\n\n```bash\npi -e git:github.com/andrewhowdencom/pi.litellm\n```\n\n## Configuration\n\n### `settings.json`\n\nAdd the extension settings to your Pi `settings.json`. The extension reads from two locations, with project-local overriding global:\n\n**Global defaults** (`~/.pi/agent/settings.json`):\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://localhost:4000\",\n \"apiKey\": \"sk-...\"\n }\n}\n```\n\n**Project-local overrides** (`./.pi/settings.json`):\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://project-proxy:4000\"\n }\n}\n```\n\nThe extension normalizes the URL automatically (adds `/v1` if missing, strips trailing slashes).\n\nWhen `apiKey` is set, the extension sends `Authorization: Bearer ` with every request.\n\n### Optional per-model overrides (`./.pi/litellm.json`)\n\nCreate `.pi/litellm.json` in your project directory to override discovered metadata for specific models:\n\n```json\n{\n \"modelOverrides\": {\n \"gpt-4\": {\n \"contextWindow\": 8192,\n \"maxTokens\": 4096,\n \"cost\": {\n \"input\": 30,\n \"output\": 60\n }\n },\n \"claude-sonnet-4\": {\n \"reasoning\": true,\n \"input\": [\"text\", \"image\"]\n }\n }\n}\n```\n\nAvailable override fields:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Display name shown in Pi's model selector |\n| `reasoning` | `boolean` | Whether the model supports extended thinking |\n| `input` | `[\"text\"]` or `[\"text\", \"image\"]` | Supported input modalities |\n| `cost.input` | `number` | Input cost per million tokens ($) |\n| `cost.output` | `number` | Output cost per million tokens ($) |\n| `cost.cacheRead` | `number` | Cache read cost per million tokens ($) |\n| `cost.cacheWrite` | `number` | Cache write cost per million tokens ($) |\n| `contextWindow` | `number` | Maximum context window in tokens |\n| `maxTokens` | `number` | Maximum output tokens |\n\n## Usage\n\n### Interactive mode\n\nStart Pi and select a LiteLLM model with `/model` or `Ctrl+L`:\n\n```bash\npi\n```\n\nThen type `/model` and search for models prefixed with `litellm/`.\n\n### Print mode (one-shot)\n\n```bash\npi --provider litellm --model gpt-4 -p \"Summarize this codebase\"\n```\n\n### With API key\n\nEnsure `apiKey` is set in your `settings.json`, then:\n\n```bash\npi --provider litellm --model claude-sonnet-4 -p \"Refactor this function\"\n```\n\n## How autodiscovery works\n\nAt startup, the extension queries your LiteLLM proxy in two phases. `{baseUrl}` below refers to your `LITELLM_BASE_URL` after normalization — it always ends with `/v1`.\n\n1. **Primary:** `GET {baseUrl}/model/info` — LiteLLM's rich metadata endpoint. Returns model IDs, context windows, token limits, and per-token costs when available.\n\n2. **Fallback:** If `/model/info` returns 404 or errors, `GET {baseUrl}/models` — OpenAI-compatible minimal list. Only model IDs are available; all other metadata uses sensible defaults.\n\n### Sensible defaults\n\nWhen metadata is missing, the extension applies these defaults:\n\n| Field | Default | Rationale |\n|-------|---------|-----------|\n| `contextWindow` | `128000` | Common default for modern models |\n| `maxTokens` | `4096` | Conservative output limit |\n| `cost.*` | `0` | Unknown costs show as \"—\" in Pi UI |\n| `input` | `[\"text\"]` | Safe default; image support detected heuristically |\n| `reasoning` | `false` | Safe default; detected heuristically from model name |\n\n### Heuristic model classification\n\nWhen LiteLLM does not expose capability metadata, the extension guesses from the model ID:\n\n- **Vision support** (`input: [\"text\", \"image\"]`): triggered by IDs containing `vision`, `gpt-4o`, `claude-.*sonnet`, `gemini`, or `llava`.\n- **Reasoning support** (`reasoning: true`): triggered by IDs matching `o1`, `o3`, `reasoning`, `thinking`, `r1`, or `deepseek-r1`.\n\nThese are conservative defaults. Use `.pi/litellm.json` overrides to correct misclassified models.\n\n## Architecture\n\n```\nPi startup\n │\n ▼\nAsync extension factory loads\n │\n ├─► Read config (settings.json + optional .pi/litellm.json)\n │\n ├─► Fetch /model/info (rich metadata)\n │ └─► On success: extract costs, context windows, token limits\n │\n ├─► On failure: fetch /models (minimal list)\n │ └─► Only model IDs available\n │\n ├─► Map each model to Pi ProviderModelConfig\n │ └─► Apply defaults for missing fields\n │ └─► Apply user overrides from config file\n │\n └─► pi.registerProvider(\"litellm\", { ... })\n```\n\nThe extension uses Pi's built-in `openai-completions` streaming API — **no custom streaming logic** is required because LiteLLM is natively OpenAI-compatible.\n\n## Troubleshooting\n\n### `LiteLLM baseUrl is required`\n\nAdd the extension configuration to your Pi `settings.json`:\n\n```json\n{\n \"github.com/andrewhowdencom/pi.litellm\": {\n \"baseUrl\": \"http://localhost:4000\"\n }\n}\n```\n\nPlace it in `~/.pi/agent/settings.json` for global defaults, or `./.pi/settings.json` for project-local configuration.\n\n### `No models discovered from LiteLLM proxy`\n\n- Verify your LiteLLM proxy is running and accessible at the configured `baseUrl`.\n- Check that the proxy has at least one model configured in its `config.yaml`.\n- If authentication is required, set `apiKey` in your `settings.json`.\n\n### Models appear with `contextWindow: 128000` and `cost: 0`\n\nYour LiteLLM proxy is not exposing the `/model/info` endpoint (common with older versions or minimal deployments). The extension falls back to `/v1/models`, which only returns model IDs. All other fields use defaults. Upgrade LiteLLM or add per-model overrides in `.pi/litellm.json`.\n\n### `Failed to fetch models from LiteLLM: ...`\n\n- Check network connectivity to the proxy.\n- Verify the base URL is correct (try `curl http://localhost:4000/v1/models`, adjusting for your proxy URL).\n- If using HTTPS with a self-signed certificate, ensure your Node.js environment trusts the certificate.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Type-check and test\nnpm run check\n\n# Type-check only\nnpm run build\n```\n\n## Requirements\n\n- [Pi](https://pi.dev) ≥ 0.72 (for `registerProvider` API)\n- [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) with at least `/v1/models` exposed\n- `/model/info` endpoint recommended for rich metadata (costs, context windows)\n- Peer dependencies (provided by Pi): `@mariozechner/pi-ai`, `@mariozechner/pi-coding-agent`, `typebox`\n\n## Support\n\nReport issues at [github.com/andrewhowdencom/pi.litellm/issues](https://github.com/andrewhowdencom/pi.litellm/issues).\n\n## License\n\nMIT\n"}, "afdd8c7918fbb062d23ecc564656eded32551bbd": {"t": 1785771643.5905182, "n": 6943, "h": "5a692d32a502490b", "c": "# pi.litellm\n\n[![CI](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewhowdencom/pi.litellm/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nPi extension that adds [LiteLLM](https://docs.litellm.ai/docs/) as a first-class provider with **automatic model discovery**. Point it at your LiteLLM proxy and all configured models appear in Pi's `/model` selector — no manual enumeration required.\n\n## Installation\n\nInstall as a Pi package from git:\n\n```bash\npi install git:github.com/andrewhowdencom/pi.litellm\n```\n\n> The npm package name is `pi-litellm`.\n\nOr load temporarily for a single session:\n\n```bash\npi -e git:github.com/andrewhowdencom/pi.litellm\n```\n\n## Configuration\n\n### Required environment variable\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000 # your LiteLLM proxy URL\n```\n\nThe extension normalizes the URL automatically (adds `/v1` if missing, strips trailing slashes).\n\n### Optional environment variable\n\n```bash\nexport LITELLM_API_KEY=sk-... # if your LiteLLM proxy requires authentication\n```\n\nWhen set, the extension sends `Authorization: Bearer ` with every request.\n\n### Optional per-model overrides (`./.pi/litellm.json`)\n\nCreate `.pi/litellm.json` in your project directory to override discovered metadata for specific models:\n\n```json\n{\n \"modelOverrides\": {\n \"gpt-4\": {\n \"contextWindow\": 8192,\n \"maxTokens\": 4096,\n \"cost\": {\n \"input\": 30,\n \"output\": 60\n }\n },\n \"claude-sonnet-4\": {\n \"reasoning\": true,\n \"input\": [\"text\", \"image\"]\n }\n }\n}\n```\n\nAvailable override fields:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Display name shown in Pi's model selector |\n| `reasoning` | `boolean` | Whether the model supports extended thinking |\n| `input` | `[\"text\"]` or `[\"text\", \"image\"]` | Supported input modalities |\n| `cost.input` | `number` | Input cost per million tokens ($) |\n| `cost.output` | `number` | Output cost per million tokens ($) |\n| `cost.cacheRead` | `number` | Cache read cost per million tokens ($) |\n| `cost.cacheWrite` | `number` | Cache write cost per million tokens ($) |\n| `contextWindow` | `number` | Maximum context window in tokens |\n| `maxTokens` | `number` | Maximum output tokens |\n\n## Usage\n\n### Interactive mode\n\nStart Pi and select a LiteLLM model with `/model` or `Ctrl+L`:\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000\npi\n```\n\nThen type `/model` and search for models prefixed with `litellm/`.\n\n### Print mode (one-shot)\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000\npi --provider litellm --model gpt-4 -p \"Summarize this codebase\"\n```\n\n### With API key\n\n```bash\nexport LITELLM_BASE_URL=https://litellm.internal.company.com\nexport LITELLM_API_KEY=sk-...\npi --provider litellm --model claude-sonnet-4 -p \"Refactor this function\"\n```\n\n## How autodiscovery works\n\nAt startup, the extension queries your LiteLLM proxy in two phases. `{baseUrl}` below refers to your `LITELLM_BASE_URL` after normalization — it always ends with `/v1`.\n\n1. **Primary:** `GET {baseUrl}/model/info` — LiteLLM's rich metadata endpoint. Returns model IDs, context windows, token limits, and per-token costs when available.\n\n2. **Fallback:** If `/model/info` returns 404 or errors, `GET {baseUrl}/models` — OpenAI-compatible minimal list. Only model IDs are available; all other metadata uses sensible defaults.\n\n### Sensible defaults\n\nWhen metadata is missing, the extension applies these defaults:\n\n| Field | Default | Rationale |\n|-------|---------|-----------|\n| `contextWindow` | `128000` | Common default for modern models |\n| `maxTokens` | `4096` | Conservative output limit |\n| `cost.*` | `0` | Unknown costs show as \"—\" in Pi UI |\n| `input` | `[\"text\"]` | Safe default; image support detected heuristically |\n| `reasoning` | `false` | Safe default; detected heuristically from model name |\n\n### Heuristic model classification\n\nWhen LiteLLM does not expose capability metadata, the extension guesses from the model ID:\n\n- **Vision support** (`input: [\"text\", \"image\"]`): triggered by IDs containing `vision`, `gpt-4o`, `claude-.*sonnet`, `gemini`, or `llava`.\n- **Reasoning support** (`reasoning: true`): triggered by IDs matching `o1`, `o3`, `reasoning`, `thinking`, `r1`, or `deepseek-r1`.\n\nThese are conservative defaults. Use `.pi/litellm.json` overrides to correct misclassified models.\n\n## Architecture\n\n```\nPi startup\n │\n ▼\nAsync extension factory loads\n │\n ├─► Read config (env vars + optional .pi/litellm.json)\n │\n ├─► Fetch /model/info (rich metadata)\n │ └─► On success: extract costs, context windows, token limits\n │\n ├─► On failure: fetch /models (minimal list)\n │ └─► Only model IDs available\n │\n ├─► Map each model to Pi ProviderModelConfig\n │ └─► Apply defaults for missing fields\n │ └─► Apply user overrides from config file\n │\n └─► pi.registerProvider(\"litellm\", { ... })\n```\n\nThe extension uses Pi's built-in `openai-completions` streaming API — **no custom streaming logic** is required because LiteLLM is natively OpenAI-compatible.\n\n## Troubleshooting\n\n### `LITELLM_BASE_URL environment variable is required`\n\nSet the environment variable before starting Pi:\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000\n```\n\n### `No models discovered from LiteLLM proxy`\n\n- Verify your LiteLLM proxy is running and accessible at `LITELLM_BASE_URL`.\n- Check that the proxy has at least one model configured in its `config.yaml`.\n- If authentication is required, set `LITELLM_API_KEY`.\n\n### Models appear with `contextWindow: 128000` and `cost: 0`\n\nYour LiteLLM proxy is not exposing the `/model/info` endpoint (common with older versions or minimal deployments). The extension falls back to `/v1/models`, which only returns model IDs. All other fields use defaults. Upgrade LiteLLM or add per-model overrides in `.pi/litellm.json`.\n\n### `Failed to fetch models from LiteLLM: ...`\n\n- Check network connectivity to the proxy.\n- Verify the base URL is correct (try `curl $LITELLM_BASE_URL/v1/models`).\n- If using HTTPS with a self-signed certificate, ensure your Node.js environment trusts the certificate.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Type-check and test\nnpm run check\n\n# Type-check only\nnpm run build\n```\n\n## Requirements\n\n- [Pi](https://pi.dev) ≥ 0.72 (for `registerProvider` API)\n- [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) with at least `/v1/models` exposed\n- `/model/info` endpoint recommended for rich metadata (costs, context windows)\n- Peer dependencies (provided by Pi): `@mariozechner/pi-ai`, `@mariozechner/pi-coding-agent`, `typebox`\n\n## Support\n\nReport issues at [github.com/andrewhowdencom/pi.litellm/issues](https://github.com/andrewhowdencom/pi.litellm/issues).\n\n## License\n\nMIT\n"}, "9d4a23bdcb1ab717090ea40c0e7990aec03d22fa": {"t": 1785771646.9231436, "n": 6144, "h": "d0fb7bd5e5e41d9a", "c": "# pi.litellm\n\nPi extension that adds [LiteLLM](https://docs.litellm.ai/docs/) as a first-class provider with **automatic model discovery**. Point it at your LiteLLM proxy and all configured models appear in Pi's `/model` selector — no manual enumeration required.\n\n## Installation\n\nInstall as a Pi package from git:\n\n```bash\npi install git:github.com/andrewhowdencom/pi.litellm\n```\n\nOr load temporarily for a single session:\n\n```bash\npi -e git:github.com/andrewhowdencom/pi.litellm\n```\n\n## Configuration\n\n### Required environment variable\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000 # your LiteLLM proxy URL\n```\n\nThe extension normalizes the URL automatically (adds `/v1` if missing, strips trailing slashes).\n\n### Optional environment variable\n\n```bash\nexport LITELLM_API_KEY=sk-... # if your LiteLLM proxy requires authentication\n```\n\nWhen set, the extension sends `Authorization: Bearer ` with every request.\n\n### Optional per-model overrides (`./.pi/litellm.json`)\n\nCreate `.pi/litellm.json` in your project directory to override discovered metadata for specific models:\n\n```json\n{\n \"modelOverrides\": {\n \"gpt-4\": {\n \"contextWindow\": 8192,\n \"maxTokens\": 4096,\n \"cost\": {\n \"input\": 30,\n \"output\": 60\n }\n },\n \"claude-sonnet-4\": {\n \"reasoning\": true,\n \"input\": [\"text\", \"image\"]\n }\n }\n}\n```\n\nAvailable override fields:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `name` | `string` | Display name shown in Pi's model selector |\n| `reasoning` | `boolean` | Whether the model supports extended thinking |\n| `input` | `[\"text\"]` or `[\"text\", \"image\"]` | Supported input modalities |\n| `cost.input` | `number` | Input cost per million tokens ($) |\n| `cost.output` | `number` | Output cost per million tokens ($) |\n| `cost.cacheRead` | `number` | Cache read cost per million tokens ($) |\n| `cost.cacheWrite` | `number` | Cache write cost per million tokens ($) |\n| `contextWindow` | `number` | Maximum context window in tokens |\n| `maxTokens` | `number` | Maximum output tokens |\n\n## Usage\n\n### Interactive mode\n\nStart Pi and select a LiteLLM model with `/model` or `Ctrl+L`:\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000\npi\n```\n\nThen type `/model` and search for models prefixed with `litellm/`.\n\n### Print mode (one-shot)\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000\npi --provider litellm --model gpt-4 -p \"Summarize this codebase\"\n```\n\n### With API key\n\n```bash\nexport LITELLM_BASE_URL=https://litellm.internal.company.com\nexport LITELLM_API_KEY=sk-...\npi --provider litellm --model claude-sonnet-4 -p \"Refactor this function\"\n```\n\n## How autodiscovery works\n\nAt startup, the extension queries your LiteLLM proxy in two phases:\n\n1. **Primary:** `GET {baseUrl}/model/info` — LiteLLM's rich metadata endpoint. Returns model IDs, context windows, token limits, and per-token costs when available.\n\n2. **Fallback:** If `/model/info` returns 404 or errors, `GET {baseUrl}/v1/models` — OpenAI-compatible minimal list. Only model IDs are available; all other metadata uses sensible defaults.\n\n### Sensible defaults\n\nWhen metadata is missing, the extension applies these defaults:\n\n| Field | Default | Rationale |\n|-------|---------|-----------|\n| `contextWindow` | `128000` | Common default for modern models |\n| `maxTokens` | `4096` | Conservative output limit |\n| `cost.*` | `0` | Unknown costs show as \"—\" in Pi UI |\n| `input` | `[\"text\"]` | Safe default; image support detected heuristically |\n| `reasoning` | `false` | Safe default; detected heuristically from model name |\n\n### Heuristic model classification\n\nWhen LiteLLM does not expose capability metadata, the extension guesses from the model ID:\n\n- **Vision support** (`input: [\"text\", \"image\"]`): triggered by IDs containing `vision`, `gpt-4o`, `claude-.*sonnet`, `gemini`, or `llava`.\n- **Reasoning support** (`reasoning: true`): triggered by IDs matching `o1`, `o3`, `reasoning`, `thinking`, `r1`, or `deepseek-r1`.\n\nThese are conservative defaults. Use `.pi/litellm.json` overrides to correct misclassified models.\n\n## Architecture\n\n```\nPi startup\n │\n ▼\nAsync extension factory loads\n │\n ├─► Read config (env vars + optional .pi/litellm.json)\n │\n ├─► Fetch /model/info (rich metadata)\n │ └─► On success: extract costs, context windows, token limits\n │\n ├─► On failure: fetch /v1/models (minimal list)\n │ └─► Only model IDs available\n │\n ├─► Map each model to Pi ProviderModelConfig\n │ └─► Apply defaults for missing fields\n │ └─► Apply user overrides from config file\n │\n └─► pi.registerProvider(\"litellm\", { ... })\n```\n\nThe extension uses Pi's built-in `openai-completions` streaming API — **no custom streaming logic** is required because LiteLLM is natively OpenAI-compatible.\n\n## Troubleshooting\n\n### `LITELLM_BASE_URL environment variable is required`\n\nSet the environment variable before starting Pi:\n\n```bash\nexport LITELLM_BASE_URL=http://localhost:4000\n```\n\n### `No models discovered from LiteLLM proxy`\n\n- Verify your LiteLLM proxy is running and accessible at `LITELLM_BASE_URL`.\n- Check that the proxy has at least one model configured in its `config.yaml`.\n- If authentication is required, set `LITELLM_API_KEY`.\n\n### Models appear with `contextWindow: 128000` and `cost: 0`\n\nYour LiteLLM proxy is not exposing the `/model/info` endpoint (common with older versions or minimal deployments). The extension falls back to `/v1/models`, which only returns model IDs. All other fields use defaults. Upgrade LiteLLM or add per-model overrides in `.pi/litellm.json`.\n\n### `Failed to fetch models from LiteLLM: ...`\n\n- Check network connectivity to the proxy.\n- Verify the base URL is correct (try `curl $LITELLM_BASE_URL/v1/models`).\n- If using HTTPS with a self-signed certificate, ensure your Node.js environment trusts the certificate.\n\n## Requirements\n\n- [Pi](https://pi.dev) ≥ 0.72 (for `registerProvider` API)\n- [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) with at least `/v1/models` exposed\n- `/model/info` endpoint recommended for rich metadata (costs, context windows)\n\n## License\n\nMIT\n"}}}}