@blockrun/franklin 3.10.5 → 3.11.0
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/loop.js
CHANGED
|
@@ -17,7 +17,6 @@ import { resetToolSessionState } from '../tools/index.js';
|
|
|
17
17
|
import { CORE_TOOL_NAMES, dynamicToolsEnabled } from '../tools/tool-categories.js';
|
|
18
18
|
import { createActivateToolCapability } from '../tools/activate.js';
|
|
19
19
|
import { recordUsage } from '../stats/tracker.js';
|
|
20
|
-
import { loadConfig } from '../commands/config.js';
|
|
21
20
|
import { recordSessionUsage } from '../stats/session-tracker.js';
|
|
22
21
|
import { appendAudit, extractLastUserPrompt } from '../stats/audit.js';
|
|
23
22
|
import { estimateCost, OPUS_PRICING } from '../pricing.js';
|
|
@@ -436,18 +435,7 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
436
435
|
const cmdResult = await handleSlashCommand(input, {
|
|
437
436
|
history, config, client, sessionId, onEvent,
|
|
438
437
|
skillRegistry,
|
|
439
|
-
skillVars: getSkillVars({
|
|
440
|
-
chain: config.chain,
|
|
441
|
-
perTurnCapUsd: (() => {
|
|
442
|
-
const raw = loadConfig()['max-turn-spend-usd'];
|
|
443
|
-
if (raw == null)
|
|
444
|
-
return 1.0;
|
|
445
|
-
const n = Number(raw);
|
|
446
|
-
if (!Number.isFinite(n))
|
|
447
|
-
return 1.0;
|
|
448
|
-
return n <= 0 ? Infinity : n;
|
|
449
|
-
})(),
|
|
450
|
-
}),
|
|
438
|
+
skillVars: getSkillVars({ chain: config.chain }),
|
|
451
439
|
});
|
|
452
440
|
if (cmdResult.handled)
|
|
453
441
|
continue;
|
|
@@ -551,37 +539,6 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
551
539
|
// ── No-progress guardrail: kill infinite tiny-response loops ──
|
|
552
540
|
let consecutiveTinyResponses = 0; // Count of consecutive calls with <10 output tokens
|
|
553
541
|
const MAX_TINY_RESPONSES = 2; // Break after N tiny responses — if 2 calls return near-empty, something is wrong
|
|
554
|
-
let turnSpend = 0; // Cost spent this user turn (USD)
|
|
555
|
-
// Hard circuit breaker per user message — defends user wallets against
|
|
556
|
-
// a runaway model+tool combo on a single prompt. User-overridable via
|
|
557
|
-
// `franklin config set max-turn-spend-usd <number>`. Explicit "0" or a
|
|
558
|
-
// negative number disables the cap; a non-numeric / unparseable value
|
|
559
|
-
// is treated as a typo and falls back to the safe default rather than
|
|
560
|
-
// silently removing the wallet guard.
|
|
561
|
-
//
|
|
562
|
-
// Default lineage: $0.25 (≤ v3.8.41) → $1.00 (v3.8.42) → $2.00 (v3.9.1).
|
|
563
|
-
// v3.8.42's $1.00 was tuned for "multi-stage dashboard scaffold" workloads
|
|
564
|
-
// landing in the $0.20–$0.80 range on a single prompt. Real coding turns
|
|
565
|
-
// since — full BTC-style dashboards, multi-file refactors that pull in
|
|
566
|
-
// sonnet/opus on a COMPLEX-tier route — routinely cross $1.00 in their
|
|
567
|
-
// first planning pass alone, leaving no headroom for the execution call
|
|
568
|
-
// and tripping the cap mid-task. $2.00 keeps the runaway-protection
|
|
569
|
-
// promise (catches the buggy-loop drain v3.8.41's retry-policy targets)
|
|
570
|
-
// while letting a legitimate complex coding task finish in one turn.
|
|
571
|
-
// Users who liked the old ceiling can pin it via the config.
|
|
572
|
-
const TURN_SPEND_DEFAULT_USD = 2.0;
|
|
573
|
-
const turnSpendCap = (() => {
|
|
574
|
-
const raw = loadConfig()['max-turn-spend-usd'];
|
|
575
|
-
if (raw == null)
|
|
576
|
-
return TURN_SPEND_DEFAULT_USD;
|
|
577
|
-
const parsed = Number(raw);
|
|
578
|
-
if (!Number.isFinite(parsed))
|
|
579
|
-
return TURN_SPEND_DEFAULT_USD; // typo → keep default
|
|
580
|
-
if (parsed <= 0)
|
|
581
|
-
return Infinity; // explicit opt-out
|
|
582
|
-
return parsed;
|
|
583
|
-
})();
|
|
584
|
-
const MAX_TURN_SPEND_USD = turnSpendCap;
|
|
585
542
|
// ── Turn analysis (one classifier call, drives routing + prefetch) ──
|
|
586
543
|
// Single LLM pass that answers every routing-adjacent question the
|
|
587
544
|
// harness needs BEFORE the main model runs: tier, ticker intent,
|
|
@@ -1120,16 +1077,12 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1120
1077
|
const costEstimate = estimateCost(resolvedModel, inputTokens, usage.outputTokens, 1);
|
|
1121
1078
|
recordUsage(resolvedModel, inputTokens, usage.outputTokens, costEstimate, 0);
|
|
1122
1079
|
// ── Circuit breakers: prevent infinite-loop wallet drain ──
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
});
|
|
1130
|
-
onEvent({ kind: 'turn_done', reason: 'budget' });
|
|
1131
|
-
break;
|
|
1132
|
-
}
|
|
1080
|
+
// Per-turn $-cap was removed in v3.11.0 — runaway loops are caught by
|
|
1081
|
+
// MAX_TOOL_CALLS_PER_TURN (25) and MAX_TINY_RESPONSES (2) above; the
|
|
1082
|
+
// wallet balance itself is the ultimate ceiling. Batch callers that
|
|
1083
|
+
// need a hard $ ceiling can still pass `config.maxSpendUsd` (handled
|
|
1084
|
+
// a few lines below).
|
|
1085
|
+
//
|
|
1133
1086
|
// Count a response as "no progress" only if it made no meaningful output:
|
|
1134
1087
|
// no tool call, and no text content longer than a few chars. A short but
|
|
1135
1088
|
// legitimate response (e.g. "done" or a compact tool_use) resets the counter.
|
|
@@ -6,15 +6,6 @@ export interface AppConfig {
|
|
|
6
6
|
'smart-routing'?: string;
|
|
7
7
|
'permission-mode'?: string;
|
|
8
8
|
'max-turns'?: string;
|
|
9
|
-
/**
|
|
10
|
-
* Hard per-turn spend ceiling in USD (default $1.00 as of v3.8.42).
|
|
11
|
-
* Numeric string, e.g. "0.5" or "2". Set to "0" to disable the cap.
|
|
12
|
-
* The agent loop stops a turn the moment cumulative cost crosses this
|
|
13
|
-
* threshold, preventing a runaway model + tool combo from draining the
|
|
14
|
-
* wallet. Earlier versions used $0.25, which routinely fired on legit
|
|
15
|
-
* multi-stage tasks (dashboard scaffolds, image-to-image edits).
|
|
16
|
-
*/
|
|
17
|
-
'max-turn-spend-usd'?: string;
|
|
18
9
|
'auto-compact'?: string;
|
|
19
10
|
'session-save'?: string;
|
|
20
11
|
'debug'?: string;
|
package/dist/commands/config.js
CHANGED
|
@@ -21,7 +21,5 @@ export interface BundledLoad {
|
|
|
21
21
|
export declare function loadBundledSkills(): BundledLoad;
|
|
22
22
|
export interface SkillVarSource {
|
|
23
23
|
chain?: 'base' | 'solana';
|
|
24
|
-
/** Per-turn spend cap in USD; mirrors the `max-turn-spend-usd` config key. */
|
|
25
|
-
perTurnCapUsd?: number;
|
|
26
24
|
}
|
|
27
25
|
export declare function getSkillVars(src: SkillVarSource): Record<string, string>;
|
package/dist/skills/bootstrap.js
CHANGED
|
@@ -28,13 +28,5 @@ export function getSkillVars(src) {
|
|
|
28
28
|
const out = {};
|
|
29
29
|
if (src.chain)
|
|
30
30
|
out.wallet_chain = src.chain;
|
|
31
|
-
if (typeof src.perTurnCapUsd === 'number' && Number.isFinite(src.perTurnCapUsd)) {
|
|
32
|
-
const cap = src.perTurnCapUsd.toFixed(2);
|
|
33
|
-
out.per_turn_cap = cap;
|
|
34
|
-
// Skills run at turn boundary, so spent-this-turn is always zero at
|
|
35
|
-
// substitution time and remaining equals the cap.
|
|
36
|
-
out.spent_this_turn = '0.00';
|
|
37
|
-
out.turn_budget_remaining = cap;
|
|
38
|
-
}
|
|
39
31
|
return out;
|
|
40
32
|
}
|
|
@@ -5,7 +5,7 @@ argument-hint: <plan or topic to grill on>
|
|
|
5
5
|
cost-receipt: true
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
You are running inside Franklin, an Economic Agent powered by an x402 USDC wallet on {{wallet_chain}}. The user
|
|
8
|
+
You are running inside Franklin, an Economic Agent powered by an x402 USDC wallet on {{wallet_chain}}. The user funds the wallet directly; every paid call ($-priced tools, model API calls) draws against that balance, so wasteful spending shows up immediately on the receipt.
|
|
9
9
|
|
|
10
10
|
Your job: interview the user relentlessly about the plan below, **one question at a time**, until you reach a shared understanding of every branch of the decision tree. For every question, also propose your recommended answer and the reasoning behind it.
|
|
11
11
|
|
package/package.json
CHANGED