pi-hypercharm-provider 1.2.2 → 1.3.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.
@@ -0,0 +1,298 @@
1
+ {
2
+ "version": 1,
3
+ "layers": [
4
+ {
5
+ "path": "/Users/monotykamary/.mcporter/mcporter.json",
6
+ "mtimeMs": 1786708960950.6536,
7
+ "size": 180
8
+ }
9
+ ],
10
+ "updatedAt": "2026-08-16T20:51:31.788Z",
11
+ "servers": {
12
+ "fal-ai": {
13
+ "definitionHash": "ee48434dcd3ee4daa319d25c1b24434511497a99764bc200a43f3d93335573c0",
14
+ "transport": "http",
15
+ "description": null,
16
+ "fetchedAt": "2026-08-16T20:51:31.638Z",
17
+ "stale": false,
18
+ "tools": [
19
+ {
20
+ "name": "search_models",
21
+ "description": "Search fal.ai's model catalog. Use this to discover available models.\nCategories: text-to-image, image-to-video, text-to-video, text-to-speech, speech-to-text, text-to-music, image-to-3d, text-to-3d, image-editing, llm, and more.\nReturns model IDs you can pass to get_model_schema or run_model.",
22
+ "inputSchema": {
23
+ "type": "object",
24
+ "properties": {
25
+ "query": {
26
+ "type": "string",
27
+ "description": "Free-text search (e.g. 'flux', 'video generation', 'upscale')"
28
+ },
29
+ "category": {
30
+ "type": "string",
31
+ "description": "Filter by category: text-to-image, image-to-video, text-to-video, text-to-speech, speech-to-text, text-to-music, image-to-3d, image-editing, llm"
32
+ },
33
+ "limit": {
34
+ "type": "number",
35
+ "minimum": 1,
36
+ "maximum": 100,
37
+ "description": "Max results to return (default 20)"
38
+ },
39
+ "cursor": {
40
+ "type": "string",
41
+ "description": "Pagination cursor from a previous response's next_cursor to fetch the next page"
42
+ }
43
+ },
44
+ "additionalProperties": false,
45
+ "$schema": "http://json-schema.org/draft-07/schema#"
46
+ }
47
+ },
48
+ {
49
+ "name": "get_model_schema",
50
+ "description": "Get the full input/output schema for a specific fal.ai model.\nReturns all parameters the model accepts and what it returns.\nUse this before run_model to understand what inputs are needed.",
51
+ "inputSchema": {
52
+ "type": "object",
53
+ "properties": {
54
+ "endpoint_id": {
55
+ "type": "string",
56
+ "description": "The model endpoint ID (e.g. 'fal-ai/flux/dev', 'fal-ai/wan-t2v')"
57
+ }
58
+ },
59
+ "required": [
60
+ "endpoint_id"
61
+ ],
62
+ "additionalProperties": false,
63
+ "$schema": "http://json-schema.org/draft-07/schema#"
64
+ }
65
+ },
66
+ {
67
+ "name": "run_model",
68
+ "description": "Run a fal.ai model: submits to the queue and waits a short, bounded time for the result.\nIMPORTANT: If the user does NOT specify a model by name, you MUST call recommend_model first to find the best trending model. Never pick a model from your own knowledge — always use recommend_model to get the current best option. Only skip recommend_model if the user explicitly asks for a specific model (e.g. \"use FLUX\" or \"use Kling\").\n\nThis tool returns one of two statuses:\n- \"completed\": the result is included.\n- \"processing\": the wait budget elapsed but the job is still running. This is NORMAL for video, 3D, training, or a busy queue. A request_id, status_url, and response_url are returned. Poll check_job, then call get_job_result when queue_status is COMPLETED. Do NOT call run_model again for the same request — that starts a new, billable job.\n\nFor video, 3D, or training (long-running by nature), prefer submit_job + check_job + get_job_result from the start.\nFor image URLs in the output, present them directly to the user.",
69
+ "inputSchema": {
70
+ "type": "object",
71
+ "properties": {
72
+ "endpoint_id": {
73
+ "type": "string",
74
+ "description": "The model endpoint ID (e.g. 'fal-ai/flux/dev')"
75
+ },
76
+ "input": {
77
+ "type": "object",
78
+ "additionalProperties": {},
79
+ "description": "Model input parameters as a JSON object. Use get_model_schema first to see what parameters are accepted."
80
+ },
81
+ "expiration_seconds": {
82
+ "type": "number",
83
+ "description": "Optional CDN expiration in seconds. Generated media will be deleted after this duration. Omit to use account default."
84
+ },
85
+ "store_payload": {
86
+ "type": "boolean",
87
+ "description": "Optional. Set to false to prevent fal from storing the request JSON payload (default: true)."
88
+ }
89
+ },
90
+ "required": [
91
+ "endpoint_id",
92
+ "input"
93
+ ],
94
+ "additionalProperties": false,
95
+ "$schema": "http://json-schema.org/draft-07/schema#"
96
+ }
97
+ },
98
+ {
99
+ "name": "check_job",
100
+ "description": "Check the status of a running fal.ai job.\nUse this for long-running jobs (video generation, training, etc.) or when run_model returns status \"processing\".",
101
+ "inputSchema": {
102
+ "type": "object",
103
+ "properties": {
104
+ "endpoint_id": {
105
+ "type": "string",
106
+ "description": "The model endpoint ID"
107
+ },
108
+ "request_id": {
109
+ "type": "string",
110
+ "description": "The request ID returned by run_model or submit_job"
111
+ },
112
+ "status_url": {
113
+ "type": "string",
114
+ "format": "uri",
115
+ "description": "Canonical status_url returned by submit_job or run_model. Prefer passing this when available."
116
+ }
117
+ },
118
+ "required": [
119
+ "endpoint_id",
120
+ "request_id"
121
+ ],
122
+ "additionalProperties": false,
123
+ "$schema": "http://json-schema.org/draft-07/schema#"
124
+ }
125
+ },
126
+ {
127
+ "name": "upload_file",
128
+ "description": "Upload a file to fal.ai's CDN so it can be used as input to models. Returns a fal.ai CDN URL.\n\nHOW TO USE:\n- PUBLIC URL → pass it as 'url'. Easiest option.\n- LOCAL FILE (recommended for any size) → upload it yourself directly to fal REST API:\n 1. POST https://rest.alpha.fal.ai/storage/upload/initiate with header \"Authorization: Key $FAL_KEY\" and body {\"file_name\":\"...\",\"content_type\":\"...\"}\n 2. PUT the file bytes to the returned upload_url\n 3. Use the returned file_url as the CDN URL\n This avoids token/size limits from passing file content through MCP.\n- LOCAL FILE (small, <1MB) → read the file, base64-encode it, and pass as 'data' with 'file_name'.\n- Do NOT use file_path — it will always fail on hosted MCP servers.",
129
+ "inputSchema": {
130
+ "type": "object",
131
+ "properties": {
132
+ "file_path": {
133
+ "type": "string",
134
+ "description": "Local file path (only works in stdio mode, not HTTP)"
135
+ },
136
+ "url": {
137
+ "type": "string",
138
+ "description": "URL of a remote file to upload to fal.ai CDN"
139
+ },
140
+ "data": {
141
+ "type": "string",
142
+ "description": "Base64-encoded file content. Use this for local files when connected over HTTP."
143
+ },
144
+ "file_name": {
145
+ "type": "string",
146
+ "description": "Filename (required when using 'data')"
147
+ }
148
+ },
149
+ "additionalProperties": false,
150
+ "$schema": "http://json-schema.org/draft-07/schema#"
151
+ }
152
+ },
153
+ {
154
+ "name": "submit_job",
155
+ "description": "Submit a job to the queue WITHOUT waiting for completion. Returns immediately with a request_id.\nUse this instead of run_model for long-running tasks (video generation, 3D, training).\nThen use check_job to poll status and get_job_result to retrieve the result when ready.",
156
+ "inputSchema": {
157
+ "type": "object",
158
+ "properties": {
159
+ "endpoint_id": {
160
+ "type": "string",
161
+ "description": "The model endpoint ID (e.g. 'fal-ai/veo3.1')"
162
+ },
163
+ "input": {
164
+ "type": "object",
165
+ "additionalProperties": {},
166
+ "description": "Model input parameters as a JSON object."
167
+ },
168
+ "expiration_seconds": {
169
+ "type": "number",
170
+ "description": "Optional CDN expiration in seconds for generated media."
171
+ },
172
+ "store_payload": {
173
+ "type": "boolean",
174
+ "description": "Optional. Set to false to prevent fal from storing the request JSON payload."
175
+ }
176
+ },
177
+ "required": [
178
+ "endpoint_id",
179
+ "input"
180
+ ],
181
+ "additionalProperties": false,
182
+ "$schema": "http://json-schema.org/draft-07/schema#"
183
+ }
184
+ },
185
+ {
186
+ "name": "get_pricing",
187
+ "description": "Get pricing information for a fal.ai model. Returns cost per run or per second.\nUse this before running expensive models (video, training) to estimate costs.",
188
+ "inputSchema": {
189
+ "type": "object",
190
+ "properties": {
191
+ "endpoint_id": {
192
+ "type": "string",
193
+ "description": "The model endpoint ID to check pricing for"
194
+ }
195
+ },
196
+ "required": [
197
+ "endpoint_id"
198
+ ],
199
+ "additionalProperties": false,
200
+ "$schema": "http://json-schema.org/draft-07/schema#"
201
+ }
202
+ },
203
+ {
204
+ "name": "get_job_result",
205
+ "description": "Fetch the result for a completed fal.ai queue job.\nUse check_job first when you are not sure the request has completed.",
206
+ "inputSchema": {
207
+ "type": "object",
208
+ "properties": {
209
+ "endpoint_id": {
210
+ "type": "string",
211
+ "description": "The model endpoint ID"
212
+ },
213
+ "request_id": {
214
+ "type": "string",
215
+ "description": "The request ID returned by run_model or submit_job"
216
+ },
217
+ "response_url": {
218
+ "type": "string",
219
+ "format": "uri",
220
+ "description": "Canonical response_url returned by submit_job, run_model, or check_job. Prefer passing this when available."
221
+ }
222
+ },
223
+ "required": [
224
+ "endpoint_id",
225
+ "request_id"
226
+ ],
227
+ "additionalProperties": false,
228
+ "$schema": "http://json-schema.org/draft-07/schema#"
229
+ }
230
+ },
231
+ {
232
+ "name": "cancel_job",
233
+ "description": "Cancel a running fal.ai queue job.\nOnly use this when the user explicitly asks to cancel a specific request_id.",
234
+ "inputSchema": {
235
+ "type": "object",
236
+ "properties": {
237
+ "endpoint_id": {
238
+ "type": "string",
239
+ "description": "The model endpoint ID"
240
+ },
241
+ "request_id": {
242
+ "type": "string",
243
+ "description": "The request ID returned by run_model or submit_job"
244
+ },
245
+ "cancel_url": {
246
+ "type": "string",
247
+ "format": "uri",
248
+ "description": "Canonical cancel_url returned by submit_job, run_model, or check_job. Prefer passing this when available."
249
+ }
250
+ },
251
+ "required": [
252
+ "endpoint_id",
253
+ "request_id"
254
+ ],
255
+ "additionalProperties": false,
256
+ "$schema": "http://json-schema.org/draft-07/schema#"
257
+ }
258
+ },
259
+ {
260
+ "name": "recommend_model",
261
+ "description": "Get model recommendations based on what you want to create.\nSearches the live fal.ai catalog and returns the best models for your use case.\nModels are ranked by platform popularity (most-used models appear first).",
262
+ "inputSchema": {
263
+ "type": "object",
264
+ "properties": {
265
+ "task": {
266
+ "type": "string",
267
+ "description": "What you want to do (e.g. 'generate a photorealistic portrait', 'create a 10s cinematic video from text', 'upscale an image to 4K', 'remove background')"
268
+ }
269
+ },
270
+ "required": [
271
+ "task"
272
+ ],
273
+ "additionalProperties": false,
274
+ "$schema": "http://json-schema.org/draft-07/schema#"
275
+ }
276
+ },
277
+ {
278
+ "name": "search_docs",
279
+ "description": "Search the fal.ai documentation for guides, API references, code examples, and implementation details.\nUse this when you need to understand how fal.ai works, find specific API docs, or get code snippets.",
280
+ "inputSchema": {
281
+ "type": "object",
282
+ "properties": {
283
+ "query": {
284
+ "type": "string",
285
+ "description": "Search query (e.g. 'how to upload a file', 'queue API', 'LoRA training')"
286
+ }
287
+ },
288
+ "required": [
289
+ "query"
290
+ ],
291
+ "additionalProperties": false,
292
+ "$schema": "http://json-schema.org/draft-07/schema#"
293
+ }
294
+ }
295
+ ]
296
+ }
297
+ }
298
+ }
@@ -1,13 +1,108 @@
1
1
  {
2
2
  "format": 1,
3
- "entries": {},
3
+ "entries": {
4
+ "topology/hosts/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85": {
5
+ "key": "topology/hosts/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85",
6
+ "value": {
7
+ "format": 1,
8
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
9
+ "rootId": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
10
+ "identity": {
11
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
12
+ "name": "main",
13
+ "kind": "main",
14
+ "sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
15
+ },
16
+ "startedAt": 1786958035702,
17
+ "updatedAt": 1786958850932,
18
+ "expiresAt": 1786958865932
19
+ },
20
+ "version": 196,
21
+ "updatedAt": 1786958850934,
22
+ "updatedBy": {
23
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
24
+ "name": "main",
25
+ "kind": "main",
26
+ "sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
27
+ }
28
+ },
29
+ "sessions/01a00efe-4e23-7b2b-8583-2e8493780899": {
30
+ "key": "sessions/01a00efe-4e23-7b2b-8583-2e8493780899",
31
+ "value": {
32
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
33
+ "name": "Peer 01a00efe",
34
+ "kind": "peer",
35
+ "status": "running",
36
+ "runner": "pi",
37
+ "transport": "host",
38
+ "cwd": "/Users/monotykamary/VCS/working-remote/open-source/pi-hypercharm-provider",
39
+ "sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899",
40
+ "model": "neuralwatt/kimi-k3",
41
+ "thinking": "max",
42
+ "startedAt": 1786958035702,
43
+ "updatedAt": 1786958850932,
44
+ "pendingMessages": false,
45
+ "local": false
46
+ },
47
+ "version": 196,
48
+ "updatedAt": 1786958850935,
49
+ "updatedBy": {
50
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
51
+ "name": "main",
52
+ "kind": "main",
53
+ "sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
54
+ }
55
+ },
56
+ "topology/participants/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85": {
57
+ "key": "topology/participants/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85",
58
+ "value": {
59
+ "format": 1,
60
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
61
+ "kind": "root",
62
+ "rootId": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
63
+ "ownerHostId": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
64
+ "ownerIdentityId": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
65
+ "name": "main",
66
+ "status": "running",
67
+ "runner": "pi",
68
+ "transport": "host",
69
+ "capabilities": [
70
+ "steer",
71
+ "followUp",
72
+ "fabric"
73
+ ],
74
+ "cwd": "/Users/monotykamary/VCS/working-remote/open-source/pi-hypercharm-provider",
75
+ "sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899",
76
+ "model": "neuralwatt/kimi-k3",
77
+ "thinking": "max",
78
+ "startedAt": 1786958035702,
79
+ "updatedAt": 1786958850932,
80
+ "pendingMessages": false,
81
+ "controlProtocol": "v1"
82
+ },
83
+ "version": 196,
84
+ "updatedAt": 1786958850936,
85
+ "updatedBy": {
86
+ "id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
87
+ "name": "main",
88
+ "kind": "main",
89
+ "sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
90
+ }
91
+ }
92
+ },
4
93
  "versions": {
5
94
  "topology/hosts/e9758aa8c95305a8d60a8aa2c20fd53195591d479b2460e1273457793d3f1fec": 18,
6
95
  "sessions/019fe2c8-1dd2-7435-9fa1-fa664831df18": 17,
7
96
  "topology/participants/e9758aa8c95305a8d60a8aa2c20fd53195591d479b2460e1273457793d3f1fec": 18,
8
97
  "topology/hosts/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f": 632,
9
98
  "sessions/019fe2d3-1ac4-7f63-a2e7-b396c7bb1738": 631,
10
- "topology/participants/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f": 632
99
+ "topology/participants/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f": 632,
100
+ "topology/hosts/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a": 217,
101
+ "sessions/01a00c57-b7aa-7ea3-b78a-11e22d3cdd86": 216,
102
+ "topology/participants/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a": 217,
103
+ "topology/hosts/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85": 196,
104
+ "sessions/01a00efe-4e23-7b2b-8583-2e8493780899": 196,
105
+ "topology/participants/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85": 196
11
106
  },
12
107
  "tombstoneOrder": [
13
108
  "sessions/019fe2c8-1dd2-7435-9fa1-fa664831df18",
@@ -15,6 +110,9 @@
15
110
  "topology/hosts/e9758aa8c95305a8d60a8aa2c20fd53195591d479b2460e1273457793d3f1fec",
16
111
  "sessions/019fe2d3-1ac4-7f63-a2e7-b396c7bb1738",
17
112
  "topology/participants/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f",
18
- "topology/hosts/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f"
113
+ "topology/hosts/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f",
114
+ "sessions/01a00c57-b7aa-7ea3-b78a-11e22d3cdd86",
115
+ "topology/participants/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a",
116
+ "topology/hosts/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a"
19
117
  ]
20
118
  }
package/README.md CHANGED
@@ -15,7 +15,7 @@ _Hyperoptimized coding models — DeepSeek, GLM, Kimi, Qwen, MiniMax, Gemma, GPT
15
15
 
16
16
  ## Features
17
17
 
18
- - **24+ 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
18
+ - **26+ 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
19
19
  - **DeepSeek Native Thinking** — Uses the `deepseek` thinking format for Charm Hyper requests, with native `reasoning_effort` on models that publish levels
20
20
  - **OpenAI-compatible API** via Charm Hyper's `/v1/chat/completions` endpoint
21
21
  - **Official Catalog Sync** from Charm's typed `/v1/provider` endpoint, matching `@charmland/pi-hyper-provider`
@@ -29,17 +29,19 @@ _Hyperoptimized coding models — DeepSeek, GLM, Kimi, Qwen, MiniMax, Gemma, GPT
29
29
  | DeepSeek V4 Flash | Text | 1.0M | 384K | $0.20 | $0.40 |
30
30
  | DeepSeek V4 Flash 0731 | Text | 1.0M | 384K | $0.20 | $0.40 |
31
31
  | DeepSeek V4 Pro | Text | 1.0M | 384K | $2.40 | $4.80 |
32
- | Gemma 4 26B A4B | Text | 256K | 26K | $0.13 | $0.42 |
32
+ | DeepSeek V4 Pro 0813 | Text | 1.0M | 262K | $1.44 | $4.31 |
33
+ | Gemma 4 26B A4B | Text | 256K | 26K | $0.12 | $0.42 |
34
+ | GLM-5 | Text | 203K | 20K | $0.76 | $2.36 |
33
35
  | GLM-5.1 | Text | 203K | 3K | $1.52 | $4.79 |
34
36
  | GLM-5.2 | Text | 1.0M | 33K | $1.40 | $4.40 |
35
- | gpt-oss-120b | Text | 131K | 13K | $0.19 | $0.70 |
36
- | Kimi K2.5 | Text | 262K | 26K | $0.53 | $2.80 |
37
+ | gpt-oss-120b | Text | 131K | 13K | $0.16 | $0.65 |
38
+ | Kimi K2.5 | Text | 262K | 26K | $0.56 | $2.94 |
37
39
  | Kimi K2.6 | Text + Image | 262K | 26K | $0.95 | $4.00 |
38
40
  | Kimi K2.7 Code | Text + Image | 256K | 16K | $0.95 | $4.00 |
39
- | Kimi K3 | Text + Image | 1.0M | 131K | $3.27 | $16.33 |
40
- | Llama 3.3 70B Instruct | Text | 128K | 13K | $0.60 | $0.74 |
41
+ | Kimi K3 | Text + Image | 1.0M | 131K | $3.00 | $15.00 |
42
+ | Llama 3.3 70B Instruct | Text | 128K | 13K | $0.61 | $0.84 |
41
43
  | Llama 4 Maverick 17B 128E Instruct FP8 | Text | 430K | 43K | $0.27 | $0.90 |
42
- | MiniMax M2.7 | Text | 262K | 7K | $0.47 | $1.76 |
44
+ | MiniMax M2.7 | Text | 262K | 7K | $0.43 | $1.62 |
43
45
  | MiniMax M3 | Text + Image | 512K | 512K | $0.33 | $1.31 |
44
46
  | Qwen3 Coder 480B A35B Instruct INT4 Mixed AR | Text | 106K | 11K | $0.45 | $2.15 |
45
47
  | Qwen3 Next 80B A3B Instruct | Text | 262K | 26K | $0.12 | $1.14 |
@@ -1,34 +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.85,
20
- "output": 2.742,
21
- "cacheRead": 0.425,
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-08-08T02:00:08.813Z"
33
- }
34
- }
1
+ {}
package/index.ts CHANGED
@@ -41,6 +41,10 @@
41
41
  * again on pi's agent_settled event (fires only once no automatic retry,
42
42
  * compaction, or queued continuation can follow) — and nowhere else, so
43
43
  * sessions without HyperCharm turns make zero status-related API calls.
44
+ * Between polls the balance moves optimistically: each turn's
45
+ * usage.cost.hypercredits is deducted from the last /v1/credits value at
46
+ * turn_end so the account line tracks spend live; the agent_settled poll
47
+ * reconciles any drift.
44
48
  *
45
49
  * Unit note (observed): 20 hypercredits = $1. usage.cost.hypercredits is in
46
50
  * the same display unit /v1/credits reports; usage.cost.usd ÷ 20 matches.
@@ -92,6 +96,7 @@ import customModelsData from "./custom-models.json" with { type: "json" };
92
96
  import patchData from "./patch.json" with { type: "json" };
93
97
  import deprecatedData from "./deprecated-models.json" with { type: "json" };
94
98
  import {
99
+ applyOptimisticSpend,
95
100
  buildAccountTiers,
96
101
  buildSessionLine,
97
102
  coerceStatusConfig,
@@ -280,8 +285,8 @@ function transformApiModel(apiModel: any): JsonModel | null {
280
285
  cost: {
281
286
  input: apiModel.cost_per_1m_in || 0,
282
287
  output: apiModel.cost_per_1m_out || 0,
283
- cacheRead: apiModel.cost_per_1m_in_cached || 0,
284
- cacheWrite: 0,
288
+ cacheRead: apiModel.cost_per_1m_out_cached || 0,
289
+ cacheWrite: apiModel.cost_per_1m_in_cached || 0,
285
290
  },
286
291
  contextWindow: apiModel.context_window || 0,
287
292
  maxTokens: apiModel.default_max_tokens || apiModel.context_window || 0,
@@ -772,6 +777,13 @@ function commitPending(ctx: ExtensionContext): void {
772
777
  if (!pendingSawUsage && pendingRequests === 0) return;
773
778
  sessionStats.requests += pendingRequests;
774
779
  sessionStats.spendHc += pendingSpendHc;
780
+
781
+ // Optimistic balance: deduct this turn's observed spend so the account
782
+ // line ticks down per turn with zero extra API calls. Every credits poll
783
+ // overwrites account.balance (never adjusts), so this cannot
784
+ // double-count; the agent_settled poll reconciles any drift.
785
+ applyOptimisticSpend(account, pendingSpendHc);
786
+
775
787
  pendingRequests = 0;
776
788
  pendingSpendHc = 0;
777
789
  pendingSawUsage = false;
package/models.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "cost": {
19
19
  "input": 0.2,
20
20
  "output": 0.4,
21
- "cacheRead": 0,
21
+ "cacheRead": 0.04,
22
22
  "cacheWrite": 0
23
23
  },
24
24
  "contextWindow": 1000000,
@@ -49,7 +49,7 @@
49
49
  "cost": {
50
50
  "input": 0.2,
51
51
  "output": 0.4,
52
- "cacheRead": 0,
52
+ "cacheRead": 0.04,
53
53
  "cacheWrite": 0
54
54
  },
55
55
  "contextWindow": 1000000,
@@ -80,7 +80,7 @@
80
80
  "cost": {
81
81
  "input": 2.4,
82
82
  "output": 4.8,
83
- "cacheRead": 0,
83
+ "cacheRead": 0.2,
84
84
  "cacheWrite": 0
85
85
  },
86
86
  "contextWindow": 1000000,
@@ -92,6 +92,37 @@
92
92
  "maxTokensField": "max_tokens"
93
93
  }
94
94
  },
95
+ {
96
+ "id": "deepseek-v4-pro-0813",
97
+ "name": "DeepSeek V4 Pro 0813",
98
+ "reasoning": true,
99
+ "thinkingLevelMap": {
100
+ "off": "none",
101
+ "minimal": null,
102
+ "low": null,
103
+ "medium": null,
104
+ "high": "high",
105
+ "xhigh": "xhigh",
106
+ "max": null
107
+ },
108
+ "input": [
109
+ "text"
110
+ ],
111
+ "cost": {
112
+ "input": 1.437216,
113
+ "output": 4.311648,
114
+ "cacheRead": 0.0479072,
115
+ "cacheWrite": 0
116
+ },
117
+ "contextWindow": 1048576,
118
+ "maxTokens": 262144,
119
+ "compat": {
120
+ "supportsStore": false,
121
+ "supportsReasoningEffort": true,
122
+ "thinkingFormat": "deepseek",
123
+ "maxTokensField": "max_tokens"
124
+ }
125
+ },
95
126
  {
96
127
  "id": "gemma-4-26b-a4b-it",
97
128
  "name": "Gemma 4 26B A4B",
@@ -109,10 +140,10 @@
109
140
  "text"
110
141
  ],
111
142
  "cost": {
112
- "input": 0.126,
143
+ "input": 0.124,
113
144
  "output": 0.42,
114
- "cacheRead": 0.063,
115
- "cacheWrite": 0
145
+ "cacheRead": 0,
146
+ "cacheWrite": 0.062
116
147
  },
117
148
  "contextWindow": 256000,
118
149
  "maxTokens": 25600,
@@ -123,6 +154,37 @@
123
154
  "maxTokensField": "max_tokens"
124
155
  }
125
156
  },
157
+ {
158
+ "id": "glm-5",
159
+ "name": "GLM-5",
160
+ "reasoning": true,
161
+ "thinkingLevelMap": {
162
+ "off": "off",
163
+ "minimal": null,
164
+ "low": null,
165
+ "medium": null,
166
+ "high": null,
167
+ "xhigh": null,
168
+ "max": "max"
169
+ },
170
+ "input": [
171
+ "text"
172
+ ],
173
+ "cost": {
174
+ "input": 0.76,
175
+ "output": 2.356,
176
+ "cacheRead": 0,
177
+ "cacheWrite": 0.38
178
+ },
179
+ "contextWindow": 202752,
180
+ "maxTokens": 20275,
181
+ "compat": {
182
+ "supportsStore": false,
183
+ "supportsReasoningEffort": false,
184
+ "thinkingFormat": "deepseek",
185
+ "maxTokensField": "max_tokens"
186
+ }
187
+ },
126
188
  {
127
189
  "id": "glm-5.1",
128
190
  "name": "GLM-5.1",
@@ -142,7 +204,7 @@
142
204
  "cost": {
143
205
  "input": 1.52432,
144
206
  "output": 4.79072,
145
- "cacheRead": 0,
207
+ "cacheRead": 0.283088,
146
208
  "cacheWrite": 0
147
209
  },
148
210
  "contextWindow": 202800,
@@ -173,7 +235,7 @@
173
235
  "cost": {
174
236
  "input": 1.4,
175
237
  "output": 4.4,
176
- "cacheRead": 0,
238
+ "cacheRead": 0.28,
177
239
  "cacheWrite": 0
178
240
  },
179
241
  "contextWindow": 1000000,
@@ -202,9 +264,9 @@
202
264
  "text"
203
265
  ],
204
266
  "cost": {
205
- "input": 0.188,
206
- "output": 0.7,
207
- "cacheRead": 0.094,
267
+ "input": 0.16332,
268
+ "output": 0.65328,
269
+ "cacheRead": 0.0152432,
208
270
  "cacheWrite": 0
209
271
  },
210
272
  "contextWindow": 131072,
@@ -233,10 +295,10 @@
233
295
  "text"
234
296
  ],
235
297
  "cost": {
236
- "input": 0.532,
237
- "output": 2.8,
238
- "cacheRead": 0.266,
239
- "cacheWrite": 0
298
+ "input": 0.558,
299
+ "output": 2.94,
300
+ "cacheRead": 0,
301
+ "cacheWrite": 0.279
240
302
  },
241
303
  "contextWindow": 262144,
242
304
  "maxTokens": 26214,
@@ -267,8 +329,8 @@
267
329
  "cost": {
268
330
  "input": 0.95,
269
331
  "output": 4,
270
- "cacheRead": 0.16,
271
- "cacheWrite": 0
332
+ "cacheRead": 0,
333
+ "cacheWrite": 0.16
272
334
  },
273
335
  "contextWindow": 262000,
274
336
  "maxTokens": 26214,
@@ -290,7 +352,7 @@
290
352
  "cost": {
291
353
  "input": 0.95,
292
354
  "output": 4,
293
- "cacheRead": 0,
355
+ "cacheRead": 0.19,
294
356
  "cacheWrite": 0
295
357
  },
296
358
  "contextWindow": 256000,
@@ -320,10 +382,10 @@
320
382
  "image"
321
383
  ],
322
384
  "cost": {
323
- "input": 3.2664,
324
- "output": 16.332,
385
+ "input": 3,
386
+ "output": 15,
325
387
  "cacheRead": 0,
326
- "cacheWrite": 0
388
+ "cacheWrite": 0.3
327
389
  },
328
390
  "contextWindow": 1048576,
329
391
  "maxTokens": 131072,
@@ -351,10 +413,10 @@
351
413
  "text"
352
414
  ],
353
415
  "cost": {
354
- "input": 0.598,
355
- "output": 0.738,
356
- "cacheRead": 0.299,
357
- "cacheWrite": 0
416
+ "input": 0.608,
417
+ "output": 0.838,
418
+ "cacheRead": 0,
419
+ "cacheWrite": 0.304
358
420
  },
359
421
  "contextWindow": 128000,
360
422
  "maxTokens": 12800,
@@ -384,8 +446,8 @@
384
446
  "cost": {
385
447
  "input": 0.274,
386
448
  "output": 0.8992,
387
- "cacheRead": 0.137,
388
- "cacheWrite": 0
449
+ "cacheRead": 0,
450
+ "cacheWrite": 0.137
389
451
  },
390
452
  "contextWindow": 430000,
391
453
  "maxTokens": 43000,
@@ -404,10 +466,10 @@
404
466
  "text"
405
467
  ],
406
468
  "cost": {
407
- "input": 0.47,
408
- "output": 1.76,
409
- "cacheRead": 0.235,
410
- "cacheWrite": 0
469
+ "input": 0.426,
470
+ "output": 1.62,
471
+ "cacheRead": 0,
472
+ "cacheWrite": 0.213
411
473
  },
412
474
  "contextWindow": 262100,
413
475
  "maxTokens": 6553,
@@ -438,7 +500,7 @@
438
500
  "cost": {
439
501
  "input": 0.32664,
440
502
  "output": 1.30656,
441
- "cacheRead": 0,
503
+ "cacheRead": 0.0642392,
442
504
  "cacheWrite": 0
443
505
  },
444
506
  "contextWindow": 512000,
@@ -460,8 +522,8 @@
460
522
  "cost": {
461
523
  "input": 0.445,
462
524
  "output": 2.145,
463
- "cacheRead": 0.2225,
464
- "cacheWrite": 0
525
+ "cacheRead": 0,
526
+ "cacheWrite": 0.2225
465
527
  },
466
528
  "contextWindow": 106000,
467
529
  "maxTokens": 10600,
@@ -482,8 +544,8 @@
482
544
  "cost": {
483
545
  "input": 0.1175,
484
546
  "output": 1.136,
485
- "cacheRead": 0.05875,
486
- "cacheWrite": 0
547
+ "cacheRead": 0,
548
+ "cacheWrite": 0.05875
487
549
  },
488
550
  "contextWindow": 262144,
489
551
  "maxTokens": 26214,
@@ -514,8 +576,8 @@
514
576
  "cost": {
515
577
  "input": 1,
516
578
  "output": 4,
517
- "cacheRead": 1.25,
518
- "cacheWrite": 0
579
+ "cacheRead": 0.1,
580
+ "cacheWrite": 1.25
519
581
  },
520
582
  "contextWindow": 1000000,
521
583
  "maxTokens": 64000,
@@ -545,8 +607,8 @@
545
607
  "cost": {
546
608
  "input": 2,
547
609
  "output": 12,
548
- "cacheRead": 2.5,
549
- "cacheWrite": 0
610
+ "cacheRead": 0.2,
611
+ "cacheWrite": 2.5
550
612
  },
551
613
  "contextWindow": 256000,
552
614
  "maxTokens": 64000,
@@ -577,8 +639,8 @@
577
639
  "cost": {
578
640
  "input": 2,
579
641
  "output": 6,
580
- "cacheRead": 2.5,
581
- "cacheWrite": 0
642
+ "cacheRead": 0.2,
643
+ "cacheWrite": 2.5
582
644
  },
583
645
  "contextWindow": 1000000,
584
646
  "maxTokens": 64000,
@@ -609,7 +671,7 @@
609
671
  "cost": {
610
672
  "input": 0.2,
611
673
  "output": 0.8,
612
- "cacheRead": 0,
674
+ "cacheRead": 0.04,
613
675
  "cacheWrite": 0
614
676
  },
615
677
  "contextWindow": 1000000,
@@ -640,7 +702,7 @@
640
702
  "cost": {
641
703
  "input": 2.5,
642
704
  "output": 7.5,
643
- "cacheRead": 0,
705
+ "cacheRead": 0.5,
644
706
  "cacheWrite": 0
645
707
  },
646
708
  "contextWindow": 1000000,
@@ -672,7 +734,7 @@
672
734
  "cost": {
673
735
  "input": 1.2,
674
736
  "output": 4.8,
675
- "cacheRead": 0,
737
+ "cacheRead": 0.24,
676
738
  "cacheWrite": 0
677
739
  },
678
740
  "contextWindow": 1000000,
@@ -704,7 +766,7 @@
704
766
  "cost": {
705
767
  "input": 2,
706
768
  "output": 6,
707
- "cacheRead": 0,
769
+ "cacheRead": 0.25,
708
770
  "cacheWrite": 0
709
771
  },
710
772
  "contextWindow": 1000000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-hypercharm-provider",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
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",
@@ -255,10 +255,10 @@ function transformModel(apiModel) {
255
255
  cost: {
256
256
  input: typeof apiModel.cost_per_1m_in === 'number' ? apiModel.cost_per_1m_in : 0,
257
257
  output: typeof apiModel.cost_per_1m_out === 'number' ? apiModel.cost_per_1m_out : 0,
258
- cacheRead: typeof apiModel.cost_per_1m_in_cached === 'number' ? apiModel.cost_per_1m_in_cached : 0,
259
- // Hyper exposes discounted cached-output pricing, not cache-write pricing;
260
- // pi's cost.cacheWrite field remains unused. This matches Charm's official extension.
261
- cacheWrite: 0,
258
+ // Matches Charm's official extension: cacheRead is the discounted cached-output
259
+ // price, cacheWrite the cached-input price.
260
+ cacheRead: typeof apiModel.cost_per_1m_out_cached === 'number' ? apiModel.cost_per_1m_out_cached : 0,
261
+ cacheWrite: typeof apiModel.cost_per_1m_in_cached === 'number' ? apiModel.cost_per_1m_in_cached : 0,
262
262
  },
263
263
  contextWindow: apiModel.context_window || 0,
264
264
  maxTokens: apiModel.default_max_tokens || apiModel.context_window || 0,
package/status.ts CHANGED
@@ -96,6 +96,19 @@ export interface SessionStats {
96
96
 
97
97
  export const EMPTY_SESSION_STATS: SessionStats = { requests: 0, spendHc: 0 };
98
98
 
99
+ /**
100
+ * Optimistically deduct observed turn spend from the last polled balance.
101
+ * Safe against double-counting only because callers overwrite (never adjust)
102
+ * `balance` on every credits poll — the agent_settled poll reconciles drift.
103
+ * Unknown balances stay unknown; estimates clamp at 0 (real exhaustion is
104
+ * still signaled by the 402 path, not by an estimated zero).
105
+ */
106
+ export function applyOptimisticSpend(acc: AccountState, spendHc: number): void {
107
+ if (spendHc > 0 && acc.balance !== null) {
108
+ acc.balance = Math.max(0, acc.balance - spendHc);
109
+ }
110
+ }
111
+
99
112
  // ─── Formatters ───────────────────────────────────────────────────────────────
100
113
 
101
114
  function trimZeros(text: string): string {
@@ -9,6 +9,7 @@ import {
9
9
  EMPTY_ACCOUNT,
10
10
  StatusLineWidget,
11
11
  accountHasData,
12
+ applyOptimisticSpend,
12
13
  buildAccountTiers,
13
14
  buildSessionLine,
14
15
  coerceStatusConfig,
@@ -65,6 +66,20 @@ const balOnly = buildAccountTiers(acc({ balance: 12 }), true);
65
66
  assert.equal(balOnly[0], "⚠ ◆ 12 hc");
66
67
  assert.ok(balOnly.includes("12 hc"));
67
68
 
69
+ // optimistic spend deduction
70
+ {
71
+ const opt = acc({ balance: 249 });
72
+ applyOptimisticSpend(opt, 0.5);
73
+ assert.equal(opt.balance, 248.5);
74
+ applyOptimisticSpend(opt, 0); // zero spend is a no-op
75
+ assert.equal(opt.balance, 248.5);
76
+ applyOptimisticSpend(opt, 300); // clamps at 0, never negative
77
+ assert.equal(opt.balance, 0);
78
+ const unknown = acc({ balance: null });
79
+ applyOptimisticSpend(unknown, 1); // unknown balance stays unknown
80
+ assert.equal(unknown.balance, null);
81
+ }
82
+
68
83
  // ── width math ──
69
84
  assert.equal(termVisWidth("abc"), 3);
70
85
  assert.equal(termVisWidth(""), 0);