@blockrun/franklin 3.7.0 → 3.7.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.
- package/dist/agent/context.js +1 -0
- package/dist/commands/start.js +78 -17
- package/package.json +1 -1
package/dist/agent/context.js
CHANGED
|
@@ -38,6 +38,7 @@ You are an interactive agent — not a chatbot. Use the tools available to you t
|
|
|
38
38
|
- **Search strategy**: Glob/Grep for directed searches (known file/symbol). Use Agent for open-ended exploration that may require multiple rounds.
|
|
39
39
|
- **Batch bash**: chain sequential shell commands with && in a single call. Only split when you need intermediate output.
|
|
40
40
|
- **AskUser discipline**: Only use AskUser when you need explicit confirmation for a destructive action (deleting files, dropping databases). NEVER use AskUser to ask what the user wants — just answer their message directly. If the request is vague, make a reasonable assumption and proceed.
|
|
41
|
+
- **Greetings**: When the user sends only a greeting or filler ("hi", "hello", "hey", "ok", "thanks", "yo"), reply with ONE short plain-text sentence (e.g. "Hi — what do you want to work on?"). Do NOT call AskUser. Do NOT assume a marketing/trading/coding task. Do NOT invoke any tools.
|
|
41
42
|
- Never write to /etc, /usr, ~/.ssh, ~/.aws. Don't commit secrets.`;
|
|
42
43
|
}
|
|
43
44
|
function getCodeStyleSection() {
|
package/dist/commands/start.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { getOrCreateWallet, getOrCreateSolanaWallet } from '@blockrun/llm';
|
|
3
3
|
import { loadChain, API_URLS } from '../config.js';
|
|
4
|
-
import { flushStats } from '../stats/tracker.js';
|
|
4
|
+
import { flushStats, loadStats } from '../stats/tracker.js';
|
|
5
|
+
import { OPUS_PRICING } from '../pricing.js';
|
|
5
6
|
import { loadConfig } from './config.js';
|
|
6
7
|
import { printBanner } from '../banner.js';
|
|
7
8
|
import { assembleInstructions } from '../agent/context.js';
|
|
@@ -114,11 +115,17 @@ export async function startCommand(options) {
|
|
|
114
115
|
}
|
|
115
116
|
printBanner(version);
|
|
116
117
|
const workDir = process.cwd();
|
|
118
|
+
// Auto-start panel in background unless explicitly disabled.
|
|
119
|
+
// Binds loopback-only (wallet secrets on /api/wallet/secret — never expose on LAN).
|
|
120
|
+
let panelUrl;
|
|
121
|
+
if (process.env.FRANKLIN_PANEL_AUTOSTART !== '0') {
|
|
122
|
+
panelUrl = await startPanelBackground(3100);
|
|
123
|
+
}
|
|
117
124
|
// Session info — aligned, minimal. Model + balance live in the input bar below.
|
|
118
125
|
// Full wallet address is shown so the user can copy-paste it to fund the wallet.
|
|
119
126
|
console.log(chalk.dim(' Wallet: ') + (walletAddress || chalk.yellow('not set')));
|
|
120
127
|
console.log(chalk.dim(' Dir: ') + workDir);
|
|
121
|
-
console.log(chalk.dim(' Dashboard: ') + chalk.cyan('franklin panel') + chalk.dim(' → http://localhost:3100'));
|
|
128
|
+
console.log(chalk.dim(' Dashboard: ') + (panelUrl ? chalk.cyan(panelUrl) : chalk.cyan('franklin panel') + chalk.dim(' → http://localhost:3100')));
|
|
122
129
|
console.log(chalk.dim(' Help: ') + chalk.cyan('/help'));
|
|
123
130
|
console.log('');
|
|
124
131
|
// Balance fetcher — used at startup and after each turn
|
|
@@ -257,6 +264,7 @@ export async function startCommand(options) {
|
|
|
257
264
|
}
|
|
258
265
|
// ─── Ink UI (interactive terminal) ─────────────────────────────────────────
|
|
259
266
|
async function runWithInkUI(agentConfig, model, workDir, version, walletInfo, onBalanceReady, fetchBalance) {
|
|
267
|
+
const startSnapshot = snapshotStats();
|
|
260
268
|
const ui = launchInkUI({
|
|
261
269
|
model,
|
|
262
270
|
workDir,
|
|
@@ -324,15 +332,17 @@ async function runWithInkUI(agentConfig, model, workDir, version, walletInfo, on
|
|
|
324
332
|
catch { /* extraction is best-effort */ }
|
|
325
333
|
}
|
|
326
334
|
await disconnectMcpServers();
|
|
327
|
-
// Session summary —
|
|
335
|
+
// Session summary — delta vs. snapshot at session start
|
|
328
336
|
try {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
337
|
+
const delta = statsDelta(startSnapshot);
|
|
338
|
+
if (delta.requests > 0) {
|
|
339
|
+
const cost = delta.cost.toFixed(4);
|
|
340
|
+
const savedStr = delta.saved > 0.001 ? ` · saved $${delta.saved.toFixed(2)} vs Opus` : '';
|
|
341
|
+
const tokens = `${(delta.inputTokens / 1000).toFixed(0)}k in / ${(delta.outputTokens / 1000).toFixed(0)}k out`;
|
|
342
|
+
console.log(chalk.dim(`\n Session: ${delta.requests} requests · $${cost} USDC${savedStr} · ${tokens}`));
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
console.log(chalk.dim('\n Session: 0 requests · no spend'));
|
|
336
346
|
}
|
|
337
347
|
}
|
|
338
348
|
catch { /* stats unavailable */ }
|
|
@@ -343,6 +353,7 @@ async function runWithBasicUI(agentConfig, model, workDir) {
|
|
|
343
353
|
const { TerminalUI } = await import('../ui/terminal.js');
|
|
344
354
|
const ui = new TerminalUI();
|
|
345
355
|
ui.printWelcome(model, workDir);
|
|
356
|
+
const startSnapshot = snapshotStats();
|
|
346
357
|
let lastTerminalPrompt = '';
|
|
347
358
|
try {
|
|
348
359
|
await interactiveSession(agentConfig, async () => {
|
|
@@ -390,19 +401,69 @@ async function runWithBasicUI(agentConfig, model, workDir) {
|
|
|
390
401
|
}
|
|
391
402
|
// Session summary for piped mode
|
|
392
403
|
try {
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
console.error(`Session: ${stats.totalRequests} requests · $${cost} USDC${savedStr} · ${tokens}`);
|
|
404
|
+
const delta = statsDelta(startSnapshot);
|
|
405
|
+
if (delta.requests > 0) {
|
|
406
|
+
const cost = delta.cost.toFixed(4);
|
|
407
|
+
const savedStr = delta.saved > 0.001 ? ` · saved $${delta.saved.toFixed(2)} vs Opus` : '';
|
|
408
|
+
const tokens = `${(delta.inputTokens / 1000).toFixed(0)}k in / ${(delta.outputTokens / 1000).toFixed(0)}k out`;
|
|
409
|
+
console.error(`Session: ${delta.requests} requests · $${cost} USDC${savedStr} · ${tokens}`);
|
|
400
410
|
}
|
|
401
411
|
}
|
|
402
412
|
catch { /* stats unavailable */ }
|
|
403
413
|
ui.printGoodbye();
|
|
404
414
|
flushStats();
|
|
405
415
|
}
|
|
416
|
+
// ─── Panel auto-start ──────────────────────────────────────────────────────
|
|
417
|
+
async function startPanelBackground(startPort) {
|
|
418
|
+
const MAX_ATTEMPTS = 20;
|
|
419
|
+
try {
|
|
420
|
+
const { createPanelServer } = await import('../panel/server.js');
|
|
421
|
+
return await new Promise((resolve) => {
|
|
422
|
+
const tryListen = (port, attempt) => {
|
|
423
|
+
const server = createPanelServer(port);
|
|
424
|
+
server.on('error', (err) => {
|
|
425
|
+
if (err.code === 'EADDRINUSE' && attempt < MAX_ATTEMPTS) {
|
|
426
|
+
tryListen(port + 1, attempt + 1);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
resolve(undefined);
|
|
430
|
+
});
|
|
431
|
+
server.listen(port, '127.0.0.1', () => {
|
|
432
|
+
server.unref?.();
|
|
433
|
+
resolve(`http://localhost:${port}`);
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
tryListen(startPort, 0);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
return undefined;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function snapshotStats() {
|
|
444
|
+
try {
|
|
445
|
+
const s = loadStats();
|
|
446
|
+
return {
|
|
447
|
+
requests: s.totalRequests,
|
|
448
|
+
cost: s.totalCostUsd,
|
|
449
|
+
inputTokens: s.totalInputTokens,
|
|
450
|
+
outputTokens: s.totalOutputTokens,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
return { requests: 0, cost: 0, inputTokens: 0, outputTokens: 0 };
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function statsDelta(before) {
|
|
458
|
+
const now = loadStats();
|
|
459
|
+
const requests = Math.max(0, now.totalRequests - before.requests);
|
|
460
|
+
const cost = Math.max(0, now.totalCostUsd - before.cost);
|
|
461
|
+
const inputTokens = Math.max(0, now.totalInputTokens - before.inputTokens);
|
|
462
|
+
const outputTokens = Math.max(0, now.totalOutputTokens - before.outputTokens);
|
|
463
|
+
const opusCost = (inputTokens / 1_000_000) * OPUS_PRICING.input +
|
|
464
|
+
(outputTokens / 1_000_000) * OPUS_PRICING.output;
|
|
465
|
+
return { requests, cost, inputTokens, outputTokens, saved: Math.max(0, opusCost - cost) };
|
|
466
|
+
}
|
|
406
467
|
async function handleSlashCommand(cmd, config, ui) {
|
|
407
468
|
const parts = cmd.trim().split(/\s+/);
|
|
408
469
|
const command = parts[0].toLowerCase();
|
package/package.json
CHANGED