troxy-cli 1.29.61 → 1.29.62
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "troxy-cli",
|
|
3
|
-
"version": "1.29.
|
|
3
|
+
"version": "1.29.62",
|
|
4
4
|
"description": "A secure control layer for AI agents: policies across payments, messages, logins, destructive actions, model usage, and secrets, all enforceable from the CLI",
|
|
5
5
|
"homepage": "https://troxy.io",
|
|
6
6
|
"bugs": {
|
|
@@ -156,25 +156,17 @@ function bar(fraction) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
// One line, most important first, e.g.
|
|
159
|
-
//
|
|
159
|
+
// This session: savings under measurement · 5h: 19% used · 7d: 12% used
|
|
160
160
|
function savedLine(money, rateLimits = []) {
|
|
161
|
-
const paid = money && money.cost_paid_usd
|
|
161
|
+
const paid = money && money.cost_paid_usd;
|
|
162
162
|
if (!(paid > 0)) return undefined;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const used = Math.round(w.percentUsed);
|
|
171
|
-
parts.push(`${WINDOW_LABEL[w.kind]}: ${used < 1 ? 'not moved yet' : `${used} instead of ${Math.round(used * scale)}`}`);
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
parts.push('meter not moved yet');
|
|
175
|
-
}
|
|
176
|
-
parts.push('estimate');
|
|
177
|
-
return `${bar(1 / scale)} ${parts.join(' · ')}`;
|
|
163
|
+
// No "N times longer" claim: the 2026-10-15/16 fixed-job A/Bs (Troxy on vs off, bar read
|
|
164
|
+
// from Claude Code) found routing used MORE bar, so the estimate is not shown until a
|
|
165
|
+
// measured replacement exists.
|
|
166
|
+
const moved = rateLimits.filter(w => WINDOW_LABEL[w.kind] && Math.round(w.percentUsed) >= 1);
|
|
167
|
+
if (!(money.dollars_saved_usd > 0) && !moved.length) return undefined; // nothing routed or cleared yet
|
|
168
|
+
return ['This session: savings under measurement',
|
|
169
|
+
...moved.map(w => `${WINDOW_LABEL[w.kind]}: ${Math.round(w.percentUsed)}% used`)].join(' · ');
|
|
178
170
|
}
|
|
179
171
|
|
|
180
172
|
// t.kept: what the content Troxy cleared or compressed would have cost (server's
|
|
@@ -63,20 +63,16 @@ test('real subprocess: a real Bash command still runs normally through the mod (
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
test('savedLine:
|
|
66
|
+
test('savedLine: no savings claim until measured, then the meter', () => {
|
|
67
67
|
const { savedLine } = _internal;
|
|
68
68
|
const meter = [{ kind: 'five_hour', percentUsed: 19 }, { kind: 'seven_day', percentUsed: 12.4 }];
|
|
69
69
|
assert.equal(savedLine({ cost_paid_usd: 19, dollars_saved_usd: 13 }, meter),
|
|
70
|
-
'
|
|
70
|
+
'This session: savings under measurement · 5h: 19% used · 7d: 12% used');
|
|
71
71
|
assert.equal(savedLine({ cost_paid_usd: 92, dollars_saved_usd: 8 }, [{ kind: 'five_hour', percentUsed: 12 }, { kind: 'seven_day', percentUsed: 0 }]),
|
|
72
|
-
'
|
|
73
|
-
assert.equal(savedLine({ cost_paid_usd: 1.64, dollars_saved_usd: 4.53 }, [
|
|
74
|
-
'[███░░░░░░░] This session: your bar lasts 3.8x longer · meter not moved yet · estimate');
|
|
75
|
-
assert.equal(savedLine({ cost_paid_usd: 92, dollars_saved_usd: 8 }, []),
|
|
76
|
-
'[█████████░] This session: your bar lasts 1.09x longer · meter not moved yet · estimate');
|
|
77
|
-
assert.equal(savedLine({ cost_paid_usd: 10, dollars_saved_usd: 0 }, meter),
|
|
78
|
-
'[██████████] This session: your bar lasts 1.00x longer · 5h: 19 instead of 19 · 7d: 12 instead of 12 · estimate');
|
|
72
|
+
'This session: savings under measurement · 5h: 12% used');
|
|
73
|
+
assert.equal(savedLine({ cost_paid_usd: 1.64, dollars_saved_usd: 4.53 }, []), 'This session: savings under measurement');
|
|
79
74
|
assert.equal(savedLine(null, meter), undefined);
|
|
75
|
+
assert.doesNotMatch(savedLine({ cost_paid_usd: 10, dollars_saved_usd: 50 }, meter), /longer|instead of/);
|
|
80
76
|
});
|
|
81
77
|
|
|
82
78
|
test('addTurn: a session total from its own turns, a routed one counted at the asked-for price', () => {
|
|
@@ -87,11 +83,11 @@ test('addTurn: a session total from its own turns, a routed one counted at the a
|
|
|
87
83
|
// Not routed; the 5h window reset mid-turn, so its move counts as 0, not negative.
|
|
88
84
|
t = addTurn(t, { cost: 1.5, meter: { five_hour: 13, seven_day: 5 } }, { cost: 2, meter: { five_hour: 1, seven_day: 6 } }, 1);
|
|
89
85
|
assert.deepEqual(t, { paid: 1, full: 1.5, meter: { five_hour: 3, seven_day: 2 } });
|
|
90
|
-
assert.equal(sessionLine(t), '
|
|
86
|
+
assert.equal(sessionLine(t), 'This session: savings under measurement · 5h: 3% used · 7d: 2% used');
|
|
91
87
|
// Cleared/compressed content counts too, and survives the next turn: $1 paid, $0.5 swap + $1.5 kept = 3x.
|
|
92
88
|
t = addTurn({ ...t, kept: 1.5 }, { cost: 2, meter: {} }, { cost: 2, meter: {} }, 1);
|
|
93
89
|
assert.equal(t.kept, 1.5);
|
|
94
|
-
assert.match(sessionLine(t), /
|
|
90
|
+
assert.match(sessionLine(t), /savings under measurement · 5h: 3% used/);
|
|
95
91
|
// Server total of a session already 28 dollars deep: only growth after the first reading counts.
|
|
96
92
|
const { withKept } = _internal;
|
|
97
93
|
let k = { paid: 1, full: 1, meter: {} };
|
|
@@ -109,7 +105,7 @@ test('statusText: version, routing, this session, plan usage, where the account
|
|
|
109
105
|
const totals = { paid: 0.03, full: 0.12, meter: {} };
|
|
110
106
|
assert.equal(statusText({ version: '1.29.42', paused: false, totals, rateLimits: [{ kind: 'five_hour', percentUsed: 23.4 }, { kind: 'seven_day', percentUsed: 77 }] }),
|
|
111
107
|
'Troxy 1.29.42 · routing is on\n'
|
|
112
|
-
+ 'This session:
|
|
108
|
+
+ 'This session: savings under measurement\n'
|
|
113
109
|
+ 'Plan usage now: 5h 23% · 7d 77%\n'
|
|
114
110
|
+ 'The model is picked at the start, after an hour idle or after a compaction, then kept (switching would rewrite the cache). /model always wins.\n'
|
|
115
111
|
+ 'Idle compaction is on: sessions over 100k tokens are compacted after 55 min idle (/troxy compact off).\n'
|