@blockrun/franklin 3.15.87 → 3.15.89
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 +45 -6
- package/dist/agent/evaluator.js +1 -1
- package/dist/agent/llm.d.ts +16 -0
- package/dist/agent/llm.js +62 -8
- package/dist/agent/loop.js +32 -20
- package/dist/agent/media-router.js +3 -3
- package/dist/agent/optimize.js +42 -7
- package/dist/agent/turn-analyzer.js +7 -7
- package/dist/commands/content.d.ts +3 -3
- package/dist/commands/content.js +3 -3
- package/dist/commands/panel.js +16 -2
- package/dist/commands/start.js +15 -2
- package/dist/learnings/extractor.js +1 -1
- package/dist/proxy/server.js +77 -13
- package/dist/router/categories.js +4 -6
- package/dist/router/index.js +10 -8
- package/dist/social/a11y.d.ts +1 -1
- package/dist/social/a11y.js +5 -4
- package/dist/social/browser.js +63 -4
- package/dist/stats/cost-log.d.ts +52 -17
- package/dist/stats/cost-log.js +67 -17
- package/dist/tools/prediction.debug.js +1 -1
- package/dist/tools/prediction.js +1 -1
- package/dist/tools/searchx.js +3 -3
- package/dist/tools/wallet.js +1 -1
- package/dist/ui/app.js +1 -1
- package/package.json +1 -1
package/dist/stats/cost-log.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reader for `~/.blockrun/cost_log.jsonl` — the
|
|
3
|
-
* settled x402 payment.
|
|
2
|
+
* Reader (and limited writer) for `~/.blockrun/cost_log.jsonl` — the
|
|
3
|
+
* append-only ledger of every settled x402 payment.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* History: this file was originally SDK-only territory. `@blockrun/llm`'s
|
|
6
|
+
* internal `appendCostLog` writes one line per micropayment when callers
|
|
7
|
+
* use SDK helper methods (modal sandbox, prediction market, exa, etc.).
|
|
8
|
+
* But Franklin's main LLM stream — both the in-process agent loop
|
|
9
|
+
* (`src/agent/llm.ts`) and the proxy server (`src/proxy/server.ts`) —
|
|
10
|
+
* have **their own** x402 signers that bypass the SDK entirely. Verified
|
|
11
|
+
* 2026-05-09 on a real machine: a single paid agent turn dropped the
|
|
12
|
+
* wallet by $0.001 and updated `franklin-stats.json` correctly, but
|
|
13
|
+
* cost_log.jsonl gained zero entries. So cost_log was never the
|
|
14
|
+
* "wallet truth" it advertised — it was an SDK-subset.
|
|
12
15
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* alongside the recorded total.
|
|
16
|
+
* Fix (2026-05-09): expose `appendSettlementRow` so the agent and proxy
|
|
17
|
+
* signers can write the same shape the SDK does. The format contract
|
|
18
|
+
* (snake_case `cost_usd`, `ts` in unix seconds with subsecond precision,
|
|
19
|
+
* one JSON object per line) is preserved exactly so both writers
|
|
20
|
+
* interleave cleanly. Order in the file follows wall-clock arrival.
|
|
19
21
|
*
|
|
20
|
-
* Responsibility: read-only. We never
|
|
21
|
-
* the SDK
|
|
22
|
+
* Responsibility: read + append-only write. We never trim or rotate
|
|
23
|
+
* cost_log.jsonl — that contract still belongs to the SDK / hygiene.
|
|
22
24
|
*/
|
|
23
25
|
import fs from 'node:fs';
|
|
24
26
|
import path from 'node:path';
|
|
@@ -79,6 +81,54 @@ export function loadSdkSettlements(opts) {
|
|
|
79
81
|
}
|
|
80
82
|
return rows;
|
|
81
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Append one settlement row to ~/.blockrun/cost_log.jsonl in the same
|
|
86
|
+
* shape `@blockrun/llm`'s internal `appendCostLog` writes. Best-effort:
|
|
87
|
+
* silently swallows fs errors so a logging failure never breaks the
|
|
88
|
+
* paid call that just succeeded. Costs <= 0 are treated as no-op (no
|
|
89
|
+
* point logging $0 — the file's purpose is "what was actually paid").
|
|
90
|
+
*
|
|
91
|
+
* Honors FRANKLIN_NO_AUDIT=1 the same way `appendAudit` and `recordUsage`
|
|
92
|
+
* do, so test runs (test/e2e.mjs sets this) don't pollute the user's
|
|
93
|
+
* real cost_log. Verified 2026-05-10 on a real machine: two
|
|
94
|
+
* `/v1/messages: $0.000001` rows leaked into the user's cost_log from
|
|
95
|
+
* a paid e2e run because this gate was missing — paid e2e was hitting
|
|
96
|
+
* the real gateway with a real wallet, but the test framework expected
|
|
97
|
+
* NO writes to land. Restoring the gate keeps cost_log a clean ledger
|
|
98
|
+
* of REAL traffic.
|
|
99
|
+
*/
|
|
100
|
+
export function appendSettlementRow(endpoint, costUsd, meta) {
|
|
101
|
+
if (process.env.FRANKLIN_NO_AUDIT === '1' || process.env.FRANKLIN_NO_PERSIST === '1')
|
|
102
|
+
return;
|
|
103
|
+
if (!Number.isFinite(costUsd) || costUsd <= 0)
|
|
104
|
+
return;
|
|
105
|
+
if (typeof endpoint !== 'string' || endpoint.length === 0)
|
|
106
|
+
return;
|
|
107
|
+
try {
|
|
108
|
+
fs.mkdirSync(path.dirname(getCostLogPath()), { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
catch { /* best-effort */ }
|
|
111
|
+
// Match SDK conventions exactly: snake_case keys, ts in unix seconds
|
|
112
|
+
// with subsecond precision (Python convention — divide ms epoch by 1e3
|
|
113
|
+
// so the SDK reader and our reader agree on the timestamp).
|
|
114
|
+
const entry = {
|
|
115
|
+
ts: Date.now() / 1e3,
|
|
116
|
+
endpoint,
|
|
117
|
+
cost_usd: costUsd,
|
|
118
|
+
};
|
|
119
|
+
if (meta?.model)
|
|
120
|
+
entry.model = meta.model;
|
|
121
|
+
if (meta?.wallet)
|
|
122
|
+
entry.wallet = meta.wallet;
|
|
123
|
+
if (meta?.network)
|
|
124
|
+
entry.network = meta.network;
|
|
125
|
+
if (meta?.client_kind)
|
|
126
|
+
entry.client_kind = meta.client_kind;
|
|
127
|
+
try {
|
|
128
|
+
fs.appendFileSync(getCostLogPath(), JSON.stringify(entry) + '\n');
|
|
129
|
+
}
|
|
130
|
+
catch { /* best-effort */ }
|
|
131
|
+
}
|
|
82
132
|
/** Aggregate the SDK ledger into a single summary object. */
|
|
83
133
|
export function summarizeSdkSettlements(opts) {
|
|
84
134
|
const rows = loadSdkSettlements(opts);
|
|
@@ -767,7 +767,7 @@ export const predictionMarketCapability = {
|
|
|
767
767
|
'Default routing: ' +
|
|
768
768
|
'"is there a market on X anywhere" → searchAll. ' +
|
|
769
769
|
'"top wallets / who is profitable / who should I follow on Polymarket" → leaderboard. ' +
|
|
770
|
-
'"analyze this wallet / can I copy this trader /
|
|
770
|
+
'"analyze this wallet / can I copy this trader / copy trade / show me their P&L AND positions" → run walletProfile + walletPnl + walletPositions IN PARALLEL with the same address — three $0.005 calls give the full picture for $0.015. Do not Bash-curl Polymarket directly; the agent has paid tools for this. ' +
|
|
771
771
|
'"what are smart traders betting on right now" → smartActivity. ' +
|
|
772
772
|
'"show smart money on this specific Polymarket market" → smartMoney with conditionId. ' +
|
|
773
773
|
'"should I bet on X" → run searchPolymarket + searchKalshi in parallel and compare implied probabilities — divergence is the signal.',
|
package/dist/tools/prediction.js
CHANGED
|
@@ -825,7 +825,7 @@ export const predictionMarketCapability = {
|
|
|
825
825
|
'Default routing: ' +
|
|
826
826
|
'"is there a market on X anywhere" → searchAll. ' +
|
|
827
827
|
'"top wallets / who is profitable / who should I follow on Polymarket" → leaderboard. ' +
|
|
828
|
-
'"analyze this wallet / can I copy this trader /
|
|
828
|
+
'"analyze this wallet / can I copy this trader / show me their P&L AND positions" → run walletProfile + walletPnl + walletPositions IN PARALLEL with the same address — three $0.005 calls give the full picture for $0.015. Do not Bash-curl Polymarket directly; the agent has paid tools for this. ' +
|
|
829
829
|
'"what are smart traders betting on right now" → smartActivity. ' +
|
|
830
830
|
'"show smart money on this specific Polymarket market" → smartMoney with conditionId. ' +
|
|
831
831
|
'"should I bet on X" → run searchPolymarket + searchKalshi in parallel and compare implied probabilities — divergence is the signal.',
|
package/dist/tools/searchx.js
CHANGED
|
@@ -13,14 +13,14 @@ import { detectProduct } from '../social/ai.js';
|
|
|
13
13
|
import { loadConfig, isConfigReady } from '../social/config.js';
|
|
14
14
|
import { browserPool } from '../social/browser-pool.js';
|
|
15
15
|
// ─── Intent detection (code-level, not LLM-level) ──────────────────────────
|
|
16
|
-
// When the user asks "check my @handle mentions/notifications
|
|
17
|
-
//
|
|
16
|
+
// When the user asks "check my @handle mentions/notifications", the tool
|
|
17
|
+
// itself routes to x.com/notifications. English-only keyword fast-path;
|
|
18
|
+
// the LLM-level classifier handles non-English queries before this point.
|
|
18
19
|
const NOTIFICATION_KEYWORDS = [
|
|
19
20
|
'notification', 'notifications',
|
|
20
21
|
'mention', 'mentions', 'mentioned',
|
|
21
22
|
'reply', 'replies',
|
|
22
23
|
'interact', 'interaction', 'interactions',
|
|
23
|
-
'互动', '通知', '提及', '回复', '看看',
|
|
24
24
|
'check my', 'my account', 'my x',
|
|
25
25
|
'to:', 'from:', '@',
|
|
26
26
|
];
|
package/dist/tools/wallet.js
CHANGED
|
@@ -50,7 +50,7 @@ export const walletCapability = {
|
|
|
50
50
|
spec: {
|
|
51
51
|
name: 'Wallet',
|
|
52
52
|
description: 'Read Franklin\'s wallet status — chain, address, and USDC balance. ' +
|
|
53
|
-
'Use this for any "what\'s my balance / how much money /
|
|
53
|
+
'Use this for any "what\'s my balance / how much money / wallet status" question. ' +
|
|
54
54
|
'Cheaper and more direct than running `franklin balance` via Bash, and never costs USDC.',
|
|
55
55
|
input_schema: {
|
|
56
56
|
type: 'object',
|
package/dist/ui/app.js
CHANGED
|
@@ -309,7 +309,7 @@ function InputBox({ input, setInput, onSubmit, model, balance, chain, walletTail
|
|
|
309
309
|
const m = balance.match(/\$([\d.]+)/);
|
|
310
310
|
const num = m ? parseFloat(m[1]) : null;
|
|
311
311
|
if (num !== null && num < 0.50) {
|
|
312
|
-
return _jsxs(_Fragment, { children: [_jsx(Text, { color: "red", bold: true, children: balance }), _jsx(Text, { color: "red", children: " \u26A0 low \u2014
|
|
312
|
+
return _jsxs(_Fragment, { children: [_jsx(Text, { color: "red", bold: true, children: balance }), _jsx(Text, { color: "red", children: " \u26A0 low \u2014 deposit at http://localhost:3100/#wallet or /model free" })] });
|
|
313
313
|
}
|
|
314
314
|
if (num !== null && num < 1.00) {
|
|
315
315
|
return _jsx(Text, { color: "yellow", children: balance });
|
package/package.json
CHANGED