pi-ollama-cloud 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +62 -39
- package/index.ts +15 -114
- package/models.generated.ts +75 -491
- package/models.ts +203 -137
- package/package.json +10 -4
- package/pricing.generated.ts +32 -0
- package/thinking-levels.ts +13 -0
- package/utils.ts +17 -0
- package/web-tools.ts +160 -125
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.8.0] - 2026-08-09
|
|
6
|
+
|
|
7
|
+
- **Breaking:** Migrate model refresh to pi's native `refreshModels` mechanism. Remove the `/ollama-cloud-refresh` command and the manual `~/.pi/agent/cache/ollama-cloud-models.json` cache. The catalog now refreshes automatically on startup, on `/model` open, and via `pi update --models`, persisted through pi's own `FileModelsStore`. Users should delete the orphaned cache file after upgrade: `rm ~/.pi/agent/cache/ollama-cloud-models.json`.
|
|
8
|
+
- The shipped `GENERATED_MODELS` list is now a first-launch fallback; releases are no longer required for model freshness (only for deprecation or pricing changes).
|
|
9
|
+
- Refresh the generated catalog from the live API: add `deepseek-v4-flash:0731`, `deepseek-v4-flash:preview`, and `kimi-k3`; remove `kimi-k2.5` and `minimax-m2.5`, which are no longer listed. Refresh models.dev pricing, including the new models. Thanks @noruthedev (#43).
|
|
10
|
+
- Requires a pi version with the `stored`/`publish` `RefreshModelsContext` (pi 0.84.0+). Add `@earendil-works/pi-ai` as a peer dependency.
|
|
11
|
+
- Web tools now throw on errors instead of returning an `isError` result, aligning with pi 0.84.0's `AgentToolResult` contract.
|
|
12
|
+
- Fix `ollama_web_fetch` failing on pages where the API returns `links: null` (e.g. GitHub PR pages); the response is now accepted and rendered without a links list.
|
|
13
|
+
- Refresh robustness: add a 4-hour cooldown so repeated `/model` opens don't re-fetch the catalog; on a partial refresh failure, keep the last-good catalog and surface the error instead of silently returning an incomplete list.
|
|
14
|
+
- Add `tsgo --noEmit` type-checking to `npm run check` and CI.
|
|
15
|
+
|
|
16
|
+
## [0.7.0] - 2026-07-18
|
|
17
|
+
|
|
18
|
+
- Fix extension crash on pi 0.80.8+ where `AuthStorage` is no longer exported by `@earendil-works/pi-coding-agent`. Web tools now resolve the API key through the tool execution context's `modelRegistry.getApiKeyForProvider()`, preserving runtime/CLI overrides and the registered `apiKey: "$OLLAMA_API_KEY"` config. Thanks @badlogic for the cross-version analysis (#34, #35, #37).
|
|
19
|
+
- Restore the `OLLAMA_API_KEY` env-var fallback in `ollama_web_search` and `ollama_web_fetch`. Thanks @cawilliamson (#26).
|
|
20
|
+
- Add a 15s timeout to web search/fetch requests and preserve tool-cancellation by extending `fetchJsonWithTimeout` with an external `AbortSignal`.
|
|
21
|
+
- Always target `https://ollama.com` and warn when `OLLAMA_API_BASE` is set to a non-cloud host, instead of silently querying a local Ollama daemon. Thanks @valueforvalue (#32, #33).
|
|
22
|
+
- Add a `glm-5.2` thinking level map exposing `off`, `high`, and `xhigh` (`reasoning_effort: "none"`, `"high"`, `"max"`). Thanks @Thinkscape (#29).
|
|
23
|
+
- Add estimated per-token pricing for Ollama Cloud models so `/cost` shows comparable usage. Prices are generated from [models.dev](https://models.dev) (the same source pi uses) via `scripts/generate-pricing.ts` into `pricing.generated.ts`, not hand-typed, and regenerate with the catalog via `npm run generate-models`. Prices are pinned to the installed package version: `/ollama-cloud-refresh` updates the model list and metadata but does not re-fetch prices, so newly added models register with zero cost until the next release. Not actual subscription charges. Thanks @DxTa (#9).
|
|
24
|
+
- Refresh the generated model catalog from the live Ollama Cloud API. Adds `glm-5.2` (1M context, text-only) and `kimi-k2.7-code` (262K context, text + image). `deepseek-v4-pro` context window is now 524288 (was 1048576).
|
|
25
|
+
- Retire models deprecated per https://docs.ollama.com/cloud#deprecations: July 15, 2026 batch (`deepseek-v3.1:671b`, `deepseek-v3.2`, `devstral-2:123b`, `devstral-small-2:24b`, `ministral-3:14b`, `ministral-3:3b`, `ministral-3:8b`, `gemini-3-flash-preview`, `gemma3:12b`, `gemma3:27b`, `gemma3:4b`, `glm-4.7`, `glm-5`, `minimax-m2.1`, `qwen3-coder-next`, `qwen3-coder:480b`) and June 30 (`rnj-1:8b`). The shipped catalog goes from 30 to 18 models.
|
|
26
|
+
- Bump `@earendil-works/pi-coding-agent` runtime dependency to 0.80.10.
|
|
27
|
+
|
|
5
28
|
## [0.6.0] - 2026-06-05
|
|
6
29
|
|
|
7
30
|
- Fix `apiKey` registered as a literal string instead of an environment variable reference. Changed `apiKey: "OLLAMA_API_KEY"` to `apiKey: "$OLLAMA_API_KEY"` in `registerProvider`, resolving the deprecation warning emitted by pi v0.77.0+ and making the `OLLAMA_API_KEY` env var work alongside `auth.json` (env var takes priority, falls back to `auth.json`). Thanks @mandusm (#21).
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-ollama-cloud
|
|
2
2
|
|
|
3
|
-
Ollama Cloud provider plugin for [Pi](https://
|
|
3
|
+
Ollama Cloud provider plugin for the [Pi](https://pi.dev) coding agent.
|
|
4
4
|
|
|
5
5
|
Registers Ollama Cloud as a model provider with dynamically fetched models, and provides `ollama_web_search` and `ollama_web_fetch` tools that use the [Ollama Cloud web search API](https://docs.ollama.com/capabilities/web-search) - no local Ollama server required.
|
|
6
6
|
|
|
@@ -8,13 +8,11 @@ Registers Ollama Cloud as a model provider with dynamically fetched models, and
|
|
|
8
8
|
|
|
9
9
|
- **Dynamic model discovery** - Fetches the full model list from `ollama.com/v1/models`, then fetches per-model details via `/api/show` to determine capabilities, context length, and tool support.
|
|
10
10
|
- **Curated thinking levels** - Maps Pi's thinking levels to Ollama Cloud's OpenAI-compatible `reasoning_effort` values via `thinking-levels.ts`, with per-model exceptions based on API testing.
|
|
11
|
-
- **Baked-in model list** - A generated
|
|
12
|
-
- **
|
|
13
|
-
- **Auto-refresh on stale cache** - When the disk cache is older than 30 days, the extension uses it immediately and shows a visible refresh progress widget on the next `session_start` to pull in any new models.
|
|
14
|
-
- **`/ollama-cloud-refresh` command** - Re-fetches the model list and updates the cache and provider registration live (no restart needed).
|
|
11
|
+
- **Baked-in model list** - A generated fallback list (`models.generated.ts`) ships with the extension so models are available on first launch without any network calls. It is only a fallback: pi refreshes the live catalog at runtime, so shipping a new release for catalog freshness is no longer needed.
|
|
12
|
+
- **Automatic model refresh** - On startup, `/model` open, and `pi update --models`, pi calls the extension's `refreshModels` callback to fetch the latest models from the API and persists them through pi's own model store. No manual refresh command.
|
|
15
13
|
- **`ollama_web_search` tool** - Search the web for real-time information using Ollama Cloud's `/api/web_search` endpoint. Returns titles, URLs, and content snippets.
|
|
16
14
|
- **`ollama_web_fetch` tool** - Fetch and extract text content from a web page URL using Ollama Cloud's `/api/web_fetch` endpoint. Returns page title, content, and links.
|
|
17
|
-
- **
|
|
15
|
+
- **Estimated cost tracking** - Models are registered with estimated per-token costs sourced from [models.dev](https://models.dev) (the same catalog pi uses), so Pi's `/cost` shows comparable usage. Ollama Cloud is subscription-billed (Free, Pro, Max), so these are equivalent pay-as-you-go estimates, not actual charges. See [ollama.com/pricing](https://ollama.com/pricing) for plan details.
|
|
18
16
|
|
|
19
17
|
## Prerequisites
|
|
20
18
|
|
|
@@ -110,19 +108,7 @@ Example `ollama-cloud.json`:
|
|
|
110
108
|
|
|
111
109
|
The `PI_OLLAMA_WEB_TOOLS` environment variable still works as an override above config files. Set it to `0`, `false`, `no`, or `off` to disable web tools regardless of config file settings.
|
|
112
110
|
|
|
113
|
-
### 4.
|
|
114
|
-
|
|
115
|
-
On first launch the plugin uses a baked-in model list shipped with the extension — no network calls needed. If you want the very latest models, run `/ollama-cloud-refresh` to fetch from the API and cache the result to disk. After that, the disk cache is used on subsequent launches.
|
|
116
|
-
|
|
117
|
-
If the disk cache is older than 30 days, the extension uses it immediately and runs a visible refresh on the next session start (progress appears in the UI widget). You can also run:
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
/ollama-cloud-refresh
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
This fetches the full model list from the Ollama Cloud API and overwrites the local cache.
|
|
124
|
-
|
|
125
|
-
### 5. Select a model
|
|
111
|
+
### 4. Select a model
|
|
126
112
|
|
|
127
113
|
Use `/model` or `Ctrl+L` to switch to an Ollama Cloud model. Models appear under the `ollama-cloud` provider.
|
|
128
114
|
|
|
@@ -135,18 +121,20 @@ The plugin uses two Ollama Cloud API endpoints to build the model list:
|
|
|
135
121
|
|
|
136
122
|
Only models with the `tools` capability are registered - these are the ones Pi can use for tool-calling.
|
|
137
123
|
|
|
138
|
-
The
|
|
124
|
+
The model list refreshes automatically: pi calls the extension's `refreshModels` callback on startup, when `/model` opens, and on `pi update --models`, fetching the live catalog and persisting it through pi's own model store. A model removed from the Ollama Cloud API disappears after the next successful refresh. The baked-in `models.generated.ts` list (regenerated via `npm run generate-models`) is only a first-launch fallback when no persisted catalog exists yet.
|
|
139
125
|
|
|
140
|
-
|
|
126
|
+
The model fetch itself is keyless (the `/v1/models` and `/api/show` endpoints are public), but pi only runs the live refresh when a credential resolves, so a user without a configured API key stays on the baked-in list until they add one. That is a non-issue in practice because a credentialless user cannot run models anyway.
|
|
127
|
+
|
|
128
|
+
Model metadata is derived from the `/api/show` response:
|
|
141
129
|
|
|
142
130
|
| Field | Source |
|
|
143
131
|
|---|---|
|
|
144
132
|
| `reasoning` | `capabilities` includes `"thinking"` |
|
|
145
|
-
| `thinkingLevelMap` | [`thinking-levels.ts`](thinking-levels.ts) with
|
|
133
|
+
| `thinkingLevelMap` | [`thinking-levels.ts`](thinking-levels.ts) with 5 maps (DEFAULT, GPT_OSS, QWEN3, GLM_52, NO_OFF) based on API testing |
|
|
146
134
|
| `input` | `["text", "image"]` if `capabilities` includes `"vision"`, else `["text"]` |
|
|
147
135
|
| `contextWindow` | `model_info.*.context_length` (falls back to 128000) |
|
|
148
136
|
| `maxTokens` | Fixed at 32768 |
|
|
149
|
-
| `cost` |
|
|
137
|
+
| `cost` | Estimated per-1M-token prices from [models.dev](https://models.dev), generated by `scripts/generate-pricing.ts` into `pricing.generated.ts`. Ollama Cloud is subscription-billed, so these are equivalent pay-as-you-go estimates, not actual charges. Unmapped models default to zero. Prices are pinned to the installed package version and only update on a new release, so newly added models register with zero cost until then. |
|
|
150
138
|
|
|
151
139
|
### Thinking level mapping
|
|
152
140
|
|
|
@@ -157,18 +145,11 @@ Pi's thinking levels are mapped to Ollama Cloud's OpenAI-compatible `reasoning_e
|
|
|
157
145
|
| `DEFAULT` | Most thinking models | off, low, medium, high, xhigh | `minimal` hidden (duplicate of low) |
|
|
158
146
|
| `GPT_OSS` | `gpt-oss*` | low, medium, high | Can't disable thinking, no off or xhigh |
|
|
159
147
|
| `QWEN3` | `qwen3*` (except `qwen3-vl*`) | off, medium | Binary-only (think/nothink), no gradation |
|
|
148
|
+
| `GLM_52` | `glm-5.2` | off, high, xhigh | GLM supports disabled thinking; Ollama's model page confirms `high` and `max` reasoning efforts |
|
|
160
149
|
| `NO_OFF` | `qwen3-vl*`, `kimi-k2-thinking`, `minimax*` | low, medium, high, xhigh | "none" doesn't disable thinking on these models |
|
|
161
150
|
|
|
162
151
|
See [docs/think-experiment.md](docs/think-experiment.md) for the testing methodology and results.
|
|
163
152
|
|
|
164
|
-
Refresh from inside Pi:
|
|
165
|
-
|
|
166
|
-
```text
|
|
167
|
-
/ollama-cloud-refresh
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
That command updates `~/.pi/agent/cache/ollama-cloud-models.json` with a new `timestamp` and re-registers the provider live, so no restart is required.
|
|
171
|
-
|
|
172
153
|
## Tools
|
|
173
154
|
|
|
174
155
|
| Tool | Description |
|
|
@@ -182,19 +163,48 @@ Both tools use the same Ollama Cloud API key configured for the provider. No loc
|
|
|
182
163
|
|
|
183
164
|
| Command | Description |
|
|
184
165
|
|---|---|
|
|
185
|
-
| `/ollama-cloud-refresh` | Fetch models from the Ollama Cloud API, update cache, and re-register the provider |
|
|
186
166
|
| `/ollama-webtools [on\|off\|enable\|disable]` | Enable or disable the `ollama_web_search` and `ollama_web_fetch` tools. Toggles if no argument given. |
|
|
187
167
|
|
|
188
168
|
## Development
|
|
189
169
|
|
|
190
170
|
```bash
|
|
191
|
-
npm install # install devDependencies
|
|
192
|
-
npm run check # lint + format
|
|
193
|
-
npm run lint
|
|
194
|
-
npm run
|
|
171
|
+
npm install # install devDependencies
|
|
172
|
+
npm run check # lint + format + type-check (auto-fix)
|
|
173
|
+
npm run lint # lint only (no fixes)
|
|
174
|
+
npm run typecheck # type-check only (tsgo --noEmit)
|
|
175
|
+
npm run format # format only
|
|
195
176
|
```
|
|
196
177
|
|
|
197
|
-
The project uses [Biome](https://biomejs.dev/) for linting and formatting (2-space indent, line width 120).
|
|
178
|
+
The project uses [Biome](https://biomejs.dev/) for linting and formatting (2-space indent, line width 120) and [tsgo](https://github.com/microsoft/typescript-go) for type-checking.
|
|
179
|
+
|
|
180
|
+
### Testing local changes
|
|
181
|
+
|
|
182
|
+
Static checks (no API key needed):
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npm install
|
|
186
|
+
npm run check # lint + format + type-check
|
|
187
|
+
npm run test # unit tests
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Live smoke against the real API (needs an `OLLAMA_API_KEY` or an `ollama-cloud` entry in `auth.json`):
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Run pi with the local extension, no install required. The --no-* flags isolate
|
|
194
|
+
# the run from other installed extensions, skills, prompt templates, themes,
|
|
195
|
+
# context files, and session storage so only the local checkout is exercised.
|
|
196
|
+
pi --no-extensions --no-skills --no-prompt-templates --no-themes --no-context-files --no-session \
|
|
197
|
+
-e ./index.ts --model "ollama-cloud/gemma4:31b" --no-tools -p "Say hi in one word"
|
|
198
|
+
|
|
199
|
+
# Verify thinking is suppressed when off
|
|
200
|
+
pi --no-extensions --no-skills --no-prompt-templates --no-themes --no-context-files --no-session \
|
|
201
|
+
-e ./index.ts --thinking off --model "ollama-cloud/glm-5.2" --no-tools --mode json -p 'hi'
|
|
202
|
+
|
|
203
|
+
# Web tools
|
|
204
|
+
npm run smoke:web-tools
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The `-e`/`--extension` flag loads the extension from the local checkout without installing it; `--no-extensions` disables all other extension discovery so the run cannot pick up an installed `pi-ollama-cloud` or other plugins. The same commands run in CI (`.github/workflows/test.yml`), gated on the `OLLAMA_CLOUD_API_KEY` secret.
|
|
198
208
|
|
|
199
209
|
## How is this different from `ollama launch pi`?
|
|
200
210
|
|
|
@@ -210,7 +220,7 @@ The project uses [Biome](https://biomejs.dev/) for linting and formatting (2-spa
|
|
|
210
220
|
| **Authentication** | Handled by the local server (sign-in flow via `ollama`) | Ollama Cloud API key (set via `OLLAMA_API_KEY` or `auth.json`) |
|
|
211
221
|
| **Model discovery** | Interactive picker with curated recommendations + pulled models | Dynamic - fetches all available cloud models with tool support from the API |
|
|
212
222
|
| **Web tools** | Auto-installed (`@ollama/pi-web-search`) when cloud is enabled | ✅ Built-in: `ollama_web_search` and `ollama_web_fetch` use the [Ollama Cloud web search API](https://docs.ollama.com/capabilities/web-search) directly (same API key, no local server needed) |
|
|
213
|
-
| **Setup effort** | One command: `ollama launch pi` | Install extension + API key
|
|
223
|
+
| **Setup effort** | One command: `ollama launch pi` | Install extension + API key |
|
|
214
224
|
| **Use when** | You're already running Ollama locally and want the default experience | You don't want to run a local server, or want a standalone cloud-only provider alongside your local setup |
|
|
215
225
|
|
|
216
226
|
**You can use both at the same time.** The providers live under different names (`ollama` vs `ollama-cloud`), so you can switch between them with `/model` or `Ctrl+L`. For example, use your local `ollama` provider for low-latency work on smaller models, and `ollama-cloud` for direct access to the full catalog of cloud models without needing a local server.
|
|
@@ -228,6 +238,11 @@ npm version minor # or patch, or major
|
|
|
228
238
|
git push --tags
|
|
229
239
|
```
|
|
230
240
|
|
|
241
|
+
Because the model catalog refreshes automatically at runtime, a release is **not** needed to ship new models. Publish only when:
|
|
242
|
+
|
|
243
|
+
- A model is retired and still listed by the API: add it to `RETIRED_MODEL_IDS` in `scripts/generate-models.ts` (check https://docs.ollama.com/cloud#retirements, then regenerate `models.generated.ts`).
|
|
244
|
+
- Pricing changes: models.dev prices updated, or a new model needs an `OLLAMA_TO_MODELSDEV` mapping line (regenerate `pricing.generated.ts`).
|
|
245
|
+
|
|
231
246
|
The tag version must match the version in `package.json` - `npm version` handles this automatically. The workflow at `.github/workflows/publish.yml` verifies the match before publishing to npm.
|
|
232
247
|
|
|
233
248
|
The workflow uses npm's [trusted publishing](https://docs.npmjs.com/trusted-publishers/) (OIDC) - no tokens stored as secrets. To set it up:
|
|
@@ -239,7 +254,15 @@ The workflow uses npm's [trusted publishing](https://docs.npmjs.com/trusted-publ
|
|
|
239
254
|
|
|
240
255
|
Each publish also gets automatic [provenance attestation](https://docs.npmjs.com/generating-provenance-statements).
|
|
241
256
|
|
|
257
|
+
## Upgrading
|
|
258
|
+
|
|
259
|
+
Since 0.8.0:
|
|
260
|
+
|
|
261
|
+
- The `/ollama-cloud-refresh` command is removed. Models refresh automatically on startup, `/model` open, and `pi update --models`.
|
|
262
|
+
- The old cache file at `~/.pi/agent/cache/ollama-cloud-models.json` is orphaned. Delete it manually: `rm ~/.pi/agent/cache/ollama-cloud-models.json`.
|
|
263
|
+
- Requires a pi version with the native `refreshModels` API (pi 0.84.0+).
|
|
264
|
+
|
|
242
265
|
## Notes
|
|
243
266
|
|
|
244
|
-
- The fetch timeout is 10 seconds per request. On slow connections, some model detail fetches may time out
|
|
267
|
+
- The fetch timeout is 10 seconds per request. On slow connections, some model detail fetches may time out; the refresh uses whatever succeeded and only fails if every model detail fetch fails.
|
|
245
268
|
- `deepseek-v4` occasionally emits raw `<|DSML|tool_calls|>` markup as plain text instead of structured tool calls, then stops. This is DeepSeek's native tool-call format leaking through Ollama Cloud's OpenAI-compatible endpoint, so it looks like an upstream Ollama issue rather than something this extension can fix. If you hit it, retry or switch models.
|
package/index.ts
CHANGED
|
@@ -1,145 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ollama Cloud Provider Extension
|
|
3
3
|
*
|
|
4
|
-
* Registers Ollama Cloud as a model provider with
|
|
4
|
+
* Registers Ollama Cloud as a model provider with a baked-in fallback catalog
|
|
5
|
+
* and a native `refreshModels` callback that overlays live API updates.
|
|
5
6
|
*
|
|
6
7
|
* Setup:
|
|
7
8
|
* 1. Get an API key from https://ollama.com
|
|
8
9
|
* 2. Add to auth.json in the agent config dir (~/.pi/agent/auth.json, or set PI_CODING_AGENT_DIR):
|
|
9
10
|
* { "ollama-cloud": { "type": "api_key", "key": "your-key" } }
|
|
10
|
-
* 3.
|
|
11
|
-
* 4. Use /model or ctrl+l to select an Ollama Cloud model
|
|
11
|
+
* 3. Use /model or ctrl+l to select an Ollama Cloud model
|
|
12
12
|
*
|
|
13
13
|
* Two endpoints are used to build the model list:
|
|
14
14
|
* - GET https://ollama.com/v1/models -> list of model IDs
|
|
15
15
|
* - POST https://ollama.com/api/show -> per-model details (capabilities, context length)
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* - Stale cache (>30 days): uses the cached data immediately and triggers a visible refresh
|
|
24
|
-
* on session_start that shows progress in the UI widget.
|
|
25
|
-
* - Fresh cache: uses cached data directly, no refresh triggered.
|
|
17
|
+
* Catalog behavior:
|
|
18
|
+
* - The baked-in GENERATED_MODELS list (via `npm run generate-models`) is the
|
|
19
|
+
* first-launch fallback when no persisted catalog exists.
|
|
20
|
+
* - On startup, /model open, and `pi update --models`, pi calls the
|
|
21
|
+
* `refreshModels` callback, which fetches the live catalog and persists it
|
|
22
|
+
* through pi's own FileModelsStore. Refresh is automatic.
|
|
26
23
|
*
|
|
27
24
|
* Only models with "tools" capability are registered.
|
|
28
25
|
*/
|
|
29
26
|
|
|
30
|
-
import type { ExtensionAPI
|
|
27
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
31
28
|
import { loadConfig, resolveWebToolsEnv } from "./config.ts";
|
|
32
29
|
import { GENERATED_MODELS } from "./models.generated.ts";
|
|
33
|
-
import {
|
|
34
|
-
assembleModels,
|
|
35
|
-
fetchModels,
|
|
36
|
-
OLLAMA_BASE,
|
|
37
|
-
type RefreshProgress,
|
|
38
|
-
readCacheState,
|
|
39
|
-
writeCache,
|
|
40
|
-
} from "./models.ts";
|
|
30
|
+
import { OLLAMA_BASE, refreshOllamaCatalog } from "./models.ts";
|
|
41
31
|
import { registerWebFetchTool, registerWebSearchTool } from "./web-tools.ts";
|
|
42
32
|
|
|
43
|
-
// ---
|
|
33
|
+
// --- Main ---
|
|
44
34
|
|
|
45
|
-
function
|
|
35
|
+
export default async function (pi: ExtensionAPI) {
|
|
46
36
|
pi.registerProvider("ollama-cloud", {
|
|
47
37
|
name: "Ollama Cloud",
|
|
48
38
|
baseUrl: `${OLLAMA_BASE}/v1`,
|
|
49
39
|
apiKey: "$OLLAMA_API_KEY",
|
|
50
40
|
api: "openai-completions",
|
|
51
|
-
models,
|
|
41
|
+
models: GENERATED_MODELS,
|
|
42
|
+
refreshModels: refreshOllamaCatalog,
|
|
52
43
|
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function renderProgressBar(current: number, total: number, width = 15): string {
|
|
56
|
-
if (total <= 0) return `[${"░".repeat(width)}]`;
|
|
57
|
-
const ratio = Math.max(0, Math.min(1, current / total));
|
|
58
|
-
const filled = Math.round(ratio * width);
|
|
59
|
-
return `[${"█".repeat(filled)}${"░".repeat(width - filled)}]`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function createRefreshProgressUi(ctx: Pick<ExtensionCommandContext, "ui">) {
|
|
63
|
-
const key = "ollama-cloud-refresh";
|
|
64
|
-
return {
|
|
65
|
-
update(progress: RefreshProgress) {
|
|
66
|
-
const current = progress.current ?? 0;
|
|
67
|
-
const total = progress.total ?? 0;
|
|
68
|
-
const percent = total > 0 ? Math.round((current / total) * 100) : 0;
|
|
69
|
-
const failed = progress.failed ? `, ${progress.failed} failed` : "";
|
|
70
|
-
const stage =
|
|
71
|
-
progress.stage === "list"
|
|
72
|
-
? "Discovering models"
|
|
73
|
-
: progress.stage === "details"
|
|
74
|
-
? "Fetching model details"
|
|
75
|
-
: "Done";
|
|
76
|
-
const summary = total > 0 ? `${current}/${total} (${percent}%${failed})` : progress.message;
|
|
77
|
-
const line = `☁ Ollama Cloud - ${stage} — ${summary} ${renderProgressBar(current, total)}`;
|
|
78
|
-
|
|
79
|
-
ctx.ui.setWorkingMessage(`Refreshing Ollama Cloud models - ${stage.toLowerCase()}`);
|
|
80
|
-
ctx.ui.setWidget(key, [line], { placement: "belowEditor" });
|
|
81
|
-
},
|
|
82
|
-
clear() {
|
|
83
|
-
ctx.ui.setWidget(key, undefined);
|
|
84
|
-
ctx.ui.setStatus(key, undefined);
|
|
85
|
-
ctx.ui.setWorkingMessage();
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function runRefresh(pi: ExtensionAPI, ctx: Pick<ExtensionCommandContext, "ui">) {
|
|
91
|
-
const progressUi = createRefreshProgressUi(ctx);
|
|
92
|
-
try {
|
|
93
|
-
progressUi.update({ stage: "list", message: "Starting refresh..." });
|
|
94
|
-
|
|
95
|
-
const raw = await fetchModels(ctx, (progress) => progressUi.update(progress));
|
|
96
|
-
if (!raw) return false;
|
|
97
|
-
|
|
98
|
-
writeCache(raw);
|
|
99
|
-
const newModels = assembleModels(raw);
|
|
100
|
-
|
|
101
|
-
registerProvider(pi, newModels);
|
|
102
|
-
|
|
103
|
-
ctx.ui.notify(`Registered ${newModels.length} Ollama Cloud models`, "info");
|
|
104
|
-
return true;
|
|
105
|
-
} finally {
|
|
106
|
-
progressUi.clear();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function registerRefreshCommand(pi: ExtensionAPI) {
|
|
111
|
-
pi.registerCommand("ollama-cloud-refresh", {
|
|
112
|
-
description: "Refresh Ollama Cloud models from the API",
|
|
113
|
-
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
|
114
|
-
await runRefresh(pi, ctx);
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// --- Main ---
|
|
120
|
-
|
|
121
|
-
export default async function (pi: ExtensionAPI) {
|
|
122
|
-
const cacheState = readCacheState();
|
|
123
|
-
// Auto-refresh only when the disk cache is stale (>30 days).
|
|
124
|
-
// When cache is missing, GENERATED_MODELS serves as the cache —
|
|
125
|
-
// it is manually generated via `npm run generate-models` and committed to the repo.
|
|
126
|
-
const needsStartupRefresh = cacheState.status === "stale";
|
|
127
|
-
// GENERATED_MODELS ships with the package (36 tool-capable models from
|
|
128
|
-
// the build script). Used when no local cache exists. A fresh user cache
|
|
129
|
-
// from /ollama-cloud-refresh takes precedence over the generated list.
|
|
130
|
-
const models = cacheState.status === "missing" ? GENERATED_MODELS : assembleModels(cacheState.models);
|
|
131
|
-
|
|
132
|
-
registerProvider(pi, models);
|
|
133
|
-
registerRefreshCommand(pi);
|
|
134
|
-
|
|
135
|
-
if (needsStartupRefresh) {
|
|
136
|
-
let started = false;
|
|
137
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
138
|
-
if (started) return;
|
|
139
|
-
started = true;
|
|
140
|
-
await runRefresh(pi, ctx);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
44
|
|
|
144
45
|
// --- Web Tools Management ---
|
|
145
46
|
|