nyxora 26.7.2 → 26.7.3
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/CHANGELOG.md +95 -47
- package/README.md +23 -19
- package/bin/nyxora.mjs +4 -6
- package/dist/launcher.js +44 -8
- package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
- package/dist/packages/core/src/agent/cronManager.js +2 -2
- package/dist/packages/core/src/agent/llmProvider.js +242 -0
- package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
- package/dist/packages/core/src/agent/osAgent.js +203 -29
- package/dist/packages/core/src/agent/reasoning.js +353 -60
- package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
- package/dist/packages/core/src/agent/transactionManager.js +36 -31
- package/dist/packages/core/src/agent/web3Agent.js +263 -37
- package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
- package/dist/packages/core/src/config/parser.js +10 -4
- package/dist/packages/core/src/gateway/chat.js +56 -13
- package/dist/packages/core/src/gateway/cli.js +3 -0
- package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
- package/dist/packages/core/src/gateway/server.js +58 -9
- package/dist/packages/core/src/gateway/setup-ml.js +64 -0
- package/dist/packages/core/src/gateway/setup.js +39 -3
- package/dist/packages/core/src/gateway/telegram.js +120 -24
- package/dist/packages/core/src/memory/episodic.js +47 -3
- package/dist/packages/core/src/memory/logger.js +120 -2
- package/dist/packages/core/src/memory/promotionEngine.js +18 -5
- package/dist/packages/core/src/system/agentskills.js +10 -0
- package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
- package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
- package/dist/packages/core/src/system/skillExtractor.js +16 -5
- package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
- package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
- package/dist/packages/core/src/test_mainnet.js +45 -0
- package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
- package/dist/packages/core/src/utils/skillManager.js +1 -1
- package/dist/packages/core/src/utils/streamSimulator.js +85 -0
- package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
- package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
- package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
- package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
- package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
- package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
- package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
- package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
- package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
- package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
- package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
- package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
- package/dist/packages/core/src/web3/skills/customTx.js +3 -0
- package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
- package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
- package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
- package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
- package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
- package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
- package/dist/packages/core/src/web3/skills/transfer.js +2 -0
- package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
- package/dist/packages/core/src/web3/utils/chains.js +19 -0
- package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
- package/dist/packages/signer/src/NyxoraSigner.js +181 -0
- package/dist/packages/signer/src/index.js +17 -0
- package/dist/packages/signer/src/server.js +25 -161
- package/launcher.ts +38 -9
- package/package.json +6 -2
- package/packages/core/package.json +21 -10
- package/packages/core/src/agent/bridgeWatcher.ts +3 -2
- package/packages/core/src/agent/cronManager.ts +2 -2
- package/packages/core/src/agent/llmProvider.ts +219 -0
- package/packages/core/src/agent/nyxDaemon.ts +104 -0
- package/packages/core/src/agent/osAgent.ts +230 -32
- package/packages/core/src/agent/reasoning.ts +376 -64
- package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
- package/packages/core/src/agent/transactionManager.ts +36 -28
- package/packages/core/src/agent/web3Agent.ts +291 -40
- package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
- package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
- package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
- package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
- package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
- package/packages/core/src/config/parser.ts +15 -4
- package/packages/core/src/gateway/chat.ts +57 -15
- package/packages/core/src/gateway/cli.ts +4 -0
- package/packages/core/src/gateway/discordAdapter.ts +87 -0
- package/packages/core/src/gateway/server.ts +66 -10
- package/packages/core/src/gateway/setup-ml.ts +68 -0
- package/packages/core/src/gateway/setup.ts +41 -3
- package/packages/core/src/gateway/telegram.ts +138 -27
- package/packages/core/src/memory/episodic.ts +64 -3
- package/packages/core/src/memory/logger.ts +142 -2
- package/packages/core/src/memory/promotionEngine.ts +19 -5
- package/packages/core/src/system/agentskills.ts +10 -0
- package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
- package/packages/core/src/system/plugins/createSkill.ts +1 -1
- package/packages/core/src/system/skillExtractor.ts +16 -5
- package/packages/core/src/system/skills/forgetMemory.ts +7 -4
- package/packages/core/src/system/skills/scheduleTask.ts +7 -2
- package/packages/core/src/utils/contextSummarizer.ts +100 -0
- package/packages/core/src/utils/skillManager.ts +1 -1
- package/packages/core/src/utils/streamSimulator.ts +88 -0
- package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
- package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
- package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
- package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
- package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
- package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
- package/packages/core/src/web3/skills/checkAddress.ts +2 -0
- package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
- package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
- package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
- package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
- package/packages/core/src/web3/skills/customTx.ts +3 -0
- package/packages/core/src/web3/skills/defiLending.ts +2 -0
- package/packages/core/src/web3/skills/getBalance.ts +2 -0
- package/packages/core/src/web3/skills/getPrice.ts +134 -30
- package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
- package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
- package/packages/core/src/web3/skills/mintNft.ts +3 -0
- package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
- package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
- package/packages/core/src/web3/skills/swapToken.ts +20 -3
- package/packages/core/src/web3/skills/transfer.ts +2 -0
- package/packages/core/src/web3/skills/yieldVault.ts +2 -0
- package/packages/core/src/web3/utils/chains.ts +12 -0
- package/packages/core/src/web3/utils/marketEngine.ts +27 -33
- package/packages/dashboard/dist/assets/index-BTfp141V.js +18 -0
- package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +10 -10
- package/packages/mcp-server/dist/server.js +5 -1
- package/packages/mcp-server/package.json +6 -6
- package/packages/mcp-server/src/server.ts +11 -7
- package/packages/policy/package.json +3 -3
- package/packages/signer/package.json +16 -6
- package/packages/signer/src/NyxoraSigner.ts +161 -0
- package/packages/signer/src/index.ts +1 -0
- package/packages/signer/src/server.ts +25 -135
- package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
- package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
- package/dist/packages/core/src/gateway/test.js +0 -15
- package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
- package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
- package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
- package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
- package/packages/core/src/agent/honchoDaemon.ts +0 -96
- package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
- package/packages/core/src/plugin/registry.test.ts +0 -46
- package/packages/core/src/utils/formatter.test.ts +0 -41
- package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
- package/packages/dashboard/dist/assets/index-DbRWEoSr.js +0 -16
|
@@ -18,6 +18,10 @@ exports.scheduleTaskDefinition = {
|
|
|
18
18
|
prompt: {
|
|
19
19
|
type: "string",
|
|
20
20
|
description: "The prompt/command that the AI should execute when the cron triggers. E.g., 'What is the current price of Ethereum?'"
|
|
21
|
+
},
|
|
22
|
+
languageContext: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Optional. The specific language constraint for the AI's response (e.g., 'Reply strictly in Indonesian informal style', 'Reply in Japanese'). Infer this automatically from the user's current conversation language."
|
|
21
25
|
}
|
|
22
26
|
},
|
|
23
27
|
required: ["cronExpression", "prompt"]
|
|
@@ -25,12 +29,13 @@ exports.scheduleTaskDefinition = {
|
|
|
25
29
|
}
|
|
26
30
|
};
|
|
27
31
|
async function executeScheduleTask(args) {
|
|
28
|
-
const { cronExpression, prompt } = args;
|
|
32
|
+
const { cronExpression, prompt, languageContext } = args;
|
|
29
33
|
if (!cronExpression || !prompt) {
|
|
30
34
|
return "Error: Missing required parameters cronExpression or prompt.";
|
|
31
35
|
}
|
|
32
36
|
try {
|
|
33
|
-
const
|
|
37
|
+
const finalPrompt = languageContext ? `${prompt}\n(System Context: ${languageContext})` : prompt;
|
|
38
|
+
const jobId = cronManager_1.cronManager.addJob(cronExpression, finalPrompt);
|
|
34
39
|
return `Success! I have scheduled the background task.\nJob ID: ${jobId}\nSchedule: ${cronExpression}\nPrompt to execute: "${prompt}"\n\nYou will receive a notification via Telegram every time this task completes.`;
|
|
35
40
|
}
|
|
36
41
|
catch (error) {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const providerRegistry_1 = require("./web3/aggregator/providerRegistry");
|
|
4
|
+
const routeSelector_1 = require("./web3/aggregator/routeSelector");
|
|
5
|
+
async function testMainnetSwap(providerName) {
|
|
6
|
+
try {
|
|
7
|
+
const req = {
|
|
8
|
+
fromChain: 'ethereum',
|
|
9
|
+
toChain: 'ethereum',
|
|
10
|
+
fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
11
|
+
toToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
12
|
+
amountInWei: '1000000',
|
|
13
|
+
amountFormatted: '1',
|
|
14
|
+
userAddress: '0x1234567890123456789012345678901234567890',
|
|
15
|
+
slippageTolerance: 50,
|
|
16
|
+
preferredProvider: providerName
|
|
17
|
+
};
|
|
18
|
+
console.log(`\n--- Testing ${providerName} ---`);
|
|
19
|
+
const quote = await (0, routeSelector_1.fetchBestRoute)(req, "best_output");
|
|
20
|
+
console.log(`[+] SUCCESS. Provider used: ${quote.provider}`);
|
|
21
|
+
console.log(` - execution.target: ${quote.execution.target}`);
|
|
22
|
+
console.log(` - approvalAddress: ${quote.approvalAddress || 'MISSING (UNDEFINED)'}`);
|
|
23
|
+
console.log(` - execution.value: ${quote.execution.value.toString()} wei (Should be 0 for ERC20)`);
|
|
24
|
+
if (quote.approvalAddress && quote.approvalAddress.toLowerCase() !== quote.execution.target.toLowerCase()) {
|
|
25
|
+
console.log(` ⚠️ WARNING: execution.target DOES NOT MATCH approvalAddress!`);
|
|
26
|
+
}
|
|
27
|
+
else if (!quote.approvalAddress) {
|
|
28
|
+
console.log(` 🚨 CRITICAL: Provider DID NOT return an approvalAddress!`);
|
|
29
|
+
}
|
|
30
|
+
if (quote.execution.value > 0n) {
|
|
31
|
+
console.log(` 🚨 FATAL EXPLOIT: Provider requested native ETH value > 0 for an ERC20 swap!`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.log(`[-] FAILED: ${err.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function main() {
|
|
39
|
+
await providerRegistry_1.aggregatorRegistry.autoDiscover();
|
|
40
|
+
const providers = ['lifi', '0x', 'oneinch', 'kyberswap', 'openocean'];
|
|
41
|
+
for (const p of providers) {
|
|
42
|
+
await testMainnetSwap(p);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.compressHistory = compressHistory;
|
|
7
|
+
exports.needsCompression = needsCompression;
|
|
8
|
+
/**
|
|
9
|
+
* Context Summarizer — P6: Prevent Context Window Overflow
|
|
10
|
+
*
|
|
11
|
+
* When conversation history grows too long, summarise older messages
|
|
12
|
+
* into a compact paragraph and return a trimmed history that fits
|
|
13
|
+
* within a safe token budget. Mirrors the approach used by Claude/GPT
|
|
14
|
+
* to maintain long-running session coherence.
|
|
15
|
+
*/
|
|
16
|
+
const llmUtils_1 = require("./llmUtils");
|
|
17
|
+
const parser_1 = require("../config/parser");
|
|
18
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
19
|
+
/** How many text-only exchanges to keep verbatim before summarising older ones. */
|
|
20
|
+
const VERBATIM_TAIL = 10;
|
|
21
|
+
/** Minimum history length (user+assistant pairs) before we bother summarising. */
|
|
22
|
+
const SUMMARISE_THRESHOLD = 20;
|
|
23
|
+
/**
|
|
24
|
+
* Returns a history array that fits in context.
|
|
25
|
+
* If history is short, returns as-is.
|
|
26
|
+
* If long, prepends a "Conversation Summary" system message and keeps the tail verbatim.
|
|
27
|
+
*/
|
|
28
|
+
async function compressHistory(history) {
|
|
29
|
+
const textMessages = history.filter(m => (m.role === 'user' || m.role === 'assistant') && m.content && !m.tool_calls);
|
|
30
|
+
if (textMessages.length < SUMMARISE_THRESHOLD) {
|
|
31
|
+
return history; // nothing to compress yet
|
|
32
|
+
}
|
|
33
|
+
// Split: old messages to summarise, recent tail to keep verbatim
|
|
34
|
+
const tailMessages = textMessages.slice(-VERBATIM_TAIL);
|
|
35
|
+
const oldMessages = textMessages.slice(0, -VERBATIM_TAIL);
|
|
36
|
+
if (oldMessages.length === 0)
|
|
37
|
+
return history;
|
|
38
|
+
try {
|
|
39
|
+
const config = (0, parser_1.loadConfig)();
|
|
40
|
+
const historyText = oldMessages
|
|
41
|
+
.map(m => `${m.role === 'user' ? 'USER' : 'ASSISTANT'}: ${m.content}`)
|
|
42
|
+
.join('\n');
|
|
43
|
+
const summaryRes = await (0, llmUtils_1.executeWithRetry)(async (client) => client.chat({
|
|
44
|
+
model: config.llm.model,
|
|
45
|
+
temperature: 0.1,
|
|
46
|
+
messages: [
|
|
47
|
+
{
|
|
48
|
+
role: 'system',
|
|
49
|
+
content: `You are a conversation summarizer. Summarize the following conversation exchange into a single concise paragraph (max 200 words).
|
|
50
|
+
Focus on: key decisions made, important facts established, user preferences expressed, and task outcomes.
|
|
51
|
+
Write in third person. Be factual, not narrative.`
|
|
52
|
+
},
|
|
53
|
+
{ role: 'user', content: historyText }
|
|
54
|
+
]
|
|
55
|
+
}));
|
|
56
|
+
const summaryText = summaryRes.message?.content?.trim() || '';
|
|
57
|
+
if (!summaryText)
|
|
58
|
+
return history;
|
|
59
|
+
console.log(picocolors_1.default.magenta(`[ContextSummarizer] Compressed ${oldMessages.length} old messages into summary.`));
|
|
60
|
+
// Return: summary as system note + verbatim tail + all tool messages (never drop tool messages)
|
|
61
|
+
const toolMessages = history.filter(m => m.role === 'tool' || (m.role === 'assistant' && m.tool_calls));
|
|
62
|
+
return [
|
|
63
|
+
{
|
|
64
|
+
role: 'system',
|
|
65
|
+
content: `--- CONVERSATION SUMMARY (earlier context) ---\n${summaryText}\n--- END SUMMARY ---`
|
|
66
|
+
},
|
|
67
|
+
...tailMessages,
|
|
68
|
+
...toolMessages.slice(-6) // keep last 6 tool interactions
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
// On failure, just return the tail — never crash the agent
|
|
73
|
+
return history.slice(-VERBATIM_TAIL * 2);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Fast check — should we attempt compression?
|
|
78
|
+
*/
|
|
79
|
+
function needsCompression(history) {
|
|
80
|
+
const textCount = history.filter(m => (m.role === 'user' || m.role === 'assistant') && m.content && !m.tool_calls).length;
|
|
81
|
+
return textCount >= SUMMARISE_THRESHOLD;
|
|
82
|
+
}
|
|
@@ -48,7 +48,7 @@ const reverseSkillMapping = {
|
|
|
48
48
|
'analyze_market': { category: 'web3', name: 'marketAnalysis' },
|
|
49
49
|
'get_trending_tokens': { category: 'web3', name: 'getTrendingTokens' },
|
|
50
50
|
'manage_custom_tokens': { category: 'web3', name: 'manageCustomTokens' },
|
|
51
|
-
'
|
|
51
|
+
'get_price_and_fiat_value': { category: 'web3', name: 'getPrice' },
|
|
52
52
|
'supply_aave': { category: 'web3', name: 'aaveSupply' },
|
|
53
53
|
'revoke_approval': { category: 'web3', name: 'revokeApproval' },
|
|
54
54
|
'deposit_yield_vault': { category: 'web3', name: 'vaultDeposit' },
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSmartStreamWrapper = exports.simulateStream = void 0;
|
|
4
|
+
const simulateStream = async (text, onChunk, msPerChunk = 20, charsPerChunk = 3) => {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
let index = 0;
|
|
7
|
+
if (!text) {
|
|
8
|
+
resolve();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const intervalId = setInterval(() => {
|
|
12
|
+
if (index < text.length) {
|
|
13
|
+
const chunk = text.substring(index, index + charsPerChunk);
|
|
14
|
+
onChunk(chunk);
|
|
15
|
+
index += charsPerChunk;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
clearInterval(intervalId);
|
|
19
|
+
resolve();
|
|
20
|
+
}
|
|
21
|
+
}, msPerChunk);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
exports.simulateStream = simulateStream;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a smart wrapper around an onChunk callback.
|
|
27
|
+
* If the incoming chunk is large (e.g. Gemini buffering), it intercepts it and streams it smoothly.
|
|
28
|
+
* If the chunk is small (e.g. OpenAI native stream), it passes it instantly.
|
|
29
|
+
*/
|
|
30
|
+
const createSmartStreamWrapper = (originalOnChunk) => {
|
|
31
|
+
let isSimulating = false;
|
|
32
|
+
let queue = '';
|
|
33
|
+
let resolveWait = null;
|
|
34
|
+
let waitPromise = Promise.resolve();
|
|
35
|
+
const processQueue = async () => {
|
|
36
|
+
if (isSimulating || queue.length === 0)
|
|
37
|
+
return;
|
|
38
|
+
isSimulating = true;
|
|
39
|
+
// Create a new wait promise if one doesn't exist
|
|
40
|
+
if (!resolveWait) {
|
|
41
|
+
waitPromise = new Promise(r => { resolveWait = r; });
|
|
42
|
+
}
|
|
43
|
+
while (queue.length > 0) {
|
|
44
|
+
const chars = queue.substring(0, 3);
|
|
45
|
+
queue = queue.substring(3);
|
|
46
|
+
originalOnChunk(chars);
|
|
47
|
+
await new Promise(r => setTimeout(r, 20));
|
|
48
|
+
}
|
|
49
|
+
isSimulating = false;
|
|
50
|
+
if (resolveWait) {
|
|
51
|
+
resolveWait();
|
|
52
|
+
resolveWait = null;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
let accumulatedRaw = '';
|
|
56
|
+
let sentLength = 0;
|
|
57
|
+
return {
|
|
58
|
+
onChunk: (chunk) => {
|
|
59
|
+
accumulatedRaw += chunk;
|
|
60
|
+
// Strip any <think> or <thought> block.
|
|
61
|
+
// The (<\/\1>|$) part matches up to the closing tag, or up to the END of the string if it's unclosed.
|
|
62
|
+
const cleanText = accumulatedRaw.replace(/<(think|thought)[\s\S]*?(<\/\1>|$)/gi, '');
|
|
63
|
+
if (cleanText.length > sentLength) {
|
|
64
|
+
const newText = cleanText.substring(sentLength);
|
|
65
|
+
sentLength = cleanText.length;
|
|
66
|
+
if (newText.length > 30) {
|
|
67
|
+
queue += newText;
|
|
68
|
+
processQueue();
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
if (isSimulating) {
|
|
72
|
+
queue += newText;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
originalOnChunk(newText);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
wait: async () => {
|
|
81
|
+
await waitPromise;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
exports.createSmartStreamWrapper = createSmartStreamWrapper;
|
|
@@ -24,7 +24,9 @@ class ArbitrumBridgeProvider {
|
|
|
24
24
|
return true;
|
|
25
25
|
}
|
|
26
26
|
supports(request) {
|
|
27
|
-
|
|
27
|
+
const isL1ToL2 = request.fromChain === 'sepolia' && request.toChain === 'arbitrum_sepolia';
|
|
28
|
+
const isL2ToL1 = request.toChain === 'sepolia' && request.fromChain === 'arbitrum_sepolia';
|
|
29
|
+
if (!isL1ToL2 && !isL2ToL1)
|
|
28
30
|
return false;
|
|
29
31
|
const isNative = request.fromToken.toLowerCase() === 'eth' ||
|
|
30
32
|
request.fromToken.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ||
|
|
@@ -32,27 +34,42 @@ class ArbitrumBridgeProvider {
|
|
|
32
34
|
return isNative;
|
|
33
35
|
}
|
|
34
36
|
async getQuote(request, context) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const isL1ToL2 = request.fromChain === 'sepolia';
|
|
38
|
+
let targetAddress;
|
|
39
|
+
let callData;
|
|
40
|
+
if (isL1ToL2) {
|
|
41
|
+
targetAddress = '0xaAe29B0366299461418F5324a79Afc425BE5ae21'; // Delayed Inbox
|
|
42
|
+
const depositEthAbi = (0, viem_1.parseAbi)(['function depositEth() payable returns (uint256)']);
|
|
43
|
+
callData = (0, viem_1.encodeFunctionData)({
|
|
44
|
+
abi: depositEthAbi,
|
|
45
|
+
functionName: 'depositEth'
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
targetAddress = '0x0000000000000000000000000000000000000064'; // ArbSys precompile
|
|
50
|
+
const withdrawEthAbi = (0, viem_1.parseAbi)(['function withdrawEth(address destination) payable returns (uint256)']);
|
|
51
|
+
callData = (0, viem_1.encodeFunctionData)({
|
|
52
|
+
abi: withdrawEthAbi,
|
|
53
|
+
functionName: 'withdrawEth',
|
|
54
|
+
args: [request.userAddress]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const note = isL1ToL2 ? '100% Real L1->L2 Bridge Transaction via Arbitrum Delayed Inbox' : 'Arbitrum ArbSys L2->L1 Withdrawal (Requires ~7 day challenge period)';
|
|
41
58
|
return {
|
|
42
59
|
provider: this.manifest.name,
|
|
43
60
|
routeId: `arb-bridge-${crypto_1.default.randomUUID()}`,
|
|
44
|
-
fromChainId: 11155111
|
|
45
|
-
toChainId: 421614
|
|
61
|
+
fromChainId: isL1ToL2 ? 11155111 : 421614,
|
|
62
|
+
toChainId: isL1ToL2 ? 421614 : 11155111,
|
|
46
63
|
inputAmount: BigInt(request.amountInWei),
|
|
47
64
|
outputAmount: BigInt(request.amountInWei), // 1:1 on official bridge
|
|
48
65
|
executable: true,
|
|
49
66
|
expiresAt: Date.now() + 86400000, // Valid for a long time as it's a fixed contract call
|
|
50
67
|
execution: {
|
|
51
|
-
target:
|
|
68
|
+
target: targetAddress,
|
|
52
69
|
calldata: callData,
|
|
53
70
|
value: BigInt(request.amountInWei)
|
|
54
71
|
},
|
|
55
|
-
raw: { note
|
|
72
|
+
raw: { note }
|
|
56
73
|
};
|
|
57
74
|
}
|
|
58
75
|
async isHealthy() {
|
|
@@ -24,8 +24,9 @@ class OpBridgeProvider {
|
|
|
24
24
|
return true;
|
|
25
25
|
}
|
|
26
26
|
supports(request) {
|
|
27
|
-
const
|
|
28
|
-
|
|
27
|
+
const isL1ToL2 = request.fromChain === 'sepolia' && (request.toChain === 'optimism_sepolia' || request.toChain === 'base_sepolia');
|
|
28
|
+
const isL2ToL1 = request.toChain === 'sepolia' && (request.fromChain === 'optimism_sepolia' || request.fromChain === 'base_sepolia');
|
|
29
|
+
if (!isL1ToL2 && !isL2ToL1)
|
|
29
30
|
return false;
|
|
30
31
|
const isNative = request.fromToken.toLowerCase() === 'eth' ||
|
|
31
32
|
request.fromToken.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ||
|
|
@@ -33,34 +34,47 @@ class OpBridgeProvider {
|
|
|
33
34
|
return isNative;
|
|
34
35
|
}
|
|
35
36
|
async getQuote(request, context) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const isL1ToL2 = request.fromChain === 'sepolia';
|
|
38
|
+
let bridgeAddress;
|
|
39
|
+
let callData;
|
|
40
|
+
if (isL1ToL2) {
|
|
41
|
+
// L1 to L2
|
|
42
|
+
const BRIDGE_ADDRESSES = {
|
|
43
|
+
optimism_sepolia: '0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1',
|
|
44
|
+
base_sepolia: '0xfd0Bf71F60660E2f608ed56e1659C450eB113120',
|
|
45
|
+
};
|
|
46
|
+
bridgeAddress = BRIDGE_ADDRESSES[request.toChain];
|
|
47
|
+
if (!bridgeAddress) {
|
|
48
|
+
throw new Error(`[OpBridgeProvider] No bridge address configured for destination chain: ${request.toChain}`);
|
|
49
|
+
}
|
|
50
|
+
const depositEthAbi = (0, viem_1.parseAbi)([
|
|
51
|
+
'function depositETH(uint32 _minGasLimit, bytes _extraData) payable'
|
|
52
|
+
]);
|
|
53
|
+
callData = (0, viem_1.encodeFunctionData)({
|
|
54
|
+
abi: depositEthAbi,
|
|
55
|
+
functionName: 'depositETH',
|
|
56
|
+
args: [200000, '0x']
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// L2 to L1
|
|
61
|
+
bridgeAddress = '0x4200000000000000000000000000000000000010'; // L2StandardBridge predeploy on OP Stack
|
|
62
|
+
const bridgeEthAbi = (0, viem_1.parseAbi)([
|
|
63
|
+
'function bridgeETH(uint32 _minGasLimit, bytes _extraData) payable'
|
|
64
|
+
]);
|
|
65
|
+
callData = (0, viem_1.encodeFunctionData)({
|
|
66
|
+
abi: bridgeEthAbi,
|
|
67
|
+
functionName: 'bridgeETH',
|
|
68
|
+
args: [200000, '0x']
|
|
69
|
+
});
|
|
45
70
|
}
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
'function depositETH(uint32 _minGasLimit, bytes _extraData) payable'
|
|
49
|
-
]);
|
|
50
|
-
// OP Stack requires a minGasLimit. 200000 is a safe default for simple ETH transfers.
|
|
51
|
-
const minGasLimit = 200000;
|
|
52
|
-
const extraData = '0x';
|
|
53
|
-
const callData = (0, viem_1.encodeFunctionData)({
|
|
54
|
-
abi: depositEthAbi,
|
|
55
|
-
functionName: 'depositETH',
|
|
56
|
-
args: [minGasLimit, extraData]
|
|
57
|
-
});
|
|
58
|
-
const destChainId = request.toChain === 'optimism_sepolia' ? 11155420 : 84532;
|
|
71
|
+
const getChainId = (name) => name === 'sepolia' ? 11155111 : (name === 'optimism_sepolia' ? 11155420 : 84532);
|
|
72
|
+
const note = isL1ToL2 ? 'OP Stack Standard Bridge L1->L2' : 'OP Stack Standard Bridge L2->L1 (Requires 7-day challenge period to finalize)';
|
|
59
73
|
return {
|
|
60
74
|
provider: this.manifest.name,
|
|
61
75
|
routeId: `op-bridge-${crypto_1.default.randomUUID()}`,
|
|
62
|
-
fromChainId:
|
|
63
|
-
toChainId:
|
|
76
|
+
fromChainId: getChainId(request.fromChain),
|
|
77
|
+
toChainId: getChainId(request.toChain),
|
|
64
78
|
inputAmount: BigInt(request.amountInWei),
|
|
65
79
|
outputAmount: BigInt(request.amountInWei), // 1:1 bridging
|
|
66
80
|
executable: true,
|
|
@@ -70,7 +84,7 @@ class OpBridgeProvider {
|
|
|
70
84
|
calldata: callData,
|
|
71
85
|
value: BigInt(request.amountInWei)
|
|
72
86
|
},
|
|
73
|
-
raw: { note
|
|
87
|
+
raw: { note }
|
|
74
88
|
};
|
|
75
89
|
}
|
|
76
90
|
async isHealthy() {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TestnetSwapProvider = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
class TestnetSwapProvider {
|
|
9
|
+
manifest = {
|
|
10
|
+
id: 'testnet_mock_swap',
|
|
11
|
+
name: 'Testnet Simulated Swap',
|
|
12
|
+
version: '1.0.1',
|
|
13
|
+
networks: ['testnet'],
|
|
14
|
+
capabilities: ['swap'],
|
|
15
|
+
allowedDomains: [],
|
|
16
|
+
permissions: {
|
|
17
|
+
network: false,
|
|
18
|
+
walletAccess: 'none',
|
|
19
|
+
filesystem: 'none'
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
isCrossChainSupported() {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
supports(request) {
|
|
26
|
+
if (request.fromChain !== request.toChain)
|
|
27
|
+
return false;
|
|
28
|
+
// Only support testnet chains
|
|
29
|
+
return request.fromChain.includes('sepolia');
|
|
30
|
+
}
|
|
31
|
+
async getQuote(request, context) {
|
|
32
|
+
const chainIds = {
|
|
33
|
+
sepolia: 11155111,
|
|
34
|
+
base_sepolia: 84532,
|
|
35
|
+
optimism_sepolia: 11155420,
|
|
36
|
+
arbitrum_sepolia: 421614
|
|
37
|
+
};
|
|
38
|
+
// Simulate 1:0.98 exchange rate for testing (or a fixed amount if amounts aren't known)
|
|
39
|
+
// To make it look realistic, we just output 98% of the input conceptually (not accurate for different decimals, but works for mock UX).
|
|
40
|
+
const outAmount = (BigInt(request.amountInWei) * 98n) / 100n;
|
|
41
|
+
return {
|
|
42
|
+
provider: this.manifest.name,
|
|
43
|
+
routeId: `testnet-swap-${crypto_1.default.randomUUID()}`,
|
|
44
|
+
fromChainId: chainIds[request.fromChain] || 11155111,
|
|
45
|
+
toChainId: chainIds[request.toChain] || 11155111,
|
|
46
|
+
inputAmount: BigInt(request.amountInWei),
|
|
47
|
+
outputAmount: outAmount,
|
|
48
|
+
estimatedGasUsd: 0.05,
|
|
49
|
+
executable: true,
|
|
50
|
+
expiresAt: Date.now() + 86400000,
|
|
51
|
+
execution: {
|
|
52
|
+
// Send a 0 value transaction to the user's own address to simulate contract interaction
|
|
53
|
+
// without actually losing testnet funds or failing.
|
|
54
|
+
target: request.userAddress,
|
|
55
|
+
calldata: '0x',
|
|
56
|
+
value: 0n
|
|
57
|
+
},
|
|
58
|
+
raw: { note: 'Simulated Testnet Swap. Generating a dummy zero-value transaction for UI verification.' }
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async isHealthy() {
|
|
62
|
+
return { ok: true, checkedAt: Date.now() };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.TestnetSwapProvider = TestnetSwapProvider;
|
|
@@ -36,7 +36,13 @@ async function fetchBestRoute(request, preference = "best_output") {
|
|
|
36
36
|
// 1. Resolve eligible providers
|
|
37
37
|
let eligibleProviders = providerRegistry_1.aggregatorRegistry.resolveEligibleProviders(request);
|
|
38
38
|
if (request.preferredProvider && request.preferredProvider !== "auto") {
|
|
39
|
-
|
|
39
|
+
const filteredProviders = eligibleProviders.filter(p => p.manifest.id === request.preferredProvider);
|
|
40
|
+
if (filteredProviders.length > 0) {
|
|
41
|
+
eligibleProviders = filteredProviders;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.warn(`[RouteSelector] LLM Hallucinated or requested an ineligible provider: '${request.preferredProvider}'. Falling back to automatic provider routing.`);
|
|
45
|
+
}
|
|
40
46
|
}
|
|
41
47
|
if (eligibleProviders.length === 0) {
|
|
42
48
|
throw new Error('[RouteSelector] No eligible providers found for this route.');
|
|
@@ -16,7 +16,7 @@ const confirmPendingTx_1 = require("../skills/confirmPendingTx");
|
|
|
16
16
|
class Web3DefiPlugin {
|
|
17
17
|
name = 'Web3DefiPlugin';
|
|
18
18
|
description = 'Core DeFi operations including balance checking, portfolio analysis, and token swapping.';
|
|
19
|
-
version = '1.0.
|
|
19
|
+
version = '1.0.1';
|
|
20
20
|
tools = [
|
|
21
21
|
getBalance_1.getBalanceToolDefinition,
|
|
22
22
|
checkPortfolio_1.checkPortfolioToolDefinition,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Web3MarketPlugin = void 0;
|
|
4
4
|
const httpClient_1 = require("../../utils/httpClient");
|
|
5
|
-
const riskIntelligence_1 = require("../utils/riskIntelligence");
|
|
6
5
|
const marketConfigManager_1 = require("../../config/marketConfigManager");
|
|
7
6
|
async function fetchCexData(symbol) {
|
|
8
7
|
try {
|
|
@@ -96,139 +95,20 @@ async function fetchCexMomentum(symbol, currentP) {
|
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
}
|
|
98
|
+
const marketAnalysis_1 = require("../skills/marketAnalysis");
|
|
99
99
|
class Web3MarketPlugin {
|
|
100
100
|
name = 'MarketAnalysis';
|
|
101
|
-
version = '1.0.
|
|
101
|
+
version = '1.0.1';
|
|
102
102
|
description = 'Provides deep market intelligence and analysis for Web3 assets.';
|
|
103
103
|
tools = [
|
|
104
|
-
|
|
105
|
-
type: 'function',
|
|
106
|
-
function: {
|
|
107
|
-
name: 'analyze_market',
|
|
108
|
-
description: 'Analyzes the market health of a token (Price, FDV, TVL, Holders, Momentum) by fetching from CEX, DEX, CoinGecko, and DefiLlama. Returns a full intelligence report.',
|
|
109
|
-
parameters: {
|
|
110
|
-
type: 'object',
|
|
111
|
-
properties: {
|
|
112
|
-
tokenAddressOrSymbol: { type: 'string', description: 'The token symbol (e.g. BTC, ETH) or Contract Address.' },
|
|
113
|
-
chainName: { type: 'string', description: 'Optional chain name (e.g. ethereum, solana) if searching by address.' }
|
|
114
|
-
},
|
|
115
|
-
required: ['tokenAddressOrSymbol']
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
104
|
+
marketAnalysis_1.marketAnalysisToolDefinition
|
|
119
105
|
];
|
|
120
106
|
handlers = {
|
|
121
107
|
'analyze_market': async (args, context) => {
|
|
122
108
|
try {
|
|
123
109
|
const { chainName, tokenAddressOrSymbol } = args;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const cleanInput = String(tokenAddressOrSymbol || "").replace('$', '').toLowerCase();
|
|
127
|
-
const isAddress = cleanInput.startsWith('0x') && cleanInput.length === 42;
|
|
128
|
-
let officialSymbol = cleanInput.toUpperCase();
|
|
129
|
-
let contractAddress = isAddress ? cleanInput : null;
|
|
130
|
-
let network = chainName || "UNKNOWN";
|
|
131
|
-
let currentPrice = 0;
|
|
132
|
-
let mcapUsd = 0;
|
|
133
|
-
let liquidityUsd = 0;
|
|
134
|
-
let volume24h = 0;
|
|
135
|
-
let priceChange24h = 0;
|
|
136
|
-
let rsi = null;
|
|
137
|
-
let ma50 = null;
|
|
138
|
-
let isCexAsset = false;
|
|
139
|
-
// PHASE 1
|
|
140
|
-
if (isAddress) {
|
|
141
|
-
const targetPair = await fetchDexData(cleanInput, true, chainName);
|
|
142
|
-
if (targetPair) {
|
|
143
|
-
officialSymbol = targetPair.baseToken.symbol;
|
|
144
|
-
contractAddress = targetPair.baseToken.address;
|
|
145
|
-
network = targetPair.chainId.toUpperCase();
|
|
146
|
-
currentPrice = parseFloat(targetPair.priceUsd || "0");
|
|
147
|
-
mcapUsd = targetPair.fdv || 0;
|
|
148
|
-
liquidityUsd = targetPair.liquidity?.usd || 0;
|
|
149
|
-
volume24h = targetPair.volume?.h24 || 0;
|
|
150
|
-
priceChange24h = targetPair.priceChange?.h24 || 0;
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
return `[Market Intelligence] Failed to find data for Contract Address ${tokenAddressOrSymbol} on DEX.`;
|
|
154
|
-
}
|
|
155
|
-
const momentum = await fetchCexMomentum(officialSymbol, currentPrice);
|
|
156
|
-
ma50 = momentum.ma50;
|
|
157
|
-
rsi = momentum.rsi;
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
const cgData = await fetchCoinGeckoData(officialSymbol);
|
|
161
|
-
const cex = await fetchCexData(officialSymbol);
|
|
162
|
-
if (cgData || cex) {
|
|
163
|
-
isCexAsset = true;
|
|
164
|
-
network = `Global CEX/Market`;
|
|
165
|
-
currentPrice = cex ? cex.price : (cgData?.price || 0);
|
|
166
|
-
volume24h = cgData ? cgData.vol : (cex?.vol || 0);
|
|
167
|
-
priceChange24h = cex ? cex.change : (cgData?.change || 0);
|
|
168
|
-
mcapUsd = cgData ? cgData.fdv : (volume24h * 10);
|
|
169
|
-
liquidityUsd = cgData ? cgData.fdv * 0.1 : (volume24h * 2);
|
|
170
|
-
const momentum = await fetchCexMomentum(officialSymbol, currentPrice);
|
|
171
|
-
ma50 = momentum.ma50;
|
|
172
|
-
rsi = momentum.rsi;
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
const targetPair = await fetchDexData(cleanInput, false, chainName);
|
|
176
|
-
if (targetPair) {
|
|
177
|
-
officialSymbol = targetPair.baseToken.symbol;
|
|
178
|
-
contractAddress = targetPair.baseToken.address;
|
|
179
|
-
network = targetPair.chainId.toUpperCase();
|
|
180
|
-
currentPrice = parseFloat(targetPair.priceUsd || "0");
|
|
181
|
-
mcapUsd = targetPair.fdv || 0;
|
|
182
|
-
liquidityUsd = targetPair.liquidity?.usd || 0;
|
|
183
|
-
volume24h = targetPair.volume?.h24 || 0;
|
|
184
|
-
priceChange24h = targetPair.priceChange?.h24 || 0;
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
return `[Market Intelligence] Failed to find market data for symbol ${officialSymbol} on both CEX and DEX.`;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// PHASE 2
|
|
192
|
-
let tvlChange7d = null;
|
|
193
|
-
try {
|
|
194
|
-
const llamaData = await (0, httpClient_1.safeFetchJson)(`https://api.llama.fi/protocol/${officialSymbol.toLowerCase()}`);
|
|
195
|
-
if (llamaData && llamaData.tvl) {
|
|
196
|
-
const tvlList = llamaData.tvl;
|
|
197
|
-
if (tvlList.length > 7) {
|
|
198
|
-
const todayTvl = tvlList[tvlList.length - 1].totalLiquidityUSD;
|
|
199
|
-
const weekAgoTvl = tvlList[tvlList.length - 8].totalLiquidityUSD;
|
|
200
|
-
if (weekAgoTvl > 0)
|
|
201
|
-
tvlChange7d = ((todayTvl - weekAgoTvl) / weekAgoTvl) * 100;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
catch { }
|
|
206
|
-
// PHASE 3
|
|
207
|
-
let top10HoldersPercent = null;
|
|
208
|
-
if (contractAddress || isCexAsset) {
|
|
209
|
-
if (mcapUsd > 100000000)
|
|
210
|
-
top10HoldersPercent = 15;
|
|
211
|
-
else if (mcapUsd < 500000)
|
|
212
|
-
top10HoldersPercent = 85;
|
|
213
|
-
else
|
|
214
|
-
top10HoldersPercent = 45;
|
|
215
|
-
}
|
|
216
|
-
// PHASE 4
|
|
217
|
-
const healthResult = (0, riskIntelligence_1.generateMarketHealthReport)(liquidityUsd, mcapUsd, tvlChange7d, volume24h, priceChange24h, top10HoldersPercent, rsi, currentPrice, ma50);
|
|
218
|
-
// PHASE 5
|
|
219
|
-
let report = `📊 **Market Intelligence Report: ${officialSymbol}**\n`;
|
|
220
|
-
report += `CA: \`${contractAddress || 'N/A'}\` | Network: ${network}\n\n`;
|
|
221
|
-
report += `**⭐ Overall Market Health Score:** ${healthResult.overallScore} / 10\n\n`;
|
|
222
|
-
report += `**1. Liquidity Risk:** ${healthResult.liquidityScore !== null ? healthResult.liquidityScore + '/10' : '[ N/A ]'}\n`;
|
|
223
|
-
report += `- Liquidity: $${liquidityUsd.toLocaleString()} vs FDV: $${mcapUsd.toLocaleString()}\n`;
|
|
224
|
-
report += `**2. Smart Money Flow:** ${healthResult.smartMoneyScore !== null ? healthResult.smartMoneyScore + '/10' : '[ N/A - Not in DefiLlama ]'}\n`;
|
|
225
|
-
report += `- 24h Volume: $${volume24h.toLocaleString()} | TVL 7D Change: ${tvlChange7d !== null ? tvlChange7d.toFixed(2) + '%' : 'N/A'}\n`;
|
|
226
|
-
report += `**3. Holder Concentration:** ${healthResult.concentrationScore !== null ? healthResult.concentrationScore + '/10' : '[ N/A - RPC Pending ]'}\n`;
|
|
227
|
-
report += `- Top 10 Holders: ${top10HoldersPercent !== null ? top10HoldersPercent + '%' : 'N/A'}\n`;
|
|
228
|
-
report += `**4. Momentum (CEX):** ${healthResult.momentumScore !== null ? healthResult.momentumScore + '/10' : '[ N/A - DEX Only Coin ]'}\n`;
|
|
229
|
-
report += `- Price: $${currentPrice} | MA50: ${ma50 ? '$' + ma50.toFixed(4) : 'N/A'} | RSI: ${rsi || 'N/A'}\n\n`;
|
|
230
|
-
report += `*System Note for LLM: Use this exact data to provide a "Market Summary" and "Suggested Autonomous Actions" in the user's native language. If CEX momentum is N/A, explicitly warn about high risk Degen/Memecoin status. IMPORTANT: Always include a clear disclaimer at the end (translated into the user's native language) stating that this analysis is NOT financial advice (NFA).*`;
|
|
231
|
-
return report;
|
|
110
|
+
const { analyzeMarket } = require('../skills/marketAnalysis');
|
|
111
|
+
return await analyzeMarket(chainName, tokenAddressOrSymbol);
|
|
232
112
|
}
|
|
233
113
|
catch (error) {
|
|
234
114
|
return `[Market Intelligence] Failed to aggregate data: ${error.message}`;
|