acuvo-code 0.5.2 → 0.5.4
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/lib/input-box.mjs +15 -1
- package/lib/tool-prefix.mjs +38 -2
- package/lib/turn.mjs +21 -1
- package/package.json +1 -1
package/lib/input-box.mjs
CHANGED
|
@@ -457,7 +457,21 @@ export function pinRegion(output, { rows = 2, env = process.env } = {}) {
|
|
|
457
457
|
* otherwise sit inside our region and scroll along with the session, so the
|
|
458
458
|
* banner would never be at the top of anything.
|
|
459
459
|
*/
|
|
460
|
-
|
|
460
|
+
/**
|
|
461
|
+
* ⚠️⚠️ `3J` BEFORE `2J`, AND WITHOUT IT THE PROMPT IS OFF-SCREEN. Roman:
|
|
462
|
+
* *"when you type acuvo you have to scroll down to see the prompt area."*
|
|
463
|
+
*
|
|
464
|
+
* `ESC[2J` clears the visible screen but PUSHES what was there into
|
|
465
|
+
* SCROLLBACK — so VS Code (and most terminals) leave the viewport parked up
|
|
466
|
+
* in the history, showing the old shell output with our banner and prompt
|
|
467
|
+
* below the fold. The user has to scroll to find the thing they just started.
|
|
468
|
+
*
|
|
469
|
+
* `ESC[3J` deletes the scrollback itself, so there is nothing above to be
|
|
470
|
+
* parked in and the viewport has nowhere to sit but the top of a clean
|
|
471
|
+
* screen. Both are needed and the order matters: erase the history, erase the
|
|
472
|
+
* screen, then home.
|
|
473
|
+
*/
|
|
474
|
+
output.write(`${CSI}3J${CSI}2J${CSI}1;${bottom}r${CSI}1;1H`);
|
|
461
475
|
|
|
462
476
|
const release = () => {
|
|
463
477
|
if (released) return;
|
package/lib/tool-prefix.mjs
CHANGED
|
@@ -218,9 +218,45 @@ export function alwaysOfferedNames(maxRounds) {
|
|
|
218
218
|
* @param {{ maxRounds?: number }} [opts]
|
|
219
219
|
* @returns {Array<any>} the same schemas, constant ones first
|
|
220
220
|
*/
|
|
221
|
-
export function orderForCachePrefix(schemas, { maxRounds = 8 } = {}) {
|
|
221
|
+
export function orderForCachePrefix(schemas, { maxRounds = 8, shortlist = null } = {}) {
|
|
222
222
|
if (!Array.isArray(schemas) || schemas.length === 0) return Array.isArray(schemas) ? [...schemas] : [];
|
|
223
223
|
const core = alwaysOfferedNames(maxRounds);
|
|
224
224
|
const isCore = (t) => core.has(t?.function?.name);
|
|
225
|
-
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* ── 💰⭐⭐⭐ THE SHORTLIST GOES FIRST, OR A WIDEN BURNS THE WHOLE CACHE ──────
|
|
228
|
+
*
|
|
229
|
+
* MEASURED on a real brief, 2026-08-22: the narrow offer is 27 tools / 24,602
|
|
230
|
+
* bytes and the widened offer is 64 / 62,470 — and only **6,866 bytes were a
|
|
231
|
+
* shared prefix. 27.9%.** So widening rewrote 72% of the tools block, and
|
|
232
|
+
* `tool-prefix`'s own header measures that block at 94% of the shared head.
|
|
233
|
+
* One widen therefore threw away roughly **68% of everything cacheable.**
|
|
234
|
+
*
|
|
235
|
+
* ⚠️ AND THE ORDERING ABOVE DID NOT PREVENT IT. Sorting core-first is correct
|
|
236
|
+
* and insufficient: the SHORTLIST cuts across core-vs-conditional, so a
|
|
237
|
+
* shortlisted conditional tool sits after a non-shortlisted core one, and
|
|
238
|
+
* re-admitting the missing tools INTERLEAVES them into the middle of the
|
|
239
|
+
* block rather than appending.
|
|
240
|
+
*
|
|
241
|
+
* ⭐ THE FIX IS ORDER, NOT CONTENT. If the shortlisted tools are emitted FIRST
|
|
242
|
+
* in a stable order, the narrow block becomes a byte-prefix of the wide one —
|
|
243
|
+
* so widening APPENDS and everything already cached stays cached. The model
|
|
244
|
+
* gains capability and pays only for the tools it just gained.
|
|
245
|
+
*
|
|
246
|
+
* ⚠️ `shortlist` is optional and omitting it keeps the previous behaviour
|
|
247
|
+
* exactly, so nothing that does not know about this changes.
|
|
248
|
+
*/
|
|
249
|
+
const inShortlist = shortlist ? new Set(shortlist) : null;
|
|
250
|
+
const rank = (t) => {
|
|
251
|
+
const name = t?.function?.name;
|
|
252
|
+
if (inShortlist) return inShortlist.has(name) ? (isCore(t) ? 0 : 1) : (isCore(t) ? 2 : 3);
|
|
253
|
+
return isCore(t) ? 0 : 1;
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* ⚠️ A STABLE SORT, AND NODE'S IS GUARANTEED STABLE since V8 7.0 — so tools of
|
|
257
|
+
* equal rank keep their registry order and the block is byte-identical run to
|
|
258
|
+
* run. An unstable sort here would change the prefix on every process for no
|
|
259
|
+
* reason at all, which is the same defect as the random sticky key.
|
|
260
|
+
*/
|
|
261
|
+
return [...schemas].sort((a, b) => rank(a) - rank(b));
|
|
226
262
|
}
|
package/lib/turn.mjs
CHANGED
|
@@ -2713,7 +2713,27 @@ export async function runSession({
|
|
|
2713
2713
|
* definition — they are the one part of the block that CANNOT be shared — so
|
|
2714
2714
|
* they belong behind everything that can be.
|
|
2715
2715
|
*/
|
|
2716
|
-
|
|
2716
|
+
/**
|
|
2717
|
+
* ── 💰⭐⭐⭐ THE ORDERING KEY IS THE *NARROW* LIST, ALWAYS ────────────────────
|
|
2718
|
+
*
|
|
2719
|
+
* Computed with `widened: false` even after a widen, deliberately. It is not
|
|
2720
|
+
* the set of tools to offer — it is the ORDER to emit them in, and it has to
|
|
2721
|
+
* be the same before and after so the narrow block stays a byte-prefix of the
|
|
2722
|
+
* wide one.
|
|
2723
|
+
*
|
|
2724
|
+
* MEASURED before this: a widen shared only **6,866 of 24,602 bytes — 27.9%**
|
|
2725
|
+
* — with the rest of the tools block rewritten. `tool-prefix`'s own header
|
|
2726
|
+
* puts that block at 94% of the shared head, so one widen threw away ~68% of
|
|
2727
|
+
* everything cacheable. With the narrow list pinning the order: **100%.**
|
|
2728
|
+
*
|
|
2729
|
+
* ⚠️ Passing the WIDENED list here would silently undo it — the order would
|
|
2730
|
+
* change the moment it widened, which is the exact failure being fixed.
|
|
2731
|
+
*/
|
|
2732
|
+
const orderKey = shortlistEnabled ? shortlistTools(task ?? '', environmentOffer, { widened: false }) : null;
|
|
2733
|
+
const tools = [
|
|
2734
|
+
...orderForCachePrefix(toolSchemasFor(offered, { shell }), { maxRounds, shortlist: orderKey }),
|
|
2735
|
+
...mcpSchemas,
|
|
2736
|
+
];
|
|
2717
2737
|
/**
|
|
2718
2738
|
* ⚠️ APPEND, NEVER REBUILD. The system prompt and the workspace context are the
|
|
2719
2739
|
* cacheable prefix; a continuing turn adds one user message to the end and
|