troxy-cli 1.29.53 → 1.29.54
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.54",
|
|
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": {
|
package/src/interceptor.js
CHANGED
|
@@ -118,9 +118,9 @@ function _readModRoute(dir, sessionId) {
|
|
|
118
118
|
const arm = n.arm === 'treated' || n.arm === 'holdout' ? n.arm : null;
|
|
119
119
|
const isFresh = Date.now() - n.ts < _MOD_ROUTE_MAX_AGE_MS;
|
|
120
120
|
const routed = isFresh && typeof n.from === 'string' && typeof n.to === 'string';
|
|
121
|
-
return { arm, from: routed ? n.from : null, to: routed ? n.to : null, compact: isFresh && n.compact === true };
|
|
121
|
+
return { arm, from: routed ? n.from : null, to: routed ? n.to : null, compact: isFresh && n.compact === true, cold: isFresh && typeof n.cold === 'boolean' ? n.cold : null };
|
|
122
122
|
} catch {
|
|
123
|
-
return { arm: null, from: null, to: null, compact: false };
|
|
123
|
+
return { arm: null, from: null, to: null, compact: false, cold: null };
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -183,6 +183,8 @@ export function buildTroxyForwardHeaders(incomingHeaders, troxyKey, sandboxState
|
|
|
183
183
|
if (modRoute && modRoute.arm) headers['x-troxy-mod-arm'] = modRoute.arm;
|
|
184
184
|
// The mod's idle compaction is in flight: this is its summary request.
|
|
185
185
|
if (modRoute && modRoute.compact) headers['x-troxy-mod-compact'] = '1';
|
|
186
|
+
// Tagged: whether this request hit the cold or warm path (for measurement).
|
|
187
|
+
if (modRoute && typeof modRoute.cold === 'boolean') headers['x-troxy-switch'] = modRoute.cold ? 'cold' : 'warm';
|
|
186
188
|
headers.authorization = `Bearer ${troxyKey}`;
|
|
187
189
|
return headers;
|
|
188
190
|
}
|
|
@@ -453,9 +453,10 @@ async function* routeStep($, e, next) {
|
|
|
453
453
|
const h = held.get(sid) || { decision: null, prompts: 0 };
|
|
454
454
|
const newPrompt = Boolean(decision) && decision !== h.decision;
|
|
455
455
|
if (newPrompt) h.decision = decision;
|
|
456
|
+
const isCold = !ls || now - ls.at >= WARM_MS || coldNext.has(sid);
|
|
456
457
|
const model = (await $.store.get('paused')) ? want : stepModel({
|
|
457
458
|
arm, requested: want, switched,
|
|
458
|
-
cold:
|
|
459
|
+
cold: isCold,
|
|
459
460
|
score: decision ? decision.score : null, warm: ls && ls.model,
|
|
460
461
|
newPrompt, heldPrompts: h.prompts, tokens: decision ? decision.tokens : Infinity,
|
|
461
462
|
});
|
|
@@ -470,7 +471,8 @@ async function* routeStep($, e, next) {
|
|
|
470
471
|
const key = `${sid}:${arm}:${want}>${model}`;
|
|
471
472
|
if (file && lastNote !== key) {
|
|
472
473
|
lastNote = key;
|
|
473
|
-
|
|
474
|
+
const route = model === want ? { arm, cold: isCold, ts: now } : { arm, from: want, to: model, cold: isCold, ts: now };
|
|
475
|
+
await $.fs.write(file, JSON.stringify(route));
|
|
474
476
|
}
|
|
475
477
|
try { await rememberAsked($, sid, want, model); } catch {} // a missed write only loses this on resume
|
|
476
478
|
if (model !== want && turn) turn.ratio = PRICE[tierOf(want)] / PRICE[tierOf(model)];
|