@oracle-agent/oracle 0.9.8 → 0.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/README.md +15 -10
- package/bin/oracle-data-mcp.mjs +9 -0
- package/docs/architecture.md +3 -1
- package/docs/profiles.md +3 -6
- package/docs/public-surface.md +133 -0
- package/package.json +3 -2
- package/public/oracle-splash/assets/cli-chain-hyperliquid.jpg +0 -0
- package/public/oracle-splash/brand/aave.webp +0 -0
- package/public/oracle-splash/brand/aavev2.webp +0 -0
- package/public/oracle-splash/brand/aborean.webp +0 -0
- package/public/oracle-splash/brand/across.webp +0 -0
- package/public/oracle-splash/brand/aerodrome.webp +0 -0
- package/public/oracle-splash/brand/afi.webp +0 -0
- package/public/oracle-splash/brand/arcus.webp +0 -0
- package/public/oracle-splash/brand/aster.webp +0 -0
- package/public/oracle-splash/brand/avant.webp +0 -0
- package/public/oracle-splash/brand/balancer.webp +0 -0
- package/public/oracle-splash/brand/beefy.webp +0 -0
- package/public/oracle-splash/brand/benqi.webp +0 -0
- package/public/oracle-splash/brand/bestinslot.ico +0 -0
- package/public/oracle-splash/brand/bitfi.webp +0 -0
- package/public/oracle-splash/brand/bonkswap.webp +0 -0
- package/public/oracle-splash/brand/bouncebit.webp +0 -0
- package/public/oracle-splash/brand/camelot.webp +0 -0
- package/public/oracle-splash/brand/compound.webp +0 -0
- package/public/oracle-splash/brand/concrete.webp +0 -0
- package/public/oracle-splash/brand/cow.webp +0 -0
- package/public/oracle-splash/brand/curve.webp +0 -0
- package/public/oracle-splash/brand/derive.webp +0 -0
- package/public/oracle-splash/brand/dolomite.webp +0 -0
- package/public/oracle-splash/brand/eigenlayer.webp +0 -0
- package/public/oracle-splash/brand/ekubo.webp +0 -0
- package/public/oracle-splash/brand/ethena.webp +0 -0
- package/public/oracle-splash/brand/etherfi.webp +0 -0
- package/public/oracle-splash/brand/etherfiborrow.webp +0 -0
- package/public/oracle-splash/brand/felix.webp +0 -0
- package/public/oracle-splash/brand/fluid.webp +0 -0
- package/public/oracle-splash/brand/fluxbeam.webp +0 -0
- package/public/oracle-splash/brand/folks.webp +0 -0
- package/public/oracle-splash/brand/fortyacres.webp +0 -0
- package/public/oracle-splash/brand/gainsnetwork.webp +0 -0
- package/public/oracle-splash/brand/gassss.webp +0 -0
- package/public/oracle-splash/brand/gmx.webp +0 -0
- package/public/oracle-splash/brand/harmonix.webp +0 -0
- package/public/oracle-splash/brand/hlorderbook.webp +0 -0
- package/public/oracle-splash/brand/hlp.webp +0 -0
- package/public/oracle-splash/brand/hop.webp +0 -0
- package/public/oracle-splash/brand/hyperbeat.webp +0 -0
- package/public/oracle-splash/brand/hyperlend.webp +0 -0
- package/public/oracle-splash/brand/hyperliquid.webp +0 -0
- package/public/oracle-splash/brand/hyperliquidhpl.webp +0 -0
- package/public/oracle-splash/brand/hyperliquidspot.webp +0 -0
- package/public/oracle-splash/brand/hyperswap.webp +0 -0
- package/public/oracle-splash/brand/hypha.webp +0 -0
- package/public/oracle-splash/brand/joedex.webp +0 -0
- package/public/oracle-splash/brand/jupiter.webp +0 -0
- package/public/oracle-splash/brand/kelp.webp +0 -0
- package/public/oracle-splash/brand/kinetiq.webp +0 -0
- package/public/oracle-splash/brand/kmhype.webp +0 -0
- package/public/oracle-splash/brand/kona.webp +0 -0
- package/public/oracle-splash/brand/konalend.webp +0 -0
- package/public/oracle-splash/brand/lfj.webp +0 -0
- package/public/oracle-splash/brand/lido.webp +0 -0
- package/public/oracle-splash/brand/lifi.webp +0 -0
- package/public/oracle-splash/brand/lighter.webp +0 -0
- package/public/oracle-splash/brand/lista.webp +0 -0
- package/public/oracle-splash/brand/loopedhype.webp +0 -0
- package/public/oracle-splash/brand/lorenzo.webp +0 -0
- package/public/oracle-splash/brand/magic-eden.webp +0 -0
- package/public/oracle-splash/brand/magiceden.webp +0 -0
- package/public/oracle-splash/brand/mempool.png +0 -0
- package/public/oracle-splash/brand/meteora.webp +0 -0
- package/public/oracle-splash/brand/morpho.webp +0 -0
- package/public/oracle-splash/brand/myriad.webp +0 -0
- package/public/oracle-splash/brand/noxa.webp +0 -0
- package/public/oracle-splash/brand/odos.webp +0 -0
- package/public/oracle-splash/brand/oneinch.webp +0 -0
- package/public/oracle-splash/brand/openbook.webp +0 -0
- package/public/oracle-splash/brand/opensea.webp +0 -0
- package/public/oracle-splash/brand/orca.webp +0 -0
- package/public/oracle-splash/brand/ordinals.png +0 -0
- package/public/oracle-splash/brand/ostium.webp +0 -0
- package/public/oracle-splash/brand/pancakeswap.webp +0 -0
- package/public/oracle-splash/brand/pendle.webp +0 -0
- package/public/oracle-splash/brand/perena.webp +0 -0
- package/public/oracle-splash/brand/pharaoh.webp +0 -0
- package/public/oracle-splash/brand/phoenix.webp +0 -0
- package/public/oracle-splash/brand/polymarket.webp +0 -0
- package/public/oracle-splash/brand/polynomial.webp +0 -0
- package/public/oracle-splash/brand/projectx.webp +0 -0
- package/public/oracle-splash/brand/pumpfun.webp +0 -0
- package/public/oracle-splash/brand/quickswap.webp +0 -0
- package/public/oracle-splash/brand/rain.webp +0 -0
- package/public/oracle-splash/brand/raydium.webp +0 -0
- package/public/oracle-splash/brand/relay.webp +0 -0
- package/public/oracle-splash/brand/rocketpool.webp +0 -0
- package/public/oracle-splash/brand/saber.webp +0 -0
- package/public/oracle-splash/brand/sakuraswap.webp +0 -0
- package/public/oracle-splash/brand/sanctum.webp +0 -0
- package/public/oracle-splash/brand/satflow.png +0 -0
- package/public/oracle-splash/brand/sierra.webp +0 -0
- package/public/oracle-splash/brand/sky.webp +0 -0
- package/public/oracle-splash/brand/solv.webp +0 -0
- package/public/oracle-splash/brand/spark.webp +0 -0
- package/public/oracle-splash/brand/sparksavings.webp +0 -0
- package/public/oracle-splash/brand/sphere.webp +0 -0
- package/public/oracle-splash/brand/ssv.webp +0 -0
- package/public/oracle-splash/brand/stabble.webp +0 -0
- package/public/oracle-splash/brand/stableswap.webp +0 -0
- package/public/oracle-splash/brand/stakewise.webp +0 -0
- package/public/oracle-splash/brand/stargate.webp +0 -0
- package/public/oracle-splash/brand/sthype.webp +0 -0
- package/public/oracle-splash/brand/sushiswap.webp +0 -0
- package/public/oracle-splash/brand/unisat.png +0 -0
- package/public/oracle-splash/brand/uniswap.webp +0 -0
- package/public/oracle-splash/brand/uniswapv2.webp +0 -0
- package/public/oracle-splash/brand/uniswapv4.webp +0 -0
- package/public/oracle-splash/brand/unit.webp +0 -0
- package/public/oracle-splash/brand/velodrome.webp +0 -0
- package/public/oracle-splash/brand/velora.webp +0 -0
- package/public/oracle-splash/brand/venus.webp +0 -0
- package/public/oracle-splash/brand/wbeth.webp +0 -0
- package/public/oracle-splash/brand/xsy.webp +0 -0
- package/public/oracle-splash/brand/yieldyak.webp +0 -0
- package/public/oracle-splash/brand/zerobase.webp +0 -0
- package/public/oracle-splash/brand/zerox.webp +0 -0
- package/public/oracle-splash/index.html +337 -197
- package/scripts/check-doc-drift.mjs +11 -0
- package/scripts/e2e-solana-bitcoin.mjs +1 -1
- package/scripts/secret-scan.mjs +1 -1
- package/src/action-receipts.mjs +108 -11
- package/src/auth/oauth.mjs +672 -0
- package/src/cli/commands/auth.mjs +193 -0
- package/src/cli/commands/bootstrap.mjs +2 -2
- package/src/cli/commands/chat.mjs +97 -75
- package/src/cli/commands/data.mjs +3 -1
- package/src/cli/commands/doctor.mjs +11 -1
- package/src/cli/commands/model.mjs +79 -23
- package/src/cli/kernel.mjs +4 -3
- package/src/cli/model-config.mjs +70 -0
- package/src/data/catalog.mjs +38 -7
- package/src/data/desk-data.mjs +12 -0
- package/src/data/providers/evm-rpc.mjs +19 -16
- package/src/data/providers/jupiter-venues.mjs +119 -0
- package/src/data/providers/jupiter.mjs +132 -0
- package/src/data/providers/magiceden-sol.mjs +13 -0
- package/src/data/providers/morpho.mjs +6 -2
- package/src/data/providers/pendle.mjs +3 -2
- package/src/data/providers/satflow.mjs +4 -1
- package/src/data/providers/signed-material-guard.mjs +108 -0
- package/src/data/providers/uniswap-v3.mjs +34 -5
- package/src/data/providers/uniswap-v4.mjs +414 -0
- package/src/prepare-envelope.mjs +22 -4
- package/src/router/prepare-route.mjs +17 -0
- package/src/router/route-sources.mjs +35 -0
- package/src/tui/app.mjs +18 -7
- package/src/tui/backend.mjs +145 -0
- package/src/tui/standalone-client.mjs +666 -0
- package/src/cards.mjs +0 -369
- package/src/cli/__pycache__/oracle-harness.cpython-311.pyc +0 -0
|
@@ -21,6 +21,7 @@ import { zeroxQuote } from "../data/providers/zerox.mjs";
|
|
|
21
21
|
import { oneinchQuote } from "../data/providers/oneinch.mjs";
|
|
22
22
|
import { cowQuote } from "../data/providers/cowswap.mjs";
|
|
23
23
|
import { uniV3QuoteExactIn, UNI_V3_CHAINS } from "../data/providers/uniswap-v3.mjs";
|
|
24
|
+
import { uniV4QuoteExactIn, UNI_V4_CHAINS } from "../data/providers/uniswap-v4.mjs";
|
|
24
25
|
import { llamaPrices } from "../data/providers/defillama.mjs";
|
|
25
26
|
import { NATIVE_PRICE_KEY } from "./best-execution.mjs";
|
|
26
27
|
|
|
@@ -67,6 +68,7 @@ export function swapCandidates({
|
|
|
67
68
|
tokenOut,
|
|
68
69
|
amountIn,
|
|
69
70
|
taker,
|
|
71
|
+
slippageBps,
|
|
70
72
|
decimalsIn,
|
|
71
73
|
decimalsOut,
|
|
72
74
|
nativePriceUsd = null,
|
|
@@ -225,6 +227,39 @@ export function swapCandidates({
|
|
|
225
227
|
});
|
|
226
228
|
}
|
|
227
229
|
|
|
230
|
+
// Uniswap V4 Quoter. Cross-chain floor alongside V3. On RH the live SQUEEZE book
|
|
231
|
+
// is V4; V3 alone can return a drained shell that looks like a real quote. Kept
|
|
232
|
+
// after V3 so best-execution still compares net output when both answer.
|
|
233
|
+
if (UNI_V4_CHAINS[Number(chainId)]) {
|
|
234
|
+
c.push({
|
|
235
|
+
source: "uniswap-v4",
|
|
236
|
+
run: async () => {
|
|
237
|
+
const q = await uniV4QuoteExactIn(
|
|
238
|
+
{ chainId, tokenIn, tokenOut, amountIn, recipient: taker, slippageBps },
|
|
239
|
+
opts,
|
|
240
|
+
);
|
|
241
|
+
return {
|
|
242
|
+
amountOut: q?.amountOut,
|
|
243
|
+
minOut: q?.minOut ?? q?.amountOutMinimum ?? null,
|
|
244
|
+
gasUsd: null,
|
|
245
|
+
meta: {
|
|
246
|
+
onchain: true,
|
|
247
|
+
venue: "uniswap-v4",
|
|
248
|
+
fee: q?.fee,
|
|
249
|
+
tickSpacing: q?.tickSpacing,
|
|
250
|
+
poolId: q?.poolId,
|
|
251
|
+
hooks: q?.hooks,
|
|
252
|
+
gasUnits: q?.gasEstimate,
|
|
253
|
+
quoter: q?.quoter,
|
|
254
|
+
poolManager: q?.poolManager,
|
|
255
|
+
prepareReady: q?.prepareReady === true,
|
|
256
|
+
executionReady: false,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
228
263
|
return c;
|
|
229
264
|
}
|
|
230
265
|
|
package/src/tui/app.mjs
CHANGED
|
@@ -371,23 +371,34 @@ export function createOracleTui(options = {}) {
|
|
|
371
371
|
});
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
export async function runOracleTui({
|
|
374
|
+
export async function runOracleTui({
|
|
375
|
+
hermesPython,
|
|
376
|
+
client,
|
|
377
|
+
tuiFactory = createOracleTui,
|
|
378
|
+
args = [],
|
|
379
|
+
env = process.env,
|
|
380
|
+
cwd = process.cwd(),
|
|
381
|
+
stdout = process.stdout,
|
|
382
|
+
stdin = process.stdin,
|
|
383
|
+
} = {}) {
|
|
375
384
|
const parsed = parseChatArgs(args);
|
|
376
385
|
if (parsed.query) return { native: false, pass: parsed.pass };
|
|
377
386
|
if (!stdin.isTTY || !stdout.isTTY) return { native: false, pass: parsed.pass };
|
|
378
|
-
|
|
379
|
-
if (env.ORACLE_NATIVE_TUI !== "1") return { native: false, pass: parsed.pass };
|
|
387
|
+
if (env.ORACLE_NATIVE_TUI === "0") return { native: false, pass: parsed.pass };
|
|
380
388
|
const invocation = hermesPython;
|
|
381
|
-
if (!invocation) return { native: false, pass: parsed.pass };
|
|
389
|
+
if (!client && !invocation) return { native: false, pass: parsed.pass };
|
|
382
390
|
const cleanEnv = activeChainEnv({
|
|
383
391
|
...env,
|
|
384
392
|
ORACLE_CHAT_SURFACE: "1",
|
|
385
393
|
ORACLE_PROFILE: "oracle",
|
|
386
394
|
ORACLE_NODE_BIN: process.execPath,
|
|
387
395
|
});
|
|
388
|
-
const tui =
|
|
389
|
-
|
|
390
|
-
|
|
396
|
+
const tui = tuiFactory({
|
|
397
|
+
...(client ? { client } : {}),
|
|
398
|
+
...(invocation ? {
|
|
399
|
+
python: invocation.command,
|
|
400
|
+
pythonArgs: invocation.prefix || [],
|
|
401
|
+
} : {}),
|
|
391
402
|
cwd,
|
|
392
403
|
env: cleanEnv,
|
|
393
404
|
stdin,
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const PROVIDERS = Object.freeze({
|
|
2
|
+
openrouter: {
|
|
3
|
+
key: "OPENROUTER_API_KEY",
|
|
4
|
+
baseUrl: "https://openrouter.ai/api/v1",
|
|
5
|
+
model: "openrouter/auto",
|
|
6
|
+
},
|
|
7
|
+
openai: {
|
|
8
|
+
key: "OPENAI_API_KEY",
|
|
9
|
+
baseUrl: "https://api.openai.com/v1",
|
|
10
|
+
model: "gpt-4.1-mini",
|
|
11
|
+
},
|
|
12
|
+
xai: {
|
|
13
|
+
key: "XAI_API_KEY",
|
|
14
|
+
baseUrl: "https://api.x.ai/v1",
|
|
15
|
+
model: "grok-4-latest",
|
|
16
|
+
},
|
|
17
|
+
deepseek: {
|
|
18
|
+
key: "DEEPSEEK_API_KEY",
|
|
19
|
+
baseUrl: "https://api.deepseek.com/v1",
|
|
20
|
+
model: "deepseek-chat",
|
|
21
|
+
},
|
|
22
|
+
gemini: {
|
|
23
|
+
key: "GEMINI_API_KEY",
|
|
24
|
+
alternateKey: "GOOGLE_API_KEY",
|
|
25
|
+
baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
26
|
+
model: "gemini-2.5-flash",
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const OAUTH_PROVIDERS = Object.freeze({
|
|
31
|
+
"anthropic-oauth": {
|
|
32
|
+
baseUrl: "https://api.anthropic.com/v1",
|
|
33
|
+
model: "claude-sonnet-4-6",
|
|
34
|
+
protocol: "anthropic-messages",
|
|
35
|
+
},
|
|
36
|
+
"openai-codex": {
|
|
37
|
+
baseUrl: "https://chatgpt.com/backend-api/codex",
|
|
38
|
+
model: "gpt-5.6-sol",
|
|
39
|
+
protocol: "responses",
|
|
40
|
+
},
|
|
41
|
+
"xai-oauth": {
|
|
42
|
+
baseUrl: "https://api.x.ai/v1",
|
|
43
|
+
model: "grok-4.5",
|
|
44
|
+
protocol: "responses",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
function positiveInteger(value, fallback) {
|
|
49
|
+
const parsed = Number.parseInt(String(value || ""), 10);
|
|
50
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function providerFromEnv(env, stored = {}) {
|
|
54
|
+
const explicit = String(env.ORACLE_PROVIDER || stored.provider || "").trim().toLowerCase();
|
|
55
|
+
if (explicit) return explicit;
|
|
56
|
+
if (env.ORACLE_BASE_URL) return "custom";
|
|
57
|
+
for (const [name, preset] of Object.entries(PROVIDERS)) {
|
|
58
|
+
if (env[preset.key] || (preset.alternateKey && env[preset.alternateKey])) return name;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function standaloneConfigFromEnv(
|
|
64
|
+
env = process.env,
|
|
65
|
+
stored = {},
|
|
66
|
+
oauthAvailable = () => false,
|
|
67
|
+
apiKeyResolver = () => "",
|
|
68
|
+
) {
|
|
69
|
+
const provider = providerFromEnv(env, stored);
|
|
70
|
+
if (!provider) return null;
|
|
71
|
+
|
|
72
|
+
const oauthPreset = OAUTH_PROVIDERS[provider];
|
|
73
|
+
const preset = PROVIDERS[provider] || oauthPreset;
|
|
74
|
+
const apiKeyEnv = String(env.ORACLE_API_KEY_ENV || stored.apiKeyEnv || "");
|
|
75
|
+
const apiKey = String(
|
|
76
|
+
env.ORACLE_API_KEY ||
|
|
77
|
+
(apiKeyEnv && env[apiKeyEnv]) ||
|
|
78
|
+
(preset && (env[preset.key] || (preset.alternateKey && env[preset.alternateKey]))) ||
|
|
79
|
+
apiKeyResolver(provider) ||
|
|
80
|
+
"",
|
|
81
|
+
);
|
|
82
|
+
const baseUrl = String(
|
|
83
|
+
oauthPreset
|
|
84
|
+
? oauthPreset.baseUrl
|
|
85
|
+
: provider === "custom"
|
|
86
|
+
? (env.ORACLE_BASE_URL || stored.baseUrl || "")
|
|
87
|
+
: (preset?.baseUrl || ""),
|
|
88
|
+
).replace(/\/+$/, "");
|
|
89
|
+
const model = String(env.ORACLE_MODEL || stored.model || preset?.model || "");
|
|
90
|
+
if (!baseUrl || !model) return null;
|
|
91
|
+
const hasOAuth = Boolean(oauthPreset && oauthAvailable(provider));
|
|
92
|
+
if (oauthPreset && !hasOAuth) return null;
|
|
93
|
+
if (!oauthPreset && provider !== "custom" && !apiKey) return null;
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
kind: "standalone",
|
|
97
|
+
provider,
|
|
98
|
+
model,
|
|
99
|
+
baseUrl,
|
|
100
|
+
...(hasOAuth ? { authType: "oauth", protocol: oauthPreset.protocol } : { apiKey }),
|
|
101
|
+
contextLength: positiveInteger(env.ORACLE_CONTEXT_LENGTH || stored.contextLength, 128000),
|
|
102
|
+
reasoningEffort: String(env.ORACLE_REASONING_EFFORT || stored.reasoningEffort || "high"),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function setupReason(extra = "") {
|
|
107
|
+
return [
|
|
108
|
+
"Oracle standalone chat does not require Hermes.",
|
|
109
|
+
"Set OPENROUTER_API_KEY, run `oracle auth login claude|codex|grok`, or configure a custom OpenAI-compatible endpoint.",
|
|
110
|
+
"If Hermes is installed, Oracle will reuse it automatically.",
|
|
111
|
+
extra,
|
|
112
|
+
].filter(Boolean).join("\n");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function resolveChatBackend({
|
|
116
|
+
env = process.env,
|
|
117
|
+
hermes = { ok: false },
|
|
118
|
+
storedConfig = null,
|
|
119
|
+
oauthAvailable = () => false,
|
|
120
|
+
apiKeyResolver = () => "",
|
|
121
|
+
} = {}) {
|
|
122
|
+
const requested = String(env.ORACLE_CHAT_BACKEND || storedConfig?.backend || "auto").trim().toLowerCase();
|
|
123
|
+
const standalone = standaloneConfigFromEnv(env, storedConfig || {}, oauthAvailable, apiKeyResolver);
|
|
124
|
+
|
|
125
|
+
if (requested === "standalone") {
|
|
126
|
+
return standalone
|
|
127
|
+
? { kind: "standalone", config: standalone }
|
|
128
|
+
: { kind: "unconfigured", reason: setupReason("ORACLE_CHAT_BACKEND=standalone was requested, but no standalone model is configured.") };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (requested === "hermes") {
|
|
132
|
+
return hermes?.ok
|
|
133
|
+
? { kind: "hermes", bin: hermes.bin }
|
|
134
|
+
: { kind: "unconfigured", reason: setupReason("ORACLE_CHAT_BACKEND=hermes was requested, but Hermes was not found.") };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (requested !== "auto") {
|
|
138
|
+
return { kind: "unconfigured", reason: setupReason(`Unknown ORACLE_CHAT_BACKEND value: ${requested}`) };
|
|
139
|
+
}
|
|
140
|
+
if (hermes?.ok) return { kind: "hermes", bin: hermes.bin };
|
|
141
|
+
if (standalone) return { kind: "standalone", config: standalone };
|
|
142
|
+
return { kind: "unconfigured", reason: setupReason() };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default { resolveChatBackend, standaloneConfigFromEnv };
|