aegis-desktop 0.7.7 → 0.7.8
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 +103 -17
- package/lib/local/endpoints.js +228 -0
- package/lib/local/engine.js +138 -18
- package/lib/settings.js +42 -1
- package/package.json +4 -3
- package/renderer/app.js +179 -63
- package/renderer/index.html +1 -0
- package/renderer/preset-fill.js +79 -0
- package/renderer/stream-policy.js +65 -1
- package/renderer/transcript-view.js +5 -0
- package/renderer/usage.js +42 -11
- package/vendor/aegis.js +21 -3
package/renderer/usage.js
CHANGED
|
@@ -159,23 +159,54 @@ const RATES = {
|
|
|
159
159
|
deepseek: { input: 0.14, output: 0.28, cacheRead: 0.014, cacheWrite: 0.14 },
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* The rate rows a model id may name as a whole word rather than as a prefix.
|
|
164
|
+
* Anthropic spells its family *inside* the id — "claude-opus-4" matches no
|
|
165
|
+
* prefix — so prefix matching alone cannot see it.
|
|
166
|
+
*/
|
|
167
|
+
const RATE_FAMILIES = Object.keys(RATES).filter((k) => k !== 'default');
|
|
168
|
+
|
|
162
169
|
/**
|
|
163
170
|
* The rate row for a model id, provider, or alias. Exact id wins, then the
|
|
164
|
-
* longest matching prefix, then the
|
|
171
|
+
* longest matching prefix, then a family named inside the id, then the
|
|
172
|
+
* Sonnet-class default.
|
|
165
173
|
*/
|
|
166
174
|
function ratesFor(model) {
|
|
167
|
-
const
|
|
168
|
-
if (!
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
const raw = String(model || '').toLowerCase();
|
|
176
|
+
if (!raw) return RATES.default;
|
|
177
|
+
// A byok model id carries its provider as a routing label:
|
|
178
|
+
// "anthropic:claude-opus-4", "deepseek:deepseek-v4-flash". The label is not
|
|
179
|
+
// a rate, and rating it as written fell through every prefix to
|
|
180
|
+
// RATES.default — so an Opus BYOK turn was priced at Sonnet's $3/$15 against
|
|
181
|
+
// the vendor's real $5/$25. 15x, on the one class whose figure can only ever
|
|
182
|
+
// be an estimate, because there the vendor bills the caller and AEGIS only
|
|
183
|
+
// relays. Try the whole id first, then the model behind the label.
|
|
184
|
+
const ids = [raw];
|
|
185
|
+
const tail = raw.slice(raw.lastIndexOf(':') + 1);
|
|
186
|
+
if (tail && tail !== raw) ids.push(tail);
|
|
187
|
+
for (const id of ids) {
|
|
188
|
+
if (RATES[id]) return RATES[id];
|
|
189
|
+
let best = null;
|
|
190
|
+
let bestLen = 0;
|
|
191
|
+
for (const [prefix, rates] of Object.entries(RATES)) {
|
|
192
|
+
if (id.startsWith(prefix) && prefix.length > bestLen) {
|
|
193
|
+
best = rates;
|
|
194
|
+
bestLen = prefix.length;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (best) return best;
|
|
198
|
+
}
|
|
199
|
+
// Longest family-key hit wins, so an overlapping pair resolves the same way
|
|
200
|
+
// twice running rather than by object key order.
|
|
201
|
+
let family = null;
|
|
202
|
+
let familyLen = 0;
|
|
203
|
+
for (const key of RATE_FAMILIES) {
|
|
204
|
+
if (raw.includes(key) && key.length > familyLen) {
|
|
205
|
+
family = RATES[key];
|
|
206
|
+
familyLen = key.length;
|
|
176
207
|
}
|
|
177
208
|
}
|
|
178
|
-
return
|
|
209
|
+
return family || RATES.default;
|
|
179
210
|
}
|
|
180
211
|
|
|
181
212
|
/**
|
package/vendor/aegis.js
CHANGED
|
@@ -354,9 +354,27 @@ function createClient(opts = {}) {
|
|
|
354
354
|
*
|
|
355
355
|
* The caller's *AEGIS* key is sent alongside the provider key as X-AEGIS-Key.
|
|
356
356
|
* Two credentials, two headers, on purpose: the provider key authenticates the
|
|
357
|
-
* upstream call, the AEGIS key says whose bank pays the handling fee
|
|
358
|
-
*
|
|
359
|
-
*
|
|
357
|
+
* upstream call, the AEGIS key says whose bank pays the handling fee —
|
|
358
|
+
* `_byok_identify_user` on the server resolves the payer from it, and nothing
|
|
359
|
+
* else. With no AEGIS key the header is omitted and the call is anonymous;
|
|
360
|
+
* THIS function still sends it, because it is a transport and the route is
|
|
361
|
+
* unauthenticated by design (aegis1 tests/test_byok_fee.py pins the anonymous
|
|
362
|
+
* path as allowed) — refusing here would break every other caller of a
|
|
363
|
+
* published endpoint.
|
|
364
|
+
*
|
|
365
|
+
* Attribution is the whole game, because an unattributed turn is the one way
|
|
366
|
+
* a BYOK call escapes the fee: the relay serves it, `charge_byok` never runs
|
|
367
|
+
* (`app.py` charges only `if _byok_user_id:`), and the call is logged against
|
|
368
|
+
* user 0 as uncollected — a free ride. So the shipped HOSTS refuse a keyless
|
|
369
|
+
* BYOK send before the relay is reached: desktop/lib/local/engine.js raises
|
|
370
|
+
* 401, and the desktop app and the CLI share that engine (the CLI stages it
|
|
371
|
+
* as cli/vendor/desktop/lib/local/engine.js), so one gate covers both. Every
|
|
372
|
+
* turn is then attributable, and therefore billable: a funded balance is
|
|
373
|
+
* debited, an unfunded one is recorded as owed — `charge_byok` clamps the
|
|
374
|
+
* debit at zero and never refuses the call, so "cannot pay" and "must not be
|
|
375
|
+
* billed" stop being the same thing. `AEGIS_BYOK_REQUIRE_BALANCE` (off by
|
|
376
|
+
* default) remains the server's own, separate 402 gate and is not what makes
|
|
377
|
+
* the fee land.
|
|
360
378
|
*/
|
|
361
379
|
async function byokChatCompletion({
|
|
362
380
|
provider = 'openai',
|