aether-code 0.34.2 → 0.34.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.
@@ -28,7 +28,7 @@ import {
28
28
  import readline from "node:readline";
29
29
  import { c, errorLine, divider, setTerminalTitle } from "../src/render.js";
30
30
 
31
- const VERSION = "0.34.2";
31
+ const VERSION = "0.34.4";
32
32
 
33
33
  /**
34
34
  * Try to start MCP servers from ~/.aether/mcp.json. Returns a started
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aether-code",
3
- "version": "0.34.2",
3
+ "version": "0.34.4",
4
4
  "description": "Uncensored AI coding agent for your terminal — Claude Code alternative with MCP support. Reads code, writes files, runs commands. Drives IDA Pro, Roblox Studio, Wireshark, Blender, and any MCP server. No refusal layer.",
5
5
  "homepage": "https://trynoguard.com",
6
6
  "repository": {
package/src/agent.js CHANGED
@@ -194,6 +194,8 @@ export async function runAgent({
194
194
  let lastWasText = false;
195
195
  let streamedChars = 0;
196
196
  const stripper = makeTokenStripper();
197
+ let leakBuf = "";
198
+ let leakSuppressing = false;
197
199
 
198
200
  // Select skills for this turn against the current user prompt + any
199
201
  // paths the model has read so far. Prepend the matching skills' bodies
@@ -216,19 +218,32 @@ export async function runAgent({
216
218
  onDelta: (text) => {
217
219
  streamedChars += text.length;
218
220
  spinner.update({ tokens: Math.ceil(streamedChars / 3.5) });
219
- // Buffered strip of leaked model channel/control tokens (which can
220
- // be split across stream chunks) before display.
221
221
  const clean = stripper.push(text);
222
222
  if (!clean) return;
223
- // Don't open a "● " bullet for leading whitespace (e.g. when a whole
224
- // turn's text was suppressed as a leak, leaving only a stray newline).
225
- if (!lastWasText && !clean.trim()) return;
223
+
224
+ // Suppress model echoing tool results (response:web_search, [{snippet:, etc.)
225
+ leakBuf += clean;
226
+ if (leakBuf.length < 40 && /^[\s\n]*(?:response:|[\[{]"?(?:snippet|title|url))/.test(leakBuf)) return;
227
+ if (leakSuppressing) {
228
+ if (clean.includes("\n\n")) { leakSuppressing = false; leakBuf = ""; }
229
+ return;
230
+ }
231
+ const checkBuf = leakBuf.trim();
232
+ if (checkBuf && /^response:\w|^\[\{(?:"?snippet|"?title)/.test(checkBuf)) {
233
+ leakSuppressing = true;
234
+ leakBuf = "";
235
+ return;
236
+ }
237
+ const emit = leakBuf;
238
+ leakBuf = "";
239
+
240
+ if (!lastWasText && !emit.trim()) return;
226
241
  stopSpin();
227
242
  if (!lastWasText) {
228
243
  process.stdout.write("\n" + c.cyan("● "));
229
244
  lastWasText = true;
230
245
  }
231
- process.stdout.write(clean);
246
+ process.stdout.write(emit);
232
247
  },
233
248
  onToolCallDelta: (delta) => {
234
249
  // Just close the streamed text line when the model starts a tool
@@ -361,10 +376,28 @@ export async function runAgent({
361
376
  const summary = toolSummary(call.function.name, result);
362
377
  if (summary) console.log(summary);
363
378
 
379
+ // Cap tool result content sent to the model to prevent it from
380
+ // echoing raw data (snippets, HTML dumps) back as text output.
381
+ let toolContent = result.output ?? (result.ok ? "(no output)" : "Failed.");
382
+ if (call.function.name === "web_search") {
383
+ try {
384
+ const arr = JSON.parse(toolContent);
385
+ if (Array.isArray(arr)) {
386
+ toolContent = JSON.stringify(arr.map((r) => ({
387
+ title: r.title, url: r.url,
388
+ snippet: (r.snippet || "").slice(0, 120),
389
+ })));
390
+ }
391
+ } catch { /* leave as-is */ }
392
+ } else if (call.function.name === "web_fetch") {
393
+ if (toolContent.length > 12000) toolContent = toolContent.slice(0, 12000) + "\n...(truncated)";
394
+ } else if (call.function.name === "read_file") {
395
+ if (toolContent.length > 30000) toolContent = toolContent.slice(0, 30000) + "\n...(truncated)";
396
+ }
364
397
  messages.push({
365
398
  role: "tool",
366
399
  tool_call_id: call.id,
367
- content: result.output ?? (result.ok ? "(no output)" : "Failed."),
400
+ content: toolContent,
368
401
  });
369
402
  }
370
403
 
package/src/box-input.js CHANGED
@@ -125,7 +125,7 @@ export function promptBox({ history = [], placeholder = "Message Aether...", mod
125
125
 
126
126
  const termCols = process.stdout.columns || 80;
127
127
  const bottomBar = c.cyan(" " + "─".repeat(termCols - 2));
128
- process.stdout.write(promptLine + "\n" + barPrefix + statusText + "\n" + bottomBar + "\n");
128
+ process.stdout.write(promptLine + "\n" + bottomBar + "\n" + barPrefix + statusText + "\n");
129
129
  drawn = 3;
130
130
  };
131
131
 
package/src/repl.js CHANGED
@@ -9,7 +9,7 @@ import { c, errorLine } from "./render.js";
9
9
  import { autoUpdate } from "./update-check.js";
10
10
  import { promptBox, EXIT_SIGNAL } from "./box-input.js";
11
11
 
12
- const VERSION = "0.34.2";
12
+ const VERSION = "0.34.4";
13
13
  const MODEL_NAME = "Aether Core";
14
14
 
15
15
  const MODEL_ALIASES = {