nyxora 26.6.14 → 26.6.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/bin/nyxora.mjs +3 -4
- package/dist/launcher.js +8 -5
- package/dist/packages/core/src/agent/reasoning.js +21 -52
- package/dist/packages/core/src/config/parser.js +13 -15
- package/dist/packages/core/src/gateway/server.js +51 -9
- package/dist/packages/core/src/gateway/setup.js +5 -5
- package/dist/packages/core/src/gateway/telegram.js +9 -19
- package/dist/packages/core/src/system/skills/updateSecurityPolicy.js +17 -11
- package/dist/packages/core/src/utils/formatter.js +13 -18
- package/dist/packages/core/src/web3/skills/createMarketWatchAgent.js +51 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +1 -1
- package/dist/packages/core/src/web3/skills/marketAnalysis.js +208 -47
- package/dist/packages/core/src/web3/utils/riskIntelligence.js +110 -0
- package/dist/packages/policy/src/server.js +38 -3
- package/dist/packages/signer/src/server.js +2 -2
- package/launcher.ts +9 -5
- package/package.json +5 -7
- package/packages/core/package.json +1 -2
- package/packages/core/src/agent/reasoning.ts +24 -50
- package/packages/core/src/config/parser.ts +14 -26
- package/packages/core/src/gateway/server.ts +55 -9
- package/packages/core/src/gateway/setup.ts +5 -5
- package/packages/core/src/gateway/telegram.ts +9 -19
- package/packages/core/src/system/skills/updateSecurityPolicy.ts +18 -11
- package/packages/core/src/utils/formatter.ts +13 -17
- package/packages/core/src/web3/skills/createMarketWatchAgent.ts +59 -0
- package/packages/core/src/web3/skills/getPrice.ts +1 -1
- package/packages/core/src/web3/skills/marketAnalysis.ts +209 -49
- package/packages/core/src/web3/utils/riskIntelligence.ts +118 -0
- package/packages/dashboard/dist/assets/index-BAXifdMN.js +16 -0
- package/packages/dashboard/dist/index.html +1 -1
- package/packages/dashboard/package.json +1 -1
- package/packages/mcp-server/dist/server.js +110 -0
- package/packages/mcp-server/package.json +1 -1
- package/packages/policy/package.json +1 -1
- package/packages/policy/src/server.ts +41 -4
- package/packages/signer/package.json +1 -1
- package/packages/signer/src/server.ts +2 -2
- package/packages/core/src/system/pluginManager.ts +0 -106
- package/packages/core/src/system/skills/installSkill.ts +0 -51
- package/packages/dashboard/dist/assets/index-BKkezv4e.js +0 -13
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ It operates under a **Zero-Trust, Defense-in-Depth Cryptographically Bound Human
|
|
|
25
25
|
* **DeFi Configuration BYOK & UI Masking**: All aggregator and provider API keys are strictly isolated via a Bring Your Own Keys (BYOK) architecture into a heavily guarded `~/.nyxora/defi_keys.yaml` file. The local web Dashboard masks these injected secrets using `***********` and `IS_SET` censorship, completely neutralizing malicious browser extensions from exfiltrating your keys.
|
|
26
26
|
* **Approval Replay Protection (Nonce Guard)**: Transactions requested by the AI are drafted as hashes and signed with a randomized 16-byte Nonce. The `/api/transactions/:id/approve` endpoint strictly enforces Nonce matching to completely eliminate double-spending and Replay Attacks.
|
|
27
27
|
* **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.
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
* **Graceful SQLite WAL Shutdown**: Integrated `SIGTERM`/`SIGINT` interceptors ensure that when the daemon stops, active requests are safely terminated and SQLite Write-Ahead Logs (WAL) are securely flushed, preventing database corruption.
|
|
30
30
|
|
|
31
31
|
### 🌐 Web3 Skills (On-Chain)
|
|
@@ -34,7 +34,8 @@ It operates under a **Zero-Trust, Defense-in-Depth Cryptographically Bound Human
|
|
|
34
34
|
* **6-Engine Meta-Aggregator & Anti-MEV**: The core engine interfaces with a powerful 6-Engine Meta-Aggregator (**1inch, 0x, LI.FI, Relay, OpenOcean, and KyberSwap**) to route tokens cross-chain, ensuring absolute maximum liquidity depth.
|
|
35
35
|
* **Adaptive Auto Slippage Protection**: Nyxora enforces a dynamic and adaptive **'auto' slippage** by default to leverage dynamic MEV-protection from these industry-standard aggregators. However, the user retains absolute control to override this dynamically—either globally via the Dashboard Settings or on a per-transaction basis through NLP chat commands (e.g., *"Swap 1 ETH to PEPE with 10% slippage"*).
|
|
36
36
|
|
|
37
|
-
* **
|
|
37
|
+
* **Dual-Routing Market Intelligence Engine**: Real-time asset tracking utilizing a sophisticated API Waterfall. Symbol queries are routed to CoinGecko/CEXs for global FDV, while Contract Addresses trigger DexScreener for live on-chain liquidity metrics across all networks.
|
|
38
|
+
* **Asynchronous Watchdog Agents**: Seamlessly spawn detached background instances for long-running monitoring tasks (e.g., *"Notify me when $ETH drops below $2500"*), leaving your primary chat session free for other operations.
|
|
38
39
|
* **"Lean Degen" Auto-Whitelist**: Automatically intercepts Contract Addresses (CAs) whenever you check balances or swap tokens, saving them to your localized `user_whitelist.json` for future tracking.
|
|
39
40
|
* **Dynamic Portfolio Engine**: Merges standard tokens, your custom Degen CAs, and CoinGecko's daily trending list into a single hyper-fast Multicall scan to deliver a clean, spam-free PnL portfolio report in under 1 second.
|
|
40
41
|
* **Deep Transaction History**: Accurately fetch your 30-day (or custom timeframe) Native and ERC-20 transaction history across all supported EVM chains. Powered by the Unified Etherscan API V2, enabling seamless cross-chain fetching (Mainnets & Testnets) using a single API key.
|
|
@@ -171,7 +172,7 @@ For complete technical deep-dives into our Cryptographic Architecture, please vi
|
|
|
171
172
|
**❤️ Support the Project**
|
|
172
173
|
|
|
173
174
|
Building and maintaining a highly secure, zero-trust architecture takes significant time and resources. If you love what we are building, you can help us keep Nyxora open, secure, and constantly evolving by sending a coffee our way:
|
|
174
|
-
- **EVM:** `
|
|
175
|
+
- **EVM (Multi-Sig Safe):** `0x490717E50D6434C348AA0D2bD5fe682392823708`
|
|
175
176
|
|
|
176
177
|
---
|
|
177
178
|
**License:** MIT License
|
package/bin/nyxora.mjs
CHANGED
|
@@ -15,9 +15,9 @@ const pidFile = path.join(appDir, 'run', 'daemon.pid');
|
|
|
15
15
|
const logFile = path.join(appDir, 'run', 'gateway.log');
|
|
16
16
|
const tokenFile = path.join(appDir, 'auth', 'auth.token');
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
fs.mkdirSync(
|
|
20
|
-
}
|
|
18
|
+
[path.join(appDir, 'run'), path.join(appDir, 'auth')].forEach(dir => {
|
|
19
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
});
|
|
21
21
|
|
|
22
22
|
const command = process.argv[2];
|
|
23
23
|
|
|
@@ -291,7 +291,6 @@ async function unlock() {
|
|
|
291
291
|
} catch (e) {}
|
|
292
292
|
}
|
|
293
293
|
try {
|
|
294
|
-
const fetch = (await import('node-fetch')).default;
|
|
295
294
|
const res = await fetch('http://localhost:3000/api/status/unlock', {
|
|
296
295
|
method: 'POST',
|
|
297
296
|
headers: {
|
package/dist/launcher.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
// @ts-ignore
|
|
6
7
|
const safeLogger_1 = require("./packages/core/src/utils/safeLogger");
|
|
7
8
|
(0, safeLogger_1.initSafeLogger)();
|
|
8
9
|
const child_process_1 = require("child_process");
|
|
@@ -107,19 +108,21 @@ if (fs_1.default.existsSync(socketPath)) {
|
|
|
107
108
|
fs_1.default.unlinkSync(socketPath);
|
|
108
109
|
}
|
|
109
110
|
const children = [];
|
|
110
|
-
const
|
|
111
|
+
const __filenameResolved = __filename;
|
|
112
|
+
const __dirnameResolved = __dirname;
|
|
113
|
+
const isCompiled = __filenameResolved.endsWith('.js');
|
|
111
114
|
const ext = isCompiled ? '.js' : '.ts';
|
|
112
|
-
const cmd = isCompiled ? 'node' : path_1.default.join(
|
|
115
|
+
const cmd = isCompiled ? 'node' : path_1.default.join(__dirnameResolved, 'node_modules', '.bin', 'ts-node');
|
|
113
116
|
const baseArgs = isCompiled ? [] : ['-T'];
|
|
114
|
-
const signerPath = path_1.default.join(
|
|
117
|
+
const signerPath = path_1.default.join(__dirnameResolved, `packages/signer/src/server${ext}`);
|
|
115
118
|
const signer = spawnService('Signer', cmd, [...baseArgs, signerPath], env);
|
|
116
119
|
children.push(signer);
|
|
117
120
|
setTimeout(() => {
|
|
118
|
-
const policyPath = path_1.default.join(
|
|
121
|
+
const policyPath = path_1.default.join(__dirnameResolved, `packages/policy/src/server${ext}`);
|
|
119
122
|
const policy = spawnService('Policy', cmd, [...baseArgs, policyPath], env);
|
|
120
123
|
children.push(policy);
|
|
121
124
|
setTimeout(() => {
|
|
122
|
-
const corePath = path_1.default.join(
|
|
125
|
+
const corePath = path_1.default.join(__dirnameResolved, `packages/core/src/gateway/cli${ext}`);
|
|
123
126
|
const args = process.argv.slice(2);
|
|
124
127
|
const core = spawnService('Core', cmd, [...baseArgs, corePath, ...args], env, true);
|
|
125
128
|
children.push(core);
|
|
@@ -22,6 +22,7 @@ const mintNft_1 = require("../web3/skills/mintNft");
|
|
|
22
22
|
const customTx_1 = require("../web3/skills/customTx");
|
|
23
23
|
const checkSecurity_1 = require("../web3/skills/checkSecurity");
|
|
24
24
|
const marketAnalysis_1 = require("../web3/skills/marketAnalysis");
|
|
25
|
+
const createMarketWatchAgent_1 = require("../web3/skills/createMarketWatchAgent");
|
|
25
26
|
const checkPortfolio_1 = require("../web3/skills/checkPortfolio");
|
|
26
27
|
const checkAddress_1 = require("../web3/skills/checkAddress");
|
|
27
28
|
const getMyAddress_1 = require("../web3/skills/getMyAddress");
|
|
@@ -41,7 +42,6 @@ const generateExcel_1 = require("../system/skills/generateExcel");
|
|
|
41
42
|
const executeShell_1 = require("../system/skills/executeShell");
|
|
42
43
|
const browseWeb_1 = require("../system/skills/browseWeb");
|
|
43
44
|
const searchWeb_1 = require("../system/skills/searchWeb");
|
|
44
|
-
const installSkill_1 = require("../system/skills/installSkill");
|
|
45
45
|
const editFile_1 = require("../system/skills/editFile");
|
|
46
46
|
const gitManager_1 = require("../system/skills/gitManager");
|
|
47
47
|
const xManager_1 = require("../system/skills/xManager");
|
|
@@ -49,7 +49,6 @@ const notionWorkspace_1 = require("../system/skills/notionWorkspace");
|
|
|
49
49
|
const audioTranscribe_1 = require("../system/skills/audioTranscribe");
|
|
50
50
|
const summarizeText_1 = require("../system/skills/summarizeText");
|
|
51
51
|
const googleWorkspace_1 = require("../system/skills/googleWorkspace");
|
|
52
|
-
const pluginManager_1 = require("../system/pluginManager");
|
|
53
52
|
const paths_1 = require("../config/paths");
|
|
54
53
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
55
54
|
exports.logger = new logger_1.Logger();
|
|
@@ -134,7 +133,7 @@ IMPORTANT: The <think> block is strictly for your internal hidden monologue. NEV
|
|
|
134
133
|
|
|
135
134
|
[EXECUTION WORKFLOW]
|
|
136
135
|
CRITICAL RULE 1: NEVER expose internal JSON tool calls to the user. Always parse them and explain the outcome naturally.
|
|
137
|
-
CRITICAL RULE 2: STRICT LANGUAGE MATCHING. You MUST strictly reply in the exact same language as the user's LATEST prompt.
|
|
136
|
+
CRITICAL RULE 2: STRICT LANGUAGE MATCHING. You MUST strictly reply in the exact same language as the user's LATEST prompt. Render all output, metric labels, and suggested actions entirely in the language the user initiated the prompt with, while strictly preserving the visual structure of the progress bars.
|
|
138
137
|
CRITICAL RULE 3: FORMATTING & CONCISENESS. Provide concise analytical summaries of data rather than just dumping raw markdown tables. Be analytical but brief. Use commas for thousands.
|
|
139
138
|
CRITICAL RULE 4: TOOL PRIORITIZATION. Web3 tasks must use Web3 Skills exclusively. OS Skills (search, browse) are fallbacks only. Use get_my_address to show wallet address, and check_portfolio to show balances.
|
|
140
139
|
CRITICAL RULE 5: DEFAULT CHAIN HANDLING. Default to: ${config.agent.default_chain} unless specified. If overridden, confirm the chain politely. For 2-chain txs (bridge), default source to ${config.agent.default_chain}.
|
|
@@ -174,16 +173,20 @@ CRITICAL RULE 19: MARKET CONFIDENCE SCORE. When analyzing market data, token sec
|
|
|
174
173
|
catch (error) {
|
|
175
174
|
console.error('Failed to read user.md:', error);
|
|
176
175
|
}
|
|
177
|
-
// Read
|
|
176
|
+
// Read policy.yaml for NLP security constraints
|
|
178
177
|
try {
|
|
179
|
-
const policyPath = (0, paths_1.getPath)('
|
|
178
|
+
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
180
179
|
if (fs_1.default.existsSync(policyPath)) {
|
|
181
|
-
const
|
|
182
|
-
|
|
180
|
+
const yaml = require('yaml'); // lazily import if not imported
|
|
181
|
+
const file = fs_1.default.readFileSync(policyPath, 'utf8');
|
|
182
|
+
const parsed = yaml.parse(file) || {};
|
|
183
|
+
if (parsed.custom_llm_rules && Array.isArray(parsed.custom_llm_rules) && parsed.custom_llm_rules.length > 0) {
|
|
184
|
+
basePrompt += `\n\n--- SECURITY POLICY (MANDATORY RULES) ---\n${parsed.custom_llm_rules.map((r) => `* ${r}`).join('\n')}\n\nCRITICAL: If the user asks you to perform an action that violates the Security Policy above, YOU MUST NOT EXECUTE IT DIRECTLY. Instead, ask for their explicit permission first.`;
|
|
185
|
+
}
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
188
|
catch (error) {
|
|
186
|
-
console.error('Failed to read
|
|
189
|
+
console.error('Failed to read policy.yaml:', error);
|
|
187
190
|
}
|
|
188
191
|
// Inject Episodic Memories (Smart Suggestions Context)
|
|
189
192
|
try {
|
|
@@ -250,19 +253,19 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
250
253
|
const hasGoogleKeyword = /email|gmail|calendar|sheet|doc|form|event/i.test(lowerInput);
|
|
251
254
|
let tools = [];
|
|
252
255
|
if ((0, skillManager_1.isSkillActive)('web3')) {
|
|
253
|
-
tools.push(getBalance_1.getBalanceToolDefinition, transfer_1.transferToolDefinition, getPrice_1.getPriceToolDefinition, swapToken_1.swapTokenToolDefinition, bridgeToken_1.bridgeTokenToolDefinition, mintNft_1.mintNftToolDefinition, customTx_1.customTxToolDefinition, checkSecurity_1.checkSecurityToolDefinition, marketAnalysis_1.marketAnalysisToolDefinition, checkPortfolio_1.checkPortfolioToolDefinition, checkAddress_1.checkAddressToolDefinition, getMyAddress_1.getMyAddressToolDefinition, manageCustomTokens_1.manageCustomTokensDefinition, revokeApprovals_1.revokeApprovalToolDefinition, defiLending_1.aaveSupplyToolDefinition, yieldVault_1.vaultDepositToolDefinition, provideLiquidity_1.provideLiquidityToolDefinition, getTxHistory_1.getTxHistoryToolDefinition, createLimitOrder_1.createLimitOrderToolDefinition);
|
|
256
|
+
tools.push(getBalance_1.getBalanceToolDefinition, transfer_1.transferToolDefinition, getPrice_1.getPriceToolDefinition, swapToken_1.swapTokenToolDefinition, bridgeToken_1.bridgeTokenToolDefinition, mintNft_1.mintNftToolDefinition, customTx_1.customTxToolDefinition, checkSecurity_1.checkSecurityToolDefinition, marketAnalysis_1.marketAnalysisToolDefinition, createMarketWatchAgent_1.createMarketWatchAgentToolDefinition, checkPortfolio_1.checkPortfolioToolDefinition, checkAddress_1.checkAddressToolDefinition, getMyAddress_1.getMyAddressToolDefinition, manageCustomTokens_1.manageCustomTokensDefinition, revokeApprovals_1.revokeApprovalToolDefinition, defiLending_1.aaveSupplyToolDefinition, yieldVault_1.vaultDepositToolDefinition, provideLiquidity_1.provideLiquidityToolDefinition, getTxHistory_1.getTxHistoryToolDefinition, createLimitOrder_1.createLimitOrderToolDefinition);
|
|
254
257
|
}
|
|
255
|
-
const SYSTEM_TOOLS = [updateProfile_1.updateProfileToolDefinition, updateSecurityPolicy_1.updateSecurityPolicyToolDefinition, analyzeDocument_1.analyzeDocumentToolDefinition, readFile_1.readLocalFileToolDefinition, writeFile_1.writeLocalFileToolDefinition, generateExcel_1.generateExcelToolDefinition, executeShell_1.runTerminalCommandToolDefinition, browseWeb_1.browseWebsiteToolDefinition, searchWeb_1.searchWebToolDefinition,
|
|
258
|
+
const SYSTEM_TOOLS = [updateProfile_1.updateProfileToolDefinition, updateSecurityPolicy_1.updateSecurityPolicyToolDefinition, analyzeDocument_1.analyzeDocumentToolDefinition, readFile_1.readLocalFileToolDefinition, writeFile_1.writeLocalFileToolDefinition, generateExcel_1.generateExcelToolDefinition, executeShell_1.runTerminalCommandToolDefinition, browseWeb_1.browseWebsiteToolDefinition, searchWeb_1.searchWebToolDefinition, editFile_1.editLocalFileToolDefinition, gitManager_1.gitManagerToolDefinition, xManager_1.xManagerToolDefinition, notionWorkspace_1.notionWorkspaceToolDefinition, audioTranscribe_1.audioTranscribeToolDefinition, summarizeText_1.summarizeTextToolDefinition];
|
|
256
259
|
const GOOGLE_TOOLS = [googleWorkspace_1.readGmailInboxToolDefinition, googleWorkspace_1.listCalendarEventsToolDefinition, googleWorkspace_1.appendRowToSheetsToolDefinition, googleWorkspace_1.readGoogleDocsToolDefinition, googleWorkspace_1.readGoogleFormResponsesToolDefinition];
|
|
257
260
|
let activeTools = [];
|
|
258
261
|
if (hasGoogleKeyword && !hasWeb3Keyword) {
|
|
259
|
-
activeTools = [...GOOGLE_TOOLS, ...SYSTEM_TOOLS
|
|
262
|
+
activeTools = [...GOOGLE_TOOLS, ...SYSTEM_TOOLS];
|
|
260
263
|
}
|
|
261
264
|
else if (hasWeb3Keyword && !hasGoogleKeyword) {
|
|
262
|
-
activeTools = [...tools, ...SYSTEM_TOOLS
|
|
265
|
+
activeTools = [...tools, ...SYSTEM_TOOLS];
|
|
263
266
|
}
|
|
264
267
|
else {
|
|
265
|
-
activeTools = [...tools, ...SYSTEM_TOOLS, ...GOOGLE_TOOLS
|
|
268
|
+
activeTools = [...tools, ...SYSTEM_TOOLS, ...GOOGLE_TOOLS];
|
|
266
269
|
}
|
|
267
270
|
activeTools = activeTools.filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
|
|
268
271
|
const response = await executeWithRetry(async (client) => {
|
|
@@ -323,10 +326,6 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
323
326
|
}
|
|
324
327
|
case 'transfer_token':
|
|
325
328
|
case 'transfer_native': {
|
|
326
|
-
if (config.permissions?.web3?.allow_transfer === false) {
|
|
327
|
-
result = `[Security Blocked] Runtime Permission Denied: Web3 transfers are disabled. Update config.yaml to allow.`;
|
|
328
|
-
break;
|
|
329
|
-
}
|
|
330
329
|
result = await (0, transfer_1.prepareTransfer)(args.chainName, args.toAddress, args.amountStr || args.amountEth, args.token);
|
|
331
330
|
break;
|
|
332
331
|
}
|
|
@@ -335,18 +334,10 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
335
334
|
break;
|
|
336
335
|
}
|
|
337
336
|
case 'swap_token': {
|
|
338
|
-
if (config.permissions?.web3?.allow_swap === false) {
|
|
339
|
-
result = `[Security Blocked] Runtime Permission Denied: Web3 swaps are disabled. Update config.yaml to allow.`;
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
337
|
result = await (0, swapToken_1.prepareSwapToken)(args.chainName, args.fromToken, args.toToken, args.amountStr || args.amount, args.mode, args.providerName);
|
|
343
338
|
break;
|
|
344
339
|
}
|
|
345
340
|
case 'bridge_token': {
|
|
346
|
-
if (config.permissions?.web3?.allow_transfer === false) {
|
|
347
|
-
result = `[Security Blocked] Runtime Permission Denied: Web3 bridging (transfer) is disabled. Update config.yaml to allow.`;
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
341
|
result = await (0, bridgeToken_1.prepareBridgeToken)(args.fromChain, args.toChain, args.tokenSymbol, args.amountStr, args.mode, args.providerName);
|
|
351
342
|
break;
|
|
352
343
|
}
|
|
@@ -355,10 +346,6 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
355
346
|
break;
|
|
356
347
|
}
|
|
357
348
|
case 'custom_tx': {
|
|
358
|
-
if (config.permissions?.web3?.allow_transfer === false) {
|
|
359
|
-
result = `[Security Blocked] Runtime Permission Denied: Custom transactions are blocked because transfers are disabled.`;
|
|
360
|
-
break;
|
|
361
|
-
}
|
|
362
349
|
result = await (0, customTx_1.prepareCustomTx)(args.chainName, args.toAddress, args.dataHex, args.valueEth, args.gasLimitStr);
|
|
363
350
|
break;
|
|
364
351
|
}
|
|
@@ -370,6 +357,10 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
370
357
|
result = await (0, marketAnalysis_1.analyzeMarket)(args.chainName, args.tokenAddressOrSymbol);
|
|
371
358
|
break;
|
|
372
359
|
}
|
|
360
|
+
case 'create_market_watch_agent': {
|
|
361
|
+
result = await (0, createMarketWatchAgent_1.createMarketWatchAgent)(args.chainName, args.contractAddress, args.rules, args.durationDays);
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
373
364
|
case 'check_portfolio': {
|
|
374
365
|
result = await (0, checkPortfolio_1.checkPortfolio)(args.chainName, args.address);
|
|
375
366
|
break;
|
|
@@ -451,26 +442,14 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
451
442
|
break;
|
|
452
443
|
}
|
|
453
444
|
case 'write_local_file': {
|
|
454
|
-
if (config.permissions?.system?.allow_file_write === false) {
|
|
455
|
-
result = `[Security Blocked] Runtime Permission Denied: File writing is disabled. Update config.yaml to allow.`;
|
|
456
|
-
break;
|
|
457
|
-
}
|
|
458
445
|
result = (0, writeFile_1.writeLocalFile)(args.filePath, args.content);
|
|
459
446
|
break;
|
|
460
447
|
}
|
|
461
448
|
case 'generate_excel_file': {
|
|
462
|
-
if (config.permissions?.system?.allow_file_write === false) {
|
|
463
|
-
result = `[Security Blocked] Runtime Permission Denied: File writing is disabled. Update config.yaml to allow.`;
|
|
464
|
-
break;
|
|
465
|
-
}
|
|
466
449
|
result = await (0, generateExcel_1.generateExcelFile)(args.data, args.filePath);
|
|
467
450
|
break;
|
|
468
451
|
}
|
|
469
452
|
case 'run_terminal_command': {
|
|
470
|
-
if (config.permissions?.system?.allow_shell_execution === false) {
|
|
471
|
-
result = `[Security Blocked] Runtime Permission Denied: Shell execution is disabled. Update config.yaml to allow.`;
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
474
453
|
result = await (0, executeShell_1.runTerminalCommand)(args.command);
|
|
475
454
|
break;
|
|
476
455
|
}
|
|
@@ -482,10 +461,6 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
482
461
|
result = await (0, searchWeb_1.searchWeb)(args.query, args.depth);
|
|
483
462
|
break;
|
|
484
463
|
}
|
|
485
|
-
case 'install_external_skill': {
|
|
486
|
-
result = await (0, installSkill_1.installExternalSkill)(args.url);
|
|
487
|
-
break;
|
|
488
|
-
}
|
|
489
464
|
case 'read_gmail_inbox': {
|
|
490
465
|
result = await (0, googleWorkspace_1.readGmailInbox)(args.maxResults);
|
|
491
466
|
break;
|
|
@@ -507,13 +482,7 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
507
482
|
break;
|
|
508
483
|
}
|
|
509
484
|
default: {
|
|
510
|
-
|
|
511
|
-
if (externalResult !== null) {
|
|
512
|
-
result = externalResult;
|
|
513
|
-
}
|
|
514
|
-
else {
|
|
515
|
-
result = `Error: Tool ${toolName} is not implemented.`;
|
|
516
|
-
}
|
|
485
|
+
result = `Error: Tool ${toolName} is not implemented.`;
|
|
517
486
|
break;
|
|
518
487
|
}
|
|
519
488
|
}
|
|
@@ -66,16 +66,22 @@ function loadConfig() {
|
|
|
66
66
|
delete parsed.llm.credentials;
|
|
67
67
|
needsSave = true;
|
|
68
68
|
}
|
|
69
|
-
//
|
|
70
|
-
if (parsed.web3 && parsed.web3.rpc_urls
|
|
71
|
-
if (!fs_1.default.existsSync(rpcPath)) {
|
|
72
|
-
rpcUrls = parsed.web3.rpc_urls;
|
|
73
|
-
saveRpcConfig(rpcUrls);
|
|
74
|
-
console.log('[Config] Auto-migrated web3.rpc_urls to rpc_key.yaml.');
|
|
75
|
-
}
|
|
69
|
+
// Ensure we don't accidentally overwrite rpc_key.yaml with old config.yaml data.
|
|
70
|
+
if (parsed.web3 && parsed.web3.rpc_urls) {
|
|
76
71
|
delete parsed.web3.rpc_urls;
|
|
77
72
|
needsSave = true;
|
|
78
73
|
}
|
|
74
|
+
// Auto-migration logic: move permissions to policy.yaml
|
|
75
|
+
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
76
|
+
if (!fs_1.default.existsSync(policyPath)) {
|
|
77
|
+
const defaultPolicy = `max_usd_per_tx: ${parsed.permissions?.web3?.max_usd_per_tx || 999999999}\nwhitelist_only: false\nrequire_approval: true\n`;
|
|
78
|
+
fs_1.default.writeFileSync(policyPath, defaultPolicy, 'utf8');
|
|
79
|
+
console.log('[Config] Created default policy.yaml.');
|
|
80
|
+
}
|
|
81
|
+
if (parsed.permissions) {
|
|
82
|
+
delete parsed.permissions;
|
|
83
|
+
needsSave = true;
|
|
84
|
+
}
|
|
79
85
|
if (needsSave) {
|
|
80
86
|
try {
|
|
81
87
|
const yamlStr = yaml_1.default.stringify(parsed);
|
|
@@ -103,10 +109,6 @@ function loadConfig() {
|
|
|
103
109
|
web3: { ...parsed.web3, rpc_urls: rpcUrls },
|
|
104
110
|
integrations: parsed.integrations || {
|
|
105
111
|
telegram: { enabled: false }
|
|
106
|
-
},
|
|
107
|
-
permissions: parsed.permissions || {
|
|
108
|
-
web3: { allow_transfer: true, allow_swap: true, max_usd_per_tx: 999999999 },
|
|
109
|
-
system: { allow_shell_execution: true, allow_file_write: true }
|
|
110
112
|
}
|
|
111
113
|
};
|
|
112
114
|
}
|
|
@@ -140,10 +142,6 @@ function loadConfig() {
|
|
|
140
142
|
web3: { rpc_urls: rpcUrls },
|
|
141
143
|
integrations: {
|
|
142
144
|
telegram: { enabled: false }
|
|
143
|
-
},
|
|
144
|
-
permissions: {
|
|
145
|
-
web3: { allow_transfer: true, allow_swap: true, max_usd_per_tx: 999999999 },
|
|
146
|
-
system: { allow_shell_execution: true, allow_file_write: true }
|
|
147
145
|
}
|
|
148
146
|
};
|
|
149
147
|
}
|
|
@@ -21,6 +21,7 @@ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
|
21
21
|
const paths_1 = require("../config/paths");
|
|
22
22
|
const state_1 = require("../utils/state");
|
|
23
23
|
const fs_1 = __importDefault(require("fs"));
|
|
24
|
+
const yaml_1 = __importDefault(require("yaml"));
|
|
24
25
|
const reasoning_1 = require("../agent/reasoning");
|
|
25
26
|
const parser_1 = require("../config/parser");
|
|
26
27
|
const defiConfigManager_1 = require("../config/defiConfigManager");
|
|
@@ -28,7 +29,6 @@ const config_1 = require("../web3/config");
|
|
|
28
29
|
const tokens_1 = require("../web3/utils/tokens");
|
|
29
30
|
const tracker_1 = require("./tracker");
|
|
30
31
|
const transactionManager_1 = require("../agent/transactionManager");
|
|
31
|
-
const pluginManager_1 = require("../system/pluginManager");
|
|
32
32
|
const transfer_1 = require("../web3/skills/transfer");
|
|
33
33
|
const swapToken_1 = require("../web3/skills/swapToken");
|
|
34
34
|
const getBalance_1 = require("../web3/skills/getBalance");
|
|
@@ -55,7 +55,6 @@ const createLimitOrder_1 = require("../web3/skills/createLimitOrder");
|
|
|
55
55
|
// System Skills
|
|
56
56
|
const browseWeb_1 = require("../system/skills/browseWeb");
|
|
57
57
|
const executeShell_1 = require("../system/skills/executeShell");
|
|
58
|
-
const installSkill_1 = require("../system/skills/installSkill");
|
|
59
58
|
const readFile_1 = require("../system/skills/readFile");
|
|
60
59
|
const editFile_1 = require("../system/skills/editFile");
|
|
61
60
|
const gitManager_1 = require("../system/skills/gitManager");
|
|
@@ -349,7 +348,6 @@ app.get('/api/skills/system', (req, res) => {
|
|
|
349
348
|
generateExcel_1.generateExcelToolDefinition,
|
|
350
349
|
browseWeb_1.browseWebsiteToolDefinition,
|
|
351
350
|
updateSecurityPolicy_1.updateSecurityPolicyToolDefinition,
|
|
352
|
-
installSkill_1.installExternalSkillToolDefinition,
|
|
353
351
|
analyzeDocument_1.analyzeDocumentToolDefinition,
|
|
354
352
|
searchWeb_1.searchWebToolDefinition,
|
|
355
353
|
googleWorkspace_1.readGmailInboxToolDefinition,
|
|
@@ -802,6 +800,46 @@ app.delete('/api/memory/:id', (req, res) => {
|
|
|
802
800
|
res.status(500).json({ error: error.message });
|
|
803
801
|
}
|
|
804
802
|
});
|
|
803
|
+
// --- Policy Engine Endpoints ---
|
|
804
|
+
app.get('/api/policy', (req, res) => {
|
|
805
|
+
try {
|
|
806
|
+
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
807
|
+
if (!fs_1.default.existsSync(policyPath)) {
|
|
808
|
+
return res.json({
|
|
809
|
+
max_usd_per_tx: 999999999,
|
|
810
|
+
whitelist_only: false,
|
|
811
|
+
require_approval: true,
|
|
812
|
+
custom_llm_rules: []
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
const file = fs_1.default.readFileSync(policyPath, 'utf8');
|
|
816
|
+
const parsed = yaml_1.default.parse(file) || {};
|
|
817
|
+
res.json({
|
|
818
|
+
max_usd_per_tx: parsed.max_usd_per_tx ?? 999999999,
|
|
819
|
+
whitelist_only: parsed.whitelist_only ?? false,
|
|
820
|
+
require_approval: parsed.require_approval ?? true,
|
|
821
|
+
custom_llm_rules: parsed.custom_llm_rules || []
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
catch (error) {
|
|
825
|
+
res.status(500).json({ error: error.message });
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
app.post('/api/policy', (req, res) => {
|
|
829
|
+
try {
|
|
830
|
+
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
831
|
+
let current = {};
|
|
832
|
+
if (fs_1.default.existsSync(policyPath)) {
|
|
833
|
+
current = yaml_1.default.parse(fs_1.default.readFileSync(policyPath, 'utf8')) || {};
|
|
834
|
+
}
|
|
835
|
+
const updated = { ...current, ...req.body };
|
|
836
|
+
fs_1.default.writeFileSync(policyPath, yaml_1.default.stringify(updated), 'utf8');
|
|
837
|
+
res.json({ success: true });
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
res.status(500).json({ error: error.message });
|
|
841
|
+
}
|
|
842
|
+
});
|
|
805
843
|
// --- User Persona / Risk Profile Endpoints (V3) ---
|
|
806
844
|
app.get('/api/profile', (req, res) => {
|
|
807
845
|
try {
|
|
@@ -862,9 +900,6 @@ async function autoMigrateKeys() {
|
|
|
862
900
|
}
|
|
863
901
|
function startServer() {
|
|
864
902
|
autoMigrateKeys().catch(e => console.error('[Auto-Migrate] Error:', e));
|
|
865
|
-
pluginManager_1.pluginManager.loadPlugins().then(() => {
|
|
866
|
-
console.log(`[PluginManager] Finished loading external skills.`);
|
|
867
|
-
});
|
|
868
903
|
const PORT = Number(process.env.PORT || 3000);
|
|
869
904
|
const server = app.listen(PORT, '127.0.0.1', () => {
|
|
870
905
|
console.log(`🤖 Nyxora API Server running on port ${PORT}`);
|
|
@@ -885,18 +920,25 @@ function startServer() {
|
|
|
885
920
|
process.exit(1);
|
|
886
921
|
}
|
|
887
922
|
});
|
|
923
|
+
let isShuttingDown = false;
|
|
888
924
|
const gracefulShutdown = () => {
|
|
925
|
+
if (isShuttingDown)
|
|
926
|
+
return;
|
|
927
|
+
isShuttingDown = true;
|
|
889
928
|
console.log('[Nyxora Gateway] Received shutdown signal. Closing server...');
|
|
929
|
+
if (server.closeAllConnections) {
|
|
930
|
+
server.closeAllConnections();
|
|
931
|
+
}
|
|
890
932
|
server.close(() => {
|
|
891
933
|
console.log('[Nyxora Gateway] HTTP server closed.');
|
|
892
934
|
reasoning_1.logger.close();
|
|
893
935
|
process.exit(0);
|
|
894
936
|
});
|
|
895
|
-
// Force exit after
|
|
937
|
+
// Force exit after 3s if stuck
|
|
896
938
|
setTimeout(() => {
|
|
897
|
-
console.error('[Nyxora Gateway] Forced shutdown
|
|
939
|
+
console.error('[Nyxora Gateway] Forced shutdown.');
|
|
898
940
|
process.exit(1);
|
|
899
|
-
},
|
|
941
|
+
}, 3000).unref();
|
|
900
942
|
};
|
|
901
943
|
process.on('SIGTERM', gracefulShutdown);
|
|
902
944
|
process.on('SIGINT', gracefulShutdown);
|
|
@@ -289,9 +289,8 @@ Provider: ${config.llm.provider}`;
|
|
|
289
289
|
{ value: 'generateExcel', label: 'Generate Excel Reports' },
|
|
290
290
|
{ value: 'analyzeDocument', label: 'Analyze Docs (PDF/Word)' },
|
|
291
291
|
{ value: 'run_terminal', label: 'Run Terminal Command', hint: '⚠️ UNSAFE' },
|
|
292
|
-
{ value: 'installSkill', label: 'Install External Skills (Plugins)' },
|
|
293
292
|
{ value: 'gitManager', label: 'Git Operations (Commit/Push/Pull)' },
|
|
294
|
-
{ value: 'updateSecurityPolicy', label: 'Update
|
|
293
|
+
{ value: 'updateSecurityPolicy', label: 'Update policy.yaml rules', hint: 'safeguard' },
|
|
295
294
|
{ value: 'browseWeb', label: 'Browse & Scrape Webpages' },
|
|
296
295
|
{ value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave)', hint: 'Requires API Key' },
|
|
297
296
|
{ value: 'googleWorkspace', label: 'Google Workspace (Gmail, Docs, Sheets, Forms)', hint: 'Requires OAuth' },
|
|
@@ -410,7 +409,9 @@ Provider: ${config.llm.provider}`;
|
|
|
410
409
|
config.web_search.enabled = false;
|
|
411
410
|
}
|
|
412
411
|
if (Object.keys(newApiKeys).length > 0) {
|
|
413
|
-
|
|
412
|
+
if (!config.credentials)
|
|
413
|
+
config.credentials = {};
|
|
414
|
+
config.credentials = { ...config.credentials, ...newApiKeys };
|
|
414
415
|
}
|
|
415
416
|
if (!config.integrations)
|
|
416
417
|
config.integrations = {};
|
|
@@ -424,7 +425,6 @@ Provider: ${config.llm.provider}`;
|
|
|
424
425
|
config.integrations.telegram.authorized_chat_id = authorizedChatId;
|
|
425
426
|
}
|
|
426
427
|
(0, parser_1.saveConfig)(config);
|
|
427
|
-
(0, parser_1.saveRpcConfig)({});
|
|
428
428
|
// Sync disabled_skills.json based on user selection
|
|
429
429
|
const allWeb3Skills = [
|
|
430
430
|
'transfer', 'swapToken', 'bridgeToken', 'customTx', 'mintNft',
|
|
@@ -434,7 +434,7 @@ Provider: ${config.llm.provider}`;
|
|
|
434
434
|
];
|
|
435
435
|
const allOsSkills = [
|
|
436
436
|
'readFile', 'writeFile', 'editFile', 'generateExcel', 'analyzeDocument',
|
|
437
|
-
'run_terminal', '
|
|
437
|
+
'run_terminal', 'gitManager', 'updateSecurityPolicy',
|
|
438
438
|
'browseWeb', 'searchWeb', 'googleWorkspace', 'notionWorkspace', 'xManager',
|
|
439
439
|
'audioTranscribe', 'summarizeText'
|
|
440
440
|
];
|
|
@@ -64,13 +64,13 @@ function startTelegramBot() {
|
|
|
64
64
|
generatedPin = Math.floor(100000 + Math.random() * 900000).toString();
|
|
65
65
|
pinExpiry = Date.now() + 5 * 60 * 1000; // 5 minutes TTL
|
|
66
66
|
console.log(picocolors_1.default.yellow('\n==================================================='));
|
|
67
|
-
console.log(picocolors_1.default.yellow('🔐
|
|
67
|
+
console.log(picocolors_1.default.yellow('🔐 TELEGRAM BOT AUTHORIZATION REQUIRED'));
|
|
68
68
|
console.log(picocolors_1.default.yellow('==================================================='));
|
|
69
|
-
console.log('
|
|
70
|
-
console.log('
|
|
69
|
+
console.log('Your Telegram Bot is currently locked for security.');
|
|
70
|
+
console.log('Open your Telegram app, and send the following command to your bot:\n');
|
|
71
71
|
console.log(picocolors_1.default.cyan(` /auth ${generatedPin}\n`));
|
|
72
|
-
console.log(picocolors_1.default.gray('(
|
|
73
|
-
console.log('⏳
|
|
72
|
+
console.log(picocolors_1.default.gray('(This OTP code will expire in 5 minutes)\n'));
|
|
73
|
+
console.log('⏳ Waiting for incoming message...');
|
|
74
74
|
}
|
|
75
75
|
// Security Middleware (OTP & Authorization)
|
|
76
76
|
bot.use(async (ctx, next) => {
|
|
@@ -100,12 +100,12 @@ function startTelegramBot() {
|
|
|
100
100
|
currentConfig.integrations.telegram = { enabled: true, bot_token: token };
|
|
101
101
|
currentConfig.integrations.telegram.authorized_chat_id = ctx.chat?.id;
|
|
102
102
|
(0, parser_1.saveConfig)(currentConfig);
|
|
103
|
-
await ctx.reply('✅
|
|
103
|
+
await ctx.reply('✅ Authorization Successful! Nyxora Agent will now only obey your commands. Connection secured.');
|
|
104
104
|
console.log(picocolors_1.default.green(`\n[Telegram] Successfully paired with Chat ID: ${ctx.chat?.id}`));
|
|
105
105
|
return; // Done parsing auth, ignore this specific message for further logic
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
|
-
await ctx.reply('❌ PIN
|
|
108
|
+
await ctx.reply('❌ Incorrect PIN.');
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -115,7 +115,7 @@ function startTelegramBot() {
|
|
|
115
115
|
});
|
|
116
116
|
bot.command('clear', async (ctx) => {
|
|
117
117
|
reasoning_1.logger.clear(ctx.chat?.id.toString());
|
|
118
|
-
await ctx.reply(
|
|
118
|
+
await ctx.reply("✅ AI memory has been cleared. Let's start a new chat!");
|
|
119
119
|
});
|
|
120
120
|
bot.on('text', async (ctx) => {
|
|
121
121
|
const text = ctx.message.text;
|
|
@@ -216,17 +216,7 @@ function startTelegramBot() {
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
transactionManager_1.txManager.updateStatus(txId, 'executed', result);
|
|
219
|
-
|
|
220
|
-
const sessionId = ctx.chat?.id.toString() || 'default';
|
|
221
|
-
const history = reasoning_1.logger.getHistory(sessionId);
|
|
222
|
-
let isIndonesian = false;
|
|
223
|
-
if (history.length > 0) {
|
|
224
|
-
const lastMsg = history[history.length - 1].content.toLowerCase();
|
|
225
|
-
const idWords = ['saya', 'kamu', 'aku', 'apa', 'bagaimana', 'kenapa', 'bisa', 'tolong', 'ke', 'di', 'dari', 'yang', 'ini', 'itu', 'buat', 'cek', 'saldo'];
|
|
226
|
-
if (idWords.some(w => lastMsg.includes(w)))
|
|
227
|
-
isIndonesian = true;
|
|
228
|
-
}
|
|
229
|
-
const prettyMsg = (0, formatter_1.formatTransactionSuccess)(tx, result, isIndonesian);
|
|
219
|
+
const prettyMsg = (0, formatter_1.formatTransactionSuccess)(tx, result);
|
|
230
220
|
await ctx.reply(formatToTelegramHTML(`✅ **Transaction processed: Success**\n\n${prettyMsg}`), { parse_mode: 'HTML' });
|
|
231
221
|
(0, reasoning_1.processUserInput)(`Transaction ${txId} was APPROVED via Telegram. Result: ${result}`, 'system', undefined, ctx.chat?.id.toString()).catch(() => { });
|
|
232
222
|
}
|
|
@@ -6,28 +6,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.updateSecurityPolicyToolDefinition = void 0;
|
|
7
7
|
exports.updateSecurityPolicy = updateSecurityPolicy;
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const yaml_1 = __importDefault(require("yaml"));
|
|
9
10
|
const paths_1 = require("../../config/paths");
|
|
10
11
|
function updateSecurityPolicy(rule, action) {
|
|
11
12
|
try {
|
|
12
|
-
const policyPath = (0, paths_1.getPath)('
|
|
13
|
-
let
|
|
13
|
+
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
14
|
+
let policyRules = { max_usd_per_tx: 999999999, whitelist_only: false, require_approval: true, custom_llm_rules: [] };
|
|
14
15
|
if (fs_1.default.existsSync(policyPath)) {
|
|
15
|
-
|
|
16
|
+
const file = fs_1.default.readFileSync(policyPath, 'utf8');
|
|
17
|
+
policyRules = { ...policyRules, ...(yaml_1.default.parse(file) || {}) };
|
|
18
|
+
}
|
|
19
|
+
if (!Array.isArray(policyRules.custom_llm_rules)) {
|
|
20
|
+
policyRules.custom_llm_rules = [];
|
|
16
21
|
}
|
|
17
22
|
if (action === 'clear') {
|
|
18
|
-
|
|
23
|
+
policyRules.custom_llm_rules = [];
|
|
24
|
+
fs_1.default.writeFileSync(policyPath, yaml_1.default.stringify(policyRules), 'utf8');
|
|
19
25
|
return "Security policy cleared.";
|
|
20
26
|
}
|
|
21
27
|
else if (action === 'add') {
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
if (!policyRules.custom_llm_rules.includes(rule)) {
|
|
29
|
+
policyRules.custom_llm_rules.push(rule);
|
|
30
|
+
}
|
|
31
|
+
fs_1.default.writeFileSync(policyPath, yaml_1.default.stringify(policyRules), 'utf8');
|
|
24
32
|
return `Rule added to security policy: ${rule}`;
|
|
25
33
|
}
|
|
26
34
|
else if (action === 'remove') {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const filtered = lines.filter(l => !l.includes(rule));
|
|
30
|
-
fs_1.default.writeFileSync(policyPath, filtered.join('\n'), 'utf8');
|
|
35
|
+
policyRules.custom_llm_rules = policyRules.custom_llm_rules.filter((r) => !r.includes(rule));
|
|
36
|
+
fs_1.default.writeFileSync(policyPath, yaml_1.default.stringify(policyRules), 'utf8');
|
|
31
37
|
return `Rule removed (if it existed).`;
|
|
32
38
|
}
|
|
33
39
|
return "Invalid action.";
|
|
@@ -40,7 +46,7 @@ exports.updateSecurityPolicyToolDefinition = {
|
|
|
40
46
|
type: "function",
|
|
41
47
|
function: {
|
|
42
48
|
name: "update_security_policy",
|
|
43
|
-
description: "Updates the
|
|
49
|
+
description: "Updates the custom_llm_rules array in policy.yaml to restrict your own autonomous behavior. Use this when the user explicitly forbids you from doing something.",
|
|
44
50
|
parameters: {
|
|
45
51
|
type: "object",
|
|
46
52
|
properties: {
|