pi-hypercharm-provider 1.2.3 → 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.
- package/.pi/fabric/mesh/state.json +49 -43
- package/index.ts +12 -0
- package/package.json +1 -1
- package/status.ts +13 -0
- package/tests/status.smoke.ts +15 -0
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
3
|
"entries": {
|
|
4
|
-
"topology/hosts/
|
|
5
|
-
"key": "topology/hosts/
|
|
4
|
+
"topology/hosts/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85": {
|
|
5
|
+
"key": "topology/hosts/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85",
|
|
6
6
|
"value": {
|
|
7
7
|
"format": 1,
|
|
8
|
-
"id": "session:
|
|
9
|
-
"rootId": "session:
|
|
8
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
9
|
+
"rootId": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
10
10
|
"identity": {
|
|
11
|
-
"id": "session:
|
|
11
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
12
12
|
"name": "main",
|
|
13
13
|
"kind": "main",
|
|
14
|
-
"sessionId": "
|
|
14
|
+
"sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
|
|
15
15
|
},
|
|
16
|
-
"startedAt":
|
|
17
|
-
"updatedAt":
|
|
18
|
-
"expiresAt":
|
|
16
|
+
"startedAt": 1786958035702,
|
|
17
|
+
"updatedAt": 1786958850932,
|
|
18
|
+
"expiresAt": 1786958865932
|
|
19
19
|
},
|
|
20
|
-
"version":
|
|
21
|
-
"updatedAt":
|
|
20
|
+
"version": 196,
|
|
21
|
+
"updatedAt": 1786958850934,
|
|
22
22
|
"updatedBy": {
|
|
23
|
-
"id": "session:
|
|
23
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
24
24
|
"name": "main",
|
|
25
25
|
"kind": "main",
|
|
26
|
-
"sessionId": "
|
|
26
|
+
"sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
-
"sessions/
|
|
30
|
-
"key": "sessions/
|
|
29
|
+
"sessions/01a00efe-4e23-7b2b-8583-2e8493780899": {
|
|
30
|
+
"key": "sessions/01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
31
31
|
"value": {
|
|
32
|
-
"id": "session:
|
|
33
|
-
"name": "Peer
|
|
32
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
33
|
+
"name": "Peer 01a00efe",
|
|
34
34
|
"kind": "peer",
|
|
35
35
|
"status": "running",
|
|
36
36
|
"runner": "pi",
|
|
37
37
|
"transport": "host",
|
|
38
38
|
"cwd": "/Users/monotykamary/VCS/working-remote/open-source/pi-hypercharm-provider",
|
|
39
|
-
"sessionId": "
|
|
40
|
-
"model": "
|
|
39
|
+
"sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
40
|
+
"model": "neuralwatt/kimi-k3",
|
|
41
41
|
"thinking": "max",
|
|
42
|
-
"startedAt":
|
|
43
|
-
"updatedAt":
|
|
42
|
+
"startedAt": 1786958035702,
|
|
43
|
+
"updatedAt": 1786958850932,
|
|
44
44
|
"pendingMessages": false,
|
|
45
45
|
"local": false
|
|
46
46
|
},
|
|
47
|
-
"version":
|
|
48
|
-
"updatedAt":
|
|
47
|
+
"version": 196,
|
|
48
|
+
"updatedAt": 1786958850935,
|
|
49
49
|
"updatedBy": {
|
|
50
|
-
"id": "session:
|
|
50
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
51
51
|
"name": "main",
|
|
52
52
|
"kind": "main",
|
|
53
|
-
"sessionId": "
|
|
53
|
+
"sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
|
-
"topology/participants/
|
|
57
|
-
"key": "topology/participants/
|
|
56
|
+
"topology/participants/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85": {
|
|
57
|
+
"key": "topology/participants/b98efd3cf26df4c69c6deae014475c4c0c080b1d0e5ef1cb0ebcc8dca7501c85",
|
|
58
58
|
"value": {
|
|
59
59
|
"format": 1,
|
|
60
|
-
"id": "session:
|
|
60
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
61
61
|
"kind": "root",
|
|
62
|
-
"rootId": "session:
|
|
63
|
-
"ownerHostId": "session:
|
|
64
|
-
"ownerIdentityId": "session:
|
|
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
65
|
"name": "main",
|
|
66
66
|
"status": "running",
|
|
67
67
|
"runner": "pi",
|
|
@@ -72,21 +72,21 @@
|
|
|
72
72
|
"fabric"
|
|
73
73
|
],
|
|
74
74
|
"cwd": "/Users/monotykamary/VCS/working-remote/open-source/pi-hypercharm-provider",
|
|
75
|
-
"sessionId": "
|
|
76
|
-
"model": "
|
|
75
|
+
"sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
76
|
+
"model": "neuralwatt/kimi-k3",
|
|
77
77
|
"thinking": "max",
|
|
78
|
-
"startedAt":
|
|
79
|
-
"updatedAt":
|
|
78
|
+
"startedAt": 1786958035702,
|
|
79
|
+
"updatedAt": 1786958850932,
|
|
80
80
|
"pendingMessages": false,
|
|
81
81
|
"controlProtocol": "v1"
|
|
82
82
|
},
|
|
83
|
-
"version":
|
|
84
|
-
"updatedAt":
|
|
83
|
+
"version": 196,
|
|
84
|
+
"updatedAt": 1786958850936,
|
|
85
85
|
"updatedBy": {
|
|
86
|
-
"id": "session:
|
|
86
|
+
"id": "session:01a00efe-4e23-7b2b-8583-2e8493780899",
|
|
87
87
|
"name": "main",
|
|
88
88
|
"kind": "main",
|
|
89
|
-
"sessionId": "
|
|
89
|
+
"sessionId": "01a00efe-4e23-7b2b-8583-2e8493780899"
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
},
|
|
@@ -97,9 +97,12 @@
|
|
|
97
97
|
"topology/hosts/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f": 632,
|
|
98
98
|
"sessions/019fe2d3-1ac4-7f63-a2e7-b396c7bb1738": 631,
|
|
99
99
|
"topology/participants/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f": 632,
|
|
100
|
-
"topology/hosts/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a":
|
|
101
|
-
"sessions/01a00c57-b7aa-7ea3-b78a-11e22d3cdd86":
|
|
102
|
-
"topology/participants/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a":
|
|
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
|
|
103
106
|
},
|
|
104
107
|
"tombstoneOrder": [
|
|
105
108
|
"sessions/019fe2c8-1dd2-7435-9fa1-fa664831df18",
|
|
@@ -107,6 +110,9 @@
|
|
|
107
110
|
"topology/hosts/e9758aa8c95305a8d60a8aa2c20fd53195591d479b2460e1273457793d3f1fec",
|
|
108
111
|
"sessions/019fe2d3-1ac4-7f63-a2e7-b396c7bb1738",
|
|
109
112
|
"topology/participants/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f",
|
|
110
|
-
"topology/hosts/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f"
|
|
113
|
+
"topology/hosts/e0efb9d647e046c355b8bff12785e7805d774e7b89892edb38b4b29667ddc15f",
|
|
114
|
+
"sessions/01a00c57-b7aa-7ea3-b78a-11e22d3cdd86",
|
|
115
|
+
"topology/participants/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a",
|
|
116
|
+
"topology/hosts/3195ffccdcff6cb767344b2d1af6c5f3e1e3e4a9906a81129ffaf24352769d2a"
|
|
111
117
|
]
|
|
112
118
|
}
|
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,
|
|
@@ -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-hypercharm-provider",
|
|
3
|
-
"version": "1.
|
|
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",
|
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 {
|
package/tests/status.smoke.ts
CHANGED
|
@@ -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);
|