pi-umans-provider 1.0.3 → 1.0.5

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 CHANGED
@@ -7,6 +7,7 @@ The following files are **idempotent** and regenerated by `scripts/update-models
7
7
  | File | Why it's auto-generated |
8
8
  |------|------------------------|
9
9
  | `models.json` | Built from the provider API. `update-models.js` fetches models, preserves curated data for known IDs, and writes this file. |
10
+ | `deprecated-models.json` | Graveyard for models the API delisted. update-models.js stamps them with deprecatedAt and pi keeps serving them for a 2-week grace period, then evicts them. Never edit by hand. |
10
11
  | `README.md` (model table) | The table under `## Available Models` is replaced in-place by `update-models.js` after merging base models → patch → custom models. |
11
12
 
12
13
  ## Correct Files to Edit
package/README.md CHANGED
@@ -28,9 +28,11 @@ _A [pi](https://github.com/earendil-works/pi-coding-agent) provider extension wi
28
28
  | Model | Base | Context | Vision | Reasoning | Max Output |
29
29
  |-------|------|---------|--------|-----------|------------|
30
30
  | Coder | Kimi K2.7-Code | 262K | ✅ | ✅ | 33K |
31
+ | DeepSeek V4 Flash (experimental) | DeepSeek-V4-Flash | 1.0M | ❌ | ✅ | 393K |
31
32
  | Flash | Qwen3.6-35B-A3B | 262K | ✅ | ✅ | 33K |
32
33
  | GLM 5.2 | GLM-5.2 | 406K | ❌ | ✅ | 131K |
33
34
  | Kimi K2.7 Code | Kimi K2.7-Code | 262K | ✅ | ✅ | 33K |
35
+ | Kimi K3 | Kimi K3 | 1.0M | ✅ | ✅ | 131K |
34
36
  | Qwen3.6 35B A3B | Qwen3.6-35B-A3B | 262K | ✅ | ✅ | 33K |
35
37
 
36
38
  > **Note:** `umans-flash-beta` is deprecated (sunset 2026-06-07). Use `umans-flash` instead.
@@ -0,0 +1 @@
1
+ {}
package/index.ts CHANGED
@@ -42,6 +42,7 @@ import type { OAuthLoginCallbacks } from "@earendil-works/pi-ai";
42
42
  import modelsData from "./models.json" with { type: "json" };
43
43
  import customModelsData from "./custom-models.json" with { type: "json" };
44
44
  import patchData from "./patch.json" with { type: "json" };
45
+ import deprecatedData from "./deprecated-models.json" with { type: "json" };
45
46
  import fs from "fs";
46
47
  import path from "path";
47
48
 
@@ -192,7 +193,10 @@ function applyPatch(model: JsonModel, patch: PatchEntry): JsonModel {
192
193
  function buildModels(base: JsonModel[], custom: JsonModel[], patch: PatchData): JsonModel[] {
193
194
  const modelMap = new Map<string, JsonModel>();
194
195
 
195
- for (const model of base) {
196
+ // Seed with the base list plus grace-period deprecated models so patch.json
197
+ // entries apply to deprecated models exactly as while the model was live
198
+ // (withDeprecated keeps live data on id conflicts).
199
+ for (const model of withDeprecated(base)) {
196
200
  modelMap.set(model.id, model);
197
201
  }
198
202
 
@@ -324,6 +328,35 @@ function mergeWithEmbedded(liveModels: JsonModel[], embeddedModels: JsonModel[])
324
328
  return result;
325
329
  }
326
330
 
331
+ // Grace period for delisted models. When the provider API stops listing a
332
+ // model, update-models.js moves its last-known definition into
333
+ // deprecated-models.json (stamped with deprecatedAt) instead of dropping it.
334
+ // For 14 days the model keeps working here so in-flight sessions and saved
335
+ // model settings do not break; afterwards it is evicted permanently.
336
+ const DEPRECATED_MODEL_TTL_MS = 14 * 24 * 60 * 60 * 1000;
337
+
338
+ // Grace-period deprecated models with deprecation metadata stripped.
339
+ function activeDeprecatedModels(): JsonModel[] {
340
+ const now = Date.now();
341
+ const result: JsonModel[] = [];
342
+ for (const entry of Object.values(deprecatedData as Record<string, JsonModel & { deprecatedAt?: string }>)) {
343
+ if (!entry?.id) continue;
344
+ const removedAt = Date.parse(entry.deprecatedAt ?? "");
345
+ if (Number.isNaN(removedAt) || now - removedAt > DEPRECATED_MODEL_TTL_MS) continue;
346
+ const model = { ...entry } as JsonModel & { deprecatedAt?: string };
347
+ delete model.deprecatedAt;
348
+ result.push(model);
349
+ }
350
+ return result;
351
+ }
352
+
353
+ // Append grace-period deprecated models the list does not already have (live data wins).
354
+ function withDeprecated(models: JsonModel[]): JsonModel[] {
355
+ const seen = new Set(models.map((m) => m.id));
356
+ const extras = activeDeprecatedModels().filter((m) => !seen.has(m.id));
357
+ return extras.length > 0 ? [...models, ...extras] : models;
358
+ }
359
+
327
360
  function loadStaleModels(embeddedModels: JsonModel[]): JsonModel[] {
328
361
  const cached = loadCachedModels();
329
362
  if (!cached || cached.length === 0) return embeddedModels;
package/models.json CHANGED
@@ -16,6 +16,22 @@
16
16
  "contextWindow": 262144,
17
17
  "maxTokens": 32768
18
18
  },
19
+ {
20
+ "id": "umans-deepseek-v4-flash-0731",
21
+ "name": "Umans DeepSeek V4 Flash (experimental)",
22
+ "reasoning": true,
23
+ "input": [
24
+ "text"
25
+ ],
26
+ "cost": {
27
+ "input": 0,
28
+ "output": 0,
29
+ "cacheRead": 0,
30
+ "cacheWrite": 0
31
+ },
32
+ "contextWindow": 1048576,
33
+ "maxTokens": 393215
34
+ },
19
35
  {
20
36
  "id": "umans-flash",
21
37
  "name": "Umans Flash",
@@ -66,6 +82,23 @@
66
82
  "contextWindow": 262144,
67
83
  "maxTokens": 32768
68
84
  },
85
+ {
86
+ "id": "umans-kimi-k3",
87
+ "name": "Umans Kimi K3",
88
+ "reasoning": true,
89
+ "input": [
90
+ "text",
91
+ "image"
92
+ ],
93
+ "cost": {
94
+ "input": 0,
95
+ "output": 0,
96
+ "cacheRead": 0,
97
+ "cacheWrite": 0
98
+ },
99
+ "contextWindow": 1048576,
100
+ "maxTokens": 131071
101
+ },
69
102
  {
70
103
  "id": "umans-qwen3.6-35b-a3b",
71
104
  "name": "Umans Qwen3.6 35B A3B",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-umans-provider",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "UMANS provider extension for pi - Access Kimi K2.6, GLM 5.1, Qwen 3.6, and coding-optimized models through the UMANS API",
5
5
  "type": "module",
6
6
  "main": "index.ts",
package/patch.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "umans-coder": {
3
- "thinkingLevelMap": { "off": "none" },
3
+ "thinkingLevelMap": {
4
+ "off": "none"
5
+ },
4
6
  "compat": {
5
7
  "supportsDeveloperRole": false,
6
8
  "supportsReasoningEffort": true,
@@ -8,15 +10,9 @@
8
10
  }
9
11
  },
10
12
  "umans-flash": {
11
- "thinkingLevelMap": { "off": "none" },
12
- "compat": {
13
- "supportsDeveloperRole": false,
14
- "supportsReasoningEffort": true,
15
- "requiresReasoningContentOnAssistantMessages": true
16
- }
17
- },
18
- "umans-kimi-k2.6": {
19
- "thinkingLevelMap": { "off": "none" },
13
+ "thinkingLevelMap": {
14
+ "off": "none"
15
+ },
20
16
  "compat": {
21
17
  "supportsDeveloperRole": false,
22
18
  "supportsReasoningEffort": true,
@@ -24,43 +20,71 @@
24
20
  }
25
21
  },
26
22
  "umans-kimi-k2.7": {
27
- "thinkingLevelMap": { "off": "none" },
23
+ "thinkingLevelMap": {
24
+ "off": "none"
25
+ },
28
26
  "compat": {
29
27
  "supportsDeveloperRole": false,
30
28
  "supportsReasoningEffort": true,
31
29
  "requiresReasoningContentOnAssistantMessages": true
32
30
  }
33
31
  },
34
- "umans-glm-5.1": {
35
- "thinkingLevelMap": { "off": "none" },
32
+ "umans-glm-5.2": {
33
+ "thinkingLevelMap": {
34
+ "off": "none"
35
+ },
36
36
  "compat": {
37
37
  "supportsDeveloperRole": false,
38
38
  "supportsReasoningEffort": true,
39
39
  "requiresReasoningContentOnAssistantMessages": true
40
40
  }
41
41
  },
42
- "umans-glm-5.2": {
43
- "thinkingLevelMap": { "off": "none" },
42
+ "umans-qwen3.6-35b-a3b": {
43
+ "thinkingLevelMap": {
44
+ "off": "none"
45
+ },
44
46
  "compat": {
45
47
  "supportsDeveloperRole": false,
46
48
  "supportsReasoningEffort": true,
47
49
  "requiresReasoningContentOnAssistantMessages": true
48
50
  }
49
51
  },
50
- "umans-glm-5.2-nvfp4": {
51
- "thinkingLevelMap": { "off": "none" },
52
+ "umans-deepseek-v4-flash-0731": {
53
+ "reasoning": true,
54
+ "thinkingLevelMap": {
55
+ "off": "none",
56
+ "minimal": null,
57
+ "low": "high",
58
+ "medium": "high",
59
+ "high": "high",
60
+ "xhigh": null,
61
+ "max": "max"
62
+ },
52
63
  "compat": {
53
- "supportsDeveloperRole": false,
54
- "supportsReasoningEffort": true,
55
- "requiresReasoningContentOnAssistantMessages": true
64
+ "thinkingFormat": "openai",
65
+ "maxTokensField": "max_tokens",
66
+ "supportsReasoningEffort": true
56
67
  }
57
68
  },
58
- "umans-qwen3.6-35b-a3b": {
59
- "thinkingLevelMap": { "off": "none" },
69
+ "umans-kimi-k3": {
70
+ "reasoning": true,
71
+ "input": [
72
+ "text",
73
+ "image"
74
+ ],
75
+ "thinkingLevelMap": {
76
+ "off": null,
77
+ "minimal": null,
78
+ "low": "low",
79
+ "medium": null,
80
+ "high": "high",
81
+ "xhigh": null,
82
+ "max": "max"
83
+ },
60
84
  "compat": {
61
- "supportsDeveloperRole": false,
62
- "supportsReasoningEffort": true,
63
- "requiresReasoningContentOnAssistantMessages": true
85
+ "thinkingFormat": "openai",
86
+ "maxTokensField": "max_tokens",
87
+ "supportsReasoningEffort": true
64
88
  }
65
89
  }
66
90
  }
@@ -154,6 +154,67 @@ function cleanModelForJson(model) {
154
154
  return cleanModel;
155
155
  }
156
156
 
157
+ // Grace period for delisted models: update-models.js moves models the API no
158
+ // longer lists into deprecated-models.json (stamped with deprecatedAt) instead
159
+ // of dropping them; the runtime appends them back so sessions and saved model
160
+ // settings keep working, and after 14 days they are evicted permanently.
161
+ const DEPRECATED_MODEL_TTL_MS = 14 * 24 * 60 * 60 * 1000;
162
+
163
+ /**
164
+ * Reconcile deprecated-models.json against the freshly fetched model list.
165
+ * - in old models.json but not the API: moved into the deprecated file
166
+ * (deprecatedAt = now; preserved on repeat runs so the grace clock is not reset)
167
+ * - back in the API: resurrected (dropped from the deprecated file)
168
+ * - deprecatedAt older than 14 days: evicted permanently
169
+ * Must run BEFORE the new models.json is written; it reads the old file itself.
170
+ */
171
+ function updateDeprecatedModels(modelsJsonPath, newModels) {
172
+ const deprecatedPath = path.join(path.dirname(modelsJsonPath), 'deprecated-models.json');
173
+
174
+ let oldModels = [];
175
+ try {
176
+ const parsed = JSON.parse(fs.readFileSync(modelsJsonPath, 'utf8'));
177
+ if (Array.isArray(parsed)) oldModels = parsed;
178
+ } catch { /* first run: no previous models.json */ }
179
+
180
+ let deprecated = {};
181
+ try {
182
+ const parsed = JSON.parse(fs.readFileSync(deprecatedPath, 'utf8'));
183
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) deprecated = parsed;
184
+ } catch { /* no graveyard yet */ }
185
+
186
+ const currentIds = new Set(newModels.map(m => m.id));
187
+ const now = new Date().toISOString();
188
+ const added = [];
189
+ const resurrected = [];
190
+ const evicted = [];
191
+
192
+ for (const old of oldModels) {
193
+ if (old && old.id && !currentIds.has(old.id) && !deprecated[old.id]) {
194
+ deprecated[old.id] = { ...old, deprecatedAt: now };
195
+ added.push(old.id);
196
+ }
197
+ }
198
+
199
+ for (const [id, entry] of Object.entries(deprecated)) {
200
+ if (currentIds.has(id)) {
201
+ delete deprecated[id];
202
+ resurrected.push(id);
203
+ continue;
204
+ }
205
+ const removedAt = Date.parse(entry && entry.deprecatedAt ? entry.deprecatedAt : '');
206
+ if (Number.isNaN(removedAt) || Date.now() - removedAt > DEPRECATED_MODEL_TTL_MS) {
207
+ delete deprecated[id];
208
+ evicted.push(id);
209
+ }
210
+ }
211
+
212
+ if (added.length > 0 || resurrected.length > 0 || evicted.length > 0) {
213
+ fs.writeFileSync(deprecatedPath, JSON.stringify(deprecated, null, 2) + '\n');
214
+ console.log('Updated deprecated-models.json ' + JSON.stringify({ added, resurrected, evicted }));
215
+ }
216
+ }
217
+
157
218
  async function main() {
158
219
  console.log(`Fetching models from ${MODELS_INFO_API_URL}...`);
159
220
 
@@ -214,6 +275,8 @@ async function main() {
214
275
 
215
276
  // Update models.json — pure API data, no patches baked in
216
277
  const cleanModels = apiTransformed.map(cleanModelForJson);
278
+ // Move delisted models to deprecated-models.json BEFORE models.json is overwritten
279
+ updateDeprecatedModels(MODELS_JSON_PATH, cleanModels);
217
280
  fs.writeFileSync(MODELS_JSON_PATH, JSON.stringify(cleanModels, null, 2) + "\n");
218
281
  console.log("✓ Updated models.json (pure API data)");
219
282