feat: add @tag model override support and remove Qdrant dependencies
- Add model-tags parser for @Tag syntax in chat messages - Support Anthropic models (Sonnet, Haiku, Opus) via @tag - Remove Qdrant vector database from infrastructure and configs - Simplify license model config to use null fallbacks - Add greeting stream after model switch via @tag - Fix protobuf field names to camelCase for v7 compatibility - Add 429 rate limit retry logic with exponential backoff - Remove RAG references from agent harness documentation
This commit is contained in:
@@ -421,15 +421,79 @@ export class CCXTFetcher {
|
||||
const amount = Math.round(trade.amount * sizeMult);
|
||||
const quoteAmount = Math.round((trade.price * trade.amount) * priceMult);
|
||||
|
||||
// protobufjs v7 uses camelCase field names internally — must use camelCase here
|
||||
return {
|
||||
trade_id: trade.id || `${trade.timestamp}`,
|
||||
tradeId: trade.id || `${trade.timestamp}`,
|
||||
ticker,
|
||||
timestamp: (trade.timestamp * 1_000_000).toString(), // Convert ms to nanoseconds
|
||||
price: price.toString(),
|
||||
amount: amount.toString(),
|
||||
quote_amount: quoteAmount.toString(),
|
||||
taker_buy: trade.side === 'buy',
|
||||
sequence: trade.order ? trade.order.toString() : undefined
|
||||
timestamp: (trade.timestamp * 1_000_000).toString(), // Convert ms to nanoseconds
|
||||
price: price.toString(),
|
||||
amount: amount.toString(),
|
||||
quoteAmount: quoteAmount.toString(),
|
||||
takerBuy: trade.side === 'buy',
|
||||
sequence: trade.order ? trade.order.toString() : undefined
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch 1-minute bars covering the current open window for each configured period,
|
||||
* rolling them up into a single aggregate per period for Flink accumulator seeding.
|
||||
*
|
||||
* Returns one seed object per period (or null for periods that just started with no
|
||||
* completed 1m bars yet). Throws on exchange errors — caller handles retries.
|
||||
*
|
||||
* @param {string} ticker
|
||||
* @param {number[]} periodSeconds - configured periods (e.g. [60, 300, 900, 3600, 14400, 86400])
|
||||
* @returns {Promise<Array<{periodSeconds, open, high, low, close, volume, windowStartMs}|null>>}
|
||||
*/
|
||||
async fetchSeedCandles(ticker, periodSeconds) {
|
||||
const nowMs = Date.now();
|
||||
const maxPeriod = Math.max(...periodSeconds);
|
||||
const longestWindowStart = Math.floor(nowMs / (maxPeriod * 1000)) * (maxPeriod * 1000);
|
||||
|
||||
// fetchHistoricalOHLC expects nanoseconds as strings
|
||||
const startNs = (longestWindowStart * 1_000_000).toString();
|
||||
const endNs = (nowMs * 1_000_000).toString();
|
||||
|
||||
const bars1m = await this.fetchHistoricalOHLC(ticker, startNs, endNs, 60, null);
|
||||
|
||||
return periodSeconds.map(period => {
|
||||
const windowStart = Math.floor(nowMs / (period * 1000)) * (period * 1000);
|
||||
const relevant = bars1m.filter(b => {
|
||||
const tsMs = parseInt(b.timestamp) / 1_000_000;
|
||||
return tsMs >= windowStart && tsMs < nowMs;
|
||||
});
|
||||
if (relevant.length === 0) return null;
|
||||
|
||||
const open = parseInt(relevant[0].open);
|
||||
const high = Math.max(...relevant.map(b => parseInt(b.high)));
|
||||
const low = Math.min(...relevant.map(b => parseInt(b.low)));
|
||||
const close = parseInt(relevant[relevant.length - 1].close);
|
||||
const volume = relevant.reduce((sum, b) => sum + parseInt(b.volume), 0);
|
||||
|
||||
return { periodSeconds: period, open, high, low, close, volume, windowStartMs: windowStart };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a seed candle aggregate into a Tick-shaped object for Kafka.
|
||||
* price = open (scaled int), amount = volume (scaled int); seed_* fields carry H/L/C/period.
|
||||
*/
|
||||
convertSeedToTick(seed, ticker) {
|
||||
// protobufjs v7 uses camelCase field names internally — must use camelCase here
|
||||
return {
|
||||
tradeId: `seed-${ticker}-${seed.periodSeconds}-${seed.windowStartMs}`,
|
||||
ticker,
|
||||
timestamp: (seed.windowStartMs * 1_000_000).toString(),
|
||||
price: seed.open,
|
||||
amount: seed.volume,
|
||||
quoteAmount: 0,
|
||||
takerBuy: false,
|
||||
isSeed: true,
|
||||
seedHigh: seed.high,
|
||||
seedLow: seed.low,
|
||||
seedClose: seed.close,
|
||||
seedWindowStartMs: seed.windowStartMs,
|
||||
seedPeriodSeconds: seed.periodSeconds
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user