@blockrun/franklin 3.9.0 → 3.9.1

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.
@@ -523,15 +523,17 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
523
523
  // is treated as a typo and falls back to the safe default rather than
524
524
  // silently removing the wallet guard.
525
525
  //
526
- // Default raised from $0.25 → $1.00 in v3.8.42 the original ceiling
527
- // dated from when Franklin was mostly chat. Real workloads (multi-stage
528
- // dashboard scaffolds on sonnet, image-to-image edits, research-heavy
529
- // turns) routinely land in the $0.20–$0.80 range on a single legit
530
- // prompt. $1.00 is still meaningful as a runaway-protection guardrail
531
- // (catches the kind of failure v3.8.41's retry-policy was built for)
532
- // but doesn't impose a friction tax on every multi-stage task. Users
533
- // who liked the old ceiling can opt back in via the config.
534
- const TURN_SPEND_DEFAULT_USD = 1.0;
526
+ // Default lineage: $0.25 (≤ v3.8.41) → $1.00 (v3.8.42) $2.00 (v3.9.1).
527
+ // v3.8.42's $1.00 was tuned for "multi-stage dashboard scaffold" workloads
528
+ // landing in the $0.20–$0.80 range on a single prompt. Real coding turns
529
+ // since full BTC-style dashboards, multi-file refactors that pull in
530
+ // sonnet/opus on a COMPLEX-tier route routinely cross $1.00 in their
531
+ // first planning pass alone, leaving no headroom for the execution call
532
+ // and tripping the cap mid-task. $2.00 keeps the runaway-protection
533
+ // promise (catches the buggy-loop drain v3.8.41's retry-policy targets)
534
+ // while letting a legitimate complex coding task finish in one turn.
535
+ // Users who liked the old ceiling can pin it via the config.
536
+ const TURN_SPEND_DEFAULT_USD = 2.0;
535
537
  const turnSpendCap = (() => {
536
538
  const raw = loadConfig()['max-turn-spend-usd'];
537
539
  if (raw == null)
@@ -1058,7 +1060,7 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
1058
1060
  onEvent({
1059
1061
  kind: 'text_delta',
1060
1062
  text: `\n\n⚠️ Turn spend limit reached ($${turnSpend.toFixed(3)} > $${MAX_TURN_SPEND_USD}). Stopping to protect your wallet.\n` +
1061
- `Raise the cap with \`franklin config set max-turn-spend-usd 2.0\` (or \`0\` to disable), then \`/retry\`.\n`,
1063
+ `Raise the cap with \`franklin config set max-turn-spend-usd 4.0\` (or \`0\` to disable), then \`/retry\`.\n`,
1062
1064
  });
1063
1065
  onEvent({ kind: 'turn_done', reason: 'budget' });
1064
1066
  break;
package/dist/ui/app.js CHANGED
@@ -37,7 +37,7 @@ function useTerminalSize() {
37
37
  }, [stdout]);
38
38
  return size;
39
39
  }
40
- function InputBox({ input, setInput, onSubmit, model, balance, sessionCost, queued, queuedCount, focused, busy, contextPct, vimMode, onVimModeChange }) {
40
+ function InputBox({ input, setInput, onSubmit, model, balance, chain, walletTail, sessionCost, queued, queuedCount, focused, busy, contextPct, vimMode, onVimModeChange }) {
41
41
  const { cols } = useTerminalSize();
42
42
  // Avoid drawing right up to the terminal edge. Several terminals auto-wrap
43
43
  // a full-width border glyph onto the next row, which leaves "ghost" top
@@ -48,7 +48,7 @@ function InputBox({ input, setInput, onSubmit, model, balance, sessionCost, queu
48
48
  ? `⏎ ${queuedCount ?? 1} queued: ${queued.slice(0, 40)}`
49
49
  : 'Working...')
50
50
  : 'Type a message...';
51
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { borderStyle: "round", borderDimColor: true, paddingX: 1, width: boxWidth, children: [busy && !input ? _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " "] }) : null, _jsx(Box, { flexGrow: 1, children: vimMode ? (_jsx(VimInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: placeholder, focus: focused !== false, showMode: true, onModeChange: onVimModeChange })) : (_jsx(TextInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: placeholder, focus: focused !== false })) })] }), _jsx(Box, { marginLeft: 1, children: _jsxs(Text, { dimColor: true, children: [busy ? _jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }) : null, busy ? ' ' : '', shortModelName(model), " \u00B7 ", balance, sessionCost > 0.00001 ? _jsxs(Text, { color: "yellow", children: [" -$", sessionCost.toFixed(4)] }) : '', contextPct !== undefined && contextPct > 0 ? (() => {
51
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { borderStyle: "round", borderDimColor: true, paddingX: 1, width: boxWidth, children: [busy && !input ? _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " "] }) : null, _jsx(Box, { flexGrow: 1, children: vimMode ? (_jsx(VimInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: placeholder, focus: focused !== false, showMode: true, onModeChange: onVimModeChange })) : (_jsx(TextInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: placeholder, focus: focused !== false })) })] }), _jsx(Box, { marginLeft: 1, children: _jsxs(Text, { dimColor: true, children: [busy ? _jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }) : null, busy ? ' ' : '', shortModelName(model), " \u00B7 ", balance, chain ? _jsxs(Text, { children: [" \u00B7 ", _jsx(Text, { color: "magenta", children: chain }), walletTail ? _jsxs(Text, { dimColor: true, children: [":", walletTail] }) : ''] }) : '', sessionCost > 0.00001 ? _jsxs(Text, { color: "yellow", children: [" -$", sessionCost.toFixed(4)] }) : '', contextPct !== undefined && contextPct > 0 ? (() => {
52
52
  // Visual context bar: ▓▓▓▓▓▓░░░░ 75%
53
53
  const filled = Math.round(contextPct / 10);
54
54
  const empty = 10 - filled;
@@ -774,7 +774,7 @@ function RunCodeApp({ initialModel, workDir, walletAddress, walletBalance, chain
774
774
  const isHighlight = m.highlight === true;
775
775
  return (_jsxs(Box, { marginLeft: 2, children: [_jsxs(Text, { inverse: isSelected, color: isSelected ? 'cyan' : isHighlight ? 'yellow' : undefined, bold: isSelected || isHighlight, children: [' ', m.label.padEnd(26), ' '] }), _jsxs(Text, { dimColor: true, children: [" ", m.shortcut.padEnd(14)] }), _jsx(Text, { color: m.price === 'FREE' ? 'green' : isHighlight ? 'yellow' : undefined, dimColor: !isHighlight && m.price !== 'FREE', children: m.price }), isCurrent && _jsx(Text, { color: "green", children: " \u2190" })] }, m.id));
776
776
  })] }, cat.category))), _jsx(Box, { marginTop: 1, marginLeft: 2, children: _jsx(Text, { dimColor: true, children: "Your conversation stays above \u2014 picking a model keeps all history intact." }) })] }));
777
- })(), !inPicker && (_jsx(InputBox, { input: (permissionRequest || askUserRequest) ? '' : input, setInput: (permissionRequest || askUserRequest) ? () => { } : setInput, onSubmit: (permissionRequest || askUserRequest) ? () => { } : handleSubmit, model: currentModel, balance: liveBalance, sessionCost: totalCost, queued: queuedInputs[0] || undefined, queuedCount: queuedInputs.length, focused: !permissionRequest && !askUserRequest, busy: !askUserRequest && (waiting || thinking || tools.size > 0), contextPct: contextPct, vimMode: vimEnabled, onVimModeChange: setCurrentVimMode }))] }));
777
+ })(), !inPicker && (_jsx(InputBox, { input: (permissionRequest || askUserRequest) ? '' : input, setInput: (permissionRequest || askUserRequest) ? () => { } : setInput, onSubmit: (permissionRequest || askUserRequest) ? () => { } : handleSubmit, model: currentModel, balance: liveBalance, chain: chain, walletTail: walletAddress && walletAddress.length >= 4 && !walletAddress.startsWith('not set') ? walletAddress.slice(-4) : undefined, sessionCost: totalCost, queued: queuedInputs[0] || undefined, queuedCount: queuedInputs.length, focused: !permissionRequest && !askUserRequest, busy: !askUserRequest && (waiting || thinking || tools.size > 0), contextPct: contextPct, vimMode: vimEnabled, onVimModeChange: setCurrentVimMode }))] }));
778
778
  }
779
779
  export function launchInkUI(opts) {
780
780
  let resolveInput = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.9.0",
3
+ "version": "3.9.1",
4
4
  "description": "Franklin — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
5
5
  "type": "module",
6
6
  "exports": {