nyxora 1.7.0 → 1.7.1
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 +16 -0
- package/bin/nyxora.mjs +8 -0
- package/package.json +1 -2
- package/packages/core/package.json +1 -1
- package/packages/core/src/agent/limitOrderManager.ts +2 -2
- package/packages/core/src/agent/reasoning.ts +12 -10
- package/packages/core/src/config/parser.ts +99 -9
- package/packages/core/src/gateway/cli.ts +28 -2
- package/packages/core/src/gateway/setup.ts +44 -9
- package/packages/core/src/gateway/telegram.ts +3 -1
- package/packages/core/src/system/skills/searchWeb.ts +187 -21
- package/packages/core/src/web3/config.ts +7 -1
- package/packages/core/src/web3/skills/bridgeToken.ts +4 -3
- package/packages/core/src/web3/skills/checkAddress.ts +2 -2
- package/packages/core/src/web3/skills/checkPortfolio.ts +2 -2
- package/packages/core/src/web3/skills/checkSecurity.ts +3 -2
- package/packages/core/src/web3/skills/customTx.ts +2 -2
- package/packages/core/src/web3/skills/getBalance.ts +3 -3
- package/packages/core/src/web3/skills/marketAnalysis.ts +2 -2
- package/packages/core/src/web3/skills/mintNft.ts +2 -2
- package/packages/core/src/web3/skills/swapToken.ts +4 -3
- package/packages/core/src/web3/skills/transfer.ts +2 -2
- package/packages/core/src/web3/utils/tokens.ts +8 -0
- package/packages/dashboard/dist/assets/{index-24OeXn-k.css → index-BSk4CLkG.css} +1 -1
- package/packages/dashboard/dist/assets/{index-DQtaOlOl.js → index-Dc3Tu0Te.js} +20 -20
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +1 -1
- package/packages/mcp-server/package.json +1 -1
- package/packages/policy/package.json +1 -1
- package/packages/signer/package.json +1 -1
- package/packages/dashboard/public/favicon.svg +0 -10
- package/packages/dashboard/public/icons.svg +0 -24
- package/packages/dashboard/src/App.css +0 -184
- package/packages/dashboard/src/App.tsx +0 -585
- package/packages/dashboard/src/BalanceWidget.tsx +0 -65
- package/packages/dashboard/src/MarketWidget.tsx +0 -73
- package/packages/dashboard/src/NetworkSelector.tsx +0 -64
- package/packages/dashboard/src/NyxoraLogo.tsx +0 -25
- package/packages/dashboard/src/OsSkills.tsx +0 -352
- package/packages/dashboard/src/Overview.tsx +0 -157
- package/packages/dashboard/src/PendingTransactions.tsx +0 -75
- package/packages/dashboard/src/Settings.tsx +0 -338
- package/packages/dashboard/src/Skills.tsx +0 -200
- package/packages/dashboard/src/SwapWidget.tsx +0 -141
- package/packages/dashboard/src/TransactionWidget.tsx +0 -95
- package/packages/dashboard/src/assets/hero.png +0 -0
- package/packages/dashboard/src/assets/react.svg +0 -1
- package/packages/dashboard/src/assets/vite.svg +0 -1
- package/packages/dashboard/src/components/PillSelect.tsx +0 -65
- package/packages/dashboard/src/index.css +0 -807
- package/packages/dashboard/src/main.tsx +0 -10
- package/packages/dashboard/src/overview.css +0 -304
- package/packages/dashboard/src/utils/api.ts +0 -31
|
@@ -1,43 +1,209 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadConfig, loadApiKeys } from '../../config/parser';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
interface SearchQueryResult {
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const SEARXNG_INSTANCES = [
|
|
10
|
+
'https://search.mdosch.de',
|
|
11
|
+
'https://searx.tiekoetter.com',
|
|
12
|
+
'https://paulgo.io',
|
|
13
|
+
'https://searx.be',
|
|
14
|
+
'https://searx.fmac.network'
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
async function searchTavily(query: string, apiKey: string, depth: number = 1): Promise<SearchQueryResult[]> {
|
|
18
|
+
const searchDepth = depth > 1 ? 'advanced' : 'basic';
|
|
19
|
+
const maxResults = depth > 1 ? 15 : 8;
|
|
20
|
+
const res = await fetch('https://api.tavily.com/search', {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: { 'Content-Type': 'application/json' },
|
|
23
|
+
body: JSON.stringify({ api_key: apiKey, query, search_depth: searchDepth, max_results: maxResults })
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
const status = res.status;
|
|
28
|
+
throw new Error(`[Tavily Error] Status: ${status}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const json = await res.json();
|
|
32
|
+
if (!json.results) return [];
|
|
33
|
+
|
|
34
|
+
return json.results.map((r: any) => ({
|
|
35
|
+
title: r.title,
|
|
36
|
+
url: r.url,
|
|
37
|
+
content: r.content
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
8
40
|
|
|
9
|
-
|
|
10
|
-
|
|
41
|
+
async function searchBrave(query: string, apiKey: string, depth: number = 1): Promise<SearchQueryResult[]> {
|
|
42
|
+
const q = encodeURIComponent(query);
|
|
43
|
+
const count = depth > 1 ? 15 : 8;
|
|
44
|
+
const res = await fetch(`https://api.search.brave.com/res/v1/web/search?q=${q}&count=${count}`, {
|
|
45
|
+
headers: {
|
|
46
|
+
'Accept': 'application/json',
|
|
47
|
+
'X-Subscription-Token': apiKey
|
|
11
48
|
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
const status = res.status;
|
|
53
|
+
throw new Error(`[Brave Error] Status: ${status}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const json = await res.json();
|
|
57
|
+
if (!json.web || !json.web.results) return [];
|
|
58
|
+
|
|
59
|
+
return json.web.results.map((r: any) => ({
|
|
60
|
+
title: r.title,
|
|
61
|
+
url: r.url,
|
|
62
|
+
content: r.description || r.title
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
12
65
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
66
|
+
async function searchSearxng(query: string, depth: number = 1): Promise<SearchQueryResult[]> {
|
|
67
|
+
const q = encodeURIComponent(query);
|
|
68
|
+
const maxResults = depth > 1 ? 15 : 8;
|
|
69
|
+
for (const url of SEARXNG_INSTANCES) {
|
|
70
|
+
try {
|
|
71
|
+
const res = await fetch(`${url}/search?q=${q}&format=json`, {
|
|
72
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' },
|
|
73
|
+
signal: AbortSignal.timeout(4000)
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (res.ok) {
|
|
77
|
+
const json = await res.json();
|
|
78
|
+
if (!json.results || json.results.length === 0) continue;
|
|
79
|
+
|
|
80
|
+
return json.results.slice(0, maxResults).map((r: any) => ({
|
|
81
|
+
title: r.title || 'No title',
|
|
82
|
+
url: r.url || '#',
|
|
83
|
+
content: r.content || r.snippet || r.description || 'No description available'
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
throw new Error('[SearXNG Error] All decentralized instances failed.');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const searchCache = new Map<string, {data: SearchQueryResult[], timestamp: number}>();
|
|
94
|
+
|
|
95
|
+
export async function searchWeb(query: string, depth: number = 1): Promise<string> {
|
|
96
|
+
// Auto-inject current year for time-sensitive queries
|
|
97
|
+
const lowerQuery = query.toLowerCase();
|
|
98
|
+
const currentYear = new Date().getFullYear().toString();
|
|
99
|
+
let finalQuery = query;
|
|
100
|
+
|
|
101
|
+
if ((lowerQuery.includes('hari ini') || lowerQuery.includes('sekarang') || lowerQuery.includes('today') || lowerQuery.includes('saat ini') || lowerQuery.includes('terbaru')) && !lowerQuery.includes(currentYear)) {
|
|
102
|
+
finalQuery = `${query} ${currentYear}`;
|
|
103
|
+
console.log(`[WebSearch] Auto-injected current year: "${finalQuery}"`);
|
|
104
|
+
}
|
|
23
105
|
|
|
106
|
+
const cacheKey = `${finalQuery.trim().toLowerCase()}_depth_${depth}`;
|
|
107
|
+
const cached = searchCache.get(cacheKey);
|
|
108
|
+
if (cached && (Date.now() - cached.timestamp < 300000)) {
|
|
109
|
+
console.log(`[WebSearch] Returning cached results for: "${finalQuery}" (Depth: ${depth})`);
|
|
110
|
+
let responseText = `Search Results for "${query}" (Cached):\n\n`;
|
|
111
|
+
cached.data.forEach((r, index) => {
|
|
112
|
+
responseText += `${index + 1}. ${r.title}\n`;
|
|
113
|
+
responseText += `URL: ${r.url}\n`;
|
|
114
|
+
responseText += `Snippet: ${r.content}\n\n`;
|
|
115
|
+
});
|
|
24
116
|
return responseText.trim();
|
|
25
|
-
} catch (error: any) {
|
|
26
|
-
return `Failed to search the web: ${error.message}`;
|
|
27
117
|
}
|
|
118
|
+
|
|
119
|
+
const config = loadConfig();
|
|
120
|
+
const provider = config.web_search?.provider || 'mesh';
|
|
121
|
+
const vaultKeys = await loadApiKeys();
|
|
122
|
+
const creds = Object.keys(vaultKeys).length > 0 ? vaultKeys : (config.credentials || {});
|
|
123
|
+
|
|
124
|
+
let results: SearchQueryResult[] = [];
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
if (provider === 'tavily' && creds.tavily_key) {
|
|
128
|
+
try {
|
|
129
|
+
results = await searchTavily(finalQuery, creds.tavily_key, depth);
|
|
130
|
+
} catch (e: any) {
|
|
131
|
+
if (e.message.includes('401') || e.message.includes('429')) {
|
|
132
|
+
console.warn('[WebSearch] Primary provider (Tavily) failed with 429/401. Switching to backup provider (Brave Search)...');
|
|
133
|
+
if (creds.brave_key) {
|
|
134
|
+
try {
|
|
135
|
+
results = await searchBrave(finalQuery, creds.brave_key, depth);
|
|
136
|
+
} catch (e2: any) {
|
|
137
|
+
console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to SearXNG Mesh...');
|
|
138
|
+
results = await searchSearxng(finalQuery, depth);
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
console.warn('[WebSearch] No backup provider found. Falling back to SearXNG Mesh...');
|
|
142
|
+
results = await searchSearxng(finalQuery, depth);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
throw e;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} else if (provider === 'brave' && creds.brave_key) {
|
|
149
|
+
try {
|
|
150
|
+
results = await searchBrave(finalQuery, creds.brave_key, depth);
|
|
151
|
+
} catch (e: any) {
|
|
152
|
+
if (e.message.includes('403') || e.message.includes('429')) {
|
|
153
|
+
console.warn('[WebSearch] Primary provider (Brave) failed with 429/403. Switching to backup provider (Tavily)...');
|
|
154
|
+
if (creds.tavily_key) {
|
|
155
|
+
try {
|
|
156
|
+
results = await searchTavily(finalQuery, creds.tavily_key, depth);
|
|
157
|
+
} catch (e2: any) {
|
|
158
|
+
console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to SearXNG Mesh...');
|
|
159
|
+
results = await searchSearxng(finalQuery, depth);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
console.warn('[WebSearch] No backup provider found. Falling back to SearXNG Mesh...');
|
|
163
|
+
results = await searchSearxng(finalQuery, depth);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
throw e;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
results = await searchSearxng(finalQuery, depth);
|
|
171
|
+
}
|
|
172
|
+
} catch (e: any) {
|
|
173
|
+
return `Failed to search the web: ${e.message}`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (results.length > 0) {
|
|
177
|
+
searchCache.set(cacheKey, { data: results, timestamp: Date.now() });
|
|
178
|
+
} else {
|
|
179
|
+
return `Search Results for "${query}": No results found.`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let responseText = `Search Results for "${query}":\n\n`;
|
|
183
|
+
results.forEach((r, index) => {
|
|
184
|
+
responseText += `${index + 1}. ${r.title}\n`;
|
|
185
|
+
responseText += `URL: ${r.url}\n`;
|
|
186
|
+
responseText += `Snippet: ${r.content}\n\n`;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return responseText.trim();
|
|
28
190
|
}
|
|
29
191
|
|
|
30
192
|
export const searchWebToolDefinition = {
|
|
31
193
|
type: "function",
|
|
32
194
|
function: {
|
|
33
195
|
name: "search_web",
|
|
34
|
-
description: "Searches the internet for information using a search engine. Returns top titles, snippets, and URLs. Use this to find current events, documentation, or general facts.",
|
|
196
|
+
description: "Searches the internet for information using a search engine. Returns top titles, snippets, and URLs. Use this to find current events, documentation, or general facts. If the user asks for deep/comprehensive research, pass depth: 2 or 3.",
|
|
35
197
|
parameters: {
|
|
36
198
|
type: "object",
|
|
37
199
|
properties: {
|
|
38
200
|
query: {
|
|
39
201
|
type: "string",
|
|
40
202
|
description: "The search query to look up.",
|
|
203
|
+
},
|
|
204
|
+
depth: {
|
|
205
|
+
type: "number",
|
|
206
|
+
description: "Depth of the search (1 for basic, 2 or 3 for deep comprehensive research). Default is 1.",
|
|
41
207
|
}
|
|
42
208
|
},
|
|
43
209
|
required: ["query"],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createPublicClient, http, fallback, PublicClient, Transport } from 'viem';
|
|
2
|
-
import { mainnet, base, bsc, arbitrum, optimism, sepolia } from 'viem/chains';
|
|
2
|
+
import { mainnet, base, bsc, arbitrum, optimism, sepolia, polygon } from 'viem/chains';
|
|
3
3
|
import { loadConfig } from '../config/parser';
|
|
4
4
|
|
|
5
5
|
export const supportedChains = {
|
|
@@ -9,8 +9,10 @@ export const supportedChains = {
|
|
|
9
9
|
arbitrum: arbitrum,
|
|
10
10
|
optimism: optimism,
|
|
11
11
|
sepolia: sepolia,
|
|
12
|
+
polygon: polygon,
|
|
12
13
|
};
|
|
13
14
|
|
|
15
|
+
export const SUPPORTED_CHAIN_NAMES = Object.keys(supportedChains);
|
|
14
16
|
export type ChainName = keyof typeof supportedChains;
|
|
15
17
|
|
|
16
18
|
export function getPublicClient(chainName: ChainName): PublicClient {
|
|
@@ -53,6 +55,10 @@ export function getPublicClient(chainName: ChainName): PublicClient {
|
|
|
53
55
|
} else if (chainName === 'sepolia') {
|
|
54
56
|
transports.push(http('https://ethereum-sepolia-rpc.publicnode.com', { timeout: 5000 }));
|
|
55
57
|
transports.push(http('https://rpc.sepolia.org', { timeout: 5000 }));
|
|
58
|
+
} else if (chainName === 'polygon') {
|
|
59
|
+
transports.push(http('https://polygon-rpc.publicnode.com', { timeout: 5000 }));
|
|
60
|
+
transports.push(http('https://polygon.llamarpc.com', { timeout: 5000 }));
|
|
61
|
+
transports.push(http('https://polygon-rpc.com', { timeout: 5000 }));
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
64
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseUnits, formatUnits } from 'viem';
|
|
2
|
-
import { getPublicClient, getAddress, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { txManager } from '../../agent/transactionManager';
|
|
4
4
|
import { resolveToken, ERC20_ABI } from '../utils/tokens';
|
|
5
5
|
|
|
@@ -10,6 +10,7 @@ const CHAIN_IDS: Record<ChainName, number> = {
|
|
|
10
10
|
arbitrum: 42161,
|
|
11
11
|
optimism: 10,
|
|
12
12
|
sepolia: 11155111,
|
|
13
|
+
polygon: 137,
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
async function getLifiQuote(fromChainId: number, toChainId: number, fromToken: string, toToken: string, amountWei: string, userAddress: string, slippage: number) {
|
|
@@ -210,12 +211,12 @@ export const bridgeTokenToolDefinition = {
|
|
|
210
211
|
properties: {
|
|
211
212
|
fromChainName: {
|
|
212
213
|
type: "string",
|
|
213
|
-
enum:
|
|
214
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
214
215
|
description: "The source blockchain network",
|
|
215
216
|
},
|
|
216
217
|
toChainName: {
|
|
217
218
|
type: "string",
|
|
218
|
-
enum:
|
|
219
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
219
220
|
description: "The destination blockchain network",
|
|
220
221
|
},
|
|
221
222
|
fromToken: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAddress } from 'viem';
|
|
2
|
-
import { getPublicClient, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
|
|
4
4
|
export async function checkAddress(chainName: ChainName, address: string): Promise<string> {
|
|
5
5
|
try {
|
|
@@ -40,7 +40,7 @@ export const checkAddressToolDefinition = {
|
|
|
40
40
|
properties: {
|
|
41
41
|
chainName: {
|
|
42
42
|
type: "string",
|
|
43
|
-
enum:
|
|
43
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
44
44
|
description: "The name of the blockchain to check the address on."
|
|
45
45
|
},
|
|
46
46
|
address: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatEther, formatUnits } from 'viem';
|
|
2
|
-
import { getPublicClient, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { TOKEN_MAP, ERC20_ABI } from '../utils/tokens';
|
|
4
4
|
|
|
5
5
|
const portfolioCache: Record<string, { data: string, timestamp: number }> = {};
|
|
@@ -181,7 +181,7 @@ export const checkPortfolioToolDefinition = {
|
|
|
181
181
|
properties: {
|
|
182
182
|
chainName: {
|
|
183
183
|
type: "string",
|
|
184
|
-
enum:
|
|
184
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
185
185
|
description: "The blockchain network",
|
|
186
186
|
},
|
|
187
187
|
address: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChainName } from '../config';
|
|
1
|
+
import { ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
2
2
|
|
|
3
3
|
const CHAIN_IDS: Record<ChainName, number> = {
|
|
4
4
|
ethereum: 1,
|
|
@@ -7,6 +7,7 @@ const CHAIN_IDS: Record<ChainName, number> = {
|
|
|
7
7
|
arbitrum: 42161,
|
|
8
8
|
optimism: 10,
|
|
9
9
|
sepolia: 11155111,
|
|
10
|
+
polygon: 137,
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
export async function checkTokenSecurity(chainName: ChainName, contractAddress: string): Promise<string> {
|
|
@@ -57,7 +58,7 @@ export const checkSecurityToolDefinition = {
|
|
|
57
58
|
properties: {
|
|
58
59
|
chainName: {
|
|
59
60
|
type: "string",
|
|
60
|
-
enum:
|
|
61
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
61
62
|
description: "The blockchain network",
|
|
62
63
|
},
|
|
63
64
|
contractAddress: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseEther } from 'viem';
|
|
2
|
-
import { getPublicClient, getAddress, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { txManager } from '../../agent/transactionManager';
|
|
4
4
|
|
|
5
5
|
export async function prepareCustomTx(
|
|
@@ -91,7 +91,7 @@ export const customTxToolDefinition = {
|
|
|
91
91
|
properties: {
|
|
92
92
|
chainName: {
|
|
93
93
|
type: "string",
|
|
94
|
-
enum:
|
|
94
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
95
95
|
description: "The blockchain network",
|
|
96
96
|
},
|
|
97
97
|
toAddress: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatEther, formatUnits } from 'viem';
|
|
2
|
-
import { getPublicClient, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { ERC20_ABI, resolveToken } from '../utils/tokens';
|
|
4
4
|
import { saveTokenToWhitelist } from '../../utils/userWhitelistManager';
|
|
5
5
|
|
|
@@ -72,8 +72,8 @@ export const getBalanceToolDefinition = {
|
|
|
72
72
|
properties: {
|
|
73
73
|
chainName: {
|
|
74
74
|
type: "string",
|
|
75
|
-
enum:
|
|
76
|
-
description: "The
|
|
75
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
76
|
+
description: "The blockchain network"
|
|
77
77
|
},
|
|
78
78
|
address: {
|
|
79
79
|
type: "string",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChainName } from '../config';
|
|
1
|
+
import { ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
2
2
|
import { resolveToken } from '../utils/tokens';
|
|
3
3
|
|
|
4
4
|
export async function analyzeMarket(chainName: ChainName, tokenAddressOrSymbol: string): Promise<string> {
|
|
@@ -85,7 +85,7 @@ export const marketAnalysisToolDefinition = {
|
|
|
85
85
|
properties: {
|
|
86
86
|
chainName: {
|
|
87
87
|
type: "string",
|
|
88
|
-
enum:
|
|
88
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
89
89
|
description: "The blockchain network",
|
|
90
90
|
},
|
|
91
91
|
tokenAddressOrSymbol: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseAbi, parseEther } from 'viem';
|
|
2
|
-
import { getPublicClient, getAddress, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { txManager } from '../../agent/transactionManager';
|
|
4
4
|
|
|
5
5
|
export async function prepareMintNft(
|
|
@@ -120,7 +120,7 @@ export const mintNftToolDefinition = {
|
|
|
120
120
|
properties: {
|
|
121
121
|
chainName: {
|
|
122
122
|
type: "string",
|
|
123
|
-
enum:
|
|
123
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
124
124
|
description: "The blockchain network",
|
|
125
125
|
},
|
|
126
126
|
contractAddress: {
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { parseUnits, formatUnits } from 'viem';
|
|
2
|
-
import { getPublicClient, getAddress, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { txManager } from '../../agent/transactionManager';
|
|
4
4
|
import { resolveToken, ERC20_ABI } from '../utils/tokens';
|
|
5
5
|
import { saveTokenToWhitelist } from '../../utils/userWhitelistManager';
|
|
6
6
|
import crypto from 'crypto';
|
|
7
7
|
|
|
8
|
-
const CHAIN_IDS: Record<
|
|
8
|
+
const CHAIN_IDS: Record<string, number> = {
|
|
9
9
|
ethereum: 1,
|
|
10
10
|
base: 8453,
|
|
11
11
|
bsc: 56,
|
|
12
12
|
arbitrum: 42161,
|
|
13
13
|
optimism: 10,
|
|
14
14
|
sepolia: 11155111,
|
|
15
|
+
polygon: 137,
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
async function getLifiQuote(fromChainId: number, toChainId: number, fromToken: string, toToken: string, amountWei: string, userAddress: string, slippage: number) {
|
|
@@ -231,7 +232,7 @@ export const swapTokenToolDefinition = {
|
|
|
231
232
|
properties: {
|
|
232
233
|
chainName: {
|
|
233
234
|
type: "string",
|
|
234
|
-
enum:
|
|
235
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
235
236
|
description: "The blockchain network",
|
|
236
237
|
},
|
|
237
238
|
fromToken: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseEther, parseUnits } from 'viem';
|
|
2
|
-
import { getPublicClient, getAddress, ChainName } from '../config';
|
|
2
|
+
import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
|
|
3
3
|
import { txManager } from '../../agent/transactionManager';
|
|
4
4
|
import { resolveToken, ERC20_ABI } from '../utils/tokens';
|
|
5
5
|
|
|
@@ -120,7 +120,7 @@ export const transferToolDefinition = {
|
|
|
120
120
|
properties: {
|
|
121
121
|
chainName: {
|
|
122
122
|
type: "string",
|
|
123
|
-
enum:
|
|
123
|
+
enum: SUPPORTED_CHAIN_NAMES,
|
|
124
124
|
description: "The name of the blockchain to execute the transfer on."
|
|
125
125
|
},
|
|
126
126
|
toAddress: {
|
|
@@ -91,6 +91,14 @@ export const TOKEN_MAP: Record<ChainName, Record<string, `0x${string}`>> = {
|
|
|
91
91
|
WETH: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",
|
|
92
92
|
USDC: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", // Circle Faucet Sepolia USDC
|
|
93
93
|
USDT: "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0" // Common Sepolia USDT
|
|
94
|
+
},
|
|
95
|
+
polygon: {
|
|
96
|
+
MATIC: "0x0000000000000000000000000000000000000000",
|
|
97
|
+
POL: "0x0000000000000000000000000000000000000000",
|
|
98
|
+
WMATIC: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
|
|
99
|
+
WPOL: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
|
|
100
|
+
USDC: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
|
|
101
|
+
USDT: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
|
|
94
102
|
}
|
|
95
103
|
};
|
|
96
104
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--bg-color: #3b4252;--bg-secondary: #434c5e;--bg-sidebar: #2e3440;--text-primary: #eceff4;--text-secondary: #d8dee9;--accent: #88c0d0;--accent-hover: #81a1c1;--glass-bg: rgba(46, 52, 64, .7);--glass-border: rgba(216, 222, 233, .1);--chat-user: #88c0d0;--chat-user-text: #2e3440;--chat-agent: #2e3440;--tool-bg: #4c566a;--success: #a3be8c;--danger: #bf616a}*{box-sizing:border-box;margin:0;padding:0}body{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background-color:var(--bg-color);color:var(--text-primary);height:100vh;overflow:hidden}#root{display:flex;height:100vh;width:100vw}.sidebar{width:280px;background-color:var(--bg-sidebar);border-right:1px solid var(--glass-border);display:flex;flex-direction:column;box-shadow:10px 0 30px -10px #00000080;z-index:100}.agent-identity-card{padding:24px;display:flex;align-items:center;gap:16px;border-bottom:1px solid rgba(255,255,255,.05);margin-bottom:8px;background:linear-gradient(180deg,rgba(59,130,246,.05) 0%,transparent 100%)}.agent-avatar{display:flex;justify-content:center;align-items:center}.agent-info{display:flex;flex-direction:column;gap:4px}.agent-name{font-size:1.1rem;font-weight:700;color:#fff;letter-spacing:-.025em}.agent-status{display:flex;align-items:center;gap:6px;font-size:.75rem;color:#4ade80;font-weight:600;letter-spacing:.05em}.status-dot{width:8px;height:8px;background-color:#4ade80;border-radius:50%;box-shadow:0 0 8px #4ade80;animation:pulse-green 2s infinite}@keyframes pulse-green{0%{transform:scale(.95);box-shadow:0 0 #4ade80b3}70%{transform:scale(1);box-shadow:0 0 0 6px #4ade8000}to{transform:scale(.95);box-shadow:0 0 #4ade8000}}.sidebar-scroll-area{flex:1;overflow-y:auto;padding-bottom:24px}.sidebar-scroll-area::-webkit-scrollbar{width:4px}.sidebar-scroll-area::-webkit-scrollbar-thumb{background:#ffffff0d}.sidebar-section{padding:24px 24px 8px;font-size:.75rem;color:#8b9bb4;font-weight:500}.sidebar-nav{display:flex;flex-direction:column;gap:4px;padding:0 16px}.nav-item{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:8px;color:#94a3b8;font-size:.8rem;font-weight:500;cursor:pointer;transition:all .25s cubic-bezier(.4,0,.2,1);border:1px solid transparent}.nav-icon{transition:transform .25s cubic-bezier(.4,0,.2,1)}.nav-item:hover{background-color:#ffffff08;color:#fff;transform:translate(4px)}.nav-item:hover .nav-icon{transform:scale(1.1);color:#fff}.sessions-list{gap:0px!important;justify-content:flex-start!important;flex:none!important;height:max-content!important}.session-item{justify-content:space-between;padding:4px 10px!important;margin-bottom:2px!important;margin-top:0!important;min-height:28px!important;height:max-content!important;flex:none!important}.delete-session-btn{background:transparent;border:none;color:#bf616a;cursor:pointer;opacity:0;transition:opacity .2s ease,transform .2s ease;display:flex;align-items:center;justify-content:center;padding:4px;border-radius:6px}.delete-session-btn:hover{background:#bf616a33;transform:scale(1.1)}.session-item:hover .delete-session-btn{opacity:1}.nav-item.active{background:linear-gradient(90deg,rgba(59,130,246,.15) 0%,transparent 100%);color:#fff;border-left:3px solid var(--accent);border-radius:4px 12px 12px 4px;font-weight:600}.nav-item.active .nav-icon{color:var(--accent)}.main-content{flex:1;display:flex;flex-direction:column;background-image:radial-gradient(at 0% 0%,rgba(59,130,246,.1) 0px,transparent 50%),radial-gradient(at 100% 100%,rgba(139,92,246,.1) 0px,transparent 50%)}.topbar{height:64px;border-bottom:1px solid var(--glass-border);display:flex;align-items:center;justify-content:space-between;padding:0 24px;background:var(--bg-color)}.topbar-left{display:flex;align-items:center;gap:16px;font-size:.95rem;font-weight:500;color:var(--text-secondary)}.topbar-right{display:flex;align-items:center;gap:12px}.custom-network-selector{position:relative}.network-selector-pill{display:flex;align-items:center;gap:8px;background:#88c0d0;border:none;color:#000;font-weight:600;font-size:.85rem;border-radius:9999px;padding:8px 16px;cursor:pointer;transition:all .2s;outline:none;font-family:inherit}.network-selector-pill:hover{opacity:.9;box-shadow:0 0 10px #88c0d066}.network-selector-pill:focus-visible{box-shadow:0 0 0 2px #88c0d080}.network-icon{flex-shrink:0}.network-chevron{opacity:.7;margin-left:4px}.network-dropdown-menu{position:absolute;top:calc(100% + 8px);right:0;background:var(--bg-secondary);border:1px solid var(--glass-border);border-radius:12px;padding:6px;list-style:none;margin:0;min-width:180px;box-shadow:0 8px 24px #0006;z-index:100;animation:dropdownSlideIn .2s ease-out}@keyframes dropdownSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.network-dropdown-item{padding:10px 14px;border-radius:8px;cursor:pointer;font-size:.85rem;color:#e5e7eb;transition:background .1s}.network-dropdown-item:hover{background:#ffffff0d}.network-dropdown-item.active{background:#88c0d01a;color:#88c0d0;font-weight:600}.workspace-container{display:flex;height:calc(100vh - 64px);width:100%}.chat-wrapper{display:flex;flex-direction:column;padding:24px 0;height:100%}.resizer{width:6px;background:var(--glass-border);cursor:col-resize;transition:background .2s;z-index:10}.resizer:hover,.resizer:active{background:var(--accent)}.canvas-panel{flex:1;display:flex;flex-direction:column;background:var(--bg-sidebar);padding:32px;overflow-y:auto;position:relative;background-image:radial-gradient(at 50% 50%,rgba(59,130,246,.05) 0px,transparent 80%)}.canvas-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:32px;border-bottom:1px solid rgba(255,255,255,.05);padding-bottom:16px}.canvas-title{font-family:monospace;color:#94a3b8;font-size:.85rem;display:flex;align-items:center;gap:8px;text-transform:uppercase;letter-spacing:.05em}.canvas-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#475569;gap:16px}.chat-container{flex:1;overflow-y:auto;padding:0 24px;display:flex;flex-direction:column;gap:20px}.chat-container::-webkit-scrollbar{width:6px}.chat-container::-webkit-scrollbar-thumb{background:#ffffff1a;border-radius:4px}.message-wrapper{display:flex;flex-direction:column;max-width:85%;animation:fadeIn .3s ease-out forwards}.message-wrapper.agent{align-self:flex-start;flex-direction:row;align-items:flex-end;gap:8px}.message-wrapper.user{align-self:flex-end;flex-direction:row-reverse;align-items:flex-end;gap:8px}.copy-btn{background:transparent;border:none;color:var(--text-secondary);cursor:pointer;padding:6px;border-radius:6px;opacity:0;transition:opacity .2s,background .2s;display:flex;align-items:center;justify-content:center}.copy-btn:hover{background:var(--bg-secondary);color:var(--text-primary)}.message-wrapper:hover .copy-btn{opacity:1}.message-bubble{padding:14px 18px;border-radius:18px;line-height:1.6;font-size:.95rem;box-shadow:0 4px 6px -1px #0000001a;white-space:pre-wrap}.user .message-bubble{background-color:var(--chat-user);color:var(--chat-user-text);border-bottom-right-radius:4px}.agent .message-bubble{background-color:var(--chat-agent);border:1px solid var(--glass-border);border-bottom-left-radius:4px;color:var(--text-primary)}.tool-call{font-size:.85rem;color:var(--text-secondary);background:var(--tool-bg);padding:10px 14px;border-radius:12px;margin-top:10px;border:1px solid var(--glass-border);display:flex;align-items:center;gap:8px}.tool-call code{color:var(--accent);font-family:monospace}.input-area{padding:20px 24px 0}.input-form{display:flex;gap:12px;background:var(--bg-secondary);border:1px solid var(--glass-border);border-radius:16px;padding:8px;transition:all .2s}.input-form:focus-within{border-color:var(--accent);box-shadow:0 0 0 2px #3b82f633}.chat-input{flex:1;background:transparent;border:none;padding:12px 16px;color:#fff;font-size:.95rem;font-family:inherit;outline:none}.send-button{background:var(--accent);color:#fff;border:none;width:44px;height:44px;border-radius:12px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:all .2s}.voice-button{background:var(--bg-secondary);color:var(--text-secondary);border:1px solid var(--glass-border);width:44px;height:44px;border-radius:12px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:all .2s}.voice-button:hover{color:#fff;border-color:#ef4444}.voice-button.listening{background:#ef444433;color:#ef4444;border-color:#ef4444;animation:pulse-red 1.5s infinite}.voice-button.active-mode{border-color:#3b82f6;color:#3b82f6}.voice-button.speaking{background:#3b82f633;color:#3b82f6;border-color:#3b82f6;animation:pulse-blue 1.5s infinite}@keyframes pulse-red{0%{box-shadow:0 0 #ef444466}70%{box-shadow:0 0 0 10px #ef444400}to{box-shadow:0 0 #ef444400}}@keyframes pulse-blue{0%{box-shadow:0 0 #3b82f666}70%{box-shadow:0 0 0 10px #3b82f600}to{box-shadow:0 0 #3b82f600}}.send-button:hover:not(:disabled){background:var(--accent-hover);transform:scale(1.05)}.send-button:disabled{opacity:.5;cursor:not-allowed}.typing-indicator{display:flex;gap:4px;padding:14px 18px;background-color:var(--chat-agent);border:1px solid var(--glass-border);border-radius:18px 18px 18px 4px;width:fit-content;align-self:flex-start}.dot{width:6px;height:6px;background:var(--text-secondary);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}.dot:nth-child(1){animation-delay:-.32s}.dot:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.prompt-suggestions{display:flex;gap:12px;margin-bottom:12px;overflow-x:auto}.prompt-suggestions button{background:var(--bg-secondary);color:var(--text-secondary);border:1px solid var(--glass-border);padding:8px 16px;border-radius:20px;font-size:.85rem;cursor:pointer;white-space:nowrap;transition:all .2s}.prompt-suggestions button:hover{border-color:var(--accent);color:var(--text-primary)}.trending-tokens{display:flex;align-items:center;gap:12px;margin-top:12px;font-size:.8rem;color:var(--text-secondary)}.token-tag{background:var(--accent);color:var(--bg-color);padding:4px 10px;border-radius:12px;font-weight:600;cursor:pointer;transition:transform .2s,filter .2s}.token-tag:hover{transform:translateY(-2px);filter:brightness(1.2)}.nord-label{display:block;font-size:.75rem;font-weight:700;color:#81a1c1;text-transform:uppercase;margin-bottom:6px;letter-spacing:.05em}.nord-pill-input{width:100%;background-color:#2e3440b3;border:1px solid rgba(216,222,233,.1);color:#88c0d0;padding:10px 20px;border-radius:9999px;font-size:.9rem;font-weight:600;outline:none;transition:all .2s ease}.nord-pill-input:focus{border-color:#88c0d0;box-shadow:0 0 10px #88c0d033}.nord-pill-input::placeholder{color:#4c566a}.nord-input{width:100%;background-color:#2e3440;border:1px solid #434c5e;color:#eceff4;padding:10px 14px;border-radius:6px;font-size:.9rem;outline:none;transition:all .2s ease}.nord-input:focus{border-color:#88c0d0;box-shadow:0 0 0 2px #88c0d033}.nord-input::placeholder{color:#4c566a}.nord-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:6px;background:#4c566a;border-radius:3px;outline:none;margin-top:10px}.nord-slider::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#eceff4;cursor:pointer;border:2px solid #88c0d0;transition:all .2s ease}.nord-slider::-webkit-slider-thumb:hover{transform:scale(1.1);background:#fff}.nord-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#eceff4;cursor:pointer;border:2px solid #88c0d0;transition:all .2s ease}.nord-btn-primary{background-color:#81a1c1;color:#2e3440;border:none;border-radius:6px;padding:10px 20px;font-size:.9rem;font-weight:600;cursor:pointer;transition:background-color .2s ease;display:flex;align-items:center;justify-content:center}.nord-btn-primary:hover{background-color:#88c0d0}.nord-btn-primary:disabled{background-color:#4c566a;color:#8fbcbb;cursor:not-allowed}.nord-panel-header{display:flex;align-items:center;gap:10px;margin-bottom:20px;border-bottom:1px solid rgba(216,222,233,.05);padding-bottom:12px}.nord-panel-header h3{margin:0;font-size:1.1rem;color:#eceff4;font-weight:600}.overview-container{padding:24px;overflow-y:auto;height:calc(100vh - 64px);color:#fff;font-family:Inter,sans-serif;max-width:1200px;margin:0 auto}.overview-container::-webkit-scrollbar{width:6px}.overview-container::-webkit-scrollbar-thumb{background:#ffffff1a;border-radius:4px}.overview-header h1{font-size:1.5rem;font-weight:600;margin-bottom:4px}.overview-header p{color:var(--text-secondary);font-size:.9rem;margin-bottom:24px}.panel{background:#14182099;border:1px solid rgba(255,255,255,.05);border-radius:12px;padding:20px;margin-bottom:24px}.panel-header h3{font-size:1.1rem;font-weight:600;margin-bottom:4px}.panel-header p{color:var(--text-secondary);font-size:.85rem;margin-bottom:16px}.form-group{margin-bottom:16px}.form-row{display:flex;gap:16px}.flex-1{flex:1}label{display:block;font-size:.75rem;text-transform:uppercase;color:var(--text-secondary);margin-bottom:8px;letter-spacing:.05em}input,select{width:100%;background:#0000004d;border:1px solid rgba(255,255,255,.1);padding:10px 12px;border-radius:8px;color:#fff;font-size:.9rem;font-family:monospace}input:read-only{color:var(--text-secondary)}.input-with-icon{position:relative;display:flex;align-items:center}.input-with-icon svg{position:absolute;right:12px;color:var(--text-secondary);cursor:pointer}.form-actions{display:flex;align-items:center;gap:12px;margin-top:20px}.btn-primary{background:#3b82f6;color:#fff;border:none;padding:8px 16px;border-radius:6px;font-size:.9rem;cursor:pointer}.btn-secondary{background:transparent;color:#fff;border:1px solid rgba(255,255,255,.2);padding:8px 16px;border-radius:6px;font-size:.9rem;cursor:pointer}.action-hint{color:var(--text-secondary);font-size:.85rem;margin-left:8px}.snapshot-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}.stat-val{font-size:1.5rem;font-weight:700;margin-bottom:4px}.text-green{color:#22c55e}.stat-block p{color:var(--text-secondary);font-size:.8rem;margin-top:8px;line-height:1.4}.metrics-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;margin-bottom:32px}.metric-card{background:#14182099;border:1px solid rgba(255,255,255,.05);border-radius:12px;padding:16px}.metric-val{font-size:1.5rem;font-weight:700;margin-bottom:4px}.metric-sub{color:var(--text-secondary);font-size:.75rem}.section-title{font-size:.75rem;text-transform:uppercase;color:var(--text-secondary);margin-bottom:12px;letter-spacing:.05em}.session-item{display:flex;justify-content:space-between;padding:16px 20px;margin-bottom:24px}.text-secondary{color:var(--text-secondary)}.attention-panel{background:#eab3081a;border:1px solid rgba(234,179,8,.2);border-radius:12px;padding:16px 20px;margin-bottom:24px;display:flex;flex-direction:column}.attention-header{display:flex;align-items:center;gap:8px;color:#eab308;margin-bottom:8px}.attention-header h4{font-size:1rem;font-weight:600}.attention-content p{font-size:.95rem;margin-bottom:4px}.attention-content span{font-size:.85rem}.logs-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.log-panel{background:#0a0c10cc;border:1px solid rgba(255,255,255,.05);border-radius:12px;overflow:hidden;display:flex;flex-direction:column;height:300px}.log-header{padding:12px 16px;background:#ffffff0d;border-bottom:1px solid rgba(255,255,255,.05);font-size:.85rem;font-weight:600}.badge{background:#ffffff1a;padding:2px 6px;border-radius:10px;font-size:.7rem;margin-left:8px}.log-content{padding:12px 16px;overflow-y:auto;display:flex;flex-direction:column;gap:4px}.log-content code,.log-json{font-family:Consolas,Monaco,monospace;font-size:.75rem;color:#a3a3a3;line-height:1.4;word-break:break-all}.log-row{display:flex;gap:12px;font-family:Consolas,Monaco,monospace;font-size:.75rem;margin-bottom:4px}.log-time{color:#fb923c;min-width:60px}.log-msg{color:#d1d5db}.log-meta{color:#6b7280}.gateway-row{margin-bottom:2px}
|
|
1
|
+
:root{--bg-color: #3b4252;--bg-secondary: #434c5e;--bg-sidebar: #2e3440;--text-primary: #eceff4;--text-secondary: #d8dee9;--accent: #88c0d0;--accent-hover: #81a1c1;--glass-bg: rgba(46, 52, 64, .7);--glass-border: rgba(216, 222, 233, .1);--chat-user: #88c0d0;--chat-user-text: #2e3440;--chat-agent: #2e3440;--tool-bg: #4c566a;--success: #a3be8c;--danger: #bf616a}*{box-sizing:border-box;margin:0;padding:0}body{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background-color:var(--bg-color);color:var(--text-primary);height:100vh;overflow:hidden}#root{display:flex;height:100vh;width:100vw}.sidebar{width:280px;background-color:var(--bg-sidebar);border-right:1px solid var(--glass-border);display:flex;flex-direction:column;box-shadow:10px 0 30px -10px #00000080;z-index:100}.agent-identity-card{padding:24px;display:flex;align-items:center;gap:16px;border-bottom:1px solid rgba(255,255,255,.05);margin-bottom:8px;background:linear-gradient(180deg,rgba(59,130,246,.05) 0%,transparent 100%)}.agent-avatar{display:flex;justify-content:center;align-items:center}.agent-info{display:flex;flex-direction:column;gap:4px}.agent-name{font-size:1.1rem;font-weight:700;color:#fff;letter-spacing:-.025em}.agent-status{display:flex;align-items:center;gap:6px;font-size:.75rem;color:#4ade80;font-weight:600;letter-spacing:.05em}.status-dot{width:8px;height:8px;background-color:#4ade80;border-radius:50%;box-shadow:0 0 8px #4ade80;animation:pulse-green 2s infinite}@keyframes pulse-green{0%{transform:scale(.95);box-shadow:0 0 #4ade80b3}70%{transform:scale(1);box-shadow:0 0 0 6px #4ade8000}to{transform:scale(.95);box-shadow:0 0 #4ade8000}}.sidebar-scroll-area{flex:1;overflow-y:auto;padding-bottom:24px}.sidebar-scroll-area::-webkit-scrollbar{width:4px}.sidebar-scroll-area::-webkit-scrollbar-thumb{background:#ffffff0d}.sidebar-section{padding:24px 24px 8px;font-size:.75rem;color:#8b9bb4;font-weight:500}.sidebar-nav{display:flex;flex-direction:column;gap:4px;padding:0 16px}.nav-item{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:8px;color:#94a3b8;font-size:.8rem;font-weight:500;cursor:pointer;transition:all .25s cubic-bezier(.4,0,.2,1);border:1px solid transparent}.nav-icon{transition:transform .25s cubic-bezier(.4,0,.2,1)}.nav-item:hover{background-color:#ffffff08;color:#fff;transform:translate(4px)}.nav-item:hover .nav-icon{transform:scale(1.1);color:#fff}.sessions-list{gap:0px!important;justify-content:flex-start!important;flex:none!important;height:max-content!important}.session-item{justify-content:space-between;padding:4px 10px!important;margin-bottom:2px!important;margin-top:0!important;min-height:28px!important;height:max-content!important;flex:none!important}.delete-session-btn{background:transparent;border:none;color:#bf616a;cursor:pointer;opacity:0;transition:opacity .2s ease,transform .2s ease;display:flex;align-items:center;justify-content:center;padding:4px;border-radius:6px}.delete-session-btn:hover{background:#bf616a33;transform:scale(1.1)}.session-item:hover .delete-session-btn{opacity:1}.nav-item.active{background:linear-gradient(90deg,rgba(59,130,246,.15) 0%,transparent 100%);color:#fff;border-left:3px solid var(--accent);border-radius:4px 12px 12px 4px;font-weight:600}.nav-item.active .nav-icon{color:var(--accent)}.main-content{flex:1;display:flex;flex-direction:column;background-image:radial-gradient(at 0% 0%,rgba(59,130,246,.1) 0px,transparent 50%),radial-gradient(at 100% 100%,rgba(139,92,246,.1) 0px,transparent 50%)}.topbar{height:64px;border-bottom:1px solid var(--glass-border);display:flex;align-items:center;justify-content:space-between;padding:0 24px;background:var(--bg-color)}.topbar-left{display:flex;align-items:center;gap:16px;font-size:.95rem;font-weight:500;color:var(--text-secondary)}.topbar-right{display:flex;align-items:center;gap:12px}.custom-network-selector{position:relative}.network-selector-pill{display:flex;align-items:center;gap:8px;background:#88c0d0;border:none;color:#000;font-weight:600;font-size:.85rem;border-radius:9999px;padding:8px 16px;cursor:pointer;transition:all .2s;outline:none;font-family:inherit}.network-selector-pill:hover{opacity:.9;box-shadow:0 0 10px #88c0d066}.network-selector-pill:focus-visible{box-shadow:0 0 0 2px #88c0d080}.network-icon{flex-shrink:0}.network-chevron{opacity:.7;margin-left:4px}.network-dropdown-menu{position:absolute;top:calc(100% + 8px);right:0;background:var(--bg-secondary);border:1px solid var(--glass-border);border-radius:12px;padding:6px;list-style:none;margin:0;min-width:180px;box-shadow:0 8px 24px #0006;z-index:100;animation:dropdownSlideIn .2s ease-out}@keyframes dropdownSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.network-dropdown-item{padding:10px 14px;border-radius:8px;cursor:pointer;font-size:.85rem;color:#e5e7eb;transition:background .1s}.network-dropdown-item:hover{background:#ffffff0d}.network-dropdown-item.active{background:#88c0d01a;color:#88c0d0;font-weight:600}.workspace-container{display:flex;height:calc(100vh - 64px);width:100%}.chat-wrapper{display:flex;flex-direction:column;padding:24px 0;height:100%}.resizer{width:6px;background:var(--glass-border);cursor:col-resize;transition:background .2s;z-index:10}.resizer:hover,.resizer:active{background:var(--accent)}.canvas-panel{flex:1;display:flex;flex-direction:column;background:var(--bg-sidebar);padding:32px;overflow-y:auto;position:relative;background-image:radial-gradient(at 50% 50%,rgba(59,130,246,.05) 0px,transparent 80%)}.canvas-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:32px;border-bottom:1px solid rgba(255,255,255,.05);padding-bottom:16px}.canvas-title{font-family:monospace;color:#94a3b8;font-size:.85rem;display:flex;align-items:center;gap:8px;text-transform:uppercase;letter-spacing:.05em}.canvas-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#475569;gap:16px}.chat-container{flex:1;overflow-y:auto;padding:0 24px;display:flex;flex-direction:column;gap:20px}.chat-container::-webkit-scrollbar{width:6px}.chat-container::-webkit-scrollbar-thumb{background:#ffffff1a;border-radius:4px}.message-wrapper{display:flex;flex-direction:column;max-width:85%;animation:fadeIn .3s ease-out forwards}.message-wrapper.agent{align-self:flex-start;flex-direction:row;align-items:flex-end;gap:8px}.message-wrapper.user{align-self:flex-end;flex-direction:row-reverse;align-items:flex-end;gap:8px}.copy-btn{background:transparent;border:none;color:var(--text-secondary);cursor:pointer;padding:6px;border-radius:6px;opacity:0;transition:opacity .2s,background .2s;display:flex;align-items:center;justify-content:center}.copy-btn:hover{background:var(--bg-secondary);color:var(--text-primary)}.message-wrapper:hover .copy-btn{opacity:1}.message-bubble{padding:14px 18px;border-radius:18px;line-height:1.6;font-size:.95rem;box-shadow:0 4px 6px -1px #0000001a;white-space:pre-wrap}.user .message-bubble{background-color:var(--chat-user);color:var(--chat-user-text);border-bottom-right-radius:4px}.agent .message-bubble{background-color:var(--chat-agent);border:1px solid var(--glass-border);border-bottom-left-radius:4px;color:var(--text-primary)}.tool-call{font-size:.85rem;color:var(--text-secondary);background:var(--tool-bg);padding:10px 14px;border-radius:12px;margin-top:10px;border:1px solid var(--glass-border);display:flex;align-items:center;gap:8px}.tool-call code{color:var(--accent);font-family:monospace}.input-area{padding:20px 24px 0}.input-form{display:flex;gap:12px;background:var(--bg-secondary);border:1px solid var(--glass-border);border-radius:16px;padding:8px;transition:all .2s}.input-form:focus-within{border-color:var(--accent);box-shadow:0 0 0 2px #3b82f633}.chat-input{flex:1;background:transparent;border:none;padding:12px 16px;color:#fff;font-size:.95rem;font-family:inherit;outline:none}.send-button{background:var(--accent);color:#fff;border:none;width:44px;height:44px;border-radius:12px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:all .2s}.voice-button{background:var(--bg-secondary);color:var(--text-secondary);border:1px solid var(--glass-border);width:44px;height:44px;border-radius:12px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:all .2s}.voice-button:hover{color:#fff;border-color:#ef4444}.voice-button.listening{background:#ef444433;color:#ef4444;border-color:#ef4444;animation:pulse-red 1.5s infinite}.voice-button.active-mode{border-color:#3b82f6;color:#3b82f6}.voice-button.speaking{background:#3b82f633;color:#3b82f6;border-color:#3b82f6;animation:pulse-blue 1.5s infinite}@keyframes pulse-red{0%{box-shadow:0 0 #ef444466}70%{box-shadow:0 0 0 10px #ef444400}to{box-shadow:0 0 #ef444400}}@keyframes pulse-blue{0%{box-shadow:0 0 #3b82f666}70%{box-shadow:0 0 0 10px #3b82f600}to{box-shadow:0 0 #3b82f600}}.send-button:hover:not(:disabled){background:var(--accent-hover);transform:scale(1.05)}.send-button:disabled{opacity:.5;cursor:not-allowed}.typing-indicator{display:flex;gap:4px;padding:14px 18px;background-color:var(--chat-agent);border:1px solid var(--glass-border);border-radius:18px 18px 18px 4px;width:fit-content;align-self:flex-start}.dot{width:6px;height:6px;background:var(--text-secondary);border-radius:50%;animation:bounce 1.4s infinite ease-in-out both}.dot:nth-child(1){animation-delay:-.32s}.dot:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.prompt-suggestions{display:flex;gap:12px;margin-bottom:12px;overflow-x:auto}.prompt-suggestions button{background:var(--bg-secondary);color:var(--text-secondary);border:1px solid var(--glass-border);padding:8px 16px;border-radius:20px;font-size:.85rem;cursor:pointer;white-space:nowrap;transition:all .2s}.prompt-suggestions button:hover{border-color:var(--accent);color:var(--text-primary)}.trending-tokens{display:flex;align-items:center;gap:12px;margin-top:12px;font-size:.8rem;color:var(--text-secondary)}.token-tag{background:var(--accent);color:var(--bg-color);padding:4px 10px;border-radius:12px;font-weight:600;cursor:pointer;transition:transform .2s,filter .2s}.token-tag:hover{transform:translateY(-2px);filter:brightness(1.2)}.nord-label{display:block;font-size:.75rem;font-weight:700;color:#81a1c1;text-transform:uppercase;margin-bottom:6px;letter-spacing:.05em}.nord-pill-input{width:100%;background-color:#2e3440b3;border:1px solid rgba(216,222,233,.1);color:#88c0d0;padding:10px 20px;border-radius:9999px;font-size:.9rem;font-weight:600;outline:none;transition:all .2s ease}.nord-pill-input:focus{border-color:#88c0d0;box-shadow:0 0 10px #88c0d033}.nord-pill-input::placeholder{color:#4c566a}.nord-input{width:100%;background-color:#2e3440;border:1px solid #434c5e;color:#eceff4;padding:10px 14px;border-radius:6px;font-size:.9rem;outline:none;transition:all .2s ease}.nord-input:focus{border-color:#88c0d0;box-shadow:0 0 0 2px #88c0d033}.nord-input::placeholder{color:#4c566a}.nord-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:6px;background:#4c566a;border-radius:3px;outline:none;margin-top:10px}.nord-slider::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#eceff4;cursor:pointer;border:2px solid #88c0d0;transition:all .2s ease}.nord-slider::-webkit-slider-thumb:hover{transform:scale(1.1);background:#fff}.nord-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#eceff4;cursor:pointer;border:2px solid #88c0d0;transition:all .2s ease}.nord-btn-primary{background-color:#81a1c1;color:#2e3440;border:none;border-radius:6px;padding:10px 20px;font-size:.9rem;font-weight:600;cursor:pointer;transition:background-color .2s ease;display:flex;align-items:center;justify-content:center}.nord-btn-primary:hover{background-color:#88c0d0}.nord-btn-primary:disabled{background-color:#4c566a;color:#8fbcbb;cursor:not-allowed}.nord-panel-header{display:flex;align-items:center;gap:10px;margin-bottom:20px;border-bottom:1px solid rgba(216,222,233,.05);padding-bottom:12px}.nord-panel-header h3{margin:0;font-size:1.1rem;color:#eceff4;font-weight:600}.overview-container{padding:24px;overflow-y:auto;height:calc(100vh - 64px);color:#fff;font-family:Inter,sans-serif;max-width:1200px;margin:0 auto}.overview-container::-webkit-scrollbar{width:6px}.overview-container::-webkit-scrollbar-thumb{background:#ffffff1a;border-radius:4px}.overview-header h1{font-size:1.5rem;font-weight:600;margin-bottom:4px}.overview-header p{color:var(--text-secondary);font-size:.9rem;margin-bottom:24px}.panel{background:#14182099;border:1px solid rgba(255,255,255,.05);border-radius:12px;padding:20px;margin-bottom:24px}.panel-header h3{font-size:1.1rem;font-weight:600;margin-bottom:4px}.panel-header p{color:var(--text-secondary);font-size:.85rem;margin-bottom:16px}.form-group{margin-bottom:16px}.form-row{display:flex;gap:16px}.flex-1{flex:1}label{display:block;font-size:.75rem;text-transform:uppercase;color:var(--text-secondary);margin-bottom:8px;letter-spacing:.05em}input,select{width:100%;background:#0000004d;border:1px solid rgba(255,255,255,.1);padding:10px 12px;border-radius:8px;color:#fff;font-size:.9rem;font-family:monospace}input:read-only{color:var(--text-secondary)}.input-with-icon{position:relative;display:flex;align-items:center}.input-with-icon svg{position:absolute;right:12px;color:var(--text-secondary);cursor:pointer}.form-actions{display:flex;align-items:center;gap:12px;margin-top:20px}.btn-primary{background:#3b82f6;color:#fff;border:none;padding:8px 16px;border-radius:6px;font-size:.9rem;cursor:pointer}.btn-secondary{background:transparent;color:#fff;border:1px solid rgba(255,255,255,.2);padding:8px 16px;border-radius:6px;font-size:.9rem;cursor:pointer}.action-hint{color:var(--text-secondary);font-size:.85rem;margin-left:8px}.snapshot-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}.stat-val{font-size:1.5rem;font-weight:700;margin-bottom:4px}.text-green{color:#22c55e}.stat-block p{color:var(--text-secondary);font-size:.8rem;margin-top:8px;line-height:1.4}.metrics-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;margin-bottom:32px}.metric-card{background:#14182099;border:1px solid rgba(255,255,255,.05);border-radius:12px;padding:16px}.metric-val{font-size:1.5rem;font-weight:700;margin-bottom:4px}.metric-sub{color:var(--text-secondary);font-size:.75rem}.section-title{font-size:.75rem;text-transform:uppercase;color:var(--text-secondary);margin-bottom:12px;letter-spacing:.05em}.session-item{display:flex;justify-content:space-between;padding:16px 20px;margin-bottom:24px}.text-secondary{color:var(--text-secondary)}.attention-panel{background:#eab3081a;border:1px solid rgba(234,179,8,.2);border-radius:12px;padding:16px 20px;margin-bottom:24px;display:flex;flex-direction:column}.attention-header{display:flex;align-items:center;gap:8px;color:#eab308;margin-bottom:8px}.attention-header h4{font-size:1rem;font-weight:600}.attention-content p{font-size:.95rem;margin-bottom:4px}.attention-content span{font-size:.85rem}.logs-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.log-panel{background:#0a0c10cc;border:1px solid rgba(255,255,255,.05);border-radius:12px;overflow:hidden;display:flex;flex-direction:column;height:300px}.log-header{padding:12px 16px;background:#ffffff0d;border-bottom:1px solid rgba(255,255,255,.05);font-size:.85rem;font-weight:600}.badge{background:#ffffff1a;padding:2px 6px;border-radius:10px;font-size:.7rem;margin-left:8px}.log-content{padding:12px 16px;overflow-y:auto;overflow-x:auto;display:flex;flex-direction:column;gap:4px}.log-content::-webkit-scrollbar{width:6px;height:6px}.log-content::-webkit-scrollbar-thumb{background:#434c5e;border-radius:4px}.log-content::-webkit-scrollbar-thumb:hover{background:#4c566a}.log-content::-webkit-scrollbar-corner{background:transparent}.log-content code,.log-json{font-family:Consolas,Monaco,monospace;font-size:.75rem;color:#a3a3a3;line-height:1.4;word-break:break-all}.log-row{display:flex;gap:12px;font-family:Consolas,Monaco,monospace;font-size:.75rem;margin-bottom:4px}.log-time{color:#fb923c;min-width:60px}.log-msg{color:#d1d5db}.log-meta{color:#6b7280}.gateway-row{margin-bottom:2px}
|