@blockrun/franklin 3.15.92 → 3.15.94
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/dist/agent/loop.js +18 -2
- package/dist/commands/doctor.js +12 -4
- package/dist/version-check.d.ts +14 -0
- package/dist/version-check.js +27 -0
- package/package.json +1 -1
package/dist/agent/loop.js
CHANGED
|
@@ -1011,10 +1011,26 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1011
1011
|
// where input-replay tax has clearly started biting; the
|
|
1012
1012
|
// fire-once-per-turn flag still bounds the worst case at one
|
|
1013
1013
|
// extra summary call (~$0.005).
|
|
1014
|
+
//
|
|
1015
|
+
// 2026-05-11: added a high-cost early-exit. The original
|
|
1016
|
+
// (>15 calls AND >$0.03) gate works well for cheap models
|
|
1017
|
+
// where 15 calls clears the $0.03 floor trivially. For Opus-
|
|
1018
|
+
// class models, cost climbs much faster than call count —
|
|
1019
|
+
// verified in production from a real session:
|
|
1020
|
+
// `Research-bloat compacted at 16 calls / $9.4552: ~3129
|
|
1021
|
+
// tokens`. By the time the 16-call gate fired, $9.45 was
|
|
1022
|
+
// already spent on input-replay. With an early-exit at
|
|
1023
|
+
// $1.00 turn-cost, the compact would have fired around
|
|
1024
|
+
// call 4-5, saving ~$8 on that turn. The cost cap is
|
|
1025
|
+
// intentionally conservative — even extended-thinking Opus
|
|
1026
|
+
// shouldn't legitimately need >$1 of context-replay before
|
|
1027
|
+
// compacting (the compact itself runs on a cheaper model
|
|
1028
|
+
// and costs <$0.05).
|
|
1029
|
+
const TURN_COST_CAP_FOR_EARLY_COMPACT = 1.00;
|
|
1014
1030
|
if (!bloatCompactedThisTurn &&
|
|
1015
1031
|
compactFailures < 3 &&
|
|
1016
|
-
turnToolCalls > 15 &&
|
|
1017
|
-
|
|
1032
|
+
((turnToolCalls > 15 && turnCostUsd > 0.03) ||
|
|
1033
|
+
turnCostUsd > TURN_COST_CAP_FOR_EARLY_COMPACT)) {
|
|
1018
1034
|
try {
|
|
1019
1035
|
const beforeTokens = estimateHistoryTokens(history);
|
|
1020
1036
|
const { history: compacted, compacted: didCompact } = await forceCompact(history, config.model, client, config.debug);
|
package/dist/commands/doctor.js
CHANGED
|
@@ -17,9 +17,17 @@ import os from 'node:os';
|
|
|
17
17
|
import { setupAgentWallet, setupAgentSolanaWallet, } from '@blockrun/llm';
|
|
18
18
|
import { loadChain, API_URLS, VERSION, BLOCKRUN_DIR } from '../config.js';
|
|
19
19
|
import { isTelemetryEnabled, readAllRecords } from '../telemetry/store.js';
|
|
20
|
-
import {
|
|
20
|
+
import { getAvailableUpdateFresh, kickoffVersionCheck } from '../version-check.js';
|
|
21
21
|
async function runChecks() {
|
|
22
22
|
const out = [];
|
|
23
|
+
// Kick off the authoritative version fetch FIRST, in parallel with the
|
|
24
|
+
// other checks. Doctor is a diagnostic — the user just asked "am I
|
|
25
|
+
// healthy?" — so a 24h-stale cache is the wrong answer. The fetch is
|
|
26
|
+
// bounded by the same 2s timeout the background check uses, and falls
|
|
27
|
+
// back to the cached value on failure. By the time we render the
|
|
28
|
+
// Franklin-version check below, the fetch has typically settled in
|
|
29
|
+
// <300ms (npm is fast) and we have a current answer.
|
|
30
|
+
const freshUpdatePromise = getAvailableUpdateFresh();
|
|
23
31
|
// ── 1. Runtime ────────────────────────────────────────────────────
|
|
24
32
|
const nodeVer = process.versions.node;
|
|
25
33
|
const nodeMajor = parseInt(nodeVer.split('.')[0], 10);
|
|
@@ -30,10 +38,10 @@ async function runChecks() {
|
|
|
30
38
|
remedy: nodeMajor >= 20 ? undefined : 'Upgrade Node.js: https://nodejs.org',
|
|
31
39
|
});
|
|
32
40
|
// ── 2. Franklin version ───────────────────────────────────────────
|
|
33
|
-
//
|
|
34
|
-
//
|
|
41
|
+
// Keep kickoffVersionCheck() so non-doctor entry points (banner etc.)
|
|
42
|
+
// still warm the cache through their normal daily refresh path.
|
|
35
43
|
kickoffVersionCheck();
|
|
36
|
-
const update =
|
|
44
|
+
const update = await freshUpdatePromise;
|
|
37
45
|
out.push({
|
|
38
46
|
name: 'Franklin',
|
|
39
47
|
status: update ? 'warn' : 'ok',
|
package/dist/version-check.d.ts
CHANGED
|
@@ -37,3 +37,17 @@ export interface UpdateInfo {
|
|
|
37
37
|
* background check settles — returns null (we don't speculate).
|
|
38
38
|
*/
|
|
39
39
|
export declare function getAvailableUpdate(): UpdateInfo | null;
|
|
40
|
+
/**
|
|
41
|
+
* Authoritative check that forces a fresh fetch (up to FETCH_TIMEOUT_MS).
|
|
42
|
+
* Use for on-demand diagnostics like `franklin doctor` where the user
|
|
43
|
+
* explicitly asked "am I up to date?" and a 24h-stale cache is the wrong
|
|
44
|
+
* answer. Verified 2026-05-11: between two same-day releases (3.15.91 →
|
|
45
|
+
* 3.15.92), the daily cache made `franklin doctor` show green for a user
|
|
46
|
+
* who was actually 4 versions behind (3.15.88), because they ran doctor
|
|
47
|
+
* in the brief gap between npm publish and the next cache refresh.
|
|
48
|
+
*
|
|
49
|
+
* Falls back to the cached value if the fetch fails (offline, slow npm,
|
|
50
|
+
* etc.) — same behavior as the cached check, just refreshed when
|
|
51
|
+
* possible.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getAvailableUpdateFresh(): Promise<UpdateInfo | null>;
|
package/dist/version-check.js
CHANGED
|
@@ -132,3 +132,30 @@ export function getAvailableUpdate() {
|
|
|
132
132
|
}
|
|
133
133
|
return null;
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Authoritative check that forces a fresh fetch (up to FETCH_TIMEOUT_MS).
|
|
137
|
+
* Use for on-demand diagnostics like `franklin doctor` where the user
|
|
138
|
+
* explicitly asked "am I up to date?" and a 24h-stale cache is the wrong
|
|
139
|
+
* answer. Verified 2026-05-11: between two same-day releases (3.15.91 →
|
|
140
|
+
* 3.15.92), the daily cache made `franklin doctor` show green for a user
|
|
141
|
+
* who was actually 4 versions behind (3.15.88), because they ran doctor
|
|
142
|
+
* in the brief gap between npm publish and the next cache refresh.
|
|
143
|
+
*
|
|
144
|
+
* Falls back to the cached value if the fetch fails (offline, slow npm,
|
|
145
|
+
* etc.) — same behavior as the cached check, just refreshed when
|
|
146
|
+
* possible.
|
|
147
|
+
*/
|
|
148
|
+
export async function getAvailableUpdateFresh() {
|
|
149
|
+
if (isDisabled())
|
|
150
|
+
return getAvailableUpdate();
|
|
151
|
+
const latest = await fetchLatestVersion();
|
|
152
|
+
if (latest) {
|
|
153
|
+
writeCache({ latestVersion: latest, checkedAt: Date.now() });
|
|
154
|
+
if (compareSemver(latest, VERSION) > 0) {
|
|
155
|
+
return { current: VERSION, latest };
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
// Fetch failed — fall back to whatever the cache says.
|
|
160
|
+
return getAvailableUpdate();
|
|
161
|
+
}
|
package/package.json
CHANGED