pi-hypercharm-provider 1.3.36 → 1.3.38

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/README.md CHANGED
@@ -20,7 +20,7 @@ Run `bun run test:pi` for offline manifest, catalog, lifecycle and streaming che
20
20
 
21
21
  ## Features
22
22
 
23
- - **34+ AI Models** including DeepSeek V4 Flash/Pro, GLM 5/5.1, Kimi K2.5/K2.6, Qwen3.6/3.7, MiniMax M2.7, Gemma 4, GPT-OSS, and Llama
23
+ - **23+ AI Models** including DeepSeek V4 Flash/Pro, GLM 5/5.1, Kimi K2.5/K2.6, Qwen3.6/3.7, MiniMax M2.7, Gemma 4, GPT-OSS, and Llama
24
24
  - **DeepSeek Native Thinking** — Uses the `deepseek` thinking format for Charm Hyper requests, with native `reasoning_effort` on models that publish levels
25
25
  - **OpenAI-compatible API** via Charm Hyper's `/v1/chat/completions` endpoint
26
26
  - **OAuth Device Flow** — sign in with `/login` under the `hypercharm` provider (independent of the official provider's `hyper` registration)
@@ -36,29 +36,18 @@ Run `bun run test:pi` for offline manifest, catalog, lifecycle and streaming che
36
36
  | DeepSeek V4 Flash 0731 | Text | 1.0M | 384K | $0.44 | $1.32 |
37
37
  | DeepSeek V4 Pro | Text | 1.0M | 384K | $2.40 | $4.80 |
38
38
  | DeepSeek V4 Pro 0813 | Text | 1.0M | 262K | $1.44 | $4.31 |
39
- | DeepSeek V4.1 Flash | Text + Image | 1.0M | 33K | $0.30 | $1.20 |
39
+ | DeepSeek V4.1 Flash | Text + Image | 1.0M | 262K | $0.33 | $1.31 |
40
40
  | Gemma 4 26B A4B | Text | 256K | 26K | $0.10 | $0.33 |
41
41
  | GLM 5.3 | Text | 1.0M | 128K | $1.52 | $4.79 |
42
42
  | GLM 5.3 Flash | Text + Image | 1.0M | 131K | $0.16 | $0.54 |
43
- | GLM-5 | Text | 203K | 20K | $0.86 | $2.75 |
44
- | GLM-5.1 | Text | 203K | 3K | $1.36 | $4.27 |
45
43
  | GLM-5.2 | Text | 1.0M | 33K | $1.52 | $4.79 |
46
44
  | gpt-oss-120b | Text | 131K | 13K | $0.18 | $0.68 |
47
45
  | Inkling | Text + Image | 1.0M | 66K | $1.09 | $4.41 |
48
46
  | Kimi K2 Thinking | Text | 262K | 26K | $0.60 | $2.50 |
49
- | Kimi K2.5 | Text | 262K | 26K | $0.56 | $2.94 |
50
- | Kimi K2.6 | Text + Image | 262K | 26K | $1.03 | $4.36 |
51
47
  | Kimi K2.7 Code | Text + Image | 256K | 16K | $1.03 | $4.36 |
52
48
  | Kimi K3 | Text + Image | 1.0M | 16K | $3.27 | $16.33 |
53
- | Llama 3.3 70B Instruct | Text | 128K | 13K | $0.61 | $1.04 |
54
- | Llama 4 Maverick 17B 128E Instruct FP8 | Text | 430K | 43K | $0.25 | $0.83 |
55
49
  | MiniMax M2.7 | Text | 262K | 7K | $0.48 | $1.85 |
56
50
  | MiniMax M3 | Text + Image | 512K | 512K | $0.33 | $1.31 |
57
- | Qwen3 Coder 480B A35B Instruct INT4 Mixed AR | Text | 106K | 11K | $0.45 | $2.15 |
58
- | Qwen3 Next 80B A3B Instruct | Text | 262K | 26K | $0.12 | $1.14 |
59
- | Qwen3.6-Flash | Text + Image | 1.0M | 64K | $1.00 | $4.00 |
60
- | Qwen3.6-Max | Text | 256K | 64K | $2.00 | $12.00 |
61
- | Qwen3.6-Plus | Text + Image | 1.0M | 64K | $2.00 | $6.00 |
62
51
  | Qwen3.7-Flash | Text + Image | 1.0M | 64K | $0.20 | $0.80 |
63
52
  | Qwen3.7-Max | Text | 1.0M | 64K | $2.50 | $7.50 |
64
53
  | Qwen3.7-Plus | Text + Image | 1.0M | 64K | $1.20 | $4.80 |
@@ -1,339 +1 @@
1
- {
2
- "glm-5": {
3
- "id": "glm-5",
4
- "name": "GLM-5",
5
- "reasoning": true,
6
- "thinkingLevelMap": {
7
- "off": "off",
8
- "minimal": null,
9
- "low": null,
10
- "medium": null,
11
- "high": null,
12
- "xhigh": null,
13
- "max": "max"
14
- },
15
- "input": [
16
- "text"
17
- ],
18
- "cost": {
19
- "input": 0.86,
20
- "output": 2.752,
21
- "cacheRead": 0.43,
22
- "cacheWrite": 0
23
- },
24
- "contextWindow": 202752,
25
- "maxTokens": 20275,
26
- "compat": {
27
- "supportsStore": false,
28
- "supportsReasoningEffort": false,
29
- "thinkingFormat": "deepseek",
30
- "maxTokensField": "max_tokens"
31
- },
32
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
33
- },
34
- "glm-5.1": {
35
- "id": "glm-5.1",
36
- "name": "GLM-5.1",
37
- "reasoning": true,
38
- "thinkingLevelMap": {
39
- "off": "off",
40
- "minimal": null,
41
- "low": null,
42
- "medium": null,
43
- "high": null,
44
- "xhigh": null,
45
- "max": "max"
46
- },
47
- "input": [
48
- "text"
49
- ],
50
- "cost": {
51
- "input": 1.358,
52
- "output": 4.268,
53
- "cacheRead": 0.679,
54
- "cacheWrite": 0
55
- },
56
- "contextWindow": 202750,
57
- "maxTokens": 3276,
58
- "compat": {
59
- "supportsStore": false,
60
- "supportsReasoningEffort": false,
61
- "thinkingFormat": "deepseek",
62
- "maxTokensField": "max_tokens"
63
- },
64
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
65
- },
66
- "kimi-k2.5": {
67
- "id": "kimi-k2.5",
68
- "name": "Kimi K2.5",
69
- "reasoning": true,
70
- "thinkingLevelMap": {
71
- "off": "off",
72
- "minimal": null,
73
- "low": null,
74
- "medium": null,
75
- "high": null,
76
- "xhigh": null,
77
- "max": "max"
78
- },
79
- "input": [
80
- "text"
81
- ],
82
- "cost": {
83
- "input": 0.5584,
84
- "output": 2.935,
85
- "cacheRead": 0.2792,
86
- "cacheWrite": 0
87
- },
88
- "contextWindow": 262144,
89
- "maxTokens": 26214,
90
- "compat": {
91
- "supportsStore": false,
92
- "supportsReasoningEffort": false,
93
- "thinkingFormat": "deepseek",
94
- "maxTokensField": "max_tokens"
95
- },
96
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
97
- },
98
- "kimi-k2.6": {
99
- "id": "kimi-k2.6",
100
- "name": "Kimi K2.6",
101
- "reasoning": true,
102
- "thinkingLevelMap": {
103
- "off": null,
104
- "minimal": null,
105
- "low": "low",
106
- "medium": "medium",
107
- "high": "high",
108
- "xhigh": null,
109
- "max": null
110
- },
111
- "input": [
112
- "text",
113
- "image"
114
- ],
115
- "cost": {
116
- "input": 1.03436,
117
- "output": 4.3552,
118
- "cacheRead": 0.174208,
119
- "cacheWrite": 0
120
- },
121
- "contextWindow": 262000,
122
- "maxTokens": 26214,
123
- "compat": {
124
- "supportsStore": false,
125
- "supportsReasoningEffort": true,
126
- "thinkingFormat": "deepseek",
127
- "maxTokensField": "max_tokens"
128
- },
129
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
130
- },
131
- "llama-3.3-70b-instruct": {
132
- "id": "llama-3.3-70b-instruct",
133
- "name": "Llama 3.3 70B Instruct",
134
- "reasoning": true,
135
- "thinkingLevelMap": {
136
- "off": "off",
137
- "minimal": null,
138
- "low": null,
139
- "medium": null,
140
- "high": null,
141
- "xhigh": null,
142
- "max": "max"
143
- },
144
- "input": [
145
- "text"
146
- ],
147
- "cost": {
148
- "input": 0.6066,
149
- "output": 1.0386,
150
- "cacheRead": 0.3033,
151
- "cacheWrite": 0
152
- },
153
- "contextWindow": 128000,
154
- "maxTokens": 12800,
155
- "compat": {
156
- "supportsStore": false,
157
- "supportsReasoningEffort": false,
158
- "thinkingFormat": "deepseek",
159
- "maxTokensField": "max_tokens"
160
- },
161
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
162
- },
163
- "llama-4-maverick-17b-128e-instruct-fp8": {
164
- "id": "llama-4-maverick-17b-128e-instruct-fp8",
165
- "name": "Llama 4 Maverick 17B 128E Instruct FP8",
166
- "reasoning": true,
167
- "thinkingLevelMap": {
168
- "off": "off",
169
- "minimal": null,
170
- "low": null,
171
- "medium": null,
172
- "high": null,
173
- "xhigh": null,
174
- "max": "max"
175
- },
176
- "input": [
177
- "text"
178
- ],
179
- "cost": {
180
- "input": 0.25188,
181
- "output": 0.82563,
182
- "cacheRead": 0.12594,
183
- "cacheWrite": 0
184
- },
185
- "contextWindow": 430000,
186
- "maxTokens": 43000,
187
- "compat": {
188
- "supportsStore": false,
189
- "supportsReasoningEffort": false,
190
- "thinkingFormat": "deepseek",
191
- "maxTokensField": "max_tokens"
192
- },
193
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
194
- },
195
- "qwen3-coder-480b-a35b-instruct-int4-mixed-ar": {
196
- "id": "qwen3-coder-480b-a35b-instruct-int4-mixed-ar",
197
- "name": "Qwen3 Coder 480B A35B Instruct INT4 Mixed AR",
198
- "reasoning": false,
199
- "input": [
200
- "text"
201
- ],
202
- "cost": {
203
- "input": 0.445,
204
- "output": 2.145,
205
- "cacheRead": 0.2225,
206
- "cacheWrite": 0
207
- },
208
- "contextWindow": 106000,
209
- "maxTokens": 10600,
210
- "compat": {
211
- "supportsStore": false,
212
- "supportsReasoningEffort": false,
213
- "thinkingFormat": "deepseek",
214
- "maxTokensField": "max_tokens"
215
- },
216
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
217
- },
218
- "qwen3-next-80b-a3b-instruct": {
219
- "id": "qwen3-next-80b-a3b-instruct",
220
- "name": "Qwen3 Next 80B A3B Instruct",
221
- "reasoning": false,
222
- "input": [
223
- "text"
224
- ],
225
- "cost": {
226
- "input": 0.1175,
227
- "output": 1.136,
228
- "cacheRead": 0.05875,
229
- "cacheWrite": 0
230
- },
231
- "contextWindow": 262144,
232
- "maxTokens": 26214,
233
- "compat": {
234
- "supportsStore": false,
235
- "supportsReasoningEffort": false,
236
- "thinkingFormat": "deepseek",
237
- "maxTokensField": "max_tokens"
238
- },
239
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
240
- },
241
- "qwen3.6-flash": {
242
- "id": "qwen3.6-flash",
243
- "name": "Qwen3.6-Flash",
244
- "reasoning": true,
245
- "thinkingLevelMap": {
246
- "off": "none",
247
- "minimal": "minimal",
248
- "low": "low",
249
- "medium": "medium",
250
- "high": "high",
251
- "xhigh": null,
252
- "max": null
253
- },
254
- "input": [
255
- "text",
256
- "image"
257
- ],
258
- "cost": {
259
- "input": 1,
260
- "output": 4,
261
- "cacheRead": 0.1,
262
- "cacheWrite": 1.25
263
- },
264
- "contextWindow": 1000000,
265
- "maxTokens": 64000,
266
- "compat": {
267
- "supportsStore": false,
268
- "supportsReasoningEffort": true,
269
- "thinkingFormat": "deepseek",
270
- "maxTokensField": "max_tokens"
271
- },
272
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
273
- },
274
- "qwen3.6-max": {
275
- "id": "qwen3.6-max",
276
- "name": "Qwen3.6-Max",
277
- "reasoning": true,
278
- "thinkingLevelMap": {
279
- "off": "none",
280
- "minimal": "minimal",
281
- "low": "low",
282
- "medium": "medium",
283
- "high": "high",
284
- "xhigh": null,
285
- "max": null
286
- },
287
- "input": [
288
- "text"
289
- ],
290
- "cost": {
291
- "input": 2,
292
- "output": 12,
293
- "cacheRead": 0.2,
294
- "cacheWrite": 2.5
295
- },
296
- "contextWindow": 256000,
297
- "maxTokens": 64000,
298
- "compat": {
299
- "supportsStore": false,
300
- "supportsReasoningEffort": true,
301
- "thinkingFormat": "deepseek",
302
- "maxTokensField": "max_tokens"
303
- },
304
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
305
- },
306
- "qwen3.6-plus": {
307
- "id": "qwen3.6-plus",
308
- "name": "Qwen3.6-Plus",
309
- "reasoning": true,
310
- "thinkingLevelMap": {
311
- "off": "none",
312
- "minimal": "minimal",
313
- "low": "low",
314
- "medium": "medium",
315
- "high": "high",
316
- "xhigh": null,
317
- "max": null
318
- },
319
- "input": [
320
- "text",
321
- "image"
322
- ],
323
- "cost": {
324
- "input": 2,
325
- "output": 6,
326
- "cacheRead": 0.2,
327
- "cacheWrite": 2.5
328
- },
329
- "contextWindow": 1000000,
330
- "maxTokens": 64000,
331
- "compat": {
332
- "supportsStore": false,
333
- "supportsReasoningEffort": true,
334
- "thinkingFormat": "deepseek",
335
- "maxTokensField": "max_tokens"
336
- },
337
- "deprecatedAt": "2026-09-17T02:00:12.965Z"
338
- }
339
- }
1
+ {}
package/models.json CHANGED
@@ -141,13 +141,13 @@
141
141
  "image"
142
142
  ],
143
143
  "cost": {
144
- "input": 0.3,
145
- "output": 1.2,
144
+ "input": 0.33,
145
+ "output": 1.31,
146
146
  "cacheRead": 0.03,
147
147
  "cacheWrite": 0
148
148
  },
149
149
  "contextWindow": 1048576,
150
- "maxTokens": 32768,
150
+ "maxTokens": 262144,
151
151
  "compat": {
152
152
  "supportsStore": false,
153
153
  "supportsReasoningEffort": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-hypercharm-provider",
3
- "version": "1.3.36",
3
+ "version": "1.3.38",
4
4
  "description": "HyperCharm provider extension for pi - Access DeepSeek, GLM, Kimi, Qwen, MiniMax, Gemma, and GPT-OSS models through the Charm Hyper API",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -35,10 +35,13 @@
35
35
  "@earendil-works/pi-ai": "*",
36
36
  "@earendil-works/pi-coding-agent": "*"
37
37
  },
38
+ "overrides": {
39
+ "brace-expansion": "5.0.12"
40
+ },
38
41
  "devDependencies": {
39
- "@earendil-works/pi-ai": "1.0.0",
40
- "@earendil-works/pi-coding-agent": "1.0.0",
41
- "@earendil-works/pi-tui": "1.0.0",
42
+ "@earendil-works/pi-ai": "1.1.0",
43
+ "@earendil-works/pi-coding-agent": "1.1.0",
44
+ "@earendil-works/pi-tui": "1.1.0",
42
45
  "@types/node": "^24.10.1",
43
46
  "jiti": "2.7.0",
44
47
  "typescript": "6.0.3"
@@ -1,4 +1,4 @@
1
- // Offline Pi 1.0 manifest, lifecycle, catalog and real transport regression.
1
+ // Offline Pi 1.1.0 manifest, lifecycle, catalog and real transport regression.
2
2
  import assert from 'node:assert/strict';
3
3
  import { mkdtemp, readFile, rm } from 'node:fs/promises';
4
4
  import { tmpdir } from 'node:os';
@@ -18,13 +18,13 @@ try {
18
18
  const hostEntry = process.env.PI1_HOST_ENTRY === 'bundle' ? 'dist/bundle/index.js' : 'dist/index.js';
19
19
  const sdk = await import(host ? pathToFileURL(join(host, hostEntry)).href : '@earendil-works/pi-coding-agent');
20
20
  const { createAgentSession, DefaultResourceLoader, ModelRuntime, SessionManager, SettingsManager, VERSION } = sdk;
21
- assert.equal(VERSION, '1.0.0', 'executing host version');
22
- assert.equal((await import('@earendil-works/pi-coding-agent')).VERSION, '1.0.0', 'development host version');
21
+ assert.equal(VERSION, '1.1.0', 'executing host version');
22
+ assert.equal((await import('@earendil-works/pi-coding-agent')).VERSION, '1.1.0', 'development host version');
23
23
  const manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
24
24
  for (const name of ['@earendil-works/pi-ai', '@earendil-works/pi-agent-core', '@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', 'typebox']) {
25
25
  assert.equal(manifest.dependencies?.[name], undefined, `${name}: do not bundle host packages`);
26
26
  if (manifest.peerDependencies?.[name] !== undefined) assert.equal(manifest.peerDependencies[name], '*');
27
- if (name !== 'typebox' && manifest.devDependencies?.[name]) assert.equal(manifest.devDependencies[name], '1.0.0');
27
+ if (name !== 'typebox' && manifest.devDependencies?.[name]) assert.equal(manifest.devDependencies[name], '1.1.0');
28
28
  }
29
29
  const settingsManager = SettingsManager.inMemory({ packages: [root], compaction: { enabled: false }, retry: { enabled: false } });
30
30
  const resourceLoader = new DefaultResourceLoader({ cwd: home, agentDir: home, settingsManager,
@@ -9,7 +9,7 @@
9
9
  * official provider's identifier surface (tests/fixtures/official-surface.ts).
10
10
  */
11
11
  import assert from "node:assert/strict";
12
- import { mkdtempSync, readFileSync, rmSync } from "node:fs";
12
+ import { copyFileSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
13
13
  import { tmpdir } from "node:os";
14
14
  import path from "node:path";
15
15
  import { after, test } from "node:test";
@@ -22,7 +22,6 @@ delete process.env.HYPERCHARM_API_KEY;
22
22
 
23
23
  const extensionPath = fileURLToPath(new URL("../index.ts", import.meta.url));
24
24
  const officialSurfacePath = fileURLToPath(new URL("./fixtures/official-surface.ts", import.meta.url));
25
- const deprecatedModelsPath = fileURLToPath(new URL("../deprecated-models.json", import.meta.url));
26
25
  const embeddedModelsPath = fileURLToPath(new URL("../models.json", import.meta.url));
27
26
 
28
27
  const EMBEDDED_AUTHORITY_NOTE = "tests must run against the embedded catalog";
@@ -199,9 +198,22 @@ test("loads offline: embedded catalog, deprecated grace, namespaced registration
199
198
  const stderr = captureStderr();
200
199
  let harness;
201
200
  try {
202
- const graveyard = Object.values(JSON.parse(readFileSync(deprecatedModelsPath, "utf8")));
203
- const graceNow = Math.max(...graveyard.map(entry => Date.parse(entry.deprecatedAt))) + 24 * 60 * 60 * 1000;
204
- harness = await load({ catalogNow: graceNow });
201
+ // The generated graveyard may be empty. Exercise the actual extension
202
+ // against deterministic data in an isolated copy, never edit generated files.
203
+ const fixtureDir = mkdtempSync(path.join(agentDir, "grace-fixture-"));
204
+ const sourceDir = path.dirname(extensionPath);
205
+ for (const file of readdirSync(sourceDir)) {
206
+ if (/\.(ts|json)$/.test(file)) copyFileSync(path.join(sourceDir, file), path.join(fixtureDir, file));
207
+ }
208
+ const graceNow = Date.UTC(2026, 0, 15);
209
+ const base = JSON.parse(readFileSync(embeddedModelsPath, "utf8"))[0];
210
+ const deprecated = {
211
+ fresh: { ...base, id: "fixture-grace-fresh", deprecatedAt: new Date(graceNow - DEPRECATED_TTL_MS).toISOString() },
212
+ stale: { ...base, id: "fixture-grace-stale", deprecatedAt: new Date(graceNow - DEPRECATED_TTL_MS - 1).toISOString() },
213
+ invalid: { ...base, id: "fixture-grace-invalid", deprecatedAt: "invalid" },
214
+ };
215
+ writeFileSync(path.join(fixtureDir, "deprecated-models.json"), JSON.stringify(deprecated));
216
+ harness = await load({ catalogNow: graceNow, extensionPaths: [path.join(fixtureDir, "index.ts")] });
205
217
 
206
218
  const embedded = harness.runtime.getModel("hypercharm", "deepseek-v4-flash");
207
219
  assert.ok(embedded, "embedded catalog must register without any network");
@@ -211,8 +223,7 @@ test("loads offline: embedded catalog, deprecated grace, namespaced registration
211
223
  assert.equal(EMBEDDED_AUTHORITY_NOTE, "tests must run against the embedded catalog");
212
224
 
213
225
  // Deprecated grace: entries inside the 14-day TTL are still served,
214
- // entries past it are evicted. Derived from the data, not today's date.
215
- const deprecated = JSON.parse(readFileSync(deprecatedModelsPath, "utf8"));
226
+ // entries past it are evicted, including the exact TTL + 1ms boundary.
216
227
  const embeddedIds = new Set(
217
228
  (Array.isArray(JSON.parse(readFileSync(embeddedModelsPath, "utf8")))
218
229
  ? JSON.parse(readFileSync(embeddedModelsPath, "utf8"))
@@ -222,7 +233,9 @@ test("loads offline: embedded catalog, deprecated grace, namespaced registration
222
233
  const deprecatedOnly = Object.values(deprecated).filter((entry) => !embeddedIds.has(entry.id));
223
234
  const fresh = deprecatedOnly.filter((entry) => graceNow - Date.parse(entry.deprecatedAt) <= DEPRECATED_TTL_MS);
224
235
  const stale = deprecatedOnly.filter((entry) => graceNow - Date.parse(entry.deprecatedAt) > DEPRECATED_TTL_MS);
225
- assert.ok(fresh.length > 0, "expected at least one model inside the deprecated grace window");
236
+ assert.equal(fresh.length, 1, "exact TTL boundary is still served");
237
+ assert.equal(stale.length, 1, "TTL + 1ms is expired");
238
+ assert.equal(harness.runtime.getModel("hypercharm", deprecated.invalid.id), undefined, "invalid deprecation timestamps are evicted");
226
239
  for (const entry of fresh) {
227
240
  assert.ok(harness.runtime.getModel("hypercharm", entry.id), entry.id + " must be served during its grace period");
228
241
  }