pi-io-provider 1.1.57 → 1.1.59
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/AGENTS.md +1 -0
- package/CHANGELOG.md +7 -0
- package/README.md +36 -20
- package/index.ts +34 -12
- package/models.json +60 -60
- package/package.json +13 -11
- package/scripts/update-models.js +16 -0
- package/sync-policy.ts +309 -0
- package/tests/quiet-startup-sync.test.ts +265 -0
- package/tests/sync-policy.test.ts +259 -0
- package/vitest.config.ts +10 -0
- package/bun.lock +0 -319
package/AGENTS.md
CHANGED
|
@@ -19,6 +19,7 @@ When a model needs overrides, new properties, or corrections, edit the appropria
|
|
|
19
19
|
| `patch.json` | Per-model overrides keyed by model ID. Add reasoning flags, compat settings, pricing corrections, thinking level maps, etc. Applied on top of `models.json` at runtime and for README generation. |
|
|
20
20
|
| `custom-models.json` | Models that don't exist in the provider API (hidden models, router endpoints, cross-provider aliases). Merged after patch. Format: array of full model objects (same schema as `models.json` entries). |
|
|
21
21
|
| `index.ts` | Provider extension code. |
|
|
22
|
+
| `sync-policy.ts` | Quiet startup sync policy (TTL, key fingerprint, cross-process lock). Provider-agnostic and shared verbatim across pi-*-provider repos — keep it free of provider specifics. |
|
|
22
23
|
| `scripts/update-models.js` | The sync script itself (edit only if changing how models are fetched/transformed). |
|
|
23
24
|
|
|
24
25
|
## Data Flow
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.59
|
|
4
|
+
|
|
5
|
+
- Quiet startup sync: background `/api/v1/models` revalidation runs only with an API key, only when the disk cache is older than 1 hour (`PI_PROVIDER_SYNC_TTL_MS`, `0` = always), missing, or fetched with a different key, and only in one pi process at a time (lock file next to the cache). Failed refreshes back off for 5 minutes; sessions that skip adopt a cache refreshed by another process.
|
|
6
|
+
- Never store the API key: key changes are detected via a salted sha256 fingerprint in `cache/io-intelligence-models.sync.json`. The cache file format is unchanged.
|
|
7
|
+
- Write the model cache atomically and swallow API key resolution failures in `session_start`.
|
|
8
|
+
- Add vitest coverage for the sync policy and the session_start integration.
|
|
9
|
+
|
|
3
10
|
## 1.1.48
|
|
4
11
|
|
|
5
12
|
- Pin Pi SDK development dependencies to 1.0.0 while retaining wildcard host peers.
|
package/README.md
CHANGED
|
@@ -11,50 +11,51 @@ A [pi](https://github.com/badlogic/pi-mono) extension that adds [IO Intelligence
|
|
|
11
11
|
- **Prompt caching** — Cache read/write support on most models
|
|
12
12
|
- **Confidential inference** — Verifiable TEE inference with attestation (via /private/ endpoints)
|
|
13
13
|
- **Streaming** — Real-time token streaming
|
|
14
|
+
- **Quiet live model sync** — Models refresh from the IO Intelligence API in the background, at most hourly and by one pi process at a time ([details](#model-sync))
|
|
14
15
|
|
|
15
16
|
## Available Models
|
|
16
17
|
|
|
17
18
|
| Model | ID | Context | Max Output | Vision | Reasoning | Cache | Input $/M | Output $/M |
|
|
18
19
|
|-------|----|---------|------------|--------|-----------|-------|-----------|------------|
|
|
19
|
-
| DeepSeek V4.1 Flash | `deepseek-ai/DeepSeek-V4.1-Flash` | 1.0M | 131K | ✅ | ✅ | ✅ | $0.
|
|
20
|
-
| Gemma 4 26B A4B | `google/gemma-4-26b-a4b-it` | 262K | 262K | ✅ | ✅ | ✅ | $0.09 | $0.
|
|
20
|
+
| DeepSeek V4.1 Flash | `deepseek-ai/DeepSeek-V4.1-Flash` | 1.0M | 131K | ✅ | ✅ | ✅ | $0.31 | $1.26 |
|
|
21
|
+
| Gemma 4 26B A4B | `google/gemma-4-26b-a4b-it` | 262K | 262K | ✅ | ✅ | ✅ | $0.09 | $0.32 |
|
|
21
22
|
| Gemma 4 31B Instruct | `google/gemma-4-31b-it` | 262K | 16K | ✅ | ✅ | ✅ | $0.38 | $1.15 |
|
|
22
23
|
| Kimi K2.5 | `moonshotai/Kimi-K2.5` | 262K | 262K | ✅ | ✅ | ✅ | $0.53 | $2.79 |
|
|
23
|
-
| Kimi K2.6 | `moonshotai/Kimi-K2.6` | 262K | 262K | ✅ | ✅ | ✅ | $0.
|
|
24
|
-
| Kimi K2.7 Code | `moonshotai/Kimi-K2.7-Code` | 262K | 262K | ✅ | ✅ | ✅ | $1.
|
|
24
|
+
| Kimi K2.6 | `moonshotai/Kimi-K2.6` | 262K | 262K | ✅ | ✅ | ✅ | $0.85 | $3.78 |
|
|
25
|
+
| Kimi K2.7 Code | `moonshotai/Kimi-K2.7-Code` | 262K | 262K | ✅ | ✅ | ✅ | $1.03 | $4.54 |
|
|
25
26
|
| Kimi K3 | `moonshotai/Kimi-K3` | 1.0M | 1.0M | ✅ | ✅ | ✅ | $3.66 | $17.80 |
|
|
26
|
-
| Qwen3.6 27B | `Qwen/Qwen3.6-27B` | 33K | 33K | ✅ | ✅ | ✅ | $0.34 | $
|
|
27
|
-
| Qwen3.6 35B A3B | `Qwen/Qwen3.6-35B-A3B` | 262K | 262K | ✅ | ✅ | ✅ | $0.
|
|
28
|
-
| Qwen3.8 27B | `Qwen/Qwen3.8-27B` | 66K | 66K | ✅ | ✅ | ✅ | $0.
|
|
27
|
+
| Qwen3.6 27B | `Qwen/Qwen3.6-27B` | 33K | 33K | ✅ | ✅ | ✅ | $0.34 | $2.87 |
|
|
28
|
+
| Qwen3.6 35B A3B | `Qwen/Qwen3.6-35B-A3B` | 262K | 262K | ✅ | ✅ | ✅ | $0.16 | $1.04 |
|
|
29
|
+
| Qwen3.8 27B | `Qwen/Qwen3.8-27B` | 66K | 66K | ✅ | ✅ | ✅ | $0.54 | $3.19 |
|
|
29
30
|
| MiMo-V2.6-Flash | `XiaomiMiMo/MiMo-V2.6-Flash` | 1.0M | 131K | ✅ | ✅ | ✅ | $0.14 | $0.29 |
|
|
30
31
|
| GLM 5.3 Flash | `zai-org/GLM-5.3-Flash` | 262K | 131K | ✅ | ✅ | ✅ | $0.17 | $0.57 |
|
|
31
32
|
| DeepSeek R1 0528 | `deepseek-ai/DeepSeek-R1-0528` | 128K | 128K | ❌ | ✅ | ✅ | $0.57 | $2.28 |
|
|
32
33
|
| DeepSeek V3.2 | `deepseek-ai/DeepSeek-V3.2` | 164K | 164K | ❌ | ✅ | ✅ | $1.38 | $2.18 |
|
|
33
34
|
| DeepSeek V4 Flash | `deepseek-ai/DeepSeek-V4-Flash` | 33K | 33K | ❌ | ✅ | ✅ | $0.19 | $0.74 |
|
|
34
35
|
| DeepSeek V4 Flash 0731 | `deepseek-ai/DeepSeek-V4-Flash-0731` | 262K | 66K | ❌ | ✅ | ✅ | $0.19 | $0.48 |
|
|
35
|
-
| DeepSeek V4 Pro | `deepseek-ai/DeepSeek-V4-Pro` | 1.0M | 600K | ❌ | ✅ | ✅ | $1.
|
|
36
|
+
| DeepSeek V4 Pro | `deepseek-ai/DeepSeek-V4-Pro` | 1.0M | 600K | ❌ | ✅ | ✅ | $1.25 | $4.91 |
|
|
36
37
|
| DeepSeek V4 Pro 0813 | `deepseek-ai/DeepSeek-V4-Pro-0813` | 1.0M | 393K | ❌ | ✅ | ✅ | $1.13 | $3.97 |
|
|
37
|
-
| MiniMax M2.5 | `MiniMaxAI/MiniMax-M2.5` | 197K | 197K | ❌ | ✅ | ✅ | $0.
|
|
38
|
-
| MiniMax M2.7 | `MiniMaxAI/MiniMax-M2.7` | 262K | 66K | ❌ | ✅ | ✅ | $0.40 | $1.
|
|
38
|
+
| MiniMax M2.5 | `MiniMaxAI/MiniMax-M2.5` | 197K | 197K | ❌ | ✅ | ✅ | $0.36 | $1.44 |
|
|
39
|
+
| MiniMax M2.7 | `MiniMaxAI/MiniMax-M2.7` | 262K | 66K | ❌ | ✅ | ✅ | $0.40 | $1.49 |
|
|
39
40
|
| Kimi K2 Thinking | `moonshotai/Kimi-K2-Thinking` | 262K | 262K | ❌ | ✅ | ✅ | $0.60 | $2.50 |
|
|
40
|
-
| Nemotron 3.5 Lightning | `nvidia/nemotron-3.5-lightning` | 262K | 131K | ❌ | ✅ | ✅ | $0.06 | $0.
|
|
41
|
-
| gpt-oss-120b | `openai/gpt-oss-120b` | 131K | 131K | ❌ | ✅ | ✅ | $0.
|
|
42
|
-
| gpt-oss-20b | `openai/gpt-oss-20b` | 64K | 64K | ❌ | ✅ | ✅ | $0.06 | $0.
|
|
41
|
+
| Nemotron 3.5 Lightning | `nvidia/nemotron-3.5-lightning` | 262K | 131K | ❌ | ✅ | ✅ | $0.06 | $0.19 |
|
|
42
|
+
| gpt-oss-120b | `openai/gpt-oss-120b` | 131K | 131K | ❌ | ✅ | ✅ | $0.18 | $0.68 |
|
|
43
|
+
| gpt-oss-20b | `openai/gpt-oss-20b` | 64K | 64K | ❌ | ✅ | ✅ | $0.06 | $0.19 |
|
|
43
44
|
| MiMo-V2.5 | `XiaomiMiMo/MiMo-V2.5` | 1.0M | 1.0M | ❌ | ✅ | ✅ | $0.20 | $0.64 |
|
|
44
45
|
| GLM-4.5-Air | `zai-org/GLM-4.5-Air` | 131K | 131K | ❌ | ✅ | ✅ | $0.16 | $0.94 |
|
|
45
46
|
| GLM 4.6 | `zai-org/GLM-4.6` | 131K | 131K | ❌ | ✅ | ✅ | $0.52 | $2.04 |
|
|
46
47
|
| GLM 4.7 | `zai-org/GLM-4.7` | 203K | 203K | ❌ | ✅ | ✅ | $0.53 | $2.07 |
|
|
47
48
|
| GLM 4.7 Flash | `zai-org/GLM-4.7-Flash` | 200K | 200K | ❌ | ✅ | ✅ | $0.06 | $0.40 |
|
|
48
|
-
| GLM 5 | `zai-org/GLM-5` | 203K | 203K | ❌ | ✅ | ✅ | $0.
|
|
49
|
-
| GLM 5.1 | `zai-org/GLM-5.1` | 203K | 33K | ❌ | ✅ | ✅ | $1.
|
|
50
|
-
| GLM 5.2 | `zai-org/GLM-5.2` | 262K | 131K | ❌ | ✅ | ✅ | $1.
|
|
51
|
-
| GLM 5.3 | `zai-org/GLM-5.3` | 262K | 131K | ❌ | ✅ | ✅ | $1.
|
|
49
|
+
| GLM 5 | `zai-org/GLM-5` | 203K | 203K | ❌ | ✅ | ✅ | $0.86 | $2.75 |
|
|
50
|
+
| GLM 5.1 | `zai-org/GLM-5.1` | 203K | 33K | ❌ | ✅ | ✅ | $1.39 | $4.36 |
|
|
51
|
+
| GLM 5.2 | `zai-org/GLM-5.2` | 262K | 131K | ❌ | ✅ | ✅ | $1.95 | $6.40 |
|
|
52
|
+
| GLM 5.3 | `zai-org/GLM-5.3` | 262K | 131K | ❌ | ✅ | ✅ | $1.33 | $4.73 |
|
|
52
53
|
| Llama 4 Maverick 17B 128E Instruct FP8 | `meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8` | 430K | 430K | ✅ | ❌ | ✅ | $0.27 | $0.83 |
|
|
53
|
-
| Qwen3 Coder 480B A35B Instruct INT4 Mixed AR | `Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar` | 106K | 106K | ❌ | ❌ | ✅ | $0.
|
|
54
|
-
| Llama 3.3 70B Instruct | `meta-llama/Llama-3.3-70B-Instruct` | 128K | 128K | ❌ | ❌ | ✅ | $0.
|
|
54
|
+
| Qwen3 Coder 480B A35B Instruct INT4 Mixed AR | `Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar` | 106K | 106K | ❌ | ❌ | ✅ | $0.46 | $2.29 |
|
|
55
|
+
| Llama 3.3 70B Instruct | `meta-llama/Llama-3.3-70B-Instruct` | 128K | 128K | ❌ | ❌ | ✅ | $0.55 | $1.02 |
|
|
55
56
|
| Mistral Nemo Instruct 2407 | `mistralai/Mistral-Nemo-Instruct-2407` | 128K | 128K | ❌ | ❌ | ✅ | $0.05 | $0.08 |
|
|
56
57
|
| Kimi K2 Instruct 0905 | `moonshotai/Kimi-K2-Instruct-0905` | 262K | 262K | ❌ | ❌ | ✅ | $0.57 | $2.30 |
|
|
57
|
-
| Qwen3 Next 80B A3B Instruct | `Qwen/Qwen3-Next-80B-A3B-Instruct` | 262K | 262K | ❌ | ❌ | ✅ | $0.
|
|
58
|
+
| Qwen3 Next 80B A3B Instruct | `Qwen/Qwen3-Next-80B-A3B-Instruct` | 262K | 262K | ❌ | ❌ | ✅ | $0.11 | $1.04 |
|
|
58
59
|
|
|
59
60
|
*Costs are per million tokens. Cache read/write pricing available on most models.*
|
|
60
61
|
|
|
@@ -122,6 +123,7 @@ Get your API key from [io.net](https://io.net).
|
|
|
122
123
|
| Variable | Required | Description |
|
|
123
124
|
|----------|----------|-------------|
|
|
124
125
|
| `IOINTELLIGENCE_API_KEY` | No | Your IO Intelligence API key (fallback if not in auth.json) |
|
|
126
|
+
| `PI_PROVIDER_SYNC_TTL_MS` | No | Model sync freshness window in ms (default `3600000`; `0` = revalidate every session start) |
|
|
125
127
|
|
|
126
128
|
## Configuration
|
|
127
129
|
|
|
@@ -145,6 +147,20 @@ Once loaded, select a model with:
|
|
|
145
147
|
|
|
146
148
|
Or use `/models` to browse all available IO Intelligence models.
|
|
147
149
|
|
|
150
|
+
## Model sync
|
|
151
|
+
|
|
152
|
+
Startup never waits on the network. pi starts with the cached catalog (`~/.pi/agent/cache/io-intelligence-models.json`,
|
|
153
|
+
falling back to the bundled `models.json`) and revalidates against `/api/v1/models` in the background — only when:
|
|
154
|
+
|
|
155
|
+
- an IO Intelligence API key is configured (no key, no request),
|
|
156
|
+
- the cache is older than 1 hour, missing, or was fetched with a different API key, and
|
|
157
|
+
- no other pi process is already refreshing it (an `io-intelligence-models.lock` file next to the cache).
|
|
158
|
+
|
|
159
|
+
So `/new`, `/reload`, `pi -p` and fan-out child agents share one cache instead of each calling the API; a
|
|
160
|
+
session that skips the fetch still picks up a cache another process refreshed. A failed refresh is retried after
|
|
161
|
+
5 minutes at the earliest. `PI_PROVIDER_SYNC_TTL_MS` changes the window (`0` revalidates on every session start).
|
|
162
|
+
Only a hash fingerprint of the key is stored (`io-intelligence-models.sync.json`), never the key itself.
|
|
163
|
+
|
|
148
164
|
## API Documentation
|
|
149
165
|
|
|
150
166
|
- IO Intelligence Docs: https://io.net/docs/guides/confidential-inference/quick-start
|
package/index.ts
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* Model resolution strategy: Stale-While-Revalidate
|
|
8
8
|
* 1. Serve stale immediately: disk cache → embedded models.json (zero-latency)
|
|
9
9
|
* 2. Revalidate in background: live API /models → merge with embedded → cache → hot-swap
|
|
10
|
+
* Quiet startup sync (sync-policy.ts): only with an API key, only when the
|
|
11
|
+
* disk cache is older than the TTL (1h, PI_PROVIDER_SYNC_TTL_MS) or the key
|
|
12
|
+
* changed, and only one pi process at a time (lock file next to the cache).
|
|
10
13
|
* 3. patch.json + custom-models.json applied on top of whichever source won
|
|
11
14
|
*
|
|
12
15
|
* Merge order: [live|cache|embedded] → apply patch.json → merge custom-models.json
|
|
@@ -43,6 +46,7 @@ import patchData from "./patch.json" with { type: "json" };
|
|
|
43
46
|
import deprecatedData from "./deprecated-models.json" with { type: "json" };
|
|
44
47
|
import fs from "fs";
|
|
45
48
|
import path from "path";
|
|
49
|
+
import { acquireModelSync, cacheChangedSinceLoad, markCacheLoaded, writeFileAtomic } from "./sync-policy";
|
|
46
50
|
|
|
47
51
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
48
52
|
|
|
@@ -227,7 +231,8 @@ function loadCachedModels(): JsonModel[] | null {
|
|
|
227
231
|
function cacheModels(models: JsonModel[]): void {
|
|
228
232
|
try {
|
|
229
233
|
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
230
|
-
|
|
234
|
+
// Atomic (tmp + rename): other pi processes may be reading the cache right now.
|
|
235
|
+
writeFileAtomic(CACHE_PATH, JSON.stringify(models, null, 2) + "\n");
|
|
231
236
|
} catch {
|
|
232
237
|
// Cache write failure is non-fatal
|
|
233
238
|
}
|
|
@@ -300,6 +305,7 @@ function withDeprecated(models: JsonModel[]): JsonModel[] {
|
|
|
300
305
|
}
|
|
301
306
|
|
|
302
307
|
function loadStaleModels(embeddedModels: JsonModel[]): JsonModel[] {
|
|
308
|
+
markCacheLoaded(CACHE_PATH); // stat before read: lets session_start spot newer caches
|
|
303
309
|
const cached = loadCachedModels();
|
|
304
310
|
if (!cached || cached.length === 0) return embeddedModels;
|
|
305
311
|
|
|
@@ -313,13 +319,26 @@ function loadStaleModels(embeddedModels: JsonModel[]): JsonModel[] {
|
|
|
313
319
|
return cached;
|
|
314
320
|
}
|
|
315
321
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Background revalidation, gated by the quiet startup sync policy
|
|
324
|
+
* (sync-policy.ts): no key → no fetch; fresh cache (TTL) → no fetch; another
|
|
325
|
+
* process already fetching → no fetch. When skipped, a cache that another
|
|
326
|
+
* process refreshed since we loaded it is adopted from disk instead.
|
|
327
|
+
* `force` bypasses the TTL (e.g. after /login); it is still single-flight.
|
|
328
|
+
*/
|
|
329
|
+
async function revalidateModels(apiKey: string | undefined, embeddedModels: JsonModel[], signal?: AbortSignal, force = false): Promise<JsonModel[] | null> {
|
|
330
|
+
const lease = acquireModelSync({ cachePath: CACHE_PATH, apiKey, force });
|
|
331
|
+
if (!lease) return cacheChangedSinceLoad(CACHE_PATH) ? loadStaleModels(embeddedModels) : null;
|
|
332
|
+
let merged: JsonModel[] | null = null;
|
|
333
|
+
try {
|
|
334
|
+
const liveModels = apiKey ? await fetchLiveModels(apiKey, signal) : null;
|
|
335
|
+
if (!liveModels || liveModels.length === 0) return null;
|
|
336
|
+
merged = mergeWithEmbedded(liveModels, embeddedModels);
|
|
337
|
+
cacheModels(merged);
|
|
338
|
+
return merged;
|
|
339
|
+
} finally {
|
|
340
|
+
lease.release(merged ? "fetched" : signal?.aborted ? "aborted" : "failed");
|
|
341
|
+
}
|
|
323
342
|
}
|
|
324
343
|
|
|
325
344
|
// ─── API Key Resolution (via ModelRegistry) ────────────────────────────────────
|
|
@@ -348,12 +367,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
348
367
|
models: staleModels,
|
|
349
368
|
});
|
|
350
369
|
|
|
370
|
+
// Fire-and-forget: never await network here — startup must not block on the
|
|
371
|
+
// provider API. Nothing is awaited and every rejection is swallowed.
|
|
351
372
|
pi.on("session_start", async (_event, ctx) => {
|
|
352
373
|
revalidateAbort?.abort();
|
|
353
374
|
revalidateAbort = new AbortController();
|
|
354
375
|
const signal = revalidateAbort.signal;
|
|
355
|
-
resolveApiKey(ctx.modelRegistry)
|
|
356
|
-
revalidateModels(cachedApiKey, embeddedModels, signal)
|
|
376
|
+
void resolveApiKey(ctx.modelRegistry)
|
|
377
|
+
.then(() => revalidateModels(cachedApiKey, embeddedModels, signal))
|
|
378
|
+
.then((freshBase) => {
|
|
357
379
|
if (freshBase && !signal.aborted) {
|
|
358
380
|
pi.registerProvider("io-intelligence", {
|
|
359
381
|
baseUrl: BASE_URL,
|
|
@@ -362,8 +384,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
362
384
|
models: buildModels(freshBase, customModels, patches),
|
|
363
385
|
});
|
|
364
386
|
}
|
|
365
|
-
})
|
|
366
|
-
|
|
387
|
+
})
|
|
388
|
+
.catch(() => { /* keep serving the stale catalog */ });
|
|
367
389
|
});
|
|
368
390
|
|
|
369
391
|
pi.on("session_shutdown", () => {
|
package/models.json
CHANGED
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"image"
|
|
32
32
|
],
|
|
33
33
|
"cost": {
|
|
34
|
-
"input": 0.
|
|
35
|
-
"output": 1.
|
|
36
|
-
"cacheRead": 0.
|
|
34
|
+
"input": 0.313,
|
|
35
|
+
"output": 1.26,
|
|
36
|
+
"cacheRead": 0.1565,
|
|
37
37
|
"cacheWrite": 0
|
|
38
38
|
},
|
|
39
39
|
"contextWindow": 1048320,
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"text"
|
|
77
77
|
],
|
|
78
78
|
"cost": {
|
|
79
|
-
"input": 1.
|
|
80
|
-
"output": 4.
|
|
81
|
-
"cacheRead": 0.
|
|
79
|
+
"input": 1.32848,
|
|
80
|
+
"output": 4.72954,
|
|
81
|
+
"cacheRead": 0.66424,
|
|
82
82
|
"cacheWrite": 0
|
|
83
83
|
},
|
|
84
84
|
"contextWindow": 262144,
|
|
@@ -99,9 +99,9 @@
|
|
|
99
99
|
"image"
|
|
100
100
|
],
|
|
101
101
|
"cost": {
|
|
102
|
-
"input": 0.
|
|
103
|
-
"output": 3.
|
|
104
|
-
"cacheRead": 0.
|
|
102
|
+
"input": 0.5378,
|
|
103
|
+
"output": 3.188,
|
|
104
|
+
"cacheRead": 0.2689,
|
|
105
105
|
"cacheWrite": 0
|
|
106
106
|
},
|
|
107
107
|
"contextWindow": 65536,
|
|
@@ -188,9 +188,9 @@
|
|
|
188
188
|
"text"
|
|
189
189
|
],
|
|
190
190
|
"cost": {
|
|
191
|
-
"input": 1.
|
|
192
|
-
"output":
|
|
193
|
-
"cacheRead": 0.
|
|
191
|
+
"input": 1.95,
|
|
192
|
+
"output": 6.4,
|
|
193
|
+
"cacheRead": 0.975,
|
|
194
194
|
"cacheWrite": 0
|
|
195
195
|
},
|
|
196
196
|
"contextWindow": 262144,
|
|
@@ -211,9 +211,9 @@
|
|
|
211
211
|
"image"
|
|
212
212
|
],
|
|
213
213
|
"cost": {
|
|
214
|
-
"input": 1.
|
|
215
|
-
"output": 4.
|
|
216
|
-
"cacheRead": 0.
|
|
214
|
+
"input": 1.02864,
|
|
215
|
+
"output": 4.538,
|
|
216
|
+
"cacheRead": 0.51432,
|
|
217
217
|
"cacheWrite": 0
|
|
218
218
|
},
|
|
219
219
|
"contextWindow": 262144,
|
|
@@ -234,9 +234,9 @@
|
|
|
234
234
|
"image"
|
|
235
235
|
],
|
|
236
236
|
"cost": {
|
|
237
|
-
"input": 0.
|
|
238
|
-
"output": 1.
|
|
239
|
-
"cacheRead": 0.
|
|
237
|
+
"input": 0.1572,
|
|
238
|
+
"output": 1.04275,
|
|
239
|
+
"cacheRead": 0.0786,
|
|
240
240
|
"cacheWrite": 0
|
|
241
241
|
},
|
|
242
242
|
"contextWindow": 262144,
|
|
@@ -257,9 +257,9 @@
|
|
|
257
257
|
"image"
|
|
258
258
|
],
|
|
259
259
|
"cost": {
|
|
260
|
-
"input": 0.
|
|
261
|
-
"output":
|
|
262
|
-
"cacheRead": 0.
|
|
260
|
+
"input": 0.341,
|
|
261
|
+
"output": 2.87,
|
|
262
|
+
"cacheRead": 0.1705,
|
|
263
263
|
"cacheWrite": 0
|
|
264
264
|
},
|
|
265
265
|
"contextWindow": 32768,
|
|
@@ -279,9 +279,9 @@
|
|
|
279
279
|
"text"
|
|
280
280
|
],
|
|
281
281
|
"cost": {
|
|
282
|
-
"input": 0.
|
|
283
|
-
"output": 1.
|
|
284
|
-
"cacheRead": 0.
|
|
282
|
+
"input": 0.402,
|
|
283
|
+
"output": 1.488,
|
|
284
|
+
"cacheRead": 0.201,
|
|
285
285
|
"cacheWrite": 0
|
|
286
286
|
},
|
|
287
287
|
"contextWindow": 262100,
|
|
@@ -323,9 +323,9 @@
|
|
|
323
323
|
"text"
|
|
324
324
|
],
|
|
325
325
|
"cost": {
|
|
326
|
-
"input": 1.
|
|
327
|
-
"output": 4.
|
|
328
|
-
"cacheRead": 0.
|
|
326
|
+
"input": 1.25206,
|
|
327
|
+
"output": 4.9124,
|
|
328
|
+
"cacheRead": 0.62603,
|
|
329
329
|
"cacheWrite": 0
|
|
330
330
|
},
|
|
331
331
|
"contextWindow": 1048576,
|
|
@@ -346,9 +346,9 @@
|
|
|
346
346
|
"image"
|
|
347
347
|
],
|
|
348
348
|
"cost": {
|
|
349
|
-
"input": 0.
|
|
350
|
-
"output": 3.
|
|
351
|
-
"cacheRead": 0.
|
|
349
|
+
"input": 0.85,
|
|
350
|
+
"output": 3.782,
|
|
351
|
+
"cacheRead": 0.425,
|
|
352
352
|
"cacheWrite": 0
|
|
353
353
|
},
|
|
354
354
|
"contextWindow": 262142,
|
|
@@ -368,9 +368,9 @@
|
|
|
368
368
|
"text"
|
|
369
369
|
],
|
|
370
370
|
"cost": {
|
|
371
|
-
"input": 1.
|
|
372
|
-
"output": 4.
|
|
373
|
-
"cacheRead": 0.
|
|
371
|
+
"input": 1.38628,
|
|
372
|
+
"output": 4.35688,
|
|
373
|
+
"cacheRead": 0.69314,
|
|
374
374
|
"cacheWrite": 0
|
|
375
375
|
},
|
|
376
376
|
"contextWindow": 202750,
|
|
@@ -390,9 +390,9 @@
|
|
|
390
390
|
"text"
|
|
391
391
|
],
|
|
392
392
|
"cost": {
|
|
393
|
-
"input": 0.
|
|
394
|
-
"output": 1.
|
|
395
|
-
"cacheRead": 0.
|
|
393
|
+
"input": 0.359,
|
|
394
|
+
"output": 1.44,
|
|
395
|
+
"cacheRead": 0.1795,
|
|
396
396
|
"cacheWrite": 0
|
|
397
397
|
},
|
|
398
398
|
"contextWindow": 196600,
|
|
@@ -435,9 +435,9 @@
|
|
|
435
435
|
"text"
|
|
436
436
|
],
|
|
437
437
|
"cost": {
|
|
438
|
-
"input": 0.
|
|
439
|
-
"output": 2.
|
|
440
|
-
"cacheRead": 0.
|
|
438
|
+
"input": 0.86,
|
|
439
|
+
"output": 2.752,
|
|
440
|
+
"cacheRead": 0.43,
|
|
441
441
|
"cacheWrite": 0
|
|
442
442
|
},
|
|
443
443
|
"contextWindow": 202752,
|
|
@@ -524,9 +524,9 @@
|
|
|
524
524
|
"image"
|
|
525
525
|
],
|
|
526
526
|
"cost": {
|
|
527
|
-
"input": 0.
|
|
528
|
-
"output": 0.
|
|
529
|
-
"cacheRead": 0.
|
|
527
|
+
"input": 0.0893,
|
|
528
|
+
"output": 0.321,
|
|
529
|
+
"cacheRead": 0.04465,
|
|
530
530
|
"cacheWrite": 0
|
|
531
531
|
},
|
|
532
532
|
"contextWindow": 262142,
|
|
@@ -611,9 +611,9 @@
|
|
|
611
611
|
"text"
|
|
612
612
|
],
|
|
613
613
|
"cost": {
|
|
614
|
-
"input": 0.
|
|
615
|
-
"output": 0.
|
|
616
|
-
"cacheRead": 0.
|
|
614
|
+
"input": 0.178,
|
|
615
|
+
"output": 0.68,
|
|
616
|
+
"cacheRead": 0.089,
|
|
617
617
|
"cacheWrite": 0.04
|
|
618
618
|
},
|
|
619
619
|
"contextWindow": 131072,
|
|
@@ -677,9 +677,9 @@
|
|
|
677
677
|
"text"
|
|
678
678
|
],
|
|
679
679
|
"cost": {
|
|
680
|
-
"input": 0.
|
|
681
|
-
"output": 1.
|
|
682
|
-
"cacheRead": 0.
|
|
680
|
+
"input": 0.109375,
|
|
681
|
+
"output": 1.045,
|
|
682
|
+
"cacheRead": 0.054688,
|
|
683
683
|
"cacheWrite": 0.12
|
|
684
684
|
},
|
|
685
685
|
"contextWindow": 262144,
|
|
@@ -698,9 +698,9 @@
|
|
|
698
698
|
"text"
|
|
699
699
|
],
|
|
700
700
|
"cost": {
|
|
701
|
-
"input": 0.
|
|
702
|
-
"output": 2.
|
|
703
|
-
"cacheRead": 0.
|
|
701
|
+
"input": 0.46125,
|
|
702
|
+
"output": 2.29375,
|
|
703
|
+
"cacheRead": 0.230625,
|
|
704
704
|
"cacheWrite": 0.44
|
|
705
705
|
},
|
|
706
706
|
"contextWindow": 106000,
|
|
@@ -762,9 +762,9 @@
|
|
|
762
762
|
"text"
|
|
763
763
|
],
|
|
764
764
|
"cost": {
|
|
765
|
-
"input": 0.
|
|
766
|
-
"output": 0.
|
|
767
|
-
"cacheRead": 0.
|
|
765
|
+
"input": 0.055,
|
|
766
|
+
"output": 0.194,
|
|
767
|
+
"cacheRead": 0.0275,
|
|
768
768
|
"cacheWrite": 0.03
|
|
769
769
|
},
|
|
770
770
|
"contextWindow": 64000,
|
|
@@ -784,9 +784,9 @@
|
|
|
784
784
|
"text"
|
|
785
785
|
],
|
|
786
786
|
"cost": {
|
|
787
|
-
"input": 0.
|
|
788
|
-
"output":
|
|
789
|
-
"cacheRead": 0.
|
|
787
|
+
"input": 0.5466,
|
|
788
|
+
"output": 1.0226,
|
|
789
|
+
"cacheRead": 0.2733,
|
|
790
790
|
"cacheWrite": 0.2
|
|
791
791
|
},
|
|
792
792
|
"contextWindow": 128000,
|
|
@@ -850,9 +850,9 @@
|
|
|
850
850
|
"text"
|
|
851
851
|
],
|
|
852
852
|
"cost": {
|
|
853
|
-
"input": 0.
|
|
854
|
-
"output": 0.
|
|
855
|
-
"cacheRead": 0.
|
|
853
|
+
"input": 0.0578,
|
|
854
|
+
"output": 0.188,
|
|
855
|
+
"cacheRead": 0.0289,
|
|
856
856
|
"cacheWrite": 0
|
|
857
857
|
},
|
|
858
858
|
"contextWindow": 262144,
|
package/package.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-io-provider",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.59",
|
|
4
4
|
"description": "IO Intelligence provider extension for pi - Access DeepSeek, Kimi, GLM, Llama, Qwen, Mistral, and more through the IO Intelligence API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "echo 'nothing to clean'",
|
|
9
|
+
"build": "echo 'nothing to build'",
|
|
10
|
+
"check": "tsc --noEmit && vitest run && node scripts/test-pi-compat.mjs",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"update-models": "node scripts/update-models.js",
|
|
13
|
+
"test:pi": "node scripts/test-pi-compat.mjs",
|
|
14
|
+
"typecheck": "tsc --noEmit"
|
|
15
|
+
},
|
|
7
16
|
"keywords": [
|
|
8
17
|
"pi",
|
|
9
18
|
"extension",
|
|
@@ -32,17 +41,10 @@
|
|
|
32
41
|
"devDependencies": {
|
|
33
42
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
34
43
|
"typescript": "6.0.3",
|
|
35
|
-
"@types/node": "^25.9.1"
|
|
44
|
+
"@types/node": "^25.9.1",
|
|
45
|
+
"vitest": "4.1.7"
|
|
36
46
|
},
|
|
37
47
|
"peerDependencies": {
|
|
38
48
|
"@earendil-works/pi-coding-agent": "*"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"clean": "echo 'nothing to clean'",
|
|
42
|
-
"build": "echo 'nothing to build'",
|
|
43
|
-
"check": "tsc --noEmit && node scripts/test-pi-compat.mjs",
|
|
44
|
-
"update-models": "node scripts/update-models.js",
|
|
45
|
-
"test:pi": "node scripts/test-pi-compat.mjs",
|
|
46
|
-
"typecheck": "tsc --noEmit"
|
|
47
49
|
}
|
|
48
|
-
}
|
|
50
|
+
}
|
package/scripts/update-models.js
CHANGED
|
@@ -339,6 +339,7 @@ A [pi](https://github.com/badlogic/pi-mono) extension that adds [IO Intelligence
|
|
|
339
339
|
- **Prompt caching** — Cache read/write support on most models
|
|
340
340
|
- **Confidential inference** — Verifiable TEE inference with attestation (via /private/ endpoints)
|
|
341
341
|
- **Streaming** — Real-time token streaming
|
|
342
|
+
- **Quiet live model sync** — Models refresh from the IO Intelligence API in the background, at most hourly and by one pi process at a time ([details](#model-sync))
|
|
342
343
|
|
|
343
344
|
## Available Models
|
|
344
345
|
|
|
@@ -412,6 +413,7 @@ Get your API key from [io.net](https://io.net).
|
|
|
412
413
|
| Variable | Required | Description |
|
|
413
414
|
|----------|----------|-------------|
|
|
414
415
|
| \`IOINTELLIGENCE_API_KEY\` | No | Your IO Intelligence API key (fallback if not in auth.json) |
|
|
416
|
+
| \`PI_PROVIDER_SYNC_TTL_MS\` | No | Model sync freshness window in ms (default \`3600000\`; \`0\` = revalidate every session start) |
|
|
415
417
|
|
|
416
418
|
## Configuration
|
|
417
419
|
|
|
@@ -435,6 +437,20 @@ Once loaded, select a model with:
|
|
|
435
437
|
|
|
436
438
|
Or use \`/models\` to browse all available IO Intelligence models.
|
|
437
439
|
|
|
440
|
+
## Model sync
|
|
441
|
+
|
|
442
|
+
Startup never waits on the network. pi starts with the cached catalog (\`~/.pi/agent/cache/io-intelligence-models.json\`,
|
|
443
|
+
falling back to the bundled \`models.json\`) and revalidates against \`/api/v1/models\` in the background — only when:
|
|
444
|
+
|
|
445
|
+
- an IO Intelligence API key is configured (no key, no request),
|
|
446
|
+
- the cache is older than 1 hour, missing, or was fetched with a different API key, and
|
|
447
|
+
- no other pi process is already refreshing it (an \`io-intelligence-models.lock\` file next to the cache).
|
|
448
|
+
|
|
449
|
+
So \`/new\`, \`/reload\`, \`pi -p\` and fan-out child agents share one cache instead of each calling the API; a
|
|
450
|
+
session that skips the fetch still picks up a cache another process refreshed. A failed refresh is retried after
|
|
451
|
+
5 minutes at the earliest. \`PI_PROVIDER_SYNC_TTL_MS\` changes the window (\`0\` revalidates on every session start).
|
|
452
|
+
Only a hash fingerprint of the key is stored (\`io-intelligence-models.sync.json\`), never the key itself.
|
|
453
|
+
|
|
438
454
|
## API Documentation
|
|
439
455
|
|
|
440
456
|
- IO Intelligence Docs: https://io.net/docs/guides/confidential-inference/quick-start
|