@blockrun/franklin 3.9.0 → 3.9.2

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;
@@ -35,6 +35,12 @@ const MODEL_MAX_OUTPUT = {
35
35
  'google/gemini-2.5-pro': 65_536,
36
36
  'google/gemini-2.5-flash': 65_536,
37
37
  'deepseek/deepseek-chat': 8_192,
38
+ // Kimi K2.6 supports 65K output per the BlockRun gateway model entry
39
+ // (moonshot/kimi-k2.6 max_output: 65536). Without this entry the default
40
+ // 16K cap left users with 4× headroom on the table for long-form coding
41
+ // outputs and dashboard scaffolds the model can otherwise emit in a
42
+ // single response.
43
+ 'moonshot/kimi-k2.6': 65_536,
38
44
  };
39
45
  /** Get max output tokens for a model */
40
46
  export function getMaxOutputTokens(model) {
package/dist/pricing.js CHANGED
@@ -73,6 +73,8 @@ export const MODEL_PRICING = {
73
73
  'minimax/minimax-m2.5': { input: 0.3, output: 1.2 },
74
74
  // Moonshot
75
75
  'moonshot/kimi-k2.6': { input: 0.95, output: 4.0 },
76
+ // Retired (kept for legacy session-cost records; the gateway no longer
77
+ // serves these and the picker shortcuts now resolve to K2.6).
76
78
  'moonshot/kimi-k2.5': { input: 0.6, output: 3.0 },
77
79
  'nvidia/kimi-k2.5': { input: 0.55, output: 2.5 },
78
80
  // PROMOTION (active ~2026-04): flat $0.001/call for all GLM models
@@ -175,8 +175,9 @@ const MODEL_SHORTCUTS = {
175
175
  'glm5': 'zai/glm-5.1',
176
176
  kimi: 'moonshot/kimi-k2.6',
177
177
  'k2.6': 'moonshot/kimi-k2.6',
178
- 'kimi-k2.5': 'moonshot/kimi-k2.5',
179
- 'k2.5': 'moonshot/kimi-k2.5',
178
+ // K2.5 retired by the gateway — aliases resolve to K2.6 for muscle memory.
179
+ 'kimi-k2.5': 'moonshot/kimi-k2.6',
180
+ 'k2.5': 'moonshot/kimi-k2.6',
180
181
  };
181
182
  // Model pricing now uses shared source from src/pricing.ts
182
183
  function detectModelSwitch(parsed) {
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;
@@ -79,8 +79,11 @@ export const MODEL_SHORTCUTS = {
79
79
  'glm5': 'zai/glm-5.1',
80
80
  kimi: 'moonshot/kimi-k2.6',
81
81
  'k2.6': 'moonshot/kimi-k2.6',
82
- 'kimi-k2.5': 'moonshot/kimi-k2.5',
83
- 'k2.5': 'moonshot/kimi-k2.5',
82
+ // K2.5 was retired by the gateway in favor of K2.6 (256K ctx, vision +
83
+ // reasoning, $0.95 in / $4 out — strictly better in every dimension).
84
+ // The aliases stay so muscle memory keeps working but resolve to K2.6.
85
+ 'kimi-k2.5': 'moonshot/kimi-k2.6',
86
+ 'k2.5': 'moonshot/kimi-k2.6',
84
87
  };
85
88
  /**
86
89
  * Resolve a model name — supports shortcuts.
@@ -149,7 +152,6 @@ export const PICKER_CATEGORIES = [
149
152
  { id: 'google/gemini-2.5-flash', shortcut: 'flash', label: 'Gemini 2.5 Flash', price: '$0.3/$2.5' },
150
153
  { id: 'deepseek/deepseek-chat', shortcut: 'deepseek', label: 'DeepSeek V3', price: '$0.28/$0.42' },
151
154
  { id: 'moonshot/kimi-k2.6', shortcut: 'kimi', label: 'Kimi K2.6', price: '$0.95/$4' },
152
- { id: 'moonshot/kimi-k2.5', shortcut: 'kimi-k2.5', label: 'Kimi K2.5 (legacy)', price: '$0.6/$3' },
153
155
  { id: 'minimax/minimax-m2.7', shortcut: 'minimax', label: 'Minimax M2.7', price: '$0.3/$1.2' },
154
156
  ],
155
157
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.9.0",
3
+ "version": "3.9.2",
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": {