@sherwoodagent/cli 0.42.0 → 0.51.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/{addresses-DCQMJJFI.js → addresses-DOWLGXGE.js} +4 -4
- package/dist/{agent-5YEJ6W6W.js → agent-ZPAZTJG3.js} +2923 -2023
- package/dist/agent-ZPAZTJG3.js.map +1 -0
- package/dist/autoresearch-IA7HGSNW.js +267 -0
- package/dist/autoresearch-IA7HGSNW.js.map +1 -0
- package/dist/{chat-UWJ6JBFE.js → chat-MRTPUZ3X.js} +8 -8
- package/dist/{chunk-FOOZC4AM.js → chunk-2LRC7I33.js} +2 -2
- package/dist/{chunk-4EHI4SKM.js → chunk-2W4KGGPU.js} +11 -1
- package/dist/chunk-2W4KGGPU.js.map +1 -0
- package/dist/chunk-7HJXZ4NM.js +189 -0
- package/dist/chunk-7HJXZ4NM.js.map +1 -0
- package/dist/{chunk-JNDEZFXW.js → chunk-E6LH2FJ6.js} +4 -4
- package/dist/{chunk-XAUMJZU2.js → chunk-FWC57PT7.js} +2 -2
- package/dist/{chunk-4OAZ7TP5.js → chunk-IS2CLLUT.js} +4 -4
- package/dist/{chunk-T2IA6CCW.js → chunk-KJ35EF7N.js} +4 -4
- package/dist/{chunk-GMVDHSCF.js → chunk-OHQOTSFG.js} +39 -3
- package/dist/chunk-OHQOTSFG.js.map +1 -0
- package/dist/chunk-OMW47WOO.js +700 -0
- package/dist/chunk-OMW47WOO.js.map +1 -0
- package/dist/{chunk-5Q3VT6NQ.js → chunk-R7X33D2S.js} +5 -5
- package/dist/{chunk-6U3A6ZJ2.js → chunk-WMZEOR5W.js} +6 -127
- package/dist/chunk-WMZEOR5W.js.map +1 -0
- package/dist/{chunk-SWKHSKDH.js → chunk-XDBRKW7I.js} +3 -3
- package/dist/chunk-YTYXBX7B.js +495 -0
- package/dist/chunk-YTYXBX7B.js.map +1 -0
- package/dist/{client-DRVUILER.js → client-UHHCB6EZ.js} +4 -4
- package/dist/{config-YRERDZSL.js → config-REASKDIK.js} +6 -2
- package/dist/{eas-KBU2BAOD.js → eas-PEEWGSAO.js} +6 -6
- package/dist/{governor-KH7RNH2E.js → governor-MG5VVSU4.js} +6 -6
- package/dist/index.js +1424 -270
- package/dist/index.js.map +1 -1
- package/dist/{network-3HB46JMQ.js → network-3ZU7UBDU.js} +3 -3
- package/dist/{price-TTQWI672.js → price-WCCXWPDM.js} +5 -5
- package/dist/{research-J3HYU3N6.js → research-QBKISW2M.js} +9 -9
- package/dist/research-YJWSQS2A.js +14 -0
- package/dist/serve-6MYBOAX6.js +222 -0
- package/dist/serve-6MYBOAX6.js.map +1 -0
- package/dist/{session-NUPHC6ZN.js → session-FPCPCVQX.js} +10 -10
- package/dist/summary-formatter-JIGWN4QS.js +180 -0
- package/dist/summary-formatter-JIGWN4QS.js.map +1 -0
- package/dist/{trade-VGECC4QZ.js → trade-NO6CNWCA.js} +19 -17
- package/dist/{trade-VGECC4QZ.js.map → trade-NO6CNWCA.js.map} +1 -1
- package/dist/{xmtp-JO7W6RFK.js → xmtp-ACB2W573.js} +6 -6
- package/package.json +5 -2
- package/dist/agent-5YEJ6W6W.js.map +0 -1
- package/dist/chunk-4EHI4SKM.js.map +0 -1
- package/dist/chunk-6U3A6ZJ2.js.map +0 -1
- package/dist/chunk-GMVDHSCF.js.map +0 -1
- package/dist/research-NR4VC5LN.js +0 -14
- /package/dist/{addresses-DCQMJJFI.js.map → addresses-DOWLGXGE.js.map} +0 -0
- /package/dist/{chat-UWJ6JBFE.js.map → chat-MRTPUZ3X.js.map} +0 -0
- /package/dist/{chunk-FOOZC4AM.js.map → chunk-2LRC7I33.js.map} +0 -0
- /package/dist/{chunk-JNDEZFXW.js.map → chunk-E6LH2FJ6.js.map} +0 -0
- /package/dist/{chunk-XAUMJZU2.js.map → chunk-FWC57PT7.js.map} +0 -0
- /package/dist/{chunk-4OAZ7TP5.js.map → chunk-IS2CLLUT.js.map} +0 -0
- /package/dist/{chunk-T2IA6CCW.js.map → chunk-KJ35EF7N.js.map} +0 -0
- /package/dist/{chunk-5Q3VT6NQ.js.map → chunk-R7X33D2S.js.map} +0 -0
- /package/dist/{chunk-SWKHSKDH.js.map → chunk-XDBRKW7I.js.map} +0 -0
- /package/dist/{client-DRVUILER.js.map → client-UHHCB6EZ.js.map} +0 -0
- /package/dist/{config-YRERDZSL.js.map → config-REASKDIK.js.map} +0 -0
- /package/dist/{eas-KBU2BAOD.js.map → eas-PEEWGSAO.js.map} +0 -0
- /package/dist/{governor-KH7RNH2E.js.map → governor-MG5VVSU4.js.map} +0 -0
- /package/dist/{network-3HB46JMQ.js.map → network-3ZU7UBDU.js.map} +0 -0
- /package/dist/{price-TTQWI672.js.map → price-WCCXWPDM.js.map} +0 -0
- /package/dist/{research-J3HYU3N6.js.map → research-QBKISW2M.js.map} +0 -0
- /package/dist/{research-NR4VC5LN.js.map → research-YJWSQS2A.js.map} +0 -0
- /package/dist/{session-NUPHC6ZN.js.map → session-FPCPCVQX.js.map} +0 -0
- /package/dist/{xmtp-JO7W6RFK.js.map → xmtp-ACB2W573.js.map} +0 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeTradeDecision
|
|
3
|
+
} from "./chunk-YTYXBX7B.js";
|
|
4
|
+
|
|
5
|
+
// src/agent/autoresearch.ts
|
|
6
|
+
import { readFile, writeFile, appendFile } from "fs/promises";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
var DEFAULT_PARAMS = {
|
|
11
|
+
weights: {
|
|
12
|
+
smartMoney: 0.3,
|
|
13
|
+
technical: 0.25,
|
|
14
|
+
sentiment: 0.1,
|
|
15
|
+
onchain: 0.2,
|
|
16
|
+
fundamental: 0.15,
|
|
17
|
+
event: 0
|
|
18
|
+
},
|
|
19
|
+
buyThreshold: 0.14,
|
|
20
|
+
// autoresearch walk-forward validated
|
|
21
|
+
sellThreshold: -0.14,
|
|
22
|
+
stopLossPct: 0.05,
|
|
23
|
+
takeProfitRR: 2,
|
|
24
|
+
// wider TP captures more upside
|
|
25
|
+
trailPct: 0.03,
|
|
26
|
+
// tighter trail (from 4%)
|
|
27
|
+
timeStopHours: 84,
|
|
28
|
+
// shorter (from 96h)
|
|
29
|
+
leverage: 1
|
|
30
|
+
// no leverage until WR > 60%
|
|
31
|
+
};
|
|
32
|
+
function scoreParams(rows, params) {
|
|
33
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
34
|
+
for (const r of rows) {
|
|
35
|
+
if (!grouped.has(r.tokenId)) grouped.set(r.tokenId, []);
|
|
36
|
+
grouped.get(r.tokenId).push(r);
|
|
37
|
+
}
|
|
38
|
+
const allReturns = [];
|
|
39
|
+
const allHoldDurations = [];
|
|
40
|
+
let totalTrades = 0;
|
|
41
|
+
let wins = 0;
|
|
42
|
+
for (const [_token, tokenRows] of grouped) {
|
|
43
|
+
tokenRows.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
44
|
+
let position = null;
|
|
45
|
+
for (const row of tokenRows) {
|
|
46
|
+
const price = row.price;
|
|
47
|
+
if (!Number.isFinite(price) || price <= 0) continue;
|
|
48
|
+
const signals = row.signals.map((s) => ({
|
|
49
|
+
name: s.name,
|
|
50
|
+
value: s.value,
|
|
51
|
+
confidence: s.confidence,
|
|
52
|
+
source: "",
|
|
53
|
+
details: ""
|
|
54
|
+
}));
|
|
55
|
+
const regime = row.regime && row.regime !== "unknown" ? row.regime : void 0;
|
|
56
|
+
const decision = computeTradeDecision(signals, params.weights, void 0, void 0, regime);
|
|
57
|
+
let action;
|
|
58
|
+
if (decision.score >= params.buyThreshold + 0.15) action = "STRONG_BUY";
|
|
59
|
+
else if (decision.score >= params.buyThreshold) action = "BUY";
|
|
60
|
+
else if (decision.score <= params.sellThreshold - 0.1) action = "STRONG_SELL";
|
|
61
|
+
else if (decision.score <= params.sellThreshold) action = "SELL";
|
|
62
|
+
else action = "HOLD";
|
|
63
|
+
const ts = Date.parse(row.timestamp);
|
|
64
|
+
if (position) {
|
|
65
|
+
const isShort = position.side === "short";
|
|
66
|
+
if (isShort && price < position.extreme) position.extreme = price;
|
|
67
|
+
if (!isShort && price > position.extreme) position.extreme = price;
|
|
68
|
+
const rawPnl = isShort ? (position.entryPrice - price) / position.entryPrice : (price - position.entryPrice) / position.entryPrice;
|
|
69
|
+
const pnl = rawPnl * params.leverage;
|
|
70
|
+
const hours = (ts - position.entryTs) / 36e5;
|
|
71
|
+
const tpPct = params.stopLossPct * params.takeProfitRR;
|
|
72
|
+
let exit = false;
|
|
73
|
+
if (rawPnl <= -params.stopLossPct) exit = true;
|
|
74
|
+
else if (rawPnl >= tpPct) exit = true;
|
|
75
|
+
else if (params.trailPct > 0 && (isShort ? price >= position.extreme * (1 + params.trailPct) : price <= position.extreme * (1 - params.trailPct))) exit = true;
|
|
76
|
+
else if (hours > params.timeStopHours && Math.abs(pnl) < 0.01) exit = true;
|
|
77
|
+
else if (isShort ? action === "BUY" || action === "STRONG_BUY" : action === "SELL" || action === "STRONG_SELL") exit = true;
|
|
78
|
+
if (exit) {
|
|
79
|
+
allReturns.push(pnl);
|
|
80
|
+
allHoldDurations.push(ts - position.entryTs);
|
|
81
|
+
totalTrades++;
|
|
82
|
+
if (pnl > 0) wins++;
|
|
83
|
+
position = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!position) {
|
|
87
|
+
if (action === "BUY" || action === "STRONG_BUY") {
|
|
88
|
+
position = { side: "long", entryPrice: price, entryTs: ts, extreme: price };
|
|
89
|
+
} else if (action === "SELL" || action === "STRONG_SELL") {
|
|
90
|
+
position = { side: "short", entryPrice: price, entryTs: ts, extreme: price };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (totalTrades < 5) {
|
|
96
|
+
return { sharpe: -999, totalReturn: 0, maxDrawdown: 1, trades: totalTrades, winRate: 0, score: -999 };
|
|
97
|
+
}
|
|
98
|
+
const mean = allReturns.reduce((s, r) => s + r, 0) / allReturns.length;
|
|
99
|
+
const variance = allReturns.reduce((s, r) => s + (r - mean) ** 2, 0) / (allReturns.length - 1);
|
|
100
|
+
const std = Math.sqrt(variance);
|
|
101
|
+
const avgHoldMs = allHoldDurations.length > 0 ? allHoldDurations.reduce((s, d) => s + d, 0) / allHoldDurations.length : 864e5;
|
|
102
|
+
const avgHoldDays = Math.max(avgHoldMs / 864e5, 0.1);
|
|
103
|
+
const tradesPerYear = Math.max(252 / avgHoldDays, 1);
|
|
104
|
+
const sharpe = std > 0 ? mean / std * Math.sqrt(tradesPerYear) : 0;
|
|
105
|
+
const totalReturn = allReturns.reduce((eq, r) => eq * (1 + r), 1) - 1;
|
|
106
|
+
let peak = 1;
|
|
107
|
+
let equity = 1;
|
|
108
|
+
let maxDD = 0;
|
|
109
|
+
for (const r of allReturns) {
|
|
110
|
+
equity *= 1 + r;
|
|
111
|
+
if (equity > peak) peak = equity;
|
|
112
|
+
const dd = (peak - equity) / peak;
|
|
113
|
+
if (dd > maxDD) maxDD = dd;
|
|
114
|
+
}
|
|
115
|
+
const winRate = wins / totalTrades;
|
|
116
|
+
const tradePenalty = Math.sqrt(Math.min(totalTrades / 50, 1));
|
|
117
|
+
const ddPenalty = maxDD > 0.5 ? 999 : maxDD * 5;
|
|
118
|
+
const score = sharpe * tradePenalty - ddPenalty;
|
|
119
|
+
return { sharpe, totalReturn, maxDrawdown: maxDD, trades: totalTrades, winRate, score };
|
|
120
|
+
}
|
|
121
|
+
var MUTATIONS = [
|
|
122
|
+
// Weight mutations
|
|
123
|
+
{ name: "boost_technical", mutate: (p) => ({ ...p, weights: { ...p.weights, technical: Math.min(0.5, p.weights.technical + 0.05) } }) },
|
|
124
|
+
{ name: "reduce_technical", mutate: (p) => ({ ...p, weights: { ...p.weights, technical: Math.max(0.05, p.weights.technical - 0.05) } }) },
|
|
125
|
+
{ name: "boost_onchain", mutate: (p) => ({ ...p, weights: { ...p.weights, onchain: Math.min(0.5, p.weights.onchain + 0.05) } }) },
|
|
126
|
+
{ name: "reduce_onchain", mutate: (p) => ({ ...p, weights: { ...p.weights, onchain: Math.max(0, p.weights.onchain - 0.05) } }) },
|
|
127
|
+
{ name: "boost_sentiment", mutate: (p) => ({ ...p, weights: { ...p.weights, sentiment: Math.min(0.4, p.weights.sentiment + 0.05) } }) },
|
|
128
|
+
{ name: "reduce_sentiment", mutate: (p) => ({ ...p, weights: { ...p.weights, sentiment: Math.max(0, p.weights.sentiment - 0.05) } }) },
|
|
129
|
+
{ name: "zero_fundamental", mutate: (p) => ({ ...p, weights: { ...p.weights, fundamental: 0 } }) },
|
|
130
|
+
{ name: "restore_fundamental", mutate: (p) => ({ ...p, weights: { ...p.weights, fundamental: 0.05 } }) },
|
|
131
|
+
// Threshold mutations
|
|
132
|
+
{ name: "lower_buy_threshold", mutate: (p) => ({ ...p, buyThreshold: Math.max(0.05, p.buyThreshold - 0.02) }) },
|
|
133
|
+
{ name: "raise_buy_threshold", mutate: (p) => ({ ...p, buyThreshold: Math.min(0.4, p.buyThreshold + 0.02) }) },
|
|
134
|
+
{ name: "tighten_sell_threshold", mutate: (p) => ({ ...p, sellThreshold: Math.min(-0.05, p.sellThreshold + 0.02) }) },
|
|
135
|
+
{ name: "loosen_sell_threshold", mutate: (p) => ({ ...p, sellThreshold: Math.max(-0.5, p.sellThreshold - 0.02) }) },
|
|
136
|
+
// Stop/exit mutations
|
|
137
|
+
{ name: "widen_stop", mutate: (p) => ({ ...p, stopLossPct: Math.min(0.15, p.stopLossPct + 0.01) }) },
|
|
138
|
+
{ name: "tighten_stop", mutate: (p) => ({ ...p, stopLossPct: Math.max(0.02, p.stopLossPct - 0.01) }) },
|
|
139
|
+
{ name: "increase_rr", mutate: (p) => ({ ...p, takeProfitRR: Math.min(4, p.takeProfitRR + 0.5) }) },
|
|
140
|
+
{ name: "decrease_rr", mutate: (p) => ({ ...p, takeProfitRR: Math.max(1, p.takeProfitRR - 0.5) }) },
|
|
141
|
+
{ name: "widen_trail", mutate: (p) => ({ ...p, trailPct: Math.min(0.1, p.trailPct + 0.01) }) },
|
|
142
|
+
{ name: "tighten_trail", mutate: (p) => ({ ...p, trailPct: Math.max(0.01, p.trailPct - 0.01) }) },
|
|
143
|
+
{ name: "longer_time_stop", mutate: (p) => ({ ...p, timeStopHours: Math.min(96, p.timeStopHours + 12) }) },
|
|
144
|
+
{ name: "shorter_time_stop", mutate: (p) => ({ ...p, timeStopHours: Math.max(12, p.timeStopHours - 12) }) },
|
|
145
|
+
{ name: "disable_time_stop", mutate: (p) => ({ ...p, timeStopHours: 999 }) },
|
|
146
|
+
// Leverage mutations
|
|
147
|
+
{ name: "increase_leverage", mutate: (p) => ({ ...p, leverage: Math.min(5, p.leverage + 1) }) },
|
|
148
|
+
{ name: "decrease_leverage", mutate: (p) => ({ ...p, leverage: Math.max(1, p.leverage - 1) }) },
|
|
149
|
+
// Fundamental/event weight mutations (newly active categories)
|
|
150
|
+
{ name: "boost_fundamental", mutate: (p) => ({ ...p, weights: { ...p.weights, fundamental: Math.min(0.3, p.weights.fundamental + 0.05) } }) },
|
|
151
|
+
{ name: "boost_event", mutate: (p) => ({ ...p, weights: { ...p.weights, event: Math.min(0.25, p.weights.event + 0.05) } }) },
|
|
152
|
+
{ name: "reduce_event", mutate: (p) => ({ ...p, weights: { ...p.weights, event: Math.max(0, p.weights.event - 0.05) } }) }
|
|
153
|
+
];
|
|
154
|
+
async function runAutoresearch(opts) {
|
|
155
|
+
const base = join(homedir(), ".sherwood", "agent");
|
|
156
|
+
const logPath = join(base, "autoresearch-log.jsonl");
|
|
157
|
+
const paths = opts.historyPaths ?? [
|
|
158
|
+
join(base, "signal-history-2026-04-21.jsonl"),
|
|
159
|
+
join(base, "signal-history.jsonl")
|
|
160
|
+
];
|
|
161
|
+
let allRows = [];
|
|
162
|
+
for (const p of paths) {
|
|
163
|
+
try {
|
|
164
|
+
const raw = await readFile(p, "utf-8");
|
|
165
|
+
for (const line of raw.split("\n")) {
|
|
166
|
+
if (!line.trim()) continue;
|
|
167
|
+
try {
|
|
168
|
+
allRows.push(JSON.parse(line));
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (opts.lastDays) {
|
|
176
|
+
const cutoff = Date.now() - opts.lastDays * 864e5;
|
|
177
|
+
allRows = allRows.filter((r) => Date.parse(r.timestamp) >= cutoff);
|
|
178
|
+
}
|
|
179
|
+
console.log(chalk.bold(`
|
|
180
|
+
Autoresearch \u2014 ${allRows.length} signal rows loaded`));
|
|
181
|
+
if (allRows.length < 100) {
|
|
182
|
+
console.log(chalk.red(" Insufficient data for autoresearch (need 100+ rows). Aborting."));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const maxExperiments = opts.experiments ?? 50;
|
|
186
|
+
let currentParams = { ...DEFAULT_PARAMS };
|
|
187
|
+
const baseline = scoreParams(allRows, currentParams);
|
|
188
|
+
let bestScore = baseline.score;
|
|
189
|
+
console.log(chalk.dim(` Baseline: score=${baseline.score.toFixed(3)} sharpe=${baseline.sharpe.toFixed(2)} trades=${baseline.trades} WR=${(baseline.winRate * 100).toFixed(0)}% DD=${(baseline.maxDrawdown * 100).toFixed(1)}%`));
|
|
190
|
+
console.log(chalk.dim(` Running ${maxExperiments} experiments...
|
|
191
|
+
`));
|
|
192
|
+
let improvements = 0;
|
|
193
|
+
for (let exp = 1; exp <= maxExperiments; exp++) {
|
|
194
|
+
const mutation = MUTATIONS[Math.floor(Math.random() * MUTATIONS.length)];
|
|
195
|
+
const mutatedParams = mutation.mutate(currentParams);
|
|
196
|
+
const result = scoreParams(allRows, mutatedParams);
|
|
197
|
+
const improved = result.score > bestScore;
|
|
198
|
+
if (improved) {
|
|
199
|
+
currentParams = mutatedParams;
|
|
200
|
+
bestScore = result.score;
|
|
201
|
+
improvements++;
|
|
202
|
+
console.log(chalk.green(
|
|
203
|
+
` #${exp} ${mutation.name}: score ${result.score.toFixed(3)} (${improved ? "+" : ""}${(result.score - baseline.score).toFixed(3)}) sharpe=${result.sharpe.toFixed(2)} trades=${result.trades} WR=${(result.winRate * 100).toFixed(0)}% DD=${(result.maxDrawdown * 100).toFixed(1)}% \u2713`
|
|
204
|
+
));
|
|
205
|
+
} else {
|
|
206
|
+
if (exp % 10 === 0) {
|
|
207
|
+
console.log(chalk.dim(` #${exp} ${mutation.name}: score ${result.score.toFixed(3)} \u2014 no improvement (best=${bestScore.toFixed(3)})`));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const logEntry = {
|
|
211
|
+
id: exp,
|
|
212
|
+
params: improved ? mutatedParams : currentParams,
|
|
213
|
+
score: result.score,
|
|
214
|
+
sharpe: result.sharpe,
|
|
215
|
+
totalReturn: result.totalReturn,
|
|
216
|
+
maxDrawdown: result.maxDrawdown,
|
|
217
|
+
trades: result.trades,
|
|
218
|
+
winRate: result.winRate,
|
|
219
|
+
mutation: mutation.name,
|
|
220
|
+
improved,
|
|
221
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
222
|
+
};
|
|
223
|
+
await appendFile(logPath, JSON.stringify(logEntry) + "\n");
|
|
224
|
+
}
|
|
225
|
+
const sorted = [...allRows].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
226
|
+
const splitIdx = Math.floor(sorted.length * 0.7);
|
|
227
|
+
const testRows = sorted.slice(splitIdx);
|
|
228
|
+
const trainResult = scoreParams(sorted.slice(0, splitIdx), currentParams);
|
|
229
|
+
const testResult = scoreParams(testRows, currentParams);
|
|
230
|
+
const baselineTest = scoreParams(testRows, DEFAULT_PARAMS);
|
|
231
|
+
const final = scoreParams(allRows, currentParams);
|
|
232
|
+
console.log(chalk.bold(`
|
|
233
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`));
|
|
234
|
+
console.log(chalk.bold(` Autoresearch complete: ${maxExperiments} experiments, ${improvements} improvements`));
|
|
235
|
+
console.log(chalk.bold(` \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`));
|
|
236
|
+
console.log(` Baseline score: ${baseline.score.toFixed(3)} \u2192 Final: ${final.score.toFixed(3)}`);
|
|
237
|
+
console.log(` Sharpe: ${baseline.sharpe.toFixed(2)} \u2192 ${final.sharpe.toFixed(2)}`);
|
|
238
|
+
console.log(` Trades: ${baseline.trades} \u2192 ${final.trades}`);
|
|
239
|
+
console.log(` Win rate: ${(baseline.winRate * 100).toFixed(0)}% \u2192 ${(final.winRate * 100).toFixed(0)}%`);
|
|
240
|
+
console.log(` Max DD: ${(baseline.maxDrawdown * 100).toFixed(1)}% \u2192 ${(final.maxDrawdown * 100).toFixed(1)}%`);
|
|
241
|
+
console.log(chalk.bold(`
|
|
242
|
+
\u2500\u2500 Walk-Forward Validation (last 30% of data) \u2500\u2500`));
|
|
243
|
+
console.log(` Test rows: ${testRows.length} (${(testRows.length / allRows.length * 100).toFixed(0)}% of total)`);
|
|
244
|
+
if (testResult.trades >= 5) {
|
|
245
|
+
console.log(` Baseline on test: sharpe=${baselineTest.sharpe.toFixed(2)} trades=${baselineTest.trades} WR=${(baselineTest.winRate * 100).toFixed(0)}%`);
|
|
246
|
+
console.log(` Optimized on test: sharpe=${testResult.sharpe.toFixed(2)} trades=${testResult.trades} WR=${(testResult.winRate * 100).toFixed(0)}%`);
|
|
247
|
+
const testImproved = testResult.score > baselineTest.score;
|
|
248
|
+
console.log(testImproved ? chalk.green(` \u2713 Params validated \u2014 improved on held-out data`) : chalk.yellow(` \u26A0 Params may be overfit \u2014 degraded on held-out data`));
|
|
249
|
+
} else {
|
|
250
|
+
console.log(chalk.yellow(` \u26A0 Insufficient test trades (${testResult.trades}) for validation \u2014 use more data`));
|
|
251
|
+
}
|
|
252
|
+
console.log(`
|
|
253
|
+
Best params:`);
|
|
254
|
+
console.log(` weights: tech=${currentParams.weights.technical} sent=${currentParams.weights.sentiment} onchain=${currentParams.weights.onchain} fund=${currentParams.weights.fundamental}`);
|
|
255
|
+
console.log(` buyThreshold: ${currentParams.buyThreshold} sellThreshold: ${currentParams.sellThreshold}`);
|
|
256
|
+
console.log(` stop: ${(currentParams.stopLossPct * 100).toFixed(0)}% RR: ${currentParams.takeProfitRR} trail: ${(currentParams.trailPct * 100).toFixed(0)}% timeStop: ${currentParams.timeStopHours}h`);
|
|
257
|
+
console.log(`
|
|
258
|
+
Log: ${logPath}`);
|
|
259
|
+
const bestPath = join(base, "autoresearch-best-params.json");
|
|
260
|
+
await writeFile(bestPath, JSON.stringify({ ...currentParams, _score: final.score, _sharpe: final.sharpe, _experiments: maxExperiments }, null, 2));
|
|
261
|
+
console.log(` Best params saved: ${bestPath}
|
|
262
|
+
`);
|
|
263
|
+
}
|
|
264
|
+
export {
|
|
265
|
+
runAutoresearch
|
|
266
|
+
};
|
|
267
|
+
//# sourceMappingURL=autoresearch-IA7HGSNW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agent/autoresearch.ts"],"sourcesContent":["/**\n * Autoresearch — autonomous strategy parameter optimization.\n *\n * Inspired by Karpathy/Nunchi's autoresearch pattern: an AI agent\n * iteratively mutates strategy parameters, backtests via replay\n * calibration against production signal-history.jsonl, and retains\n * only improvements. Git history becomes the experiment log.\n *\n * Usage:\n * sherwood agent autoresearch [--experiments N] [--last-days D]\n *\n * The mutable state is a StrategyParams object. Each experiment:\n * 1. Proposes a single parameter mutation\n * 2. Runs replay calibration with the mutated params\n * 3. Computes a composite score (Sharpe × √min(trades/20,1) - DD penalty)\n * 4. If score improves → keeps the mutation; otherwise reverts\n * 5. Logs the experiment to autoresearch-log.jsonl\n */\n\nimport { readFile, writeFile, appendFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport chalk from 'chalk';\nimport { loadSignalHistory } from './replay-calibrator.js';\nimport { computeTradeDecision } from './scoring.js';\nimport type { ScoringWeights, Signal, TradeDecision } from './scoring.js';\nimport type { MarketRegime } from './regime.js';\n\n// ── Mutable parameter space ──\n\nexport interface StrategyParams {\n // Signal weights (must sum to ~1.0 across active categories)\n weights: ScoringWeights;\n // Thresholds\n buyThreshold: number;\n sellThreshold: number;\n // Exit params (in price-move terms, NOT leveraged)\n stopLossPct: number;\n takeProfitRR: number; // R:R multiplier on stop → TP = stop * this\n trailPct: number;\n timeStopHours: number;\n /** Leverage multiplier — PnL = raw price move × leverage. */\n leverage: number;\n}\n\nconst DEFAULT_PARAMS: StrategyParams = {\n weights: {\n smartMoney: 0.30,\n technical: 0.25,\n sentiment: 0.10,\n onchain: 0.20,\n fundamental: 0.15,\n event: 0.00,\n },\n buyThreshold: 0.14, // autoresearch walk-forward validated\n sellThreshold: -0.14,\n stopLossPct: 0.05,\n takeProfitRR: 2.0, // wider TP captures more upside\n trailPct: 0.03, // tighter trail (from 4%)\n timeStopHours: 84, // shorter (from 96h)\n leverage: 1, // no leverage until WR > 60%\n};\n\n// ── Scoring ──\n\ninterface ExperimentResult {\n id: number;\n params: StrategyParams;\n score: number;\n sharpe: number;\n totalReturn: number;\n maxDrawdown: number;\n trades: number;\n winRate: number;\n mutation: string;\n improved: boolean;\n timestamp: string;\n}\n\n/**\n * Score a parameter set against signal-history data.\n * Uses the same replay logic as replay-calibrator but with custom params.\n */\nfunction scoreParams(\n rows: SignalHistoryRow[],\n params: StrategyParams,\n): { sharpe: number; totalReturn: number; maxDrawdown: number; trades: number; winRate: number; score: number } {\n // Group by token\n const grouped = new Map<string, SignalHistoryRow[]>();\n for (const r of rows) {\n if (!grouped.has(r.tokenId)) grouped.set(r.tokenId, []);\n grouped.get(r.tokenId)!.push(r);\n }\n\n const allReturns: number[] = [];\n const allHoldDurations: number[] = []; // ms per closed trade\n let totalTrades = 0;\n let wins = 0;\n\n for (const [_token, tokenRows] of grouped) {\n tokenRows.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));\n\n let position: { side: 'long' | 'short'; entryPrice: number; entryTs: number; extreme: number } | null = null;\n\n for (const row of tokenRows) {\n const price = row.price;\n if (!Number.isFinite(price) || price <= 0) continue;\n\n const signals: Signal[] = row.signals.map(s => ({\n name: s.name, value: s.value, confidence: s.confidence, source: '', details: '',\n }));\n\n const regime = (row.regime && row.regime !== 'unknown') ? row.regime as MarketRegime : undefined;\n const decision = computeTradeDecision(signals, params.weights, undefined, undefined, regime);\n\n // Apply custom thresholds\n let action: string;\n if (decision.score >= params.buyThreshold + 0.15) action = 'STRONG_BUY';\n else if (decision.score >= params.buyThreshold) action = 'BUY';\n else if (decision.score <= params.sellThreshold - 0.10) action = 'STRONG_SELL';\n else if (decision.score <= params.sellThreshold) action = 'SELL';\n else action = 'HOLD';\n\n const ts = Date.parse(row.timestamp);\n\n // Exit logic\n if (position) {\n const isShort = position.side === 'short';\n if (isShort && price < position.extreme) position.extreme = price;\n if (!isShort && price > position.extreme) position.extreme = price;\n\n // Raw price move (before leverage) — used for stop/TP checks\n const rawPnl = isShort\n ? (position.entryPrice - price) / position.entryPrice\n : (price - position.entryPrice) / position.entryPrice;\n // Leveraged PnL — actual return on capital\n const pnl = rawPnl * params.leverage;\n const hours = (ts - position.entryTs) / 3600000;\n\n // Stop/TP are in price-move terms (not leveraged)\n const tpPct = params.stopLossPct * params.takeProfitRR;\n let exit = false;\n if (rawPnl <= -params.stopLossPct) exit = true;\n else if (rawPnl >= tpPct) exit = true;\n else if (params.trailPct > 0 && (isShort\n ? price >= position.extreme * (1 + params.trailPct)\n : price <= position.extreme * (1 - params.trailPct))) exit = true;\n else if (hours > params.timeStopHours && Math.abs(pnl) < 0.01) exit = true;\n else if (isShort ? (action === 'BUY' || action === 'STRONG_BUY') : (action === 'SELL' || action === 'STRONG_SELL')) exit = true;\n\n if (exit) {\n allReturns.push(pnl);\n allHoldDurations.push(ts - position.entryTs);\n totalTrades++;\n if (pnl > 0) wins++;\n position = null;\n }\n }\n\n // Entry\n if (!position) {\n if (action === 'BUY' || action === 'STRONG_BUY') {\n position = { side: 'long', entryPrice: price, entryTs: ts, extreme: price };\n } else if (action === 'SELL' || action === 'STRONG_SELL') {\n position = { side: 'short', entryPrice: price, entryTs: ts, extreme: price };\n }\n }\n }\n }\n\n // Compute metrics — require minimum trades for statistical significance.\n // Lower threshold during early exploration (5 trades); raise to 20+ once\n // we have weeks of signal data under the new stack.\n if (totalTrades < 5) {\n return { sharpe: -999, totalReturn: 0, maxDrawdown: 1, trades: totalTrades, winRate: 0, score: -999 };\n }\n\n const mean = allReturns.reduce((s, r) => s + r, 0) / allReturns.length;\n const variance = allReturns.reduce((s, r) => s + (r - mean) ** 2, 0) / (allReturns.length - 1);\n const std = Math.sqrt(variance);\n\n // Hold-duration-aware Sharpe annualization (from replay-calibrator).\n // Prior code used √252 blindly, inflating Sharpe ~1.8x for multi-day holds.\n const avgHoldMs = allHoldDurations.length > 0\n ? allHoldDurations.reduce((s, d) => s + d, 0) / allHoldDurations.length\n : 86400000; // 1 day fallback\n const avgHoldDays = Math.max(avgHoldMs / 86400000, 0.1);\n const tradesPerYear = Math.max(252 / avgHoldDays, 1);\n const sharpe = std > 0 ? (mean / std) * Math.sqrt(tradesPerYear) : 0;\n\n const totalReturn = allReturns.reduce((eq, r) => eq * (1 + r), 1) - 1;\n\n // Max drawdown from equity curve\n let peak = 1;\n let equity = 1;\n let maxDD = 0;\n for (const r of allReturns) {\n equity *= (1 + r);\n if (equity > peak) peak = equity;\n const dd = (peak - equity) / peak;\n if (dd > maxDD) maxDD = dd;\n }\n\n const winRate = wins / totalTrades;\n\n // Composite score — penalizes low sample sizes and large drawdowns.\n // tradePenalty scales from 0 at 20 trades to 1.0 at 50 trades (was 20).\n const tradePenalty = Math.sqrt(Math.min(totalTrades / 50, 1.0));\n const ddPenalty = maxDD > 0.50 ? 999 : maxDD * 5;\n const score = sharpe * tradePenalty - ddPenalty;\n\n return { sharpe, totalReturn, maxDrawdown: maxDD, trades: totalTrades, winRate, score };\n}\n\n// ── Mutation engine ──\n\nconst MUTATIONS: Array<{ name: string; mutate: (p: StrategyParams) => StrategyParams }> = [\n // Weight mutations\n { name: 'boost_technical', mutate: p => ({ ...p, weights: { ...p.weights, technical: Math.min(0.50, p.weights.technical + 0.05) } }) },\n { name: 'reduce_technical', mutate: p => ({ ...p, weights: { ...p.weights, technical: Math.max(0.05, p.weights.technical - 0.05) } }) },\n { name: 'boost_onchain', mutate: p => ({ ...p, weights: { ...p.weights, onchain: Math.min(0.50, p.weights.onchain + 0.05) } }) },\n { name: 'reduce_onchain', mutate: p => ({ ...p, weights: { ...p.weights, onchain: Math.max(0.0, p.weights.onchain - 0.05) } }) },\n { name: 'boost_sentiment', mutate: p => ({ ...p, weights: { ...p.weights, sentiment: Math.min(0.40, p.weights.sentiment + 0.05) } }) },\n { name: 'reduce_sentiment', mutate: p => ({ ...p, weights: { ...p.weights, sentiment: Math.max(0.0, p.weights.sentiment - 0.05) } }) },\n { name: 'zero_fundamental', mutate: p => ({ ...p, weights: { ...p.weights, fundamental: 0 } }) },\n { name: 'restore_fundamental', mutate: p => ({ ...p, weights: { ...p.weights, fundamental: 0.05 } }) },\n\n // Threshold mutations\n { name: 'lower_buy_threshold', mutate: p => ({ ...p, buyThreshold: Math.max(0.05, p.buyThreshold - 0.02) }) },\n { name: 'raise_buy_threshold', mutate: p => ({ ...p, buyThreshold: Math.min(0.40, p.buyThreshold + 0.02) }) },\n { name: 'tighten_sell_threshold', mutate: p => ({ ...p, sellThreshold: Math.min(-0.05, p.sellThreshold + 0.02) }) },\n { name: 'loosen_sell_threshold', mutate: p => ({ ...p, sellThreshold: Math.max(-0.50, p.sellThreshold - 0.02) }) },\n\n // Stop/exit mutations\n { name: 'widen_stop', mutate: p => ({ ...p, stopLossPct: Math.min(0.15, p.stopLossPct + 0.01) }) },\n { name: 'tighten_stop', mutate: p => ({ ...p, stopLossPct: Math.max(0.02, p.stopLossPct - 0.01) }) },\n { name: 'increase_rr', mutate: p => ({ ...p, takeProfitRR: Math.min(4.0, p.takeProfitRR + 0.5) }) },\n { name: 'decrease_rr', mutate: p => ({ ...p, takeProfitRR: Math.max(1.0, p.takeProfitRR - 0.5) }) },\n { name: 'widen_trail', mutate: p => ({ ...p, trailPct: Math.min(0.10, p.trailPct + 0.01) }) },\n { name: 'tighten_trail', mutate: p => ({ ...p, trailPct: Math.max(0.01, p.trailPct - 0.01) }) },\n { name: 'longer_time_stop', mutate: p => ({ ...p, timeStopHours: Math.min(96, p.timeStopHours + 12) }) },\n { name: 'shorter_time_stop', mutate: p => ({ ...p, timeStopHours: Math.max(12, p.timeStopHours - 12) }) },\n { name: 'disable_time_stop', mutate: p => ({ ...p, timeStopHours: 999 }) },\n\n // Leverage mutations\n { name: 'increase_leverage', mutate: p => ({ ...p, leverage: Math.min(5, p.leverage + 1) }) },\n { name: 'decrease_leverage', mutate: p => ({ ...p, leverage: Math.max(1, p.leverage - 1) }) },\n\n // Fundamental/event weight mutations (newly active categories)\n { name: 'boost_fundamental', mutate: p => ({ ...p, weights: { ...p.weights, fundamental: Math.min(0.30, p.weights.fundamental + 0.05) } }) },\n { name: 'boost_event', mutate: p => ({ ...p, weights: { ...p.weights, event: Math.min(0.25, p.weights.event + 0.05) } }) },\n { name: 'reduce_event', mutate: p => ({ ...p, weights: { ...p.weights, event: Math.max(0.0, p.weights.event - 0.05) } }) },\n];\n\n// ── Signal history row type (matches signal-logger output) ──\n\ninterface SignalHistoryRow {\n timestamp: string;\n tokenId: string;\n tokenSymbol?: string;\n price: number;\n decision: string;\n score: number;\n confidence: number;\n signals: Array<{ name: string; value: number; confidence: number }>;\n regime?: string;\n weights?: Record<string, number>;\n}\n\n// ── Main loop ──\n\nexport interface AutoresearchOptions {\n experiments?: number;\n lastDays?: number;\n historyPaths?: string[];\n}\n\nexport async function runAutoresearch(opts: AutoresearchOptions): Promise<void> {\n const base = join(homedir(), '.sherwood', 'agent');\n const logPath = join(base, 'autoresearch-log.jsonl');\n\n // Load signal history (combine rotated + current)\n const paths = opts.historyPaths ?? [\n join(base, 'signal-history-2026-04-21.jsonl'),\n join(base, 'signal-history.jsonl'),\n ];\n\n let allRows: SignalHistoryRow[] = [];\n for (const p of paths) {\n try {\n const raw = await readFile(p, 'utf-8');\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue;\n try { allRows.push(JSON.parse(line) as SignalHistoryRow); } catch { /* skip */ }\n }\n } catch { /* file missing */ }\n }\n\n // Filter by lastDays\n if (opts.lastDays) {\n const cutoff = Date.now() - opts.lastDays * 86400000;\n allRows = allRows.filter(r => Date.parse(r.timestamp) >= cutoff);\n }\n\n console.log(chalk.bold(`\\n Autoresearch — ${allRows.length} signal rows loaded`));\n\n if (allRows.length < 100) {\n console.log(chalk.red(' Insufficient data for autoresearch (need 100+ rows). Aborting.'));\n return;\n }\n\n const maxExperiments = opts.experiments ?? 50;\n let currentParams = { ...DEFAULT_PARAMS };\n\n // Score baseline\n const baseline = scoreParams(allRows, currentParams);\n let bestScore = baseline.score;\n console.log(chalk.dim(` Baseline: score=${baseline.score.toFixed(3)} sharpe=${baseline.sharpe.toFixed(2)} trades=${baseline.trades} WR=${(baseline.winRate*100).toFixed(0)}% DD=${(baseline.maxDrawdown*100).toFixed(1)}%`));\n console.log(chalk.dim(` Running ${maxExperiments} experiments...\\n`));\n\n let improvements = 0;\n\n for (let exp = 1; exp <= maxExperiments; exp++) {\n // Pick a random mutation\n const mutation = MUTATIONS[Math.floor(Math.random() * MUTATIONS.length)]!;\n const mutatedParams = mutation.mutate(currentParams);\n\n // Score\n const result = scoreParams(allRows, mutatedParams);\n const improved = result.score > bestScore;\n\n if (improved) {\n currentParams = mutatedParams;\n bestScore = result.score;\n improvements++;\n console.log(chalk.green(\n ` #${exp} ${mutation.name}: score ${result.score.toFixed(3)} (${improved ? '+' : ''}${(result.score - baseline.score).toFixed(3)}) ` +\n `sharpe=${result.sharpe.toFixed(2)} trades=${result.trades} WR=${(result.winRate*100).toFixed(0)}% DD=${(result.maxDrawdown*100).toFixed(1)}% ✓`\n ));\n } else {\n // Revert — currentParams stays the same\n if (exp % 10 === 0) {\n console.log(chalk.dim(` #${exp} ${mutation.name}: score ${result.score.toFixed(3)} — no improvement (best=${bestScore.toFixed(3)})`));\n }\n }\n\n // Log experiment\n const logEntry: ExperimentResult = {\n id: exp,\n params: improved ? mutatedParams : currentParams,\n score: result.score,\n sharpe: result.sharpe,\n totalReturn: result.totalReturn,\n maxDrawdown: result.maxDrawdown,\n trades: result.trades,\n winRate: result.winRate,\n mutation: mutation.name,\n improved,\n timestamp: new Date().toISOString(),\n };\n await appendFile(logPath, JSON.stringify(logEntry) + '\\n');\n }\n\n // Walk-forward validation: score optimized params on held-out data.\n // Split all rows by timestamp: first 70% = train (used above), last 30% = test.\n const sorted = [...allRows].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));\n const splitIdx = Math.floor(sorted.length * 0.7);\n const testRows = sorted.slice(splitIdx);\n const trainResult = scoreParams(sorted.slice(0, splitIdx), currentParams);\n const testResult = scoreParams(testRows, currentParams);\n const baselineTest = scoreParams(testRows, DEFAULT_PARAMS);\n\n // Final results\n const final = scoreParams(allRows, currentParams);\n console.log(chalk.bold(`\\n ═══════════════════════════════════════`));\n console.log(chalk.bold(` Autoresearch complete: ${maxExperiments} experiments, ${improvements} improvements`));\n console.log(chalk.bold(` ═══════════════════════════════════════`));\n console.log(` Baseline score: ${baseline.score.toFixed(3)} → Final: ${final.score.toFixed(3)}`);\n console.log(` Sharpe: ${baseline.sharpe.toFixed(2)} → ${final.sharpe.toFixed(2)}`);\n console.log(` Trades: ${baseline.trades} → ${final.trades}`);\n console.log(` Win rate: ${(baseline.winRate*100).toFixed(0)}% → ${(final.winRate*100).toFixed(0)}%`);\n console.log(` Max DD: ${(baseline.maxDrawdown*100).toFixed(1)}% → ${(final.maxDrawdown*100).toFixed(1)}%`);\n\n // Walk-forward report\n console.log(chalk.bold(`\\n ── Walk-Forward Validation (last 30% of data) ──`));\n console.log(` Test rows: ${testRows.length} (${(testRows.length / allRows.length * 100).toFixed(0)}% of total)`);\n if (testResult.trades >= 5) {\n console.log(` Baseline on test: sharpe=${baselineTest.sharpe.toFixed(2)} trades=${baselineTest.trades} WR=${(baselineTest.winRate*100).toFixed(0)}%`);\n console.log(` Optimized on test: sharpe=${testResult.sharpe.toFixed(2)} trades=${testResult.trades} WR=${(testResult.winRate*100).toFixed(0)}%`);\n const testImproved = testResult.score > baselineTest.score;\n console.log(testImproved\n ? chalk.green(` ✓ Params validated — improved on held-out data`)\n : chalk.yellow(` ⚠ Params may be overfit — degraded on held-out data`));\n } else {\n console.log(chalk.yellow(` ⚠ Insufficient test trades (${testResult.trades}) for validation — use more data`));\n }\n console.log(`\\n Best params:`);\n console.log(` weights: tech=${currentParams.weights.technical} sent=${currentParams.weights.sentiment} onchain=${currentParams.weights.onchain} fund=${currentParams.weights.fundamental}`);\n console.log(` buyThreshold: ${currentParams.buyThreshold} sellThreshold: ${currentParams.sellThreshold}`);\n console.log(` stop: ${(currentParams.stopLossPct*100).toFixed(0)}% RR: ${currentParams.takeProfitRR} trail: ${(currentParams.trailPct*100).toFixed(0)}% timeStop: ${currentParams.timeStopHours}h`);\n console.log(`\\n Log: ${logPath}`);\n\n // Save best params\n const bestPath = join(base, 'autoresearch-best-params.json');\n await writeFile(bestPath, JSON.stringify({ ...currentParams, _score: final.score, _sharpe: final.sharpe, _experiments: maxExperiments }, null, 2));\n console.log(` Best params saved: ${bestPath}\\n`);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSyndicate,
|
|
3
3
|
updateMetadata
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IS2CLLUT.js";
|
|
5
5
|
import {
|
|
6
6
|
getTextRecord,
|
|
7
7
|
resolveSyndicate,
|
|
8
8
|
setTextRecord
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-R7X33D2S.js";
|
|
10
10
|
import {
|
|
11
11
|
ENS
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FWC57PT7.js";
|
|
13
13
|
import {
|
|
14
14
|
formatContractError,
|
|
15
15
|
getAccount
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-XDBRKW7I.js";
|
|
17
|
+
import "./chunk-2LRC7I33.js";
|
|
18
18
|
import {
|
|
19
19
|
cacheGroupId,
|
|
20
20
|
getCachedGroupId
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-2W4KGGPU.js";
|
|
22
22
|
import "./chunk-D77JGXIV.js";
|
|
23
23
|
import {
|
|
24
24
|
fetchMetadata,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
import chalk from "chalk";
|
|
30
30
|
import ora from "ora";
|
|
31
31
|
async function loadXmtp() {
|
|
32
|
-
return import("./xmtp-
|
|
32
|
+
return import("./xmtp-ACB2W573.js");
|
|
33
33
|
}
|
|
34
34
|
function formatTimestamp(date) {
|
|
35
35
|
return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
|
|
@@ -428,4 +428,4 @@ function registerChatCommands(program) {
|
|
|
428
428
|
export {
|
|
429
429
|
registerChatCommands
|
|
430
430
|
};
|
|
431
|
-
//# sourceMappingURL=chat-
|
|
431
|
+
//# sourceMappingURL=chat-MRTPUZ3X.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getConfigRpcUrl
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2W4KGGPU.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/network.ts
|
|
6
6
|
import { defineChain } from "viem";
|
|
@@ -183,4 +183,4 @@ export {
|
|
|
183
183
|
getExplorerUrl,
|
|
184
184
|
isTestnet
|
|
185
185
|
};
|
|
186
|
-
//# sourceMappingURL=chunk-
|
|
186
|
+
//# sourceMappingURL=chunk-2LRC7I33.js.map
|
|
@@ -64,6 +64,14 @@ function setVeniceApiKey(apiKey) {
|
|
|
64
64
|
function getVeniceApiKey() {
|
|
65
65
|
return loadConfig().veniceApiKey ?? process.env.VENICE_API_KEY;
|
|
66
66
|
}
|
|
67
|
+
function setAnthropicApiKey(apiKey) {
|
|
68
|
+
const config = loadConfig();
|
|
69
|
+
config.anthropicApiKey = apiKey;
|
|
70
|
+
saveConfig(config);
|
|
71
|
+
}
|
|
72
|
+
function getAnthropicApiKey() {
|
|
73
|
+
return loadConfig().anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
74
|
+
}
|
|
67
75
|
function setAgentId(agentId) {
|
|
68
76
|
const config = loadConfig();
|
|
69
77
|
config.agentId = agentId;
|
|
@@ -194,6 +202,8 @@ export {
|
|
|
194
202
|
invalidateCachedGroupId,
|
|
195
203
|
setVeniceApiKey,
|
|
196
204
|
getVeniceApiKey,
|
|
205
|
+
setAnthropicApiKey,
|
|
206
|
+
getAnthropicApiKey,
|
|
197
207
|
setAgentId,
|
|
198
208
|
getAgentId,
|
|
199
209
|
setPrivateKey,
|
|
@@ -214,4 +224,4 @@ export {
|
|
|
214
224
|
cacheSwapRoute,
|
|
215
225
|
clearSwapRoutes
|
|
216
226
|
};
|
|
217
|
-
//# sourceMappingURL=chunk-
|
|
227
|
+
//# sourceMappingURL=chunk-2W4KGGPU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/config.ts"],"sourcesContent":["/**\n * Local config management — ~/.sherwood/config.json\n *\n * Stores group ID cache, per-chain contract addresses, and wallet config.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".sherwood\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\nconst DASHBOARD_BRIDGE_PATH = path.join(CONFIG_DIR, \"dashboard.json\");\n\n/** Per-chain user-specific addresses (stored by chainId). */\nexport interface ChainContracts {\n vault?: string; // user's default vault address\n}\n\n/** A syndicate the agent belongs to (creator or member). */\nexport interface SyndicateMembership {\n subdomain: string;\n vault: string;\n role: \"creator\" | \"agent\";\n}\n\nexport interface SherwoodConfig {\n dbEncryptionKey?: string; // legacy — no longer used, XMTP CLI manages its own DB\n privateKey?: string; // wallet private key (0x-prefixed)\n xmtpInboxId?: string;\n groupCache: Record<string, string>; // subdomain → XMTP group ID\n veniceApiKey?: string; // Venice AI inference API key\n anthropicApiKey?: string; // Anthropic Claude API key (for LLM judge)\n agentId?: number; // ERC-8004 identity token ID\n contracts?: Record<string, ChainContracts>; // chainId → user addresses\n syndicates?: Record<string, SyndicateMembership[]>; // chainId → syndicate memberships\n primarySyndicate?: Record<string, string>; // chainId → subdomain of the active syndicate\n rpc?: Record<string, string>; // network name → custom RPC URL\n notifyTo?: string; // destination for cron summaries (Telegram chat ID, phone, etc.)\n uniswapApiKey?: string; // Uniswap Trading API key (from developers.uniswap.org)\n positions?: unknown[]; // open trade positions (typed in positions.ts)\n closedPositions?: unknown[]; // historical closed positions\n _xmtpMigrated?: boolean; // one-time flag: revoked stale installations from ~/.xmtp/ era\n /** Cached swap routes per chain: chainId → { tokenPair → SwapRoute } */\n swapRoutes?: Record<string, Record<string, SwapRoute>>;\n}\n\n/** Persisted swap route detected by the CLI during portfolio strategy proposal. */\nexport interface SwapRoute {\n mode: \"direct\" | \"multi-hop\";\n feeTier: number; // direct pool fee tier\n hop?: { via: string; feeIn: number; feeOut: number }; // multi-hop details\n detectedAt: number; // unix timestamp\n}\n\nexport function loadConfig(): SherwoodConfig {\n if (fs.existsSync(CONFIG_PATH)) {\n const config = JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n if (!config.groupCache) config.groupCache = {};\n return config;\n }\n\n return { groupCache: {} };\n}\n\nexport function saveConfig(config: SherwoodConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n writeDashboardBridge(config);\n}\n\n/**\n * Public-safe derivation of config.json for Hermes dashboard plugins to read.\n * Excludes privateKey + every other sensitive field. Hermes' sherwood-companion\n * plugin reads ~/.sherwood/dashboard.json to auto-detect the operator's\n * primary syndicate without prompting.\n *\n * Wrapped in try/catch — bridge-write failure must not break a config save.\n */\nfunction writeDashboardBridge(config: SherwoodConfig): void {\n try {\n let agentWallet: string | null = null;\n if (config.privateKey) {\n const key = config.privateKey.startsWith(\"0x\")\n ? (config.privateKey as `0x${string}`)\n : (`0x${config.privateKey}` as `0x${string}`);\n agentWallet = privateKeyToAccount(key).address;\n }\n const bridge = {\n version: 1,\n agentWallet,\n syndicates: config.syndicates ?? {},\n primarySyndicate: config.primarySyndicate ?? {},\n };\n fs.writeFileSync(\n DASHBOARD_BRIDGE_PATH,\n JSON.stringify(bridge, null, 2),\n { mode: 0o600 },\n );\n } catch {\n // Non-fatal: plugin will fall back to manual subdomain entry.\n }\n}\n\nexport function cacheGroupId(subdomain: string, groupId: string): void {\n const config = loadConfig();\n config.groupCache[subdomain] = groupId;\n saveConfig(config);\n}\n\nexport function getCachedGroupId(subdomain: string): string | undefined {\n const config = loadConfig();\n return config.groupCache[subdomain];\n}\n\nexport function invalidateCachedGroupId(subdomain: string): void {\n const config = loadConfig();\n if (config.groupCache[subdomain]) {\n delete config.groupCache[subdomain];\n saveConfig(config);\n }\n}\n\nexport function setVeniceApiKey(apiKey: string): void {\n const config = loadConfig();\n config.veniceApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getVeniceApiKey(): string | undefined {\n return loadConfig().veniceApiKey ?? process.env.VENICE_API_KEY;\n}\n\n// ── Anthropic API Key ──\n\nexport function setAnthropicApiKey(apiKey: string): void {\n const config = loadConfig();\n config.anthropicApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n return loadConfig().anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;\n}\n\nexport function setAgentId(agentId: number): void {\n const config = loadConfig();\n config.agentId = agentId;\n saveConfig(config);\n}\n\nexport function getAgentId(): number | undefined {\n return loadConfig().agentId;\n}\n\nexport function setPrivateKey(key: string): void {\n const config = loadConfig();\n config.privateKey = key.startsWith(\"0x\") ? key : `0x${key}`;\n saveConfig(config);\n}\n\nexport function getPrivateKey(): string | undefined {\n return loadConfig().privateKey;\n}\n\n// ── Uniswap Trading API Key ──\n\nexport function setUniswapApiKey(apiKey: string): void {\n const config = loadConfig();\n config.uniswapApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getUniswapApiKey(): string | undefined {\n return loadConfig().uniswapApiKey ?? process.env.UNISWAP_API_KEY;\n}\n\n// ── Per-network RPC URLs ──\n\nexport function getConfigRpcUrl(network: string): string | undefined {\n return loadConfig().rpc?.[network];\n}\n\nexport function setConfigRpcUrl(network: string, url: string): void {\n const config = loadConfig();\n if (!config.rpc) config.rpc = {};\n config.rpc[network] = url;\n saveConfig(config);\n}\n\n// ── Per-chain contract addresses ──\n\nexport function getChainContracts(chainId: number): ChainContracts {\n const config = loadConfig();\n return config.contracts?.[String(chainId)] ?? {};\n}\n\nexport function getNotifyTo(): string | undefined {\n return loadConfig().notifyTo;\n}\n\nexport function setNotifyTo(id: string): void {\n const config = loadConfig();\n config.notifyTo = id;\n saveConfig(config);\n}\n\nexport function setChainContract(\n chainId: number,\n key: keyof ChainContracts,\n value: string,\n): void {\n const config = loadConfig();\n if (!config.contracts) config.contracts = {};\n const cid = String(chainId);\n if (!config.contracts[cid]) config.contracts[cid] = {};\n config.contracts[cid][key] = value;\n saveConfig(config);\n}\n\n// ── Syndicate Membership ──\n\n/**\n * Add (or update) a syndicate membership. Deduplicates by subdomain.\n * Automatically sets it as primary if it's the first syndicate on this chain.\n */\nexport function addSyndicate(\n chainId: number,\n membership: SyndicateMembership,\n): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.syndicates) config.syndicates = {};\n if (!config.syndicates[cid]) config.syndicates[cid] = [];\n\n // Upsert — replace existing entry with same subdomain\n const idx = config.syndicates[cid].findIndex(\n (s) => s.subdomain === membership.subdomain,\n );\n if (idx >= 0) {\n config.syndicates[cid][idx] = membership;\n } else {\n config.syndicates[cid].push(membership);\n }\n\n // Auto-set as primary if it's the first syndicate (or no primary set)\n if (!config.primarySyndicate) config.primarySyndicate = {};\n if (!config.primarySyndicate[cid]) {\n config.primarySyndicate[cid] = membership.subdomain;\n }\n\n saveConfig(config);\n}\n\n/** Get all syndicate memberships for a chain. */\nexport function getSyndicates(chainId: number): SyndicateMembership[] {\n const config = loadConfig();\n return config.syndicates?.[String(chainId)] ?? [];\n}\n\n/** Set which syndicate is the active/primary one for CLI commands. */\nexport function setPrimarySyndicate(\n chainId: number,\n subdomain: string,\n): void {\n const config = loadConfig();\n if (!config.primarySyndicate) config.primarySyndicate = {};\n config.primarySyndicate[String(chainId)] = subdomain;\n saveConfig(config);\n}\n\n/**\n * Get the primary syndicate for this chain.\n * Falls back to ChainContracts.vault for backwards compat with older configs.\n */\nexport function getPrimarySyndicate(\n chainId: number,\n): SyndicateMembership | undefined {\n const config = loadConfig();\n const cid = String(chainId);\n\n // Check new syndicates store first\n const primarySubdomain = config.primarySyndicate?.[cid];\n if (primarySubdomain && config.syndicates?.[cid]) {\n const found = config.syndicates[cid].find(\n (s) => s.subdomain === primarySubdomain,\n );\n if (found) return found;\n }\n\n // Backwards compat: if syndicates list has entries but no primary, use the first one\n if (config.syndicates?.[cid]?.length) {\n return config.syndicates[cid][0];\n }\n\n // Legacy fallback: config only has a vault address, no subdomain\n const vault = config.contracts?.[cid]?.vault;\n if (vault) {\n return { subdomain: \"\", vault, role: \"creator\" };\n }\n\n return undefined;\n}\n\n// ── Swap Route Cache ──\n\nfunction swapRouteKey(asset: string, token: string): string {\n return `${asset.toLowerCase()}→${token.toLowerCase()}`;\n}\n\n/** Get a cached swap route for a token pair on a chain. */\nexport function getCachedSwapRoute(chainId: number, asset: string, token: string): SwapRoute | undefined {\n const config = loadConfig();\n return config.swapRoutes?.[String(chainId)]?.[swapRouteKey(asset, token)];\n}\n\n/** Save a detected swap route to the config cache. */\nexport function cacheSwapRoute(chainId: number, asset: string, token: string, route: SwapRoute): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.swapRoutes) config.swapRoutes = {};\n if (!config.swapRoutes[cid]) config.swapRoutes[cid] = {};\n config.swapRoutes[cid][swapRouteKey(asset, token)] = route;\n saveConfig(config);\n}\n\n/** Clear all cached swap routes for a chain (e.g. after pool migration). */\nexport function clearSwapRoutes(chainId: number): void {\n const config = loadConfig();\n delete config.swapRoutes?.[String(chainId)];\n saveConfig(config);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAccount
|
|
3
|
+
} from "./chunk-XDBRKW7I.js";
|
|
4
|
+
import {
|
|
5
|
+
getVeniceApiKey,
|
|
6
|
+
setVeniceApiKey
|
|
7
|
+
} from "./chunk-2W4KGGPU.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/venice.ts
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
var VENICE_API_BASE = "https://api.venice.ai/api/v1";
|
|
12
|
+
var RETRY_MAX_ATTEMPTS = 3;
|
|
13
|
+
var RETRY_BASE_DELAYS_MS = [1e3, 2e3, 4e3];
|
|
14
|
+
var RETRY_JITTER_PCT = 0.2;
|
|
15
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
16
|
+
var VeniceHttpError = class extends Error {
|
|
17
|
+
status;
|
|
18
|
+
body;
|
|
19
|
+
constructor(status, body) {
|
|
20
|
+
super(`Venice inference failed: ${status} ${body}`);
|
|
21
|
+
this.name = "VeniceHttpError";
|
|
22
|
+
this.status = status;
|
|
23
|
+
this.body = body;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
function shouldRetry(err) {
|
|
27
|
+
if (!(err instanceof Error)) return false;
|
|
28
|
+
if (err.name === "AbortError") return false;
|
|
29
|
+
if (err instanceof VeniceHttpError) {
|
|
30
|
+
return RETRYABLE_STATUS.has(err.status);
|
|
31
|
+
}
|
|
32
|
+
if (err instanceof TypeError) return true;
|
|
33
|
+
const cause = err.cause;
|
|
34
|
+
if (cause && typeof cause === "object") {
|
|
35
|
+
const code = cause.code;
|
|
36
|
+
if (typeof code === "string" && ["ECONNRESET", "ECONNREFUSED", "ETIMEDOUT", "EAI_AGAIN", "ENOTFOUND", "EPIPE", "UND_ERR_SOCKET"].includes(code)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
function jitter(delayMs) {
|
|
43
|
+
const spread = delayMs * RETRY_JITTER_PCT;
|
|
44
|
+
return Math.max(0, Math.round(delayMs + (Math.random() * 2 - 1) * spread));
|
|
45
|
+
}
|
|
46
|
+
function sleep(ms) {
|
|
47
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
|
+
}
|
|
49
|
+
async function provisionApiKey() {
|
|
50
|
+
const account = getAccount();
|
|
51
|
+
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
52
|
+
signal: AbortSignal.timeout(15e3)
|
|
53
|
+
});
|
|
54
|
+
if (!tokenRes.ok) {
|
|
55
|
+
throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);
|
|
56
|
+
}
|
|
57
|
+
const tokenData = await tokenRes.json();
|
|
58
|
+
const token = tokenData?.data?.token;
|
|
59
|
+
if (!token) {
|
|
60
|
+
throw new Error("Venice API returned no validation token");
|
|
61
|
+
}
|
|
62
|
+
const signature = await account.signMessage({ message: token });
|
|
63
|
+
const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: {
|
|
66
|
+
"Content-Type": "application/json"
|
|
67
|
+
},
|
|
68
|
+
signal: AbortSignal.timeout(15e3),
|
|
69
|
+
body: JSON.stringify({
|
|
70
|
+
address: account.address,
|
|
71
|
+
signature,
|
|
72
|
+
token,
|
|
73
|
+
apiKeyType: "INFERENCE",
|
|
74
|
+
description: "Sherwood syndicate agent"
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
if (!keyRes.ok) {
|
|
78
|
+
const body = await keyRes.text();
|
|
79
|
+
throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);
|
|
80
|
+
}
|
|
81
|
+
const keyData = await keyRes.json();
|
|
82
|
+
const apiKey = keyData?.data?.apiKey;
|
|
83
|
+
if (!apiKey) {
|
|
84
|
+
throw new Error("Venice API returned no API key");
|
|
85
|
+
}
|
|
86
|
+
setVeniceApiKey(apiKey);
|
|
87
|
+
return apiKey;
|
|
88
|
+
}
|
|
89
|
+
async function checkApiKeyValid() {
|
|
90
|
+
const apiKey = getVeniceApiKey();
|
|
91
|
+
if (!apiKey) return false;
|
|
92
|
+
try {
|
|
93
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
94
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
95
|
+
signal: AbortSignal.timeout(15e3)
|
|
96
|
+
});
|
|
97
|
+
return res.ok;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function chatCompletion(opts) {
|
|
103
|
+
const apiKey = getVeniceApiKey();
|
|
104
|
+
if (!apiKey) {
|
|
105
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
106
|
+
}
|
|
107
|
+
const body = {
|
|
108
|
+
model: opts.model,
|
|
109
|
+
messages: opts.messages
|
|
110
|
+
};
|
|
111
|
+
if (opts.temperature !== void 0) body.temperature = opts.temperature;
|
|
112
|
+
if (opts.maxTokens !== void 0) body.max_tokens = opts.maxTokens;
|
|
113
|
+
const veniceParams = {};
|
|
114
|
+
if (opts.enableWebSearch) veniceParams.enable_web_search = "on";
|
|
115
|
+
if (opts.disableThinking) veniceParams.disable_thinking = true;
|
|
116
|
+
if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;
|
|
117
|
+
let lastErr;
|
|
118
|
+
let res;
|
|
119
|
+
for (let attempt = 1; attempt <= RETRY_MAX_ATTEMPTS; attempt++) {
|
|
120
|
+
try {
|
|
121
|
+
res = await fetch(`${VENICE_API_BASE}/chat/completions`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: {
|
|
124
|
+
"Content-Type": "application/json",
|
|
125
|
+
Authorization: `Bearer ${apiKey}`
|
|
126
|
+
},
|
|
127
|
+
signal: AbortSignal.timeout(12e4),
|
|
128
|
+
// inference can be slow
|
|
129
|
+
body: JSON.stringify(body)
|
|
130
|
+
});
|
|
131
|
+
if (!res.ok) {
|
|
132
|
+
const errBody = await res.text();
|
|
133
|
+
throw new VeniceHttpError(res.status, errBody);
|
|
134
|
+
}
|
|
135
|
+
lastErr = void 0;
|
|
136
|
+
break;
|
|
137
|
+
} catch (err) {
|
|
138
|
+
lastErr = err;
|
|
139
|
+
if (attempt >= RETRY_MAX_ATTEMPTS || !shouldRetry(err)) {
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
const baseDelay = RETRY_BASE_DELAYS_MS[attempt - 1] ?? RETRY_BASE_DELAYS_MS[RETRY_BASE_DELAYS_MS.length - 1];
|
|
143
|
+
const delayMs = jitter(baseDelay);
|
|
144
|
+
const reason = err instanceof VeniceHttpError ? `HTTP ${err.status}` : err.message || "network";
|
|
145
|
+
console.error(chalk.dim(` [venice] retry ${attempt}/${RETRY_MAX_ATTEMPTS} after ${delayMs}ms \u2014 ${reason}`));
|
|
146
|
+
await sleep(delayMs);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!res || lastErr) {
|
|
150
|
+
throw lastErr ?? new Error("Venice inference failed: no response");
|
|
151
|
+
}
|
|
152
|
+
const data = await res.json();
|
|
153
|
+
const choice = data.choices?.[0];
|
|
154
|
+
if (!choice) {
|
|
155
|
+
throw new Error("Venice returned no choices");
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
content: choice.message?.content ?? "",
|
|
159
|
+
model: data.model ?? opts.model,
|
|
160
|
+
usage: {
|
|
161
|
+
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
162
|
+
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
163
|
+
totalTokens: data.usage?.total_tokens ?? 0
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function listModels() {
|
|
168
|
+
const apiKey = getVeniceApiKey();
|
|
169
|
+
if (!apiKey) {
|
|
170
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
171
|
+
}
|
|
172
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
173
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
174
|
+
signal: AbortSignal.timeout(15e3)
|
|
175
|
+
});
|
|
176
|
+
if (!res.ok) {
|
|
177
|
+
throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);
|
|
178
|
+
}
|
|
179
|
+
const data = await res.json();
|
|
180
|
+
return (data.data ?? []).map((m) => m.id);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
provisionApiKey,
|
|
185
|
+
checkApiKeyValid,
|
|
186
|
+
chatCompletion,
|
|
187
|
+
listModels
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=chunk-7HJXZ4NM.js.map
|