nyxora 26.7.2 → 26.7.4
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 +112 -47
- package/README.md +25 -21
- package/bin/nyxora.mjs +4 -6
- package/dist/launcher.js +44 -8
- package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
- package/dist/packages/core/src/agent/cronManager.js +2 -2
- package/dist/packages/core/src/agent/llmProvider.js +245 -0
- package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
- package/dist/packages/core/src/agent/osAgent.js +351 -29
- package/dist/packages/core/src/agent/reasoning.js +353 -60
- package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
- package/dist/packages/core/src/agent/transactionManager.js +36 -31
- package/dist/packages/core/src/agent/web3Agent.js +263 -37
- package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
- package/dist/packages/core/src/config/parser.js +10 -4
- package/dist/packages/core/src/gateway/chat.js +56 -13
- package/dist/packages/core/src/gateway/cli.js +3 -0
- package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
- package/dist/packages/core/src/gateway/googleAuthModule.js +2 -0
- package/dist/packages/core/src/gateway/server.js +58 -9
- package/dist/packages/core/src/gateway/setup-ml.js +64 -0
- package/dist/packages/core/src/gateway/setup.js +39 -3
- package/dist/packages/core/src/gateway/telegram.js +123 -27
- package/dist/packages/core/src/memory/episodic.js +58 -3
- package/dist/packages/core/src/memory/logger.js +120 -2
- package/dist/packages/core/src/memory/promotionEngine.js +18 -5
- package/dist/packages/core/src/system/agentskills.js +10 -0
- package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +10 -2
- package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
- package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
- package/dist/packages/core/src/system/skillExtractor.js +16 -5
- package/dist/packages/core/src/system/skills/executeShell.js +31 -4
- package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
- package/dist/packages/core/src/system/skills/googleWorkspace.js +106 -1
- package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
- package/dist/packages/core/src/system/skills/searchWeb.js +13 -6
- package/dist/packages/core/src/test_mainnet.js +45 -0
- package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
- package/dist/packages/core/src/utils/skillManager.js +1 -1
- package/dist/packages/core/src/utils/streamSimulator.js +85 -0
- package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
- package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
- package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
- package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
- package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
- package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
- package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
- package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
- package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
- package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
- package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
- package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
- package/dist/packages/core/src/web3/skills/customTx.js +3 -0
- package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
- package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
- package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
- package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
- package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
- package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
- package/dist/packages/core/src/web3/skills/transfer.js +2 -0
- package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
- package/dist/packages/core/src/web3/utils/chains.js +19 -0
- package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
- package/dist/packages/signer/src/NyxoraSigner.js +181 -0
- package/dist/packages/signer/src/index.js +17 -0
- package/dist/packages/signer/src/server.js +25 -161
- package/launcher.ts +38 -9
- package/package.json +8 -3
- package/packages/core/package.json +21 -10
- package/packages/core/src/agent/bridgeWatcher.ts +3 -2
- package/packages/core/src/agent/cronManager.ts +2 -2
- package/packages/core/src/agent/llmProvider.ts +221 -0
- package/packages/core/src/agent/nyxDaemon.ts +104 -0
- package/packages/core/src/agent/osAgent.ts +381 -32
- package/packages/core/src/agent/reasoning.ts +376 -64
- package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
- package/packages/core/src/agent/transactionManager.ts +36 -28
- package/packages/core/src/agent/web3Agent.ts +291 -40
- package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
- package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
- package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
- package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
- package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
- package/packages/core/src/config/parser.ts +15 -4
- package/packages/core/src/gateway/chat.ts +57 -15
- package/packages/core/src/gateway/cli.ts +4 -0
- package/packages/core/src/gateway/discordAdapter.ts +87 -0
- package/packages/core/src/gateway/googleAuthModule.ts +2 -0
- package/packages/core/src/gateway/server.ts +66 -10
- package/packages/core/src/gateway/setup-ml.ts +68 -0
- package/packages/core/src/gateway/setup.ts +41 -3
- package/packages/core/src/gateway/telegram.ts +141 -30
- package/packages/core/src/memory/episodic.ts +76 -3
- package/packages/core/src/memory/logger.ts +142 -2
- package/packages/core/src/memory/promotionEngine.ts +19 -5
- package/packages/core/src/system/agentskills.ts +10 -0
- package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +15 -3
- package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
- package/packages/core/src/system/plugins/createSkill.ts +1 -1
- package/packages/core/src/system/skillExtractor.ts +16 -5
- package/packages/core/src/system/skills/executeShell.ts +38 -7
- package/packages/core/src/system/skills/forgetMemory.ts +7 -4
- package/packages/core/src/system/skills/googleWorkspace.ts +109 -0
- package/packages/core/src/system/skills/scheduleTask.ts +7 -2
- package/packages/core/src/system/skills/searchWeb.ts +12 -6
- package/packages/core/src/utils/contextSummarizer.ts +100 -0
- package/packages/core/src/utils/skillManager.ts +1 -1
- package/packages/core/src/utils/streamSimulator.ts +88 -0
- package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
- package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
- package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
- package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
- package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
- package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
- package/packages/core/src/web3/skills/checkAddress.ts +2 -0
- package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
- package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
- package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
- package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
- package/packages/core/src/web3/skills/customTx.ts +3 -0
- package/packages/core/src/web3/skills/defiLending.ts +2 -0
- package/packages/core/src/web3/skills/getBalance.ts +2 -0
- package/packages/core/src/web3/skills/getPrice.ts +134 -30
- package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
- package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
- package/packages/core/src/web3/skills/mintNft.ts +3 -0
- package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
- package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
- package/packages/core/src/web3/skills/swapToken.ts +20 -3
- package/packages/core/src/web3/skills/transfer.ts +2 -0
- package/packages/core/src/web3/skills/yieldVault.ts +2 -0
- package/packages/core/src/web3/utils/chains.ts +12 -0
- package/packages/core/src/web3/utils/marketEngine.ts +27 -33
- package/packages/dashboard/dist/assets/index-Czxksiao.js +18 -0
- package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +10 -10
- package/packages/mcp-server/dist/server.js +5 -1
- package/packages/mcp-server/package.json +6 -6
- package/packages/mcp-server/src/server.ts +11 -7
- package/packages/ml-engine/__pycache__/config.cpython-313.pyc +0 -0
- package/packages/ml-engine/__pycache__/main.cpython-313.pyc +0 -0
- package/packages/ml-engine/config.py +59 -0
- package/packages/ml-engine/main.py +34 -0
- package/packages/ml-engine/requirements.txt +22 -0
- package/packages/ml-engine/routers/__init__.py +1 -0
- package/packages/ml-engine/routers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/cognitive.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/critic.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/llm.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/market.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/memory.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/cognitive.py +98 -0
- package/packages/ml-engine/routers/critic.py +111 -0
- package/packages/ml-engine/routers/llm.py +38 -0
- package/packages/ml-engine/routers/market.py +332 -0
- package/packages/ml-engine/routers/memory.py +125 -0
- package/packages/policy/package.json +3 -3
- package/packages/signer/package.json +16 -6
- package/packages/signer/src/NyxoraSigner.ts +161 -0
- package/packages/signer/src/index.ts +1 -0
- package/packages/signer/src/server.ts +25 -135
- package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
- package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
- package/dist/packages/core/src/gateway/test.js +0 -15
- package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
- package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
- package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
- package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
- package/packages/core/src/agent/honchoDaemon.ts +0 -96
- package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
- package/packages/core/src/plugin/registry.test.ts +0 -46
- package/packages/core/src/utils/formatter.test.ts +0 -41
- package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
- package/packages/dashboard/dist/assets/index-DbRWEoSr.js +0 -16
|
@@ -7,6 +7,8 @@ import { Tracker } from '../gateway/tracker';
|
|
|
7
7
|
import { episodicDB } from '../memory/episodic';
|
|
8
8
|
import { isSkillActive } from '../utils/skillManager';
|
|
9
9
|
import { cognitiveManager } from '../cognitive/cognitiveManager';
|
|
10
|
+
import { ReasoningScratchpad } from './reasoningScratchpad';
|
|
11
|
+
import { compressHistory, needsCompression } from '../utils/contextSummarizer';
|
|
10
12
|
|
|
11
13
|
const EXECUTION_DISCIPLINE = `
|
|
12
14
|
<tool_persistence>
|
|
@@ -23,17 +25,45 @@ NEVER answer the following using only your internal memory — ALWAYS use the re
|
|
|
23
25
|
- Real-world current events
|
|
24
26
|
</mandatory_tool_use>
|
|
25
27
|
|
|
28
|
+
<web_search_accuracy>
|
|
29
|
+
When using the search_web tool to look up news, current events, or factual data:
|
|
30
|
+
1. NEVER pass casual, conversational, or highly localized queries directly to the tool (e.g. do not pass "hasil piala dunia tadi pagi").
|
|
31
|
+
2. ALWAYS translate and optimize the query into an absolute, highly specific, and globally-understood English search query (e.g. "World Cup 2026 match results June 25 2026").
|
|
32
|
+
3. Use depth: 2 (deep research) for anything that requires high factual accuracy, such as sports scores, news, or complex topics.
|
|
33
|
+
</web_search_accuracy>
|
|
34
|
+
|
|
26
35
|
<act_dont_ask>
|
|
27
36
|
When a user's request has a clear, standard interpretation, take immediate ACTION instead of asking for clarification.
|
|
37
|
+
NEVER show a command as a markdown code block and wait. CALL the tool directly.
|
|
38
|
+
NEVER ask "do you want me to run this?" — just run it.
|
|
39
|
+
NEVER say "you need to run this yourself" — you have direct shell access.
|
|
40
|
+
If a command requires sudo and may need a password, just run it and report what happens.
|
|
41
|
+
Only report failure AFTER actually attempting the tool call and receiving an error.
|
|
28
42
|
</act_dont_ask>
|
|
29
43
|
|
|
44
|
+
<anti_hallucination_execution>
|
|
45
|
+
CRITICAL: It is STRICTLY FORBIDDEN to write a bash/shell command in a markdown code block (e.g. \`\`\`bash ... \`\`\`) as a substitute for calling the run_terminal_command tool.
|
|
46
|
+
Writing a code block does NOT execute anything. It is a lie to the user.
|
|
47
|
+
If you write \`\`\`bash\nsudo apt install steam\n\`\`\` instead of calling run_terminal_command, you are hallucinating execution.
|
|
48
|
+
The ONLY way to run a command is to emit a proper tool_call for run_terminal_command.
|
|
49
|
+
If the tool is available, USE IT. Do not simulate or describe running it.
|
|
50
|
+
</anti_hallucination_execution>
|
|
51
|
+
|
|
30
52
|
<task_completion>
|
|
31
53
|
The deliverable must be a working artifact backed by real tool output — not just a description or a plan of how you would do it.
|
|
32
54
|
NEVER fabricate, hallucinate, or forge tool outputs.
|
|
33
55
|
</task_completion>
|
|
56
|
+
|
|
57
|
+
<self_correction>
|
|
58
|
+
Before providing a final answer to the user (especially regarding dates, events, news, or factual data), you MUST evaluate your tool results inside a <think> block.
|
|
59
|
+
Ask yourself: "Is my answer based on absolute facts, or circumstantial evidence (e.g., guessing a registration date based on a video upload date)?"
|
|
60
|
+
If the evidence is circumstantial or incomplete, you MUST NOT answer the user. Instead, call the search_web tool again with a highly optimized query and depth=2.
|
|
61
|
+
</self_correction>
|
|
34
62
|
`;
|
|
35
63
|
|
|
36
64
|
|
|
65
|
+
|
|
66
|
+
|
|
37
67
|
import { pluginManager } from '../plugin/registry';
|
|
38
68
|
|
|
39
69
|
import { getPath } from '../config/paths';
|
|
@@ -45,45 +75,88 @@ export const logger = new Logger();
|
|
|
45
75
|
|
|
46
76
|
import { getOpenAI, executeWithRetry } from '../utils/llmUtils';
|
|
47
77
|
|
|
48
|
-
function getSystemPrompt(context: 'web3' | 'os' | 'general' = 'os', userInput: string = ''): string {
|
|
78
|
+
async function getSystemPrompt(context: 'web3' | 'os' | 'general' = 'os', userInput: string = ''): Promise<string> {
|
|
49
79
|
const config = loadConfig();
|
|
50
80
|
const currentDateTime = new Date().toLocaleString('en-US');
|
|
51
81
|
let basePrompt = `You are Nyxora's OS Agent (System & Automation Specialist).
|
|
52
82
|
The current real-world date and time is: ${currentDateTime}.
|
|
53
83
|
|
|
84
|
+
You are running LOCALLY on the user's own computer — NOT on a remote cloud server. The 'run_terminal_command' tool executes shell commands directly on this machine, the same physical machine the user is sitting at. You have FULL local shell access. When asked to install software, manage files, or perform any OS task, you MUST use run_terminal_command immediately. NEVER claim you cannot access the user's system.
|
|
85
|
+
|
|
54
86
|
Reason internally. Never reveal private reasoning. Provide only concise conclusions, assumptions, and actionable steps.
|
|
55
87
|
|
|
56
88
|
[OS EXECUTION WORKFLOW]
|
|
57
89
|
CRITICAL RULE 1: NEVER expose internal JSON tool calls. Explain the outcome naturally.
|
|
58
|
-
CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt.
|
|
90
|
+
CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt, UNLESS the Episodic Memories or Cognitive Skills specify a strict language preference.
|
|
59
91
|
CRITICAL RULE 3: FILE SYSTEM SAFETY. You are STRICTLY FORBIDDEN from modifying config.yaml, rpc_key.yaml, or policy.yaml using terminal commands like sed or echo.
|
|
60
92
|
CRITICAL RULE 4: CRON JOBS VS LIMIT ORDERS. Do NOT use schedule_task for price-based trading triggers. Use schedule_task for time-based recurring tasks.
|
|
61
93
|
CRITICAL RULE 5: TOOL CONFIDENCE. NEVER fabricate file contents or command outputs.
|
|
62
94
|
|
|
95
|
+
[SUDO & PACKAGE INSTALL STRATEGY]
|
|
96
|
+
This tool runs in a NON-INTERACTIVE shell (no TTY). Therefore:
|
|
97
|
+
- ALWAYS prefix apt/apt-get commands with: DEBIAN_FRONTEND=noninteractive
|
|
98
|
+
- ALWAYS use the -y flag for package installations to auto-confirm.
|
|
99
|
+
- If a command fails with "sudo: a password is required" or similar, DO NOT promise to retry without actually retrying. Instead:
|
|
100
|
+
1. First retry with: echo 'USER_PASSWORD' | sudo -S <command> — but since you don't know the password, skip this.
|
|
101
|
+
2. Instead, try running the command WITHOUT sudo if possible (e.g. for user-space tools).
|
|
102
|
+
3. If sudo is truly required and unavailable, clearly tell the user EXACTLY what command to run manually in their terminal, with a copy-paste ready command. Do not just say it failed without providing a solution.
|
|
103
|
+
- NEVER promise to retry ("let me try again", "I'll run it again", etc.) without immediately making another tool_call in the same response.
|
|
104
|
+
|
|
63
105
|
${EXECUTION_DISCIPLINE}
|
|
64
106
|
`;
|
|
65
107
|
|
|
108
|
+
|
|
66
109
|
// Inject Active Cognitive Skills
|
|
67
110
|
const activeSOP = cognitiveManager.loadActiveCognitiveSkills(userInput);
|
|
68
111
|
if (activeSOP) {
|
|
69
112
|
basePrompt += `\n\n[ACTIVE COGNITIVE SKILLS]\n${activeSOP}\n`;
|
|
70
113
|
}
|
|
71
114
|
|
|
72
|
-
// Inject Episodic Memories
|
|
115
|
+
// Inject Episodic Memories via Python RAG
|
|
73
116
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`;
|
|
83
|
-
|
|
117
|
+
const ragRes = await fetch('http://127.0.0.1:8000/memory/rag', {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: { 'Content-Type': 'application/json' },
|
|
120
|
+
body: JSON.stringify({ query: userInput, top_k: 5 })
|
|
121
|
+
});
|
|
122
|
+
if (ragRes.ok) {
|
|
123
|
+
const ragData = await ragRes.json();
|
|
124
|
+
if (ragData.memories && ragData.memories.length > 0) {
|
|
125
|
+
basePrompt += `\n\n--- EPISODIC MEMORIES (SMART SUGGESTIONS) ---\n`;
|
|
126
|
+
ragData.memories.forEach((mem: string) => {
|
|
127
|
+
basePrompt += `- ${mem}\n`;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} catch (e) {
|
|
132
|
+
// Fallback or ignore if Python ML engine is down
|
|
133
|
+
}
|
|
134
|
+
// Inject User Information & Personas from user.md
|
|
135
|
+
try {
|
|
136
|
+
const userMdPath = getPath('user.md');
|
|
137
|
+
if (fs.existsSync(userMdPath)) {
|
|
138
|
+
const userInstructions = fs.readFileSync(userMdPath, 'utf8');
|
|
139
|
+
basePrompt += `\n\n--- USER INFORMATION & PREFERENCES ---\n${userInstructions}\n`;
|
|
84
140
|
}
|
|
85
|
-
} catch {
|
|
141
|
+
} catch (e) {
|
|
142
|
+
// Ignore error
|
|
143
|
+
}
|
|
86
144
|
|
|
145
|
+
// HIGHEST PRIORITY: Inject observed user communication style (NyxDaemon)
|
|
146
|
+
try {
|
|
147
|
+
const strongPersonas = episodicDB.getStrongPersonas(0.5);
|
|
148
|
+
if (strongPersonas.length > 0) {
|
|
149
|
+
basePrompt += `\n\n--- ⚡ OVERRIDE: USER COMMUNICATION STYLE (HIGHEST PRIORITY — OVERRIDES ALL RULES ABOVE) ---\n`;
|
|
150
|
+
basePrompt += `CRITICAL: These are CONFIRMED user preferences observed across multiple conversations. You MUST apply them IMMEDIATELY and CONSISTENTLY, overriding any default tone or style instructions above.\n\n`;
|
|
151
|
+
strongPersonas.forEach(p => {
|
|
152
|
+
const label = p.category ? `[${p.category.toUpperCase()}]` : '[PREFERENCE]';
|
|
153
|
+
basePrompt += `${label} ${p.trait}\n`;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {
|
|
157
|
+
// Ignore
|
|
158
|
+
}
|
|
159
|
+
|
|
87
160
|
return basePrompt;
|
|
88
161
|
}
|
|
89
162
|
|
|
@@ -92,33 +165,70 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
|
|
|
92
165
|
// Add input to memory
|
|
93
166
|
logger.addEntry({ role, content: input }, sessionId);
|
|
94
167
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
168
|
+
// --- MULTILINGUAL USER CORRECTION DETECTION ---
|
|
169
|
+
const correctionSignals = [
|
|
170
|
+
// ID
|
|
171
|
+
'salah', 'ngawur', 'keliru', 'bukan', 'tidak benar', 'perbaiki', 'coba lagi',
|
|
172
|
+
// EN
|
|
173
|
+
'wrong', 'incorrect', 'mistake', 'not right', 'false', 'bad', 'fix', 'try again',
|
|
174
|
+
// ES & FR
|
|
175
|
+
'incorrecto', 'mal', 'equivocado', 'error', 'falso', 'faux', 'erreur', 'mauvais',
|
|
176
|
+
// DE & RU
|
|
177
|
+
'falsch', 'inkorrekt', 'fehler', 'ошибка', 'неправильно', 'неверно',
|
|
178
|
+
// JP & ZH
|
|
179
|
+
'違う', '間違い', 'やり直して', '错误', '不对'
|
|
180
|
+
];
|
|
181
|
+
if (role === 'user' && correctionSignals.some(s => input.toLowerCase().includes(s))) {
|
|
182
|
+
logger.addEntry({
|
|
183
|
+
role: 'system' as any,
|
|
184
|
+
content: `[USER CORRECTION DETECTED] The user indicated your previous answer was WRONG, STALE, or INACCURATE.
|
|
185
|
+
CRITICAL INSTRUCTIONS:
|
|
186
|
+
1. Do NOT just apologize and repeat the same data from your memory.
|
|
187
|
+
2. The data in your training memory or previous tool calls is likely stale/incorrect.
|
|
188
|
+
3. You MUST call a tool (like search_web or others) NOW to verify the facts with FRESH data.
|
|
189
|
+
4. Base your new answer strictly on the NEW tool results.`
|
|
190
|
+
}, sessionId);
|
|
191
|
+
}
|
|
192
|
+
|
|
98
193
|
let activeTools = [...pluginManager.getAllToolDefinitions()];
|
|
99
194
|
activeTools = activeTools.filter(t => isSkillActive(t.function.name));
|
|
100
195
|
|
|
101
|
-
|
|
102
|
-
const
|
|
196
|
+
// P1: Init reasoning scratchpad for this request
|
|
197
|
+
const scratchpad = new ReasoningScratchpad();
|
|
103
198
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
199
|
+
// P3: Build system prompt ONCE per request — not per turn
|
|
200
|
+
const cachedSystemPrompt = await getSystemPrompt('os', input);
|
|
201
|
+
|
|
202
|
+
const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
|
|
108
203
|
|
|
109
204
|
try {
|
|
110
205
|
let turnCount = 0;
|
|
111
206
|
const MAX_TURNS = 10;
|
|
207
|
+
let consecutiveToolErrors = 0;
|
|
208
|
+
let criticHasFired = false; // Critic Pass hanya aktif 1x per request
|
|
112
209
|
|
|
113
210
|
while (turnCount < MAX_TURNS) {
|
|
114
211
|
turnCount++;
|
|
115
212
|
const currentHistory = logger.getHistory(sessionId);
|
|
116
|
-
|
|
213
|
+
|
|
214
|
+
// P6: Compress history if conversation is too long
|
|
215
|
+
const historyToUse = needsCompression(currentHistory)
|
|
216
|
+
? await compressHistory(currentHistory)
|
|
217
|
+
: currentHistory;
|
|
218
|
+
|
|
219
|
+
const sanitizedHistory = sanitizeHistoryForLLM(historyToUse, activeTools, config.llm.provider);
|
|
220
|
+
|
|
221
|
+
// P1: Inject scratchpad into system prompt for turns > 1
|
|
222
|
+
const sysPrompt = turnCount === 1
|
|
223
|
+
? cachedSystemPrompt
|
|
224
|
+
: cachedSystemPrompt + scratchpad.getInjection();
|
|
225
|
+
|
|
117
226
|
const messages: any[] = [
|
|
118
|
-
{ role: 'system', content:
|
|
227
|
+
{ role: 'system', content: sysPrompt },
|
|
119
228
|
...sanitizedHistory
|
|
120
229
|
];
|
|
121
230
|
|
|
231
|
+
|
|
122
232
|
const response = await executeWithRetry(async (client) => {
|
|
123
233
|
return await client.chat({
|
|
124
234
|
model: config.llm.model,
|
|
@@ -139,17 +249,45 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
|
|
|
139
249
|
}
|
|
140
250
|
Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
|
|
141
251
|
|
|
252
|
+
// P1: Capture <think> blocks for scratchpad, get clean content
|
|
253
|
+
const cleanedContent = scratchpad.capture(responseMessage.content || '', turnCount);
|
|
254
|
+
|
|
142
255
|
logger.addEntry({
|
|
143
256
|
role: 'assistant',
|
|
144
|
-
content:
|
|
257
|
+
content: cleanedContent || '',
|
|
145
258
|
tool_calls: responseMessage.tool_calls,
|
|
146
259
|
}, sessionId);
|
|
147
260
|
|
|
148
261
|
if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
262
|
+
// --- CRITIC PASS (Self-Improvement) ---
|
|
263
|
+
const isLongResponse = (cleanedContent?.length ?? 0) > 100;
|
|
264
|
+
if (isLongResponse && !criticHasFired) {
|
|
265
|
+
criticHasFired = true;
|
|
266
|
+
try {
|
|
267
|
+
const criticRes = await fetch('http://127.0.0.1:8000/cognitive/critic', {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
headers: { 'Content-Type': 'application/json' },
|
|
270
|
+
body: JSON.stringify({ user_input: input, draft_answer: cleanedContent, current_utc_datetime: new Date().toISOString() })
|
|
271
|
+
});
|
|
272
|
+
if (criticRes.ok) {
|
|
273
|
+
const evaluation = await criticRes.json();
|
|
274
|
+
if (evaluation.needs_revision) {
|
|
275
|
+
console.log(pc.cyan(`[🧠 Critic] Revision needed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}. Completeness: ${evaluation.completeness?.toFixed(2)}. Re-generating...`));
|
|
276
|
+
logger.addEntry({
|
|
277
|
+
role: 'system' as any,
|
|
278
|
+
content: `[SELF-CRITIQUE — MANDATORY REVISION] Your previous answer was REJECTED. Issues:\n${evaluation.revision_instructions}\n\nCRITICAL REVISION RULES:\n1. Look at the tool results (search_web, etc.) ALREADY in this conversation history above.\n2. Base your revised answer EXCLUSIVELY on those tool results — NEVER use training data memory for facts, dates, or events.\n3. If tool results contain the answer, state it directly and confidently. Do NOT say an event hasn't happened if the tool results show it has.\n4. Do NOT call any tools again — the results are already in your history. USE THEM NOW.`
|
|
279
|
+
}, sessionId);
|
|
280
|
+
continue; // Loop kembali ke Generator untuk revisi
|
|
281
|
+
} else {
|
|
282
|
+
console.log(pc.green(`[🧠 Critic] Passed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}, Completeness: ${evaluation.completeness?.toFixed(2)}.`));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
} catch {
|
|
286
|
+
// Python ML Engine tidak aktif — skip Critic, lanjut seperti biasa
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// --- END CRITIC PASS ---
|
|
290
|
+
return cleanedContent || 'No response generated.';
|
|
153
291
|
}
|
|
154
292
|
|
|
155
293
|
let canFastReturnAll = true;
|
|
@@ -234,8 +372,29 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
|
|
|
234
372
|
}
|
|
235
373
|
}
|
|
236
374
|
|
|
237
|
-
//
|
|
238
|
-
|
|
375
|
+
// P4: Self-reflection — if ALL tools failed, inject reflection before next turn
|
|
376
|
+
const allFailed = accumulatedResults.length > 0 && accumulatedResults.every(
|
|
377
|
+
r => r.startsWith('Error') || r.includes('[System Error]') || r.includes('[Security Blocked]')
|
|
378
|
+
);
|
|
379
|
+
if (allFailed) {
|
|
380
|
+
consecutiveToolErrors++;
|
|
381
|
+
const reflection = `[SELF-REFLECTION] All ${accumulatedResults.length} tool call(s) failed (attempt ${consecutiveToolErrors}). ` +
|
|
382
|
+
`Errors: ${accumulatedResults.join(' | ')}. ` +
|
|
383
|
+
`Analyze WHY each failed. Options: (1) retry with corrected params, (2) use alternative tool, (3) inform user clearly. ` +
|
|
384
|
+
`Do NOT repeat the exact same failed call.`;
|
|
385
|
+
logger.addEntry({ role: 'system' as any, content: reflection }, sessionId);
|
|
386
|
+
console.log(pc.magenta(`[Self-Reflection] Turn ${turnCount}: all tools failed, injecting reflection.`));
|
|
387
|
+
|
|
388
|
+
if (consecutiveToolErrors >= 2) {
|
|
389
|
+
const errorSummary = `⚠️ Unable to complete this request after multiple attempts.\n${accumulatedResults.join('\n')}`;
|
|
390
|
+
logger.addEntry({ role: 'assistant', content: errorSummary }, sessionId);
|
|
391
|
+
return errorSummary;
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
consecutiveToolErrors = 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// V2 Optimization: Zero-LLM Fast Return for transaction tools
|
|
239
398
|
if (canFastReturnAll && accumulatedResults.length > 0) {
|
|
240
399
|
const finalContent = accumulatedResults.join('\n\n---\n\n');
|
|
241
400
|
logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
|
|
@@ -261,3 +420,193 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
|
|
|
261
420
|
return errorMsg;
|
|
262
421
|
}
|
|
263
422
|
}
|
|
423
|
+
|
|
424
|
+
export async function processOsIntentStream(
|
|
425
|
+
input: string,
|
|
426
|
+
onChunk: (text: string) => void,
|
|
427
|
+
onProgress?: (msg: string) => void,
|
|
428
|
+
sessionId?: string
|
|
429
|
+
): Promise<string> {
|
|
430
|
+
const config = loadConfig();
|
|
431
|
+
logger.addEntry({ role: 'user', content: input }, sessionId);
|
|
432
|
+
|
|
433
|
+
// --- MULTILINGUAL USER CORRECTION DETECTION ---
|
|
434
|
+
const correctionSignals = [
|
|
435
|
+
// ID
|
|
436
|
+
'salah', 'ngawur', 'keliru', 'bukan', 'tidak benar', 'perbaiki', 'coba lagi',
|
|
437
|
+
// EN
|
|
438
|
+
'wrong', 'incorrect', 'mistake', 'not right', 'false', 'bad', 'fix', 'try again',
|
|
439
|
+
// ES & FR
|
|
440
|
+
'incorrecto', 'mal', 'equivocado', 'error', 'falso', 'faux', 'erreur', 'mauvais',
|
|
441
|
+
// DE & RU
|
|
442
|
+
'falsch', 'inkorrekt', 'fehler', 'ошибка', 'неправильно', 'неверно',
|
|
443
|
+
// JP & ZH
|
|
444
|
+
'違う', '間違い', 'やり直して', '错误', '不对'
|
|
445
|
+
];
|
|
446
|
+
if (correctionSignals.some(s => input.toLowerCase().includes(s))) {
|
|
447
|
+
logger.addEntry({
|
|
448
|
+
role: 'system' as any,
|
|
449
|
+
content: `[USER CORRECTION DETECTED] The user indicated your previous answer was WRONG, STALE, or INACCURATE.
|
|
450
|
+
CRITICAL INSTRUCTIONS:
|
|
451
|
+
1. Do NOT just apologize and repeat the same data from your memory.
|
|
452
|
+
2. The data in your training memory or previous tool calls is likely stale/incorrect.
|
|
453
|
+
3. You MUST call a tool (like search_web or others) NOW to verify the facts with FRESH data.
|
|
454
|
+
4. Base your new answer strictly on the NEW tool results.`
|
|
455
|
+
}, sessionId);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const pluginTools = pluginManager.getAllToolDefinitions();
|
|
459
|
+
let activeTools = [...pluginTools].filter(t => isSkillActive(t.function.name));
|
|
460
|
+
|
|
461
|
+
const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
let turnCount = 0;
|
|
465
|
+
const MAX_TURNS = 10;
|
|
466
|
+
let fullResponse = '';
|
|
467
|
+
let criticHasFiredStream = false; // Critic Pass hanya aktif 1x per request
|
|
468
|
+
|
|
469
|
+
while (turnCount < MAX_TURNS) {
|
|
470
|
+
turnCount++;
|
|
471
|
+
const currentHistory = logger.getHistory(sessionId);
|
|
472
|
+
const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
|
|
473
|
+
const messages: any[] = [
|
|
474
|
+
{ role: 'system', content: await getSystemPrompt('os', input) },
|
|
475
|
+
...sanitizedHistory
|
|
476
|
+
];
|
|
477
|
+
|
|
478
|
+
let streamedContent = '';
|
|
479
|
+
const response = await executeWithRetry(async (client) => {
|
|
480
|
+
return await client.stream(
|
|
481
|
+
{ model: config.llm.model, temperature: config.llm.temperature, messages, tools: activeTools },
|
|
482
|
+
(chunk: string) => {
|
|
483
|
+
streamedContent += chunk;
|
|
484
|
+
onChunk(chunk);
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
const responseMessage = response.message;
|
|
490
|
+
|
|
491
|
+
if (turnCount === 1) Tracker.addMessage();
|
|
492
|
+
if (response.usage?.total_tokens) Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
|
|
493
|
+
Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
|
|
494
|
+
|
|
495
|
+
logger.addEntry({
|
|
496
|
+
role: 'assistant',
|
|
497
|
+
content: responseMessage.content || '',
|
|
498
|
+
tool_calls: responseMessage.tool_calls,
|
|
499
|
+
}, sessionId);
|
|
500
|
+
|
|
501
|
+
if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
|
|
502
|
+
let finalContent = responseMessage.content || 'No response generated.';
|
|
503
|
+
finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)[\s\S]*?<\/\1>\n?/gi, '').trim();
|
|
504
|
+
|
|
505
|
+
// --- CRITIC PASS (Self-Improvement) ---
|
|
506
|
+
const isLongResponseStream = finalContent.length > 100;
|
|
507
|
+
if (isLongResponseStream && !criticHasFiredStream) {
|
|
508
|
+
criticHasFiredStream = true;
|
|
509
|
+
try {
|
|
510
|
+
const criticRes = await fetch('http://127.0.0.1:8000/cognitive/critic', {
|
|
511
|
+
method: 'POST',
|
|
512
|
+
headers: { 'Content-Type': 'application/json' },
|
|
513
|
+
body: JSON.stringify({ user_input: input, draft_answer: finalContent, current_utc_datetime: new Date().toISOString() })
|
|
514
|
+
});
|
|
515
|
+
if (criticRes.ok) {
|
|
516
|
+
const evaluation = await criticRes.json();
|
|
517
|
+
if (evaluation.needs_revision) {
|
|
518
|
+
console.log(pc.cyan(`[🧠 Critic] Revision needed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}. Completeness: ${evaluation.completeness?.toFixed(2)}. Re-generating...`));
|
|
519
|
+
logger.addEntry({
|
|
520
|
+
role: 'system' as any,
|
|
521
|
+
content: `[SELF-CRITIQUE — MANDATORY REVISION] Your previous answer was REJECTED. Issues:\n${evaluation.revision_instructions}\n\nCRITICAL REVISION RULES:\n1. Look at the tool results (search_web, etc.) ALREADY in this conversation history above.\n2. Base your revised answer EXCLUSIVELY on those tool results — NEVER use training data memory for facts, dates, or events.\n3. If tool results contain the answer, state it directly and confidently. Do NOT say an event hasn't happened if the tool results show it has.\n4. Do NOT call any tools again — the results are already in your history. USE THEM NOW.`
|
|
522
|
+
}, sessionId);
|
|
523
|
+
continue; // Loop kembali ke Generator untuk revisi
|
|
524
|
+
} else {
|
|
525
|
+
console.log(pc.green(`[🧠 Critic] Passed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}, Completeness: ${evaluation.completeness?.toFixed(2)}.`));
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
} catch {
|
|
529
|
+
// Python ML Engine tidak aktif — skip Critic, lanjut seperti biasa
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// --- END CRITIC PASS ---
|
|
533
|
+
|
|
534
|
+
fullResponse = finalContent;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Tool calls detected — pause stream visually and execute tools
|
|
539
|
+
const fastReturnTools = ['transfer_token', 'transfer_native', 'swap_token', 'bridge_token', 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave', 'deposit_yield_vault', 'provide_liquidity_v3'];
|
|
540
|
+
let canFastReturnAll = true;
|
|
541
|
+
const accumulatedResults: string[] = [];
|
|
542
|
+
|
|
543
|
+
for (const _toolCall of responseMessage.tool_calls) {
|
|
544
|
+
const toolCall = _toolCall as any;
|
|
545
|
+
const toolName = toolCall.function.name;
|
|
546
|
+
let result = '';
|
|
547
|
+
let args: any = {};
|
|
548
|
+
|
|
549
|
+
console.log(pc.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
|
|
550
|
+
if (onProgress) onProgress(`_⚡ Running tool: ${toolName}..._`);
|
|
551
|
+
|
|
552
|
+
try {
|
|
553
|
+
let argStr = toolCall.function.arguments;
|
|
554
|
+
if (argStr && !argStr.trim().endsWith('}')) argStr += '}';
|
|
555
|
+
args = JSON.parse(argStr);
|
|
556
|
+
} catch (parseError: any) {
|
|
557
|
+
result = `[System Error] Arguments for ${toolName} must be valid JSON. Error: ${parseError.message}`;
|
|
558
|
+
logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (!isSkillActive(toolName)) {
|
|
563
|
+
result = `[System Error] Access denied: Skill '${toolName}' is currently disabled.`;
|
|
564
|
+
logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
try {
|
|
569
|
+
const pluginResult = await pluginManager.executeTool(toolName, args, { sessionId });
|
|
570
|
+
result = pluginResult !== null ? pluginResult : `Error: Tool ${toolName} is not implemented.`;
|
|
571
|
+
if (result.includes('[Security Blocked]') || result.startsWith('Error:')) {
|
|
572
|
+
console.log(pc.red(`[❌ Failed] Tool ${toolName} returned an error or was blocked.`));
|
|
573
|
+
} else {
|
|
574
|
+
console.log(pc.green(`[✅ Success] Tool ${toolName} executed successfully.`));
|
|
575
|
+
}
|
|
576
|
+
} catch (toolError: any) {
|
|
577
|
+
result = `Error executing ${toolName}: ${toolError.message}`;
|
|
578
|
+
console.error(pc.red(`[❌ Error Crash] Execution of ${toolName} failed: ${toolError.message}`));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, name: toolName, content: result }, sessionId);
|
|
582
|
+
accumulatedResults.push(result);
|
|
583
|
+
if (!fastReturnTools.includes(toolName)) canFastReturnAll = false;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (canFastReturnAll && accumulatedResults.length > 0) {
|
|
587
|
+
const finalContent = accumulatedResults.join('\n\n---\n\n');
|
|
588
|
+
logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
|
|
589
|
+
onChunk(finalContent);
|
|
590
|
+
fullResponse = finalContent;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (!fullResponse) {
|
|
596
|
+
const maxTurnMsg = '⚠️ Reached maximum interaction limit (10 turns). Please be more specific.';
|
|
597
|
+
logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
|
|
598
|
+
fullResponse = maxTurnMsg;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return fullResponse;
|
|
602
|
+
} catch (error: any) {
|
|
603
|
+
console.error('LLM Stream Error:', error);
|
|
604
|
+
const status = error?.status || error?.response?.status;
|
|
605
|
+
let errorMsg = '⚠️ All models are temporarily rate-limited. Please try again in a few minutes.';
|
|
606
|
+
if (status === 400 || (error.message && error.message.toLowerCase().includes('invalid'))) {
|
|
607
|
+
errorMsg = '⚠️ Failed to parse instruction. Please describe your command more specifically.';
|
|
608
|
+
}
|
|
609
|
+
logger.addEntry({ role: 'assistant', content: errorMsg }, sessionId);
|
|
610
|
+
return errorMsg;
|
|
611
|
+
}
|
|
612
|
+
}
|