nyxora 1.7.3 → 26.6.5
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 +26 -2
- package/README.md +5 -0
- package/bin/nyxora.mjs +16 -0
- package/package.json +4 -2
- package/packages/core/package.json +2 -1
- package/packages/core/src/agent/reasoning.ts +73 -89
- package/packages/core/src/config/parser.ts +1 -1
- package/packages/core/src/gateway/cli.ts +14 -0
- package/packages/core/src/gateway/setup.ts +75 -25
- package/packages/core/src/memory/logger.ts +3 -0
- package/packages/dashboard/dist/assets/{index-C1Guh5O8.js → index-Xhv1dj6H.js} +9 -9
- package/packages/dashboard/dist/index.html +1 -1
- package/packages/dashboard/package.json +1 -1
- package/packages/policy/src/server.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
The format is based on [Keep a Changelog](https://
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepashangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [26.6.5] - 2026-06-04 (Hotfix Patch)
|
|
9
|
+
### Fixed
|
|
10
|
+
- **NPM Monorepo Resolution:** Synced `@inquirer/search` and `duck-duck-scrape` to root `package.json` to prevent `MODULE_NOT_FOUND` and `ERR_CONNECTION_REFUSED` on global installations.
|
|
11
|
+
|
|
12
|
+
## [26.6.4] - 2026-06-04
|
|
13
|
+
|
|
14
|
+
### AI Engine Optimizations
|
|
15
|
+
- **Semantic Keyword Router (Zero-Latency)**: Restructured the `reasoning.ts` pipeline to dynamically group tools into specific clusters (`WEB3`, `SYSTEM`, `GOOGLE`). The engine now intercepts the user's prompt using highly optimized Regex keyword-matching. This eliminates "Context Bloat" by only injecting relevant tools into the LLM payload, dramatically increasing LLM responsiveness and minimizing API token consumption.
|
|
16
|
+
- **Zero-LLM Fast Return Expansion**: Expanded the V2 `Fast Return` optimization (which skips the redundant secondary LLM summarization step) to include 7 additional data-heavy read-only tools: `get_price`, `get_my_address`, `analyze_market`, `check_token_security`, `search_web`, `read_gmail_inbox`, and `list_calendar_events`. For these queries, the agent now returns the raw markdown payload instantaneously, cutting response latency by 50-80%.
|
|
17
|
+
|
|
18
|
+
### Universal LLM Expansion
|
|
19
|
+
- **Dictionary Mapping Refactor**: Completely flattened the massive `if-else` blocks in `reasoning.ts` into a highly dynamic 15-line dictionary map. Adding new LLM providers in the future now only takes a single line of code.
|
|
20
|
+
- **Expanded Provider Ecosystem**: Added native support for **Groq, Mistral AI, xAI (Grok), dan DeepSeek**, seamlessly integrated into the React Dashboard UI's dropdown.
|
|
21
|
+
|
|
22
|
+
### CLI Enhancements
|
|
23
|
+
- **Searchable Model Prompt**: Replaced the static `@clack/prompts` list with `@inquirer/search` inside `nyxora setup`. Users can now instantly fuzzy-search their desired AI model out of dozens of variants using their keyboard.
|
|
24
|
+
- **2026 Model Roster**: Injected an exhaustive list of the latest frontier models into the CLI (including `gpt-5.5`, `o3-mini`, `gemini-3.1-pro`, `deepseek-reasoner`). A fail-safe `[Tulis Manual / Custom Model]` option is also hardcoded at the bottom of every list.
|
|
25
|
+
|
|
26
|
+
### Backend Stability (Core Engine)
|
|
27
|
+
- **Zero-Crash SQLite (WAL Mode)**: Enabled `PRAGMA journal_mode = WAL` and `busy_timeout = 5000` on the `node:sqlite` database engine (`logger.ts`). This allows parallel reads and writes without throwing fatal `SQLITE_BUSY` (database locked) errors during high-concurrency operations.
|
|
28
|
+
- **Anti-Zombie LLM Timeout**: Hardcoded a `timeout: 120000` (120 seconds) limit on the core OpenAI SDK instantiation (`reasoning.ts`). If an external AI provider (e.g., local Ollama or OpenRouter) hangs, the system will now correctly severe the connection and trigger Exponential Backoff rather than freezing indefinitely. Disabled internal SDK retries (`maxRetries: 0`) to prevent retry collisions with Nyxora's native retry wrapper.
|
|
29
|
+
|
|
30
|
+
### UI & Developer Experience
|
|
31
|
+
- **CLI Memory Purge**: Introduced a new developer utility command: `nyxora clear`. It instantly and atomically resets the AI's short-term/long-term memory SQLite database. Includes a mandatory `--force` flag safeguard to prevent accidental data destruction.
|
|
32
|
+
## [1.7.3] - 2026-06-04
|
|
9
33
|
|
|
10
34
|
### Web3 Routing & Integrations
|
|
11
35
|
- **Multi-Router Selection (DeFi)**: Added a dynamic Router dropdown to the Dashboard UI, allowing users to forcefully route transactions through specific protocols natively. Supported routers include `1inch`, `CowSwap (MEV-Protected)`, `Li.Fi`, `Relay`, `Uniswap V2`, `Uniswap V3`, and `PancakeSwap`. This integration heavily relies on deep aggregator proxying (bypassing the need for complex V2/V3 ABI calldata overhead) to ensure 100% smooth, anti-fail execution without requiring additional API keys.
|
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ It operates under an institutional-grade **Cryptographically Bound Human-in-the-
|
|
|
23
23
|
* **Cryptographically Bound Approval**: Policy changes and transactions requested by the AI are drafted as hashes (`sha256`). Approval via the UI requires a challenge nonce, preventing Man-in-the-Middle (MITM) attacks.
|
|
24
24
|
* **Immutable Policy Guardrails**: Transaction limits (e.g. `max_usd_per_tx`) are strictly enforced by the Policy Engine. The LLM has zero write-access to bypass these rules.
|
|
25
25
|
* **Plugin Sandbox VM**: Execute community-built external skills securely inside an airtight Node.js `vm` chamber with zero access to your file system or terminal processes.
|
|
26
|
+
* **Enterprise-Grade Stability**: Runs on a WAL-enabled SQLite backend with resilient anti-zombie connection timeouts to ensure maximum concurrency without database locks.
|
|
26
27
|
|
|
27
28
|
### 🌐 Web3 Skills (On-Chain)
|
|
28
29
|
* **Security Scanner**: Nyxora can scan smart contracts via GoPlus Labs to detect Honeypots, Hidden Taxes, and malicious proxy upgrades before you buy.
|
|
@@ -40,6 +41,7 @@ It operates under an institutional-grade **Cryptographically Bound Human-in-the-
|
|
|
40
41
|
* **Zero-Click Multi-Session**: Instantly create isolated chat sessions with smart auto-naming triggered by your first prompt, exactly like ChatGPT.
|
|
41
42
|
* **Dynamic Trending Tokens**: Live top 5 crypto assets feed directly injected into the dashboard, completely clickable for instant AI market analysis.
|
|
42
43
|
* **Premium Utility-Centric UI**: A sleek, dark-themed dashboard built for high readability and professional Web3 execution, featuring Pseudo-Generative UI widgets (`<BalanceWidget>`, `<MarketWidget>`, `<SwapWidget>`).
|
|
44
|
+
* **Massive 2026 Model Roster**: Out-of-the-box support for cutting-edge models via Google Gemini, OpenAI, Groq, Mistral, xAI, DeepSeek, OpenRouter, and local Ollama, equipped with a searchable CLI prompt to instantly find your favorite model.
|
|
43
45
|
* **Context Overrides Defaults (NLP Intelligence)**: The Dashboard configuration (default chain & router) acts only as a safety net. If you issue an explicit command via Telegram (e.g., *"Swap 10 USDC to USDT on Arbitrum using Li.Fi"*), the NLP engine dynamically bypasses the default settings and executes exactly what you asked for, ensuring maximum flexibility.
|
|
44
46
|
* **Deep Personalization**: Feed the agent custom rules via `user.md` and define its core persona via `IDENTITY.md`.
|
|
45
47
|
|
|
@@ -83,6 +85,9 @@ nyxora start
|
|
|
83
85
|
|
|
84
86
|
# 4. Open the Web Dashboard
|
|
85
87
|
nyxora dashboard
|
|
88
|
+
|
|
89
|
+
# Utility: Atomically clear the AI's short-term and long-term memory
|
|
90
|
+
nyxora clear --force
|
|
86
91
|
```
|
|
87
92
|
> **⚠️ IMPORTANT:** Whenever you re-run `nyxora setup` or manually edit the config files, you **must restart the daemon** by running `nyxora restart` for the changes to take effect.
|
|
88
93
|
|
package/bin/nyxora.mjs
CHANGED
|
@@ -208,9 +208,20 @@ async function setup() {
|
|
|
208
208
|
await new Promise(resolve => child.on('close', resolve));
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
async function clearMemory(args) {
|
|
212
|
+
const child = spawn('npx', ['ts-node', '-T', 'packages/core/src/gateway/cli.ts', 'clear', ...args], {
|
|
213
|
+
cwd: projectRoot,
|
|
214
|
+
stdio: 'inherit',
|
|
215
|
+
env: { ...process.env, TS_NODE_CACHE: 'false' }
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
await new Promise(resolve => child.on('close', resolve));
|
|
219
|
+
}
|
|
220
|
+
|
|
211
221
|
async function main() {
|
|
212
222
|
switch (command) {
|
|
213
223
|
case 'setup': await setup(); break;
|
|
224
|
+
case 'clear': await clearMemory(process.argv.slice(3)); break;
|
|
214
225
|
case 'start': await start(); break;
|
|
215
226
|
case 'stop': await stop(); break;
|
|
216
227
|
case 'restart': await restart(); break;
|
|
@@ -234,9 +245,14 @@ Commands:
|
|
|
234
245
|
start Start the Nyxora background daemon
|
|
235
246
|
stop Stop the running daemon
|
|
236
247
|
restart Restart the daemon
|
|
248
|
+
setup Run the interactive Setup Wizard
|
|
237
249
|
dashboard Open the dashboard in your browser
|
|
250
|
+
clear Atomically clear the AI's short/long-term memory SQLite database
|
|
238
251
|
clean-logs Clear the daemon logs
|
|
239
252
|
autostart Enable/disable autostart on boot (usage: nyxora autostart enable)
|
|
253
|
+
|
|
254
|
+
Options:
|
|
255
|
+
-v, --version Show current version
|
|
240
256
|
`);
|
|
241
257
|
}
|
|
242
258
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nyxora",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "26.6.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"packages/*"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"nyxora": "bin/nyxora.mjs"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"
|
|
12
|
+
"prepare": "npm run build --workspace=dashboard || echo '⚠️ Build failed – dashboard UI may be missing'",
|
|
13
13
|
"dev": "concurrently -n \"BACKEND,FRONTEND\" -c \"blue,green\" \"npx ts-node -T launcher.ts\" \"npm run dev --workspace=dashboard\"",
|
|
14
14
|
"start": "node ./bin/nyxora.mjs start",
|
|
15
15
|
"stop": "node ./bin/nyxora.mjs stop",
|
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@clack/prompts": "^1.4.0",
|
|
24
|
+
"@inquirer/search": "^4.2.1",
|
|
24
25
|
"@modelcontextprotocol/sdk": "^1.5.0",
|
|
25
26
|
"@napi-rs/keyring": "^1.3.0",
|
|
26
27
|
"concurrently": "^9.2.1",
|
|
27
28
|
"cors": "^2.8.6",
|
|
28
29
|
"dotenv": "^17.4.2",
|
|
30
|
+
"duck-duck-scrape": "^2.2.7",
|
|
29
31
|
"express": "^5.2.1",
|
|
30
32
|
"express-rate-limit": "^7.5.0",
|
|
31
33
|
"helmet": "^8.0.0",
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nyxora-agent-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "26.6.5",
|
|
4
4
|
"private": true,
|
|
5
5
|
"main": "src/gateway/server.ts",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@clack/prompts": "^1.4.0",
|
|
8
|
+
"@inquirer/search": "^4.2.1",
|
|
8
9
|
"cors": "^2.8.6",
|
|
9
10
|
"duck-duck-scrape": "^2.2.7",
|
|
10
11
|
"express": "^5.2.1",
|
|
@@ -48,66 +48,58 @@ export const logger = new Logger();
|
|
|
48
48
|
|
|
49
49
|
let currentKeyIndex = 0;
|
|
50
50
|
|
|
51
|
+
const PROVIDER_CONFIGS: Record<string, { baseURL?: string; requiresApiKey: boolean }> = {
|
|
52
|
+
ollama: { baseURL: process.env.OLLAMA_BASE_URL ? `${process.env.OLLAMA_BASE_URL}/v1` : 'http://localhost:11434/v1', requiresApiKey: false },
|
|
53
|
+
gemini: { baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/', requiresApiKey: true },
|
|
54
|
+
openrouter: { baseURL: 'https://openrouter.ai/api/v1', requiresApiKey: true },
|
|
55
|
+
groq: { baseURL: 'https://api.groq.com/openai/v1', requiresApiKey: true },
|
|
56
|
+
mistral: { baseURL: 'https://api.mistral.ai/v1', requiresApiKey: true },
|
|
57
|
+
xai: { baseURL: 'https://api.x.ai/v1', requiresApiKey: true },
|
|
58
|
+
deepseek: { baseURL: 'https://api.deepseek.com', requiresApiKey: true },
|
|
59
|
+
openai: { requiresApiKey: true }
|
|
60
|
+
};
|
|
61
|
+
|
|
51
62
|
async function getOpenAI(): Promise<OpenAI> {
|
|
52
63
|
const config = loadConfig();
|
|
53
64
|
const vaultKeys = await loadApiKeys();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return new OpenAI({
|
|
57
|
-
baseURL: process.env.OLLAMA_BASE_URL ? `${process.env.OLLAMA_BASE_URL}/v1` : 'http://localhost:11434/v1',
|
|
58
|
-
apiKey: 'ollama', // API key is not required for local Ollama
|
|
59
|
-
});
|
|
60
|
-
}
|
|
65
|
+
const providerName = config.llm.provider || 'openai';
|
|
66
|
+
const providerConf = PROVIDER_CONFIGS[providerName] || PROVIDER_CONFIGS['openai'];
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (Array.isArray(configuredKeys) && configuredKeys.length > 0) {
|
|
71
|
-
// Filter out empty keys
|
|
72
|
-
const keys = configuredKeys.filter(k => typeof k === 'string' && k.trim() !== '');
|
|
73
|
-
if (keys.length > 0) {
|
|
74
|
-
currentKeyIndex = currentKeyIndex % keys.length;
|
|
75
|
-
apiKey = keys[currentKeyIndex];
|
|
76
|
-
console.log(`[LLM] Using rotated API Key (${currentKeyIndex + 1}/${keys.length}): ${apiKey.substring(0, 4)}...`);
|
|
77
|
-
currentKeyIndex++; // Increment for next request
|
|
68
|
+
let apiKey = 'local';
|
|
69
|
+
if (providerConf.requiresApiKey) {
|
|
70
|
+
apiKey = '';
|
|
71
|
+
let configuredKeys = config.llm.api_keys;
|
|
72
|
+
if (typeof configuredKeys === 'string') {
|
|
73
|
+
configuredKeys = [configuredKeys];
|
|
78
74
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
apiKey = vaultKeys.openai_key || config.credentials?.openai_key || '';
|
|
75
|
+
|
|
76
|
+
if (Array.isArray(configuredKeys) && configuredKeys.length > 0) {
|
|
77
|
+
const keys = configuredKeys.filter(k => typeof k === 'string' && k.trim() !== '');
|
|
78
|
+
if (keys.length > 0) {
|
|
79
|
+
currentKeyIndex = currentKeyIndex % keys.length;
|
|
80
|
+
apiKey = keys[currentKeyIndex];
|
|
81
|
+
console.log(`[LLM] Using rotated API Key (${currentKeyIndex + 1}/${keys.length}): ${apiKey.substring(0, 4)}...`);
|
|
82
|
+
currentKeyIndex++;
|
|
83
|
+
}
|
|
89
84
|
}
|
|
85
|
+
|
|
90
86
|
if (!apiKey) {
|
|
91
|
-
|
|
87
|
+
const fallbackKeyName = `${providerName}_key`;
|
|
88
|
+
apiKey = vaultKeys[fallbackKeyName] || config.credentials?.[fallbackKeyName] || '';
|
|
89
|
+
|
|
90
|
+
if (!apiKey) {
|
|
91
|
+
throw new Error(`No API Key found for ${providerName}. Please run 'nyxora setup' to configure it.`);
|
|
92
|
+
}
|
|
93
|
+
console.log(`[LLM] Using API Key from secure vault`);
|
|
92
94
|
}
|
|
93
|
-
console.log(`[LLM] Using API Key from secure vault`);
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
return new OpenAI({
|
|
103
|
-
baseURL: 'https://openrouter.ai/api/v1',
|
|
104
|
-
apiKey: apiKey,
|
|
105
|
-
});
|
|
106
|
-
} else {
|
|
107
|
-
return new OpenAI({
|
|
108
|
-
apiKey: apiKey,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
97
|
+
return new OpenAI({
|
|
98
|
+
baseURL: providerConf.baseURL,
|
|
99
|
+
apiKey: apiKey,
|
|
100
|
+
timeout: 120 * 1000,
|
|
101
|
+
maxRetries: 0
|
|
102
|
+
});
|
|
111
103
|
}
|
|
112
104
|
|
|
113
105
|
async function executeWithRetry(
|
|
@@ -234,45 +226,33 @@ export async function processUserInput(input: string, role: 'user' | 'system' =
|
|
|
234
226
|
return `Provider ${config.llm.provider} is configured, but currently only OpenAI, OpenRouter, Ollama, and Gemini adapters are implemented.`;
|
|
235
227
|
}
|
|
236
228
|
|
|
229
|
+
// --- v1.7.4 Semantic Keyword Router ---
|
|
230
|
+
const lowerInput = input.toLowerCase();
|
|
231
|
+
const hasWeb3Keyword = /swap|transfer|price|token|crypto|bridge|wallet|balance|portfolio|buy|sell|send|receive|address|market|limit|mint|nft/i.test(lowerInput);
|
|
232
|
+
const hasGoogleKeyword = /email|gmail|calendar|sheet|doc|form|event/i.test(lowerInput);
|
|
233
|
+
|
|
234
|
+
const WEB3_TOOLS = [getBalanceToolDefinition, transferToolDefinition, getPriceToolDefinition, swapTokenToolDefinition, bridgeTokenToolDefinition, mintNftToolDefinition, customTxToolDefinition, createWalletToolDefinition, checkSecurityToolDefinition, marketAnalysisToolDefinition, checkPortfolioToolDefinition, checkAddressToolDefinition, getMyAddressToolDefinition, createLimitOrderToolDefinition, listLimitOrdersToolDefinition, cancelLimitOrderToolDefinition];
|
|
235
|
+
const SYSTEM_TOOLS = [updateProfileToolDefinition, updateSecurityPolicyToolDefinition, analyzeDocumentToolDefinition, readLocalFileToolDefinition, writeLocalFileToolDefinition, runTerminalCommandToolDefinition, browseWebsiteToolDefinition, searchWebToolDefinition, installExternalSkillToolDefinition];
|
|
236
|
+
const GOOGLE_TOOLS = [readGmailInboxToolDefinition, listCalendarEventsToolDefinition, appendRowToSheetsToolDefinition, readGoogleDocsToolDefinition, readGoogleFormResponsesToolDefinition];
|
|
237
|
+
|
|
238
|
+
let activeTools: any[] = [];
|
|
239
|
+
if (hasGoogleKeyword && !hasWeb3Keyword) {
|
|
240
|
+
activeTools = [...GOOGLE_TOOLS, ...SYSTEM_TOOLS, ...pluginManager.getToolDefinitions()];
|
|
241
|
+
} else if (hasWeb3Keyword && !hasGoogleKeyword) {
|
|
242
|
+
activeTools = [...WEB3_TOOLS, ...SYSTEM_TOOLS, ...pluginManager.getToolDefinitions()];
|
|
243
|
+
} else {
|
|
244
|
+
activeTools = [...WEB3_TOOLS, ...SYSTEM_TOOLS, ...GOOGLE_TOOLS, ...pluginManager.getToolDefinitions()];
|
|
245
|
+
}
|
|
246
|
+
activeTools = activeTools.filter(t => isSkillActive(t.function.name));
|
|
247
|
+
// ----------------------------------------
|
|
248
|
+
|
|
237
249
|
const response = await executeWithRetry(async (client) => {
|
|
238
250
|
return await client.chat.completions.create({
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
transferToolDefinition as any,
|
|
245
|
-
getPriceToolDefinition as any,
|
|
246
|
-
swapTokenToolDefinition as any,
|
|
247
|
-
bridgeTokenToolDefinition as any,
|
|
248
|
-
mintNftToolDefinition as any,
|
|
249
|
-
customTxToolDefinition as any,
|
|
250
|
-
createWalletToolDefinition as any,
|
|
251
|
-
checkSecurityToolDefinition as any,
|
|
252
|
-
marketAnalysisToolDefinition as any,
|
|
253
|
-
checkPortfolioToolDefinition as any,
|
|
254
|
-
checkAddressToolDefinition as any,
|
|
255
|
-
getMyAddressToolDefinition as any,
|
|
256
|
-
createLimitOrderToolDefinition as any,
|
|
257
|
-
listLimitOrdersToolDefinition as any,
|
|
258
|
-
cancelLimitOrderToolDefinition as any,
|
|
259
|
-
updateProfileToolDefinition as any,
|
|
260
|
-
updateSecurityPolicyToolDefinition as any,
|
|
261
|
-
analyzeDocumentToolDefinition as any,
|
|
262
|
-
readLocalFileToolDefinition as any,
|
|
263
|
-
writeLocalFileToolDefinition as any,
|
|
264
|
-
runTerminalCommandToolDefinition as any,
|
|
265
|
-
browseWebsiteToolDefinition as any,
|
|
266
|
-
searchWebToolDefinition as any,
|
|
267
|
-
installExternalSkillToolDefinition as any,
|
|
268
|
-
readGmailInboxToolDefinition as any,
|
|
269
|
-
listCalendarEventsToolDefinition as any,
|
|
270
|
-
appendRowToSheetsToolDefinition as any,
|
|
271
|
-
readGoogleDocsToolDefinition as any,
|
|
272
|
-
readGoogleFormResponsesToolDefinition as any,
|
|
273
|
-
...pluginManager.getToolDefinitions()
|
|
274
|
-
].filter(t => isSkillActive(t.function.name)),
|
|
275
|
-
tool_choice: "auto",
|
|
251
|
+
model: config.llm.model,
|
|
252
|
+
temperature: config.llm.temperature,
|
|
253
|
+
messages: messages,
|
|
254
|
+
tools: activeTools,
|
|
255
|
+
tool_choice: "auto",
|
|
276
256
|
});
|
|
277
257
|
});
|
|
278
258
|
|
|
@@ -484,9 +464,13 @@ export async function processUserInput(input: string, role: 'user' | 'system' =
|
|
|
484
464
|
content: result,
|
|
485
465
|
}, sessionId);
|
|
486
466
|
|
|
487
|
-
// V2 Optimization: Zero-LLM Fast Return for data-heavy tools
|
|
467
|
+
// V2 Optimization (Expanded in v1.7.4): Zero-LLM Fast Return for data-heavy and read-only tools
|
|
488
468
|
// If the tool already returns perfectly formatted markdown, skip the second LLM call to save 5-10s latency and tokens!
|
|
489
|
-
|
|
469
|
+
const fastReturnTools = [
|
|
470
|
+
'check_portfolio', 'check_address', 'get_price', 'get_my_address',
|
|
471
|
+
'analyze_market', 'check_token_security', 'search_web', 'read_gmail_inbox', 'list_calendar_events'
|
|
472
|
+
];
|
|
473
|
+
if (fastReturnTools.includes(toolName)) {
|
|
490
474
|
logger.addEntry({ role: 'assistant', content: result }, sessionId);
|
|
491
475
|
return result;
|
|
492
476
|
}
|
|
@@ -31,6 +31,20 @@ console.log(`================================`);
|
|
|
31
31
|
process.exit(0);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Check for memory clear command
|
|
35
|
+
if (process.argv.includes('clear')) {
|
|
36
|
+
if (process.argv.includes('--force') || process.argv.includes('-y')) {
|
|
37
|
+
const { Logger } = require('../memory/logger');
|
|
38
|
+
const logger = new Logger();
|
|
39
|
+
logger.clear();
|
|
40
|
+
console.log(pc.green('✅ Memory cleared successfully.'));
|
|
41
|
+
process.exit(0);
|
|
42
|
+
} else {
|
|
43
|
+
console.log(pc.yellow('⚠️ Warning: This will wipe all AI memory. Run "nyxora clear --force" to confirm.'));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
// Check for set-key shortcut
|
|
35
49
|
if (process.argv.includes('set-key')) {
|
|
36
50
|
const setKeyIndex = process.argv.indexOf('set-key');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { intro, outro, confirm, select, text, isCancel, cancel, note, password, spinner } from '@clack/prompts';
|
|
2
|
+
import search from '@inquirer/search';
|
|
2
3
|
import pc from 'picocolors';
|
|
3
4
|
import fs from 'fs';
|
|
4
5
|
import path from 'path';
|
|
@@ -102,47 +103,98 @@ Provider: ${config.llm.provider}`;
|
|
|
102
103
|
{ value: 'gemini', label: 'Google Gemini' },
|
|
103
104
|
{ value: 'openrouter', label: 'OpenRouter (Many Models)' },
|
|
104
105
|
{ value: 'ollama', label: 'Ollama (Local)' },
|
|
106
|
+
{ value: 'groq', label: 'Groq (Ultra-fast)' },
|
|
107
|
+
{ value: 'mistral', label: 'Mistral AI' },
|
|
108
|
+
{ value: 'xai', label: 'xAI (Grok)' },
|
|
109
|
+
{ value: 'deepseek', label: 'DeepSeek' },
|
|
105
110
|
],
|
|
106
111
|
});
|
|
107
112
|
if (isCancel(provider)) return process.exit(0);
|
|
108
113
|
|
|
109
114
|
// 2. Model Name
|
|
110
|
-
let modelOptions: { value: string,
|
|
115
|
+
let modelOptions: { value: string, name: string }[] = [];
|
|
111
116
|
if (provider === 'gemini') {
|
|
112
117
|
modelOptions = [
|
|
113
|
-
{ value: 'gemini-
|
|
114
|
-
{ value: 'gemini-
|
|
115
|
-
{ value: 'gemini-
|
|
118
|
+
{ value: 'gemini-3.1-pro', name: 'gemini-3.1-pro' },
|
|
119
|
+
{ value: 'gemini-3.1-flash-lite', name: 'gemini-3.1-flash-lite' },
|
|
120
|
+
{ value: 'gemini-2.5-flash', name: 'gemini-2.5-flash' },
|
|
121
|
+
{ value: 'gemini-2.5-pro', name: 'gemini-2.5-pro' },
|
|
122
|
+
{ value: 'gemini-1.5-pro', name: 'gemini-1.5-pro' },
|
|
123
|
+
{ value: 'gemini-1.5-flash', name: 'gemini-1.5-flash' },
|
|
116
124
|
];
|
|
117
125
|
} else if (provider === 'openai') {
|
|
118
126
|
modelOptions = [
|
|
119
|
-
{ value: 'gpt-
|
|
120
|
-
{ value: 'gpt-
|
|
121
|
-
{ value: '
|
|
122
|
-
{ value: '
|
|
127
|
+
{ value: 'gpt-5.5-pro', name: 'gpt-5.5-pro' },
|
|
128
|
+
{ value: 'gpt-5.5', name: 'gpt-5.5' },
|
|
129
|
+
{ value: 'gpt-5.4-mini', name: 'gpt-5.4-mini' },
|
|
130
|
+
{ value: 'gpt-5.4-nano', name: 'gpt-5.4-nano' },
|
|
131
|
+
{ value: 'gpt-4o', name: 'gpt-4o' },
|
|
132
|
+
{ value: 'o3-mini', name: 'o3-mini' },
|
|
123
133
|
];
|
|
124
134
|
} else if (provider === 'openrouter') {
|
|
125
135
|
modelOptions = [
|
|
126
|
-
{ value: 'anthropic/claude-3.5-sonnet',
|
|
127
|
-
{ value: 'meta-llama/llama-3.
|
|
128
|
-
{ value: '
|
|
129
|
-
{ value: '
|
|
136
|
+
{ value: 'anthropic/claude-3.5-sonnet', name: 'Claude 3.5 Sonnet' },
|
|
137
|
+
{ value: 'meta-llama/llama-3.3-70b-instruct', name: 'Llama 3.3 70B' },
|
|
138
|
+
{ value: 'google/gemini-3.1-pro', name: 'Gemini 3.1 Pro' },
|
|
139
|
+
{ value: 'openai/gpt-5.5', name: 'GPT-5.5' },
|
|
140
|
+
{ value: 'x-ai/grok-2', name: 'Grok 2' },
|
|
141
|
+
{ value: 'mistralai/mistral-large', name: 'Mistral Large' },
|
|
142
|
+
];
|
|
143
|
+
} else if (provider === 'groq') {
|
|
144
|
+
modelOptions = [
|
|
145
|
+
{ value: 'llama-3.3-70b-versatile', name: 'llama-3.3-70b-versatile' },
|
|
146
|
+
{ value: 'llama-3.1-8b-instant', name: 'llama-3.1-8b-instant' },
|
|
147
|
+
{ value: 'mixtral-8x7b-32768', name: 'mixtral-8x7b-32768' },
|
|
148
|
+
];
|
|
149
|
+
} else if (provider === 'mistral') {
|
|
150
|
+
modelOptions = [
|
|
151
|
+
{ value: 'mistral-large-latest', name: 'mistral-large-latest' },
|
|
152
|
+
{ value: 'mistral-small-latest', name: 'mistral-small-latest' },
|
|
153
|
+
{ value: 'open-mistral-nemo', name: 'open-mistral-nemo' },
|
|
154
|
+
];
|
|
155
|
+
} else if (provider === 'xai') {
|
|
156
|
+
modelOptions = [
|
|
157
|
+
{ value: 'grok-4.3', name: 'grok-4.3' },
|
|
158
|
+
{ value: 'grok-2-latest', name: 'grok-2-latest' },
|
|
159
|
+
{ value: 'grok-beta', name: 'grok-beta' },
|
|
160
|
+
];
|
|
161
|
+
} else if (provider === 'deepseek') {
|
|
162
|
+
modelOptions = [
|
|
163
|
+
{ value: 'deepseek-chat', name: 'deepseek-chat (V3)' },
|
|
164
|
+
{ value: 'deepseek-reasoner', name: 'deepseek-reasoner (R1)' },
|
|
130
165
|
];
|
|
131
166
|
} else {
|
|
132
167
|
modelOptions = [
|
|
133
|
-
{ value: 'llama3',
|
|
134
|
-
{ value: '
|
|
135
|
-
{ value: '
|
|
168
|
+
{ value: 'llama3.2', name: 'llama3.2' },
|
|
169
|
+
{ value: 'llama3.1', name: 'llama3.1' },
|
|
170
|
+
{ value: 'qwen2.5', name: 'qwen2.5' },
|
|
171
|
+
{ value: 'phi4', name: 'phi4' },
|
|
172
|
+
{ value: 'mistral', name: 'mistral' },
|
|
136
173
|
];
|
|
137
174
|
}
|
|
138
175
|
|
|
139
|
-
modelOptions.push({ value: 'custom',
|
|
140
|
-
|
|
141
|
-
let model =
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
176
|
+
modelOptions.push({ value: 'custom', name: '[Tulis Manual / Custom Model]' });
|
|
177
|
+
|
|
178
|
+
let model = '';
|
|
179
|
+
try {
|
|
180
|
+
model = await search({
|
|
181
|
+
message: 'Select AI Model (Type to search):',
|
|
182
|
+
source: async (input: string | undefined) => {
|
|
183
|
+
if (!input) {
|
|
184
|
+
return modelOptions;
|
|
185
|
+
}
|
|
186
|
+
return modelOptions.filter((opt) =>
|
|
187
|
+
opt.name.toLowerCase().includes(input.toLowerCase()) ||
|
|
188
|
+
opt.value.toLowerCase().includes(input.toLowerCase())
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
} catch (err: any) {
|
|
193
|
+
if (err.name === 'ExitPromptError') {
|
|
194
|
+
return process.exit(0);
|
|
195
|
+
}
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
146
198
|
|
|
147
199
|
if (model === 'custom') {
|
|
148
200
|
model = (await text({
|
|
@@ -282,9 +334,7 @@ Provider: ${config.llm.provider}`;
|
|
|
282
334
|
|
|
283
335
|
const newApiKeys: Record<string, string> = {};
|
|
284
336
|
if (apiKey) {
|
|
285
|
-
|
|
286
|
-
if (provider === 'gemini') newApiKeys.gemini_key = apiKey;
|
|
287
|
-
if (provider === 'openrouter') newApiKeys.openrouter_key = apiKey;
|
|
337
|
+
newApiKeys[`${provider}_key`] = apiKey;
|
|
288
338
|
}
|
|
289
339
|
|
|
290
340
|
if (!config.web_search) config.web_search = { provider: 'mesh', enabled: true };
|
|
@@ -42,6 +42,9 @@ export class Logger {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
private initDb() {
|
|
45
|
+
this.db.exec('PRAGMA journal_mode = WAL;');
|
|
46
|
+
this.db.exec('PRAGMA synchronous = NORMAL;');
|
|
47
|
+
this.db.exec('PRAGMA busy_timeout = 5000;');
|
|
45
48
|
this.db.exec(`
|
|
46
49
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
47
50
|
id TEXT PRIMARY KEY,
|