@blockrun/franklin 3.15.54 → 3.15.55
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 +22 -4
- package/package.json +1 -1
package/dist/agent/loop.js
CHANGED
|
@@ -288,6 +288,19 @@ function getBackoffDelay(attempt, maxDelayMs = 32_000) {
|
|
|
288
288
|
const jitter = base * 0.25 * (Math.random() * 2 - 1); // ±25%
|
|
289
289
|
return Math.max(500, Math.round(base + jitter));
|
|
290
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* Format the user-facing "switching model" line. Includes the resolved
|
|
293
|
+
* concrete model in parentheses when the user-facing alias (e.g.
|
|
294
|
+
* `blockrun/auto`) differs from what was actually being called (e.g.
|
|
295
|
+
* `anthropic/claude-sonnet-4.6`). Verified 2026-05-04 in a live session:
|
|
296
|
+
* a payment fail surfaced as `*blockrun/auto failed — switching to
|
|
297
|
+
* nvidia/qwen3-coder-480b*` with no hint of which concrete model
|
|
298
|
+
* actually failed, and no hint of why. The reason label closes that gap.
|
|
299
|
+
*/
|
|
300
|
+
function formatModelSwitch(alias, resolved, reason, newModel) {
|
|
301
|
+
const oldDisplay = alias === resolved ? alias : `${alias} (${resolved})`;
|
|
302
|
+
return `${oldDisplay} ${reason} — switching to ${newModel}`;
|
|
303
|
+
}
|
|
291
304
|
/**
|
|
292
305
|
* Identify models known to hallucinate tool calls (invented names, literal
|
|
293
306
|
* `[TOOLCALL]` / `<tool_call>` text in answers) — they need the explicit
|
|
@@ -1013,8 +1026,9 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1013
1026
|
const oldModel = config.model;
|
|
1014
1027
|
config.model = nextModel;
|
|
1015
1028
|
config.onModelChange?.(nextModel, 'system');
|
|
1016
|
-
|
|
1017
|
-
|
|
1029
|
+
const switchLine = formatModelSwitch(oldModel, resolvedModel, 'returned empty', nextModel);
|
|
1030
|
+
logger.warn(`[franklin] ${switchLine}`);
|
|
1031
|
+
onEvent({ kind: 'text_delta', text: `\n*${switchLine}*\n` });
|
|
1018
1032
|
continue;
|
|
1019
1033
|
}
|
|
1020
1034
|
// No fallback available OR already tried 2 models — give up, tell the user.
|
|
@@ -1177,7 +1191,11 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1177
1191
|
const oldModel = config.model;
|
|
1178
1192
|
config.model = nextFree;
|
|
1179
1193
|
config.onModelChange?.(nextFree, 'system');
|
|
1180
|
-
|
|
1194
|
+
const reason = `failed [${classified.label}]`;
|
|
1195
|
+
onEvent({
|
|
1196
|
+
kind: 'text_delta',
|
|
1197
|
+
text: `\n*${formatModelSwitch(oldModel, resolvedModel, reason, nextFree)}*\n`,
|
|
1198
|
+
});
|
|
1181
1199
|
continue; // Retry with next model
|
|
1182
1200
|
}
|
|
1183
1201
|
}
|
|
@@ -1202,7 +1220,7 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1202
1220
|
recoveryAttempts = 0;
|
|
1203
1221
|
onEvent({
|
|
1204
1222
|
kind: 'text_delta',
|
|
1205
|
-
text: `\n*${oldModel
|
|
1223
|
+
text: `\n*${formatModelSwitch(oldModel, resolvedModel, 'rate-limited', nextFree)}*\n`,
|
|
1206
1224
|
});
|
|
1207
1225
|
continue;
|
|
1208
1226
|
}
|
package/package.json
CHANGED