@blockrun/franklin 3.8.44 → 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.
Files changed (42) hide show
  1. package/README.md +3 -2
  2. package/dist/agent/commands.d.ts +5 -0
  3. package/dist/agent/commands.js +28 -0
  4. package/dist/agent/compact.js +1 -1
  5. package/dist/agent/context.js +1 -0
  6. package/dist/agent/llm.js +4 -4
  7. package/dist/agent/loop.js +40 -13
  8. package/dist/agent/verification.js +2 -2
  9. package/dist/commands/balance-retry.d.ts +15 -0
  10. package/dist/commands/balance-retry.js +20 -0
  11. package/dist/commands/skills.d.ts +8 -0
  12. package/dist/commands/skills.js +93 -0
  13. package/dist/commands/social.js +1 -1
  14. package/dist/commands/start.js +17 -13
  15. package/dist/commands/telegram.js +1 -1
  16. package/dist/index.js +9 -0
  17. package/dist/learnings/extractor.js +3 -3
  18. package/dist/plugin-sdk/workflow.js +2 -2
  19. package/dist/pricing.js +1 -1
  20. package/dist/proxy/fallback.js +1 -1
  21. package/dist/proxy/server.js +10 -10
  22. package/dist/router/index.js +8 -8
  23. package/dist/skills/bootstrap.d.ts +27 -0
  24. package/dist/skills/bootstrap.js +40 -0
  25. package/dist/skills/invoke.d.ts +23 -0
  26. package/dist/skills/invoke.js +38 -0
  27. package/dist/skills/loader.d.ts +21 -0
  28. package/dist/skills/loader.js +149 -0
  29. package/dist/skills/registry.d.ts +26 -0
  30. package/dist/skills/registry.js +54 -0
  31. package/dist/skills/types.d.ts +47 -0
  32. package/dist/skills/types.js +8 -0
  33. package/dist/skills-bundled/budget-grill/SKILL.md +24 -0
  34. package/dist/tools/index.js +2 -0
  35. package/dist/tools/moa.js +4 -4
  36. package/dist/tools/subagent.js +3 -3
  37. package/dist/tools/tool-categories.js +3 -0
  38. package/dist/tools/wallet.d.ts +23 -0
  39. package/dist/tools/wallet.js +63 -0
  40. package/dist/ui/app.js +3 -3
  41. package/dist/ui/model-picker.js +13 -17
  42. package/package.json +4 -3
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;
@@ -54,20 +54,22 @@ export const MODEL_SHORTCUTS = {
54
54
  // DeepSeek
55
55
  deepseek: 'deepseek/deepseek-chat',
56
56
  r1: 'deepseek/deepseek-reasoner',
57
- // Free (BlockRun gateway free tier — refreshed 2026-04)
58
- free: 'nvidia/glm-4.7',
59
- glm4: 'nvidia/glm-4.7',
60
- 'deepseek-free': 'nvidia/deepseek-v3.2',
57
+ // Free (agent-tested BlockRun gateway free tier — refreshed 2026-04)
58
+ free: 'nvidia/qwen3-coder-480b',
59
+ glm4: 'nvidia/qwen3-coder-480b',
60
+ 'deepseek-free': 'nvidia/qwen3-coder-480b',
61
61
  'qwen-coder': 'nvidia/qwen3-coder-480b',
62
- 'qwen-think': 'nvidia/qwen3-next-80b-a3b-thinking',
62
+ 'qwen-think': 'nvidia/qwen3-coder-480b',
63
63
  maverick: 'nvidia/llama-4-maverick',
64
- 'gpt-oss': 'nvidia/gpt-oss-120b',
65
- 'gpt-oss-small': 'nvidia/gpt-oss-20b',
66
- 'mistral-small': 'nvidia/mistral-small-4-119b',
67
- // Backward-compatibility aliases for models the gateway retired.
64
+ 'gpt-oss': 'nvidia/qwen3-coder-480b',
65
+ 'gpt-oss-small': 'nvidia/qwen3-coder-480b',
66
+ 'mistral-small': 'nvidia/llama-4-maverick',
67
+ // Backward-compatibility aliases for models the gateway retired or exposes
68
+ // unreliably on /v1/messages. Map to agent-tested free models so shortcuts
69
+ // keep working without silent paid fallback or empty tool-use turns.
68
70
  // Map to the closest current free model so old session records + user
69
71
  // muscle memory keep working.
70
- nemotron: 'nvidia/glm-4.7',
72
+ nemotron: 'nvidia/qwen3-coder-480b',
71
73
  devstral: 'nvidia/qwen3-coder-480b',
72
74
  // Others
73
75
  minimax: 'minimax/minimax-m2.7',
@@ -154,14 +156,8 @@ export const PICKER_CATEGORIES = [
154
156
  {
155
157
  category: '🆓 Free (no USDC needed)',
156
158
  models: [
157
- { id: 'nvidia/glm-4.7', shortcut: 'free', label: 'GLM-4.7', price: 'FREE' },
158
- { id: 'nvidia/qwen3-next-80b-a3b-thinking', shortcut: 'qwen-think', label: 'Qwen3-Next 80B Thinking', price: 'FREE' },
159
- { id: 'nvidia/qwen3-coder-480b', shortcut: 'qwen-coder', label: 'Qwen3 Coder 480B', price: 'FREE' },
159
+ { id: 'nvidia/qwen3-coder-480b', shortcut: 'free', label: 'Qwen3 Coder 480B', price: 'FREE' },
160
160
  { id: 'nvidia/llama-4-maverick', shortcut: 'maverick', label: 'Llama 4 Maverick', price: 'FREE' },
161
- { id: 'nvidia/deepseek-v3.2', shortcut: 'deepseek-free', label: 'DeepSeek V3.2', price: 'FREE' },
162
- { id: 'nvidia/gpt-oss-120b', shortcut: 'gpt-oss', label: 'GPT-OSS 120B', price: 'FREE' },
163
- { id: 'nvidia/gpt-oss-20b', shortcut: 'gpt-oss-small', label: 'GPT-OSS 20B', price: 'FREE' },
164
- { id: 'nvidia/mistral-small-4-119b', shortcut: 'mistral-small', label: 'Mistral Small 4 119B', price: 'FREE' },
165
161
  ],
166
162
  },
167
163
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.8.44",
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": {
@@ -31,10 +31,11 @@
31
31
  "build": "tsc && node scripts/copy-plugin-assets.mjs",
32
32
  "dev": "tsc --watch",
33
33
  "start": "node dist/index.js",
34
- "test": "npm run build && node --test --test-reporter=spec test/local.mjs",
34
+ "test": "npm run build && node --test --test-reporter=spec test/local.mjs test/skills.local.mjs",
35
35
  "test:e2e": "npm run build && node --test --test-reporter=spec test/e2e.mjs",
36
+ "test:free-models": "npm run build && node --test --test-reporter=spec test/free-model-matrix.mjs",
36
37
  "test:all": "npm run test && npm run test:e2e",
37
- "test:watch": "node --test --watch test/local.mjs",
38
+ "test:watch": "node --test --watch test/local.mjs test/skills.local.mjs",
38
39
  "test:e2e:watch": "node --test --watch test/e2e.mjs"
39
40
  },
40
41
  "keywords": [