@blockrun/franklin 3.6.13 → 3.6.15
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/compact.js +7 -1
- package/dist/commands/start.js +9 -18
- package/dist/tools/moa.d.ts +1 -1
- package/dist/tools/moa.js +9 -2
- package/dist/tools/subagent.d.ts +1 -1
- package/dist/tools/subagent.js +23 -2
- package/package.json +1 -1
package/dist/agent/compact.js
CHANGED
|
@@ -367,8 +367,14 @@ function formatCompactSummary(raw) {
|
|
|
367
367
|
}
|
|
368
368
|
/**
|
|
369
369
|
* Pick a cheaper/faster model for compaction to save cost.
|
|
370
|
+
* If the primary model is free (NVIDIA), compaction also stays free
|
|
371
|
+
* so users don't get silent charges when their context fills up.
|
|
370
372
|
*/
|
|
371
373
|
function pickCompactionModel(primaryModel) {
|
|
374
|
+
// Free parent → free compaction (no silent charge)
|
|
375
|
+
if (primaryModel.startsWith('nvidia/') || primaryModel === 'blockrun/free') {
|
|
376
|
+
return 'nvidia/nemotron-ultra-253b';
|
|
377
|
+
}
|
|
372
378
|
// Use cheapest capable model for summarization to save cost
|
|
373
379
|
// Tier down: opus/pro → sonnet, sonnet → haiku, everything else → flash (cheapest capable)
|
|
374
380
|
if (primaryModel.includes('opus') || primaryModel.includes('pro')) {
|
|
@@ -380,7 +386,7 @@ function pickCompactionModel(primaryModel) {
|
|
|
380
386
|
if (primaryModel.includes('haiku') || primaryModel.includes('mini') || primaryModel.includes('nano')) {
|
|
381
387
|
return 'google/gemini-2.5-flash'; // Cheapest capable model
|
|
382
388
|
}
|
|
383
|
-
//
|
|
389
|
+
// Unknown models — use flash
|
|
384
390
|
return 'google/gemini-2.5-flash';
|
|
385
391
|
}
|
|
386
392
|
/**
|
package/dist/commands/start.js
CHANGED
|
@@ -72,22 +72,12 @@ export async function startCommand(options) {
|
|
|
72
72
|
}
|
|
73
73
|
printBanner(version);
|
|
74
74
|
const workDir = process.cwd();
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
console.log(chalk.dim(
|
|
78
|
-
console.log(chalk.dim(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.log(chalk.dim(`\n Tip: /model to switch models · /compact to save tokens · /help for all commands`));
|
|
82
|
-
}
|
|
83
|
-
// Welcome message — show things Hermes/OpenClaw can't do.
|
|
84
|
-
// Only on first run or when no model is configured (new user indicator).
|
|
85
|
-
// After the user's first session, the tip fades and they go straight to the prompt.
|
|
86
|
-
console.log('');
|
|
87
|
-
console.log(chalk.dim(' Try something only Franklin can do:'));
|
|
88
|
-
console.log(chalk.dim(' ') + chalk.hex('#FFD700')('"what\'s BTC looking like today?"') + chalk.dim(' ← live market data'));
|
|
89
|
-
console.log(chalk.dim(' ') + chalk.hex('#60A5FA')('"generate a logo for my startup"') + chalk.dim(' ← AI image gen'));
|
|
90
|
-
console.log(chalk.dim(' Code with 55+ models. No API keys. Pay per use.'));
|
|
75
|
+
// Session info — aligned, minimal. Model + balance live in the input bar below.
|
|
76
|
+
const short = (s) => s.length > 14 ? s.slice(0, 6) + '...' + s.slice(-4) : s;
|
|
77
|
+
console.log(chalk.dim(' Wallet: ') + (walletAddress ? short(walletAddress) : chalk.yellow('not set')));
|
|
78
|
+
console.log(chalk.dim(' Dir: ') + workDir);
|
|
79
|
+
console.log(chalk.dim(' Dashboard: ') + chalk.cyan('franklin panel') + chalk.dim(' → http://localhost:3100'));
|
|
80
|
+
console.log(chalk.dim(' Help: ') + chalk.cyan('/help'));
|
|
91
81
|
console.log('');
|
|
92
82
|
// Balance fetcher — used at startup and after each turn
|
|
93
83
|
const fetchBalance = async () => {
|
|
@@ -142,10 +132,11 @@ export async function startCommand(options) {
|
|
|
142
132
|
}
|
|
143
133
|
}
|
|
144
134
|
// Build capabilities (built-in + MCP + sub-agent + MoA)
|
|
145
|
-
|
|
135
|
+
// Pass parent model so sub-agents inherit it (no silent paid spawns from free parents)
|
|
136
|
+
const subAgent = createSubAgentCapability(apiUrl, chain, allCapabilities, model);
|
|
146
137
|
// Register MoA tool config (needs API URL for parallel model queries)
|
|
147
138
|
const { registerMoAConfig } = await import('../tools/moa.js');
|
|
148
|
-
registerMoAConfig(apiUrl, chain);
|
|
139
|
+
registerMoAConfig(apiUrl, chain, model);
|
|
149
140
|
const capabilities = [...allCapabilities, ...mcpTools, subAgent];
|
|
150
141
|
// Validate tool descriptions (self-evolution: detect SearchX-style description bugs)
|
|
151
142
|
if (options.debug) {
|
package/dist/tools/moa.d.ts
CHANGED
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
import type { CapabilityHandler } from '../agent/types.js';
|
|
14
14
|
export declare const moaCapability: CapabilityHandler;
|
|
15
15
|
/** Register the API URL for MoA tool (called during agent setup). */
|
|
16
|
-
export declare function registerMoAConfig(apiUrl: string, chain: 'base' | 'solana'): void;
|
|
16
|
+
export declare function registerMoAConfig(apiUrl: string, chain: 'base' | 'solana', parentModel?: string): void;
|
package/dist/tools/moa.js
CHANGED
|
@@ -31,13 +31,18 @@ const REFERENCE_TIMEOUT_MS = 60_000;
|
|
|
31
31
|
// These will be injected at registration time
|
|
32
32
|
let registeredApiUrl = '';
|
|
33
33
|
let registeredChain = 'base';
|
|
34
|
+
let registeredParentModel = '';
|
|
34
35
|
async function execute(input, ctx) {
|
|
35
36
|
const { prompt, models, aggregator, include_reasoning } = input;
|
|
36
37
|
if (!prompt) {
|
|
37
38
|
return { output: 'Error: prompt is required', isError: true };
|
|
38
39
|
}
|
|
39
40
|
const referenceModels = models || REFERENCE_MODELS;
|
|
40
|
-
|
|
41
|
+
// If parent agent is on a free model, default aggregator to a free model too
|
|
42
|
+
// so MoA doesn't silently charge the user. Explicit `aggregator` arg wins.
|
|
43
|
+
const parentIsFree = registeredParentModel.startsWith('nvidia/') ||
|
|
44
|
+
registeredParentModel === 'blockrun/free';
|
|
45
|
+
const aggregatorModel = aggregator || (parentIsFree ? 'nvidia/nemotron-ultra-253b' : AGGREGATOR_MODEL);
|
|
41
46
|
const client = new ModelClient({
|
|
42
47
|
apiUrl: registeredApiUrl,
|
|
43
48
|
chain: registeredChain,
|
|
@@ -167,7 +172,9 @@ Parameters:
|
|
|
167
172
|
concurrent: true,
|
|
168
173
|
};
|
|
169
174
|
/** Register the API URL for MoA tool (called during agent setup). */
|
|
170
|
-
export function registerMoAConfig(apiUrl, chain) {
|
|
175
|
+
export function registerMoAConfig(apiUrl, chain, parentModel) {
|
|
171
176
|
registeredApiUrl = apiUrl;
|
|
172
177
|
registeredChain = chain;
|
|
178
|
+
if (parentModel)
|
|
179
|
+
registeredParentModel = parentModel;
|
|
173
180
|
}
|
package/dist/tools/subagent.d.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* SubAgent capability — spawn a child agent for independent tasks.
|
|
3
3
|
*/
|
|
4
4
|
import type { CapabilityHandler } from '../agent/types.js';
|
|
5
|
-
export declare function createSubAgentCapability(apiUrl: string, chain: 'base' | 'solana', capabilities: CapabilityHandler[]): CapabilityHandler;
|
|
5
|
+
export declare function createSubAgentCapability(apiUrl: string, chain: 'base' | 'solana', capabilities: CapabilityHandler[], parentModel?: string): CapabilityHandler;
|
package/dist/tools/subagent.js
CHANGED
|
@@ -6,12 +6,31 @@ import { assembleInstructions } from '../agent/context.js';
|
|
|
6
6
|
// These will be injected at registration time
|
|
7
7
|
let registeredApiUrl = '';
|
|
8
8
|
let registeredChain = 'base';
|
|
9
|
+
let registeredParentModel = '';
|
|
9
10
|
let registeredCapabilities = [];
|
|
11
|
+
// Heuristic: which model IDs are free?
|
|
12
|
+
function isFreeModel(m) {
|
|
13
|
+
return m.startsWith('nvidia/') || m === 'blockrun/free' || m === '';
|
|
14
|
+
}
|
|
10
15
|
async function execute(input, ctx) {
|
|
11
16
|
const { prompt, description, model } = input;
|
|
12
17
|
if (!prompt) {
|
|
13
18
|
return { output: 'Error: prompt is required', isError: true };
|
|
14
19
|
}
|
|
20
|
+
// Resolve which model the sub-agent will actually run on
|
|
21
|
+
const subModel = model || registeredParentModel || 'nvidia/nemotron-ultra-253b';
|
|
22
|
+
// Cost gate: if parent is free but sub-agent wants paid, ask user first.
|
|
23
|
+
// Prevents silent charges when the agent decides to spawn a more capable sub-agent.
|
|
24
|
+
if (isFreeModel(registeredParentModel) && !isFreeModel(subModel) && ctx.onAskUser) {
|
|
25
|
+
const shortLabel = subModel.split('/').pop() || subModel;
|
|
26
|
+
const answer = await ctx.onAskUser(`Sub-agent wants to use ${shortLabel} (paid). Approve?`, ['y', 'n']);
|
|
27
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
28
|
+
return {
|
|
29
|
+
output: `Sub-agent skipped — user declined paid model (${shortLabel}). Retry with a free model like nemotron.`,
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
15
34
|
const client = new ModelClient({
|
|
16
35
|
apiUrl: registeredApiUrl,
|
|
17
36
|
chain: registeredChain,
|
|
@@ -54,7 +73,7 @@ async function execute(input, ctx) {
|
|
|
54
73
|
}
|
|
55
74
|
turn++;
|
|
56
75
|
const { content: parts } = await client.complete({
|
|
57
|
-
model:
|
|
76
|
+
model: subModel,
|
|
58
77
|
messages: history,
|
|
59
78
|
system: systemPrompt,
|
|
60
79
|
tools: toolDefs,
|
|
@@ -107,10 +126,12 @@ async function execute(input, ctx) {
|
|
|
107
126
|
output: finalText || `[${label}] completed after ${turn} turn(s) with no text output.`,
|
|
108
127
|
};
|
|
109
128
|
}
|
|
110
|
-
export function createSubAgentCapability(apiUrl, chain, capabilities) {
|
|
129
|
+
export function createSubAgentCapability(apiUrl, chain, capabilities, parentModel) {
|
|
111
130
|
registeredApiUrl = apiUrl;
|
|
112
131
|
registeredChain = chain;
|
|
113
132
|
registeredCapabilities = capabilities;
|
|
133
|
+
if (parentModel)
|
|
134
|
+
registeredParentModel = parentModel;
|
|
114
135
|
return {
|
|
115
136
|
spec: {
|
|
116
137
|
name: 'Agent',
|
package/package.json
CHANGED