troxy-cli 1.30.22 → 1.30.23
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
|
@@ -360,6 +360,22 @@ const COMPACTED = { plugin: 'troxy-guard', key: 'compacted' }; // the band's not
|
|
|
360
360
|
const COMPACTED_SHOW_MS = 10 * 60 * 1000; // kept through prompts for this long, so it isn't missed
|
|
361
361
|
let compactTimer = null;
|
|
362
362
|
|
|
363
|
+
// Big-session compaction: a session past 200k compacts right after an answer, between
|
|
364
|
+
// tasks, while its cache is still warm, instead of re-reading the whole thing on every
|
|
365
|
+
// later call. A/B 2026-11-06 at 350k on Sonnet: 4.0 vs 6.0 bar points for the same 9-step
|
|
366
|
+
// job, the compaction included, same results. The short delay lets the turn settle; a
|
|
367
|
+
// prompt typed first cancels it (scorePrompt), so it never holds the user up.
|
|
368
|
+
// Off unless switched on (config bigCompact, or TROXY_BIG_COMPACT=1) until measured live.
|
|
369
|
+
const BIG_COMPACT_TOKENS = 200000;
|
|
370
|
+
const BIG_COMPACT_DELAY_MS = 3000;
|
|
371
|
+
function afterTurnDelay({ tokens, on, off }) {
|
|
372
|
+
return on && !off && tokens >= BIG_COMPACT_TOKENS ? BIG_COMPACT_DELAY_MS : COMPACT_IDLE_MS;
|
|
373
|
+
}
|
|
374
|
+
async function bigCompactOn($) {
|
|
375
|
+
if ((await $.env.get('TROXY_BIG_COMPACT')) === '1') return true;
|
|
376
|
+
return Boolean((await troxyConfig($)).bigCompact);
|
|
377
|
+
}
|
|
378
|
+
|
|
363
379
|
// What to do when the idle timer fires: skip, compact now, or wait for the meter to reset.
|
|
364
380
|
function compactPlan({ tokens, rateLimits = [], now, off }) {
|
|
365
381
|
if (off || !(tokens >= COMPACT_MIN_TOKENS)) return { action: 'skip' };
|
|
@@ -434,7 +450,7 @@ async function idleCompact($, { late = false } = {}) {
|
|
|
434
450
|
if (r.skip) return;
|
|
435
451
|
const k = n => `${Math.round(n / 1000)}k`;
|
|
436
452
|
await $.state.set(COMPACTED, { at: await $.clock.now(), text: r.tokensBefore && r.tokensAfter
|
|
437
|
-
? `compacted this
|
|
453
|
+
? `compacted this session ${k(r.tokensBefore)} → ${k(r.tokensAfter)} tokens` : 'compacted this session' });
|
|
438
454
|
}
|
|
439
455
|
|
|
440
456
|
// Where the local daemon looks for this session's routing note (see interceptor.js).
|
|
@@ -681,12 +697,16 @@ export function register(on) {
|
|
|
681
697
|
if (line) await $.state.set(LINE, line);
|
|
682
698
|
} catch {} // a missed turn only leaves the band as it was
|
|
683
699
|
}
|
|
684
|
-
let stayAwake = false;
|
|
700
|
+
let stayAwake = false, delay = COMPACT_IDLE_MS;
|
|
685
701
|
try { stayAwake = await bigSession($); } catch {}
|
|
686
|
-
|
|
702
|
+
try {
|
|
703
|
+
delay = afterTurnDelay({ tokens: ((await $.session.usage()).context || {}).tokens || 0,
|
|
704
|
+
on: await bigCompactOn($), off: await $.store.get('compactOff') });
|
|
705
|
+
} catch {}
|
|
706
|
+
armCompact($, delay, { stayAwake: stayAwake && delay === COMPACT_IDLE_MS, persist: true });
|
|
687
707
|
return r;
|
|
688
708
|
});
|
|
689
709
|
}
|
|
690
710
|
|
|
691
711
|
// Exported for tests only - not part of the mod's runtime contract.
|
|
692
|
-
export const _internal = { compressedSince, recalledSince, stepEffort, reportRow, noteStep, flushReport, pendingRows: () => pending, troxyConfig, askedFor, rememberAsked, asked, armCompact, cancelCompact, toDomainAndFields, guardBash, failClosed, parseScore, asRequest, pickModel, troxyCommand, modRouteFile, estimateTokens, MODELS, savedLine, sessionLine, addTurn, withKept, statusText, compactPlan, savingsText, fetchSavings, scorePrompt, routeStep, stepModel, lastSent };
|
|
712
|
+
export const _internal = { compressedSince, recalledSince, stepEffort, reportRow, noteStep, flushReport, pendingRows: () => pending, troxyConfig, askedFor, rememberAsked, asked, armCompact, cancelCompact, afterTurnDelay, toDomainAndFields, guardBash, failClosed, parseScore, asRequest, pickModel, troxyCommand, modRouteFile, estimateTokens, MODELS, savedLine, sessionLine, addTurn, withKept, statusText, compactPlan, savingsText, fetchSavings, scorePrompt, routeStep, stepModel, lastSent };
|
|
@@ -113,6 +113,15 @@ test('statusText: version, routing, this session, plan usage, where the account
|
|
|
113
113
|
assert.match(statusText({ paused: true }), /^Troxy · routing is off\nThis session: nothing moved to a lighter model yet\n/);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
+
test('afterTurnDelay: with bigCompact on, a session past 200k compacts right after the answer', () => {
|
|
117
|
+
const { afterTurnDelay } = _internal;
|
|
118
|
+
const IDLE = 55 * 60 * 1000;
|
|
119
|
+
assert.equal(afterTurnDelay({ tokens: 351000, on: true }), 3000);
|
|
120
|
+
assert.equal(afterTurnDelay({ tokens: 199000, on: true }), IDLE); // under 200k: idle path only
|
|
121
|
+
assert.equal(afterTurnDelay({ tokens: 351000, on: false }), IDLE); // flag off
|
|
122
|
+
assert.equal(afterTurnDelay({ tokens: 351000, on: true, off: true }), IDLE); // /troxy compact off wins
|
|
123
|
+
});
|
|
124
|
+
|
|
116
125
|
test('compactPlan: big idle sessions compact, small ones and a nearly full bar do not', () => {
|
|
117
126
|
const { compactPlan } = _internal;
|
|
118
127
|
const now = Date.parse('2026-10-08T15:00:00Z');
|