@krishivpb60/aether-ai-cli 1.4.0 → 1.4.2

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/HIGHLIGHTS.md CHANGED
@@ -1,3 +1,14 @@
1
+ # Aether CLI v1.4.2 Highlights
2
+ - **Mesh Error Transparency**:
3
+ - Implements dynamic offline fallback error alerts containing the exact error messages encountered by all failing provider nodes.
4
+ - Ensures Aether only states "No active API keys configured" if no keys are setup at all, rather than outputting it incorrectly upon network or API limit node failures.
5
+
6
+ # Aether CLI v1.4.1 Highlights
7
+ - **Krylo Companion Bot Removal**:
8
+ - Removes the fictional Krylo companion terminal response lines entirely from local failbacks and mesh failures.
9
+ - Retains and isolates the fast local offline Math solver fallback.
10
+ - Implements clean, professional offline/configuration error alerts when no API keys are active or fail to respond.
11
+
1
12
  # Aether CLI v1.4.0 Highlights
2
13
  - **Microphone Audio Input & Dynamic Nerd Font Glyphs (`/mic`)**:
3
14
  - Adds `/mic` voice command to record audio directly from your microphone inside the terminal session.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krishivpb60/aether-ai-cli",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "Aether Core AI — A cyberpunk command-line AI assistant with multi-mode reasoning, 12-node failover mesh, file context injection, and offline fallbacks.",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -1,17 +1,8 @@
1
1
  // ═══════════════════════════════════════════════════════════
2
2
  // AETHER AI CLI — Local Fallback Engine
3
- // Math Solver + Krylo Companion Bot
3
+ // Math Solver & Offline Fallback
4
4
  // ═══════════════════════════════════════════════════════════
5
5
 
6
- const KRYLO_REPLIES = [
7
- "Affirmative, commander. Systems are running at peak cybernetic capacity.",
8
- "Neon grids initialized. Matrix color modulates are at nominal density.",
9
- "Warning: Solar flare activity detected. Detuning audio synth harmonics by 18.4% to compensate.",
10
- "Neural nodes synchronized. Analyzing the portfolio's glassmorphic boundaries.",
11
- "I am Krylo, your holographic companion terminal. Ready to warp index nodes.",
12
- "Ecosystem diagnostics complete. 0 memory leaks, 100% premium responsive UI."
13
- ];
14
-
15
6
  /**
16
7
  * Detects if a prompt is a pure mathematical expression.
17
8
  * Supports basic operators, parentheses, standard math functions, and constants.
@@ -108,72 +99,29 @@ export function runMainframeHack() {
108
99
  }
109
100
 
110
101
  /**
111
- * Generates a local Krylo companion reply based on keywords.
102
+ * Generates a local offline/error reply when no AI keys are configured or fail.
112
103
  * @param {string} prompt - The user prompt
104
+ * @param {string[]} [errors] - Optional error messages from failed provider nodes
113
105
  * @returns {{ text: string, type: string }}
114
106
  */
115
- export function generateKryloReply(prompt) {
116
- const clean = prompt.toLowerCase();
117
-
118
- if (clean.includes("help") || clean.includes("shortcut") || clean.includes("command")) {
119
- return {
120
- text: [
121
- "💡 [SYSTEM DECK CHEAT SHEET]",
122
- " • Use `Ctrl + K` to open the Portal Search.",
123
- " • Use `Ctrl + Shift + L` to open the Links Directory.",
124
- " • Trigger Konami Code `↑↑↓↓←→←→BA` to launch Matrix mode!",
125
- " • Type `/mode <name>` to switch reasoning modes.",
126
- " • Type `/attach <file>` to inject file context.",
127
- " • Type `/export` to save the conversation.",
128
- ].join("\n"),
129
- type: "krylo-local",
130
- };
131
- }
132
-
133
- if (clean.includes("status") || clean.includes("hud") || clean.includes("cpu") || clean.includes("ping") || clean.includes("diagnostics")) {
107
+ export function generateOfflineReply(prompt, errors = []) {
108
+ if (errors && errors.length > 0) {
134
109
  return {
135
110
  text: [
136
- "📊 [LIVE DIAGNOSTIC READOUT]",
137
- " CPU Core Load: 15.4% (Optimized)",
138
- " • Ping Latency: 12ms (Hyper-Fast)",
139
- " • Memory Usage: 247MB / 8192MB",
140
- " Canvas Sparklines: Active and tracking vectors",
141
- " • Failover Mesh: All 12 nodes standing by",
111
+ "⚠️ All configured AI provider nodes failed to respond.",
112
+ " Errors encountered:",
113
+ ...errors.map((e) => ` • ${e}`),
114
+ "",
115
+ " Please check your API keys, network connection, or rate limits."
142
116
  ].join("\n"),
143
- type: "krylo-local",
117
+ type: "offline-error"
144
118
  };
145
119
  }
146
-
147
- if (clean.includes("matrix") || clean.includes("rain") || clean.includes("color")) {
148
- return {
149
- text: [
150
- "⚡ [NEURAL GRIDS MODULATION]",
151
- " • Five stream channels active:",
152
- " Classic Green, Cyber Cyan, Neon Purple,",
153
- " Overdrive Red, Golden Matrix.",
154
- " • Detuned Web Audio frequency active.",
155
- " • Matrix rain density: 94.2%",
156
- ].join("\n"),
157
- type: "krylo-local",
158
- };
159
- }
160
-
161
- if (clean.includes("who") || clean.includes("name") || clean.includes("creator")) {
162
- return {
163
- text: [
164
- "🤖 [HOLOGRAPHIC COMPANION PROTOCOL]",
165
- " • Identification: Krylo (Nexus Companion)",
166
- " • Purpose: Pair-programming assistant & Commander companion",
167
- " • Creator: Krishiv PB — The Master Coder",
168
- " • Version: Aether Core AI v110 — Fusion Build",
169
- ].join("\n"),
170
- type: "krylo-local",
171
- };
172
- }
173
-
174
- const index = Math.floor(Math.random() * KRYLO_REPLIES.length);
175
120
  return {
176
- text: `🤖 [KRYLO TERMINAL RESPONSE]\n ${KRYLO_REPLIES[index]}`,
177
- type: "krylo-local",
121
+ text: [
122
+ "⚠️ No active API keys configured. Please set GOOGLE_API_KEY, GROQ_API_KEY, or OPENAI_API_KEY in your config to start chatting.",
123
+ " Example: aether config set GOOGLE_API_KEY <your-key>"
124
+ ].join("\n"),
125
+ type: "offline-error"
178
126
  };
179
127
  }
package/src/ai/router.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Routes through ALL configured providers automatically
4
4
  // ═══════════════════════════════════════════════════════════
5
5
 
6
- import { detectMathExpression, solveMath, generateKryloReply } from "./fallback.js";
6
+ import { detectMathExpression, solveMath, generateOfflineReply } from "./fallback.js";
7
7
  import { PROVIDERS, getActiveProviders } from "./providers.js";
8
8
  import {
9
9
  callOpenAICompatible,
@@ -59,16 +59,16 @@ export async function routePrompt(prompt, systemPrompt, config, onToken, history
59
59
  }
60
60
  }
61
61
 
62
- // ── No providers configured → Krylo ────────────────────
62
+ // ── No providers configured → Offline ───────────────────
63
63
  if (active.length === 0) {
64
64
  const startTime = performance.now();
65
- const kryloReply = generateKryloReply(prompt);
65
+ const offlineReply = generateOfflineReply(prompt);
66
66
  const latencyMs = performance.now() - startTime;
67
67
  const pTokens = estimateTokens(systemPrompt + prompt);
68
- const cTokens = estimateTokens(kryloReply.text);
69
- const usage = recordTokenUsage("krylo-local", pTokens, cTokens);
70
- recordLatency("krylo-fallback", "local", latencyMs, pTokens, cTokens, true);
71
- return { ...kryloReply, provider: "krylo-fallback", node: 0, usage };
68
+ const cTokens = estimateTokens(offlineReply.text);
69
+ const usage = recordTokenUsage("offline-local", pTokens, cTokens);
70
+ recordLatency("offline-fallback", "local", latencyMs, pTokens, cTokens, true);
71
+ return { ...offlineReply, provider: "offline-fallback", node: 0, usage };
72
72
  }
73
73
 
74
74
  // ── Try each provider in order ──────────────────────────
@@ -128,17 +128,17 @@ export async function routePrompt(prompt, systemPrompt, config, onToken, history
128
128
  }
129
129
  }
130
130
 
131
- // ── Final Fallback: Krylo Companion ─────────────────────
132
- const startTimeKrylo = performance.now();
133
- const kryloReply = generateKryloReply(prompt);
134
- const latencyMsKrylo = performance.now() - startTimeKrylo;
131
+ // ── Final Fallback: Offline Fallback ────────────────────
132
+ const startTimeOffline = performance.now();
133
+ const offlineReply = generateOfflineReply(prompt, errors);
134
+ const latencyMsOffline = performance.now() - startTimeOffline;
135
135
  const pTokens = estimateTokens(systemPrompt + prompt + history.map(h => h.content).join(""));
136
- const cTokens = estimateTokens(kryloReply.text);
137
- const usage = recordTokenUsage("krylo-local", pTokens, cTokens);
138
- recordLatency("krylo-fallback", "local", latencyMsKrylo, pTokens, cTokens, true);
136
+ const cTokens = estimateTokens(offlineReply.text);
137
+ const usage = recordTokenUsage("offline-local", pTokens, cTokens);
138
+ recordLatency("offline-fallback", "local", latencyMsOffline, pTokens, cTokens, true);
139
139
  return {
140
- ...kryloReply,
141
- provider: "krylo-fallback",
140
+ ...offlineReply,
141
+ provider: "offline-fallback",
142
142
  node: 0,
143
143
  errors,
144
144
  usage,
package/src/chat.js CHANGED
@@ -117,7 +117,7 @@ export async function startChat(options = {}) {
117
117
  label.mesh + " " +
118
118
  colors.accent("Failover mesh online: ") +
119
119
  colors.text(unique.join(" → ")) +
120
- colors.muted(" → Krylo fallback")
120
+ colors.muted(" → Offline fallback")
121
121
  );
122
122
  console.log(
123
123
  " " + colors.dim(`${active.length} node(s) active across ${unique.length} provider(s)`) + "\n"
@@ -298,7 +298,7 @@ export async function startChat(options = {}) {
298
298
  console.log(separator("─"));
299
299
  console.log("");
300
300
 
301
- if (result.provider === "local" || result.provider === "krylo-fallback") {
301
+ if (result.provider === "local" || result.provider === "offline-fallback") {
302
302
  console.log(colors.text(" " + result.text.split("\n").join("\n ")));
303
303
  } else {
304
304
  let displayText = result.text;
@@ -897,7 +897,7 @@ function showActiveProviders(aiConfig) {
897
897
  for (const { provider } of active) {
898
898
  console.log(" " + colors.success("✓ ") + colors.text(provider.name) + colors.dim(` • ${provider.defaultModel}`));
899
899
  }
900
- console.log(" " + colors.success("✓ ") + colors.text("Krylo Companion") + colors.dim(" • Local fallback"));
900
+ console.log(" " + colors.success("✓ ") + colors.text("Offline Fallback") + colors.dim(" • Local fallback"));
901
901
  console.log(" " + colors.success("✓ ") + colors.text("Math Solver") + colors.dim(" • Local"));
902
902
  console.log("");
903
903
  }
@@ -1184,7 +1184,7 @@ function providerBadge(result) {
1184
1184
  "perplexity": chalk.bgHex("#1a2a2a").hex("#6ce8ff")(" Perplexity "),
1185
1185
  "fireworks ai": chalk.bgHex("#2a1a1a").hex("#ff6b8d")(" Fireworks "),
1186
1186
  "local": chalk.bgHex("#1a2a1a").hex("#67ffb0")(" Math Solver "),
1187
- "krylo-fallback": chalk.bgHex("#0c1825").hex("#6ce8ff")(" Krylo "),
1187
+ "offline-fallback": chalk.bgHex("#2a0a14").hex("#ff6b6b")(" Offline "),
1188
1188
  };
1189
1189
 
1190
1190
  const badge = badges[result.provider] || colors.muted(` ${result.provider} `);
package/src/cli.js CHANGED
@@ -312,7 +312,7 @@ async function handleAsk(prompt, opts) {
312
312
  console.log(separator("─"));
313
313
  console.log("");
314
314
 
315
- if (result.provider === "local" || result.provider === "krylo-fallback") {
315
+ if (result.provider === "local" || result.provider === "offline-fallback") {
316
316
  console.log(colors.text(" " + result.text.split("\n").join("\n ")));
317
317
  } else {
318
318
  let displayText = result.text;
@@ -577,11 +577,11 @@ async function handleStatus() {
577
577
  console.log("");
578
578
  console.log(colors.accent(" ◈ Local Fallbacks:"));
579
579
  console.log(keyValue(" Math Solver", colors.success("✓ Active")));
580
- console.log(keyValue(" Krylo Companion", colors.success("✓ Standing By")));
580
+ console.log(keyValue(" Offline Fallback", colors.success("✓ Standing By")));
581
581
 
582
582
  console.log("");
583
583
  console.log(colors.accent(" ◈ Failover Mesh:"));
584
- const totalNodes = 1 + active.length; // +1 for Krylo
584
+ const totalNodes = 1 + active.length; // +1 for local offline fallback
585
585
  console.log(keyValue(" Active Nodes", `${totalNodes}`));
586
586
  console.log(keyValue(" Mesh Status", active.length > 0 ? colors.success("✓ Online") : colors.warning("⚠ Local Only")));
587
587
  console.log("");
@@ -739,7 +739,7 @@ async function handleSetup() {
739
739
  console.log(" " + colors.muted("Start chatting: ") + colors.accent("aether chat"));
740
740
  console.log(" " + colors.muted("Quick query: ") + colors.accent('aether ask "Hello!"'));
741
741
  } else {
742
- console.log("\n " + colors.warning("No providers configured. Aether will use Krylo fallback mode."));
742
+ console.log("\n " + colors.warning("No providers configured. Aether will use local offline fallback mode."));
743
743
  console.log(" " + colors.muted("Run ") + colors.accent("aether setup") + colors.muted(" again anytime."));
744
744
  }
745
745
  console.log("");
@@ -536,9 +536,9 @@ const HTML_CONTENT = `<!DOCTYPE html>
536
536
  topoList.appendChild(createTopologyElement({
537
537
  name: "Local Solver Node",
538
538
  configured: true,
539
- defaultModel: "Offline Math + Krylo Companion",
539
+ defaultModel: "Offline Math & Logic",
540
540
  tier: "free",
541
- description: "Zero-latency mathematical reasoning & local assistant fallbacks."
541
+ description: "Zero-latency mathematical reasoning & local offline fallbacks."
542
542
  }, "Node 0 (Local)"));
543
543
 
544
544
  mesh.forEach((provider, idx) => {
@@ -76,7 +76,7 @@
76
76
  }
77
77
 
78
78
  .hud-frame::after {
79
- content: "AETHER CLI V1.4.0";
79
+ content: "AETHER CLI V1.4.2";
80
80
  position: absolute;
81
81
  bottom: -12px;
82
82
  right: 20px;
@@ -3,7 +3,7 @@ import assert from "node:assert";
3
3
  import {
4
4
  detectMathExpression,
5
5
  solveMath,
6
- generateKryloReply,
6
+ generateOfflineReply,
7
7
  runMainframeHack,
8
8
  } from "../src/ai/fallback.js";
9
9
 
@@ -50,38 +50,16 @@ test("Offline Math Fallback & Krylo Suite", async (t) => {
50
50
  assert.strictEqual(solveMath("console.log(1)"), null);
51
51
  });
52
52
 
53
- await t.test("generateKryloReply responds to help and shortcut keywords", () => {
54
- const reply = generateKryloReply("I need help with commands");
55
- assert.strictEqual(reply.type, "krylo-local");
56
- assert.ok(reply.text.includes("[SYSTEM DECK CHEAT SHEET]"));
57
- assert.ok(reply.text.includes("Ctrl + K"));
58
- });
59
-
60
- await t.test("generateKryloReply responds to status and diagnostic keywords", () => {
61
- const reply = generateKryloReply("What is the CPU status?");
62
- assert.strictEqual(reply.type, "krylo-local");
63
- assert.ok(reply.text.includes("[LIVE DIAGNOSTIC READOUT]"));
64
- assert.ok(reply.text.includes("Failover Mesh"));
65
- });
66
-
67
- await t.test("generateKryloReply responds to matrix/rain/color keywords", () => {
68
- const reply = generateKryloReply("change matrix color");
69
- assert.strictEqual(reply.type, "krylo-local");
70
- assert.ok(reply.text.includes("[NEURAL GRIDS MODULATION]"));
71
- assert.ok(reply.text.includes("Classic Green"));
72
- });
73
-
74
- await t.test("generateKryloReply responds to who/name/creator keywords", () => {
75
- const reply = generateKryloReply("who is your creator?");
76
- assert.strictEqual(reply.type, "krylo-local");
77
- assert.ok(reply.text.includes("[HOLOGRAPHIC COMPANION PROTOCOL]"));
78
- assert.ok(reply.text.includes("Krishiv PB"));
79
- });
53
+ await t.test("generateOfflineReply returns offline error formatting", () => {
54
+ const reply = generateOfflineReply("any query");
55
+ assert.strictEqual(reply.type, "offline-error");
56
+ assert.ok(reply.text.includes("No active API keys configured"));
80
57
 
81
- await t.test("generateKryloReply falls back to random terminal responses", () => {
82
- const reply = generateKryloReply("Unrelated query");
83
- assert.strictEqual(reply.type, "krylo-local");
84
- assert.ok(reply.text.includes("[KRYLO TERMINAL RESPONSE]"));
58
+ const replyWithErrors = generateOfflineReply("any query", ["Timeout error", "Quota exceeded"]);
59
+ assert.strictEqual(replyWithErrors.type, "offline-error");
60
+ assert.ok(replyWithErrors.text.includes("All configured AI provider nodes failed to respond"));
61
+ assert.ok(replyWithErrors.text.includes("Timeout error"));
62
+ assert.ok(replyWithErrors.text.includes("Quota exceeded"));
85
63
  });
86
64
 
87
65
  await t.test("detectMathExpression and solveMath support trig, logs, square root and constants", () => {
@@ -134,19 +134,19 @@ test("Universal AI Router Suite", async (t) => {
134
134
  assert.ok(fetchCalls[1].url.includes("key=key-success"));
135
135
  });
136
136
 
137
- await t.test("routePrompt falls back to Krylo companion when no providers are configured", async () => {
137
+ await t.test("routePrompt falls back to Offline fallback when no providers are configured", async () => {
138
138
  globalThis.fetch = async () => {
139
139
  throw new Error("Fetch should not be called");
140
140
  };
141
141
 
142
142
  const result = await routePrompt("status", "Sys prompt", {});
143
- assert.strictEqual(result.provider, "krylo-fallback");
143
+ assert.strictEqual(result.provider, "offline-fallback");
144
144
  assert.strictEqual(result.node, 0);
145
- assert.strictEqual(result.type, "krylo-local");
146
- assert.ok(result.text.includes("[LIVE DIAGNOSTIC READOUT]"));
145
+ assert.strictEqual(result.type, "offline-error");
146
+ assert.ok(result.text.includes("No active API keys configured"));
147
147
  });
148
148
 
149
- await t.test("routePrompt falls back to Krylo companion when all providers fail", async () => {
149
+ await t.test("routePrompt falls back to Offline fallback when all providers fail", async () => {
150
150
  globalThis.fetch = async (url, options) => {
151
151
  fetchCalls.push({ url, options });
152
152
  return {
@@ -164,12 +164,15 @@ test("Universal AI Router Suite", async (t) => {
164
164
 
165
165
  const result = await routePrompt("Hello", "Sys prompt", config);
166
166
 
167
- assert.strictEqual(result.provider, "krylo-fallback");
167
+ assert.strictEqual(result.provider, "offline-fallback");
168
168
  assert.strictEqual(result.node, 0);
169
169
  assert.ok(result.errors);
170
170
  assert.strictEqual(result.errors.length, 2);
171
171
  assert.ok(result.errors[0].includes("Node 1 Groq"));
172
172
  assert.ok(result.errors[1].includes("Node 2 OpenAI"));
173
+ assert.ok(result.text.includes("All configured AI provider nodes failed to respond"));
174
+ assert.ok(result.text.includes("Node 1 Groq"));
175
+ assert.ok(result.text.includes("Node 2 OpenAI"));
173
176
  });
174
177
 
175
178
  await t.test("routePrompt forwards chat history to OpenAI and Google payloads correctly", async () => {