@blockrun/franklin 3.15.52 → 3.15.54
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/tools/videogen.js
CHANGED
|
@@ -462,7 +462,13 @@ export function createVideoGenCapability(deps = {}) {
|
|
|
462
462
|
properties: {
|
|
463
463
|
prompt: { type: 'string', description: 'Text description of the video to generate' },
|
|
464
464
|
output_path: { type: 'string', description: 'Where to save the MP4. Default: generated-<timestamp>.mp4 in working directory' },
|
|
465
|
-
model: {
|
|
465
|
+
model: {
|
|
466
|
+
type: 'string',
|
|
467
|
+
description: 'Video model. Default: xai/grok-imagine-video. Known-valid models on the BlockRun gateway as of 2026-05: ' +
|
|
468
|
+
'xai/grok-imagine-video, bytedance/seedance-1.5-pro, bytedance/seedance-2.0, bytedance/seedance-2.0-fast. ' +
|
|
469
|
+
'Pick from this list; the gateway rejects unknown names with HTTP 400 (no money charged on rejection). ' +
|
|
470
|
+
'Speak "Seedance Pro" → bytedance/seedance-2.0; speak "Seedance fast" → bytedance/seedance-2.0-fast.',
|
|
471
|
+
},
|
|
466
472
|
image_url: { type: 'string', description: 'Optional seed image (image-to-video). Accepts http(s) URL, data: URI, or local file path — local paths get inlined as base64 data URIs automatically.' },
|
|
467
473
|
duration_seconds: { type: 'number', description: 'Duration billed for. Default depends on model (8s for grok-imagine-video).' },
|
|
468
474
|
contentId: { type: 'string', description: 'Optional Content id to attach and budget against.' },
|
|
@@ -7,7 +7,26 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { ProviderError } from '../standard-models.js';
|
|
9
9
|
export declare const TICKER_TO_ID: Record<string, string>;
|
|
10
|
+
/** For tests + cache invalidation. */
|
|
11
|
+
export declare function clearIdResolutionCache(): void;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a ticker to its CoinGecko id. Synchronous — checks the static
|
|
14
|
+
* map and the dynamic cache. Falls through to lowercase as a final guess.
|
|
15
|
+
*
|
|
16
|
+
* Use this from `transformData` (which is sync). Use `resolveProviderIdAsync`
|
|
17
|
+
* from `fetchData` to populate the cache before the sync read happens.
|
|
18
|
+
*/
|
|
10
19
|
export declare function resolveProviderId(ticker: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Like `resolveProviderId`, but on a static-map miss, hits CoinGecko's
|
|
22
|
+
* `/search?query=` to find the canonical id. Caches the result for 7 days
|
|
23
|
+
* so `resolveProviderId` (sync) can read it back during `transformData`.
|
|
24
|
+
*
|
|
25
|
+
* Why not always async: `transformData` is part of the Fetcher contract
|
|
26
|
+
* and is intentionally sync. `fetchData` is async, runs first, and is the
|
|
27
|
+
* right place to do network resolution. The two share state via the cache.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveProviderIdAsync(ticker: string): Promise<string>;
|
|
11
30
|
export declare function cached<T>(key: string, ttlMs: number, fn: () => Promise<T>): Promise<T>;
|
|
12
31
|
/** For tests: wipe every cached entry. */
|
|
13
32
|
export declare function clearCache(): void;
|
|
@@ -11,7 +11,15 @@ const BASE = 'https://api.coingecko.com/api/v3';
|
|
|
11
11
|
const UA = `franklin/${VERSION} (trading)`;
|
|
12
12
|
const TIMEOUT_MS = 10_000;
|
|
13
13
|
// Ticker → CoinGecko slug. Not exhaustive; unknown tickers fall through to
|
|
14
|
-
//
|
|
14
|
+
// the dynamic /search resolver below, which caches results.
|
|
15
|
+
//
|
|
16
|
+
// Verified 2026-05-04 in a live session: user asked Franklin for TON price,
|
|
17
|
+
// TradingMarket returned "No CoinGecko data for TON" because TON wasn't in
|
|
18
|
+
// this map and the lowercase fallback ("ton") doesn't match CoinGecko's
|
|
19
|
+
// actual id ("the-open-network"). Same hole exists for any token whose
|
|
20
|
+
// symbol differs from its id slug. Expanded the static map to cover the
|
|
21
|
+
// top ~30 currently-missing tokens, and added a /search-based resolver
|
|
22
|
+
// for everything else.
|
|
15
23
|
export const TICKER_TO_ID = {
|
|
16
24
|
BTC: 'bitcoin', ETH: 'ethereum', SOL: 'solana', BNB: 'binancecoin', XRP: 'ripple',
|
|
17
25
|
ADA: 'cardano', DOGE: 'dogecoin', AVAX: 'avalanche-2', DOT: 'polkadot', MATIC: 'matic-network',
|
|
@@ -20,12 +28,87 @@ export const TICKER_TO_ID = {
|
|
|
20
28
|
FIL: 'filecoin', AAVE: 'aave', MKR: 'maker', SNX: 'synthetix-network-token',
|
|
21
29
|
COMP: 'compound-governance-token', INJ: 'injective-protocol', TIA: 'celestia',
|
|
22
30
|
PEPE: 'pepe', WIF: 'dogwifcoin', RENDER: 'render-token',
|
|
31
|
+
// ── Added 2026-05-04 after live "No CoinGecko data for TON" report ──
|
|
32
|
+
TON: 'the-open-network', HYPE: 'hyperliquid', TRX: 'tron', TAO: 'bittensor',
|
|
33
|
+
WLD: 'worldcoin-wld', ENA: 'ethena', BERA: 'berachain-bera', JUP: 'jupiter-exchange-solana',
|
|
34
|
+
FET: 'fetch-ai', ONDO: 'ondo-finance', RNDR: 'render-token',
|
|
35
|
+
USDT: 'tether', USDC: 'usd-coin', DAI: 'dai', BCH: 'bitcoin-cash', ETC: 'ethereum-classic',
|
|
36
|
+
XLM: 'stellar', XMR: 'monero', IMX: 'immutable-x', GRT: 'the-graph', SAND: 'the-sandbox',
|
|
37
|
+
MANA: 'decentraland', AXS: 'axie-infinity', KAS: 'kaspa', ICP: 'internet-computer',
|
|
38
|
+
HBAR: 'hedera-hashgraph', VET: 'vechain', ALGO: 'algorand', FTM: 'fantom',
|
|
39
|
+
EGLD: 'elrond-erd-2', CRV: 'curve-dao-token', LDO: 'lido-dao', SHIB: 'shiba-inu',
|
|
40
|
+
BONK: 'bonk', POPCAT: 'popcat', FLOKI: 'floki', PNUT: 'peanut-the-squirrel',
|
|
23
41
|
};
|
|
42
|
+
const ID_RESOLUTION_CACHE = new Map();
|
|
43
|
+
const ID_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
44
|
+
function normalizeTicker(ticker) {
|
|
45
|
+
return ticker.toUpperCase().replace(/-USD$/, '').replace(/USDT?$/, '');
|
|
46
|
+
}
|
|
47
|
+
/** For tests + cache invalidation. */
|
|
48
|
+
export function clearIdResolutionCache() {
|
|
49
|
+
ID_RESOLUTION_CACHE.clear();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a ticker to its CoinGecko id. Synchronous — checks the static
|
|
53
|
+
* map and the dynamic cache. Falls through to lowercase as a final guess.
|
|
54
|
+
*
|
|
55
|
+
* Use this from `transformData` (which is sync). Use `resolveProviderIdAsync`
|
|
56
|
+
* from `fetchData` to populate the cache before the sync read happens.
|
|
57
|
+
*/
|
|
24
58
|
export function resolveProviderId(ticker) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
59
|
+
const normalized = normalizeTicker(ticker);
|
|
60
|
+
if (TICKER_TO_ID[normalized])
|
|
61
|
+
return TICKER_TO_ID[normalized];
|
|
62
|
+
if (TICKER_TO_ID[ticker.toUpperCase()])
|
|
63
|
+
return TICKER_TO_ID[ticker.toUpperCase()];
|
|
64
|
+
const cached = ID_RESOLUTION_CACHE.get(normalized);
|
|
65
|
+
if (cached && cached.expiresAt > Date.now())
|
|
66
|
+
return cached.id;
|
|
67
|
+
return normalized.toLowerCase();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Like `resolveProviderId`, but on a static-map miss, hits CoinGecko's
|
|
71
|
+
* `/search?query=` to find the canonical id. Caches the result for 7 days
|
|
72
|
+
* so `resolveProviderId` (sync) can read it back during `transformData`.
|
|
73
|
+
*
|
|
74
|
+
* Why not always async: `transformData` is part of the Fetcher contract
|
|
75
|
+
* and is intentionally sync. `fetchData` is async, runs first, and is the
|
|
76
|
+
* right place to do network resolution. The two share state via the cache.
|
|
77
|
+
*/
|
|
78
|
+
export async function resolveProviderIdAsync(ticker) {
|
|
79
|
+
const normalized = normalizeTicker(ticker);
|
|
80
|
+
// Static map and dynamic cache — fast path.
|
|
81
|
+
if (TICKER_TO_ID[normalized])
|
|
82
|
+
return TICKER_TO_ID[normalized];
|
|
83
|
+
if (TICKER_TO_ID[ticker.toUpperCase()])
|
|
84
|
+
return TICKER_TO_ID[ticker.toUpperCase()];
|
|
85
|
+
const cached = ID_RESOLUTION_CACHE.get(normalized);
|
|
86
|
+
if (cached && cached.expiresAt > Date.now())
|
|
87
|
+
return cached.id;
|
|
88
|
+
// Network: ask CoinGecko's search endpoint.
|
|
89
|
+
try {
|
|
90
|
+
const result = await coingeckoGet(`/search?query=${encodeURIComponent(normalized)}`);
|
|
91
|
+
if (result && typeof result === 'object' && !('kind' in result) && 'coins' in result) {
|
|
92
|
+
const coins = result.coins;
|
|
93
|
+
if (Array.isArray(coins) && coins.length > 0) {
|
|
94
|
+
// Prefer an exact symbol match; fall back to the highest-ranked
|
|
95
|
+
// coin (lowest market_cap_rank value, ignoring null/undefined).
|
|
96
|
+
const exact = coins.find(c => c.symbol?.toUpperCase() === normalized && typeof c.id === 'string');
|
|
97
|
+
const fallback = [...coins]
|
|
98
|
+
.filter((c) => typeof c.id === 'string')
|
|
99
|
+
.sort((a, b) => (a.market_cap_rank ?? Infinity) - (b.market_cap_rank ?? Infinity))[0];
|
|
100
|
+
const resolved = exact?.id ?? fallback?.id;
|
|
101
|
+
if (resolved) {
|
|
102
|
+
ID_RESOLUTION_CACHE.set(normalized, { id: resolved, expiresAt: Date.now() + ID_TTL_MS });
|
|
103
|
+
return resolved;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// /search itself failed — fall through to the lowercase guess.
|
|
110
|
+
}
|
|
111
|
+
return normalized.toLowerCase();
|
|
29
112
|
}
|
|
30
113
|
const cache = new Map();
|
|
31
114
|
export async function cached(key, ttlMs, fn) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cached, coingeckoGet,
|
|
1
|
+
import { cached, coingeckoGet, resolveProviderIdAsync, TTL } from './client.js';
|
|
2
2
|
export const coingeckoOHLCVFetcher = {
|
|
3
3
|
providerName: 'coingecko',
|
|
4
4
|
transformQuery(input) {
|
|
@@ -9,7 +9,7 @@ export const coingeckoOHLCVFetcher = {
|
|
|
9
9
|
return { ticker, days };
|
|
10
10
|
},
|
|
11
11
|
async fetchData(query) {
|
|
12
|
-
const id =
|
|
12
|
+
const id = await resolveProviderIdAsync(query.ticker);
|
|
13
13
|
return cached(`ohlcv:${id}:${query.days}`, TTL.ohlcv, async () => {
|
|
14
14
|
return coingeckoGet(`/coins/${id}/market_chart?vs_currency=usd&days=${query.days}&interval=daily`);
|
|
15
15
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Coerces: the nested `{ [id]: { usd: ..., usd_24h_change: ... } }`
|
|
7
7
|
* response into the standard PriceData shape.
|
|
8
8
|
*/
|
|
9
|
-
import { cached, coingeckoGet, resolveProviderId, TTL } from './client.js';
|
|
9
|
+
import { cached, coingeckoGet, resolveProviderId, resolveProviderIdAsync, TTL } from './client.js';
|
|
10
10
|
export const coingeckoPriceFetcher = {
|
|
11
11
|
providerName: 'coingecko',
|
|
12
12
|
transformQuery(input) {
|
|
@@ -17,7 +17,10 @@ export const coingeckoPriceFetcher = {
|
|
|
17
17
|
return { ticker };
|
|
18
18
|
},
|
|
19
19
|
async fetchData(query) {
|
|
20
|
-
|
|
20
|
+
// resolveProviderIdAsync warms the dynamic id cache via /search when the
|
|
21
|
+
// ticker isn't in the static map (e.g. TON → the-open-network).
|
|
22
|
+
// transformData below reads back from the same cache synchronously.
|
|
23
|
+
const id = await resolveProviderIdAsync(query.ticker);
|
|
21
24
|
return cached(`price:${id}`, TTL.price, async () => {
|
|
22
25
|
return coingeckoGet(`/simple/price?ids=${id}` +
|
|
23
26
|
`&vs_currencies=usd&include_24hr_change=true` +
|
package/package.json
CHANGED