@tiens.nguyen/gonext-local-worker 1.0.184 → 1.0.186

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/gonext-repl.mjs CHANGED
@@ -43,6 +43,11 @@ const CLEAR_LINE = "\r\x1b[K"; // carriage-return + erase-to-end-of-line
43
43
  // also drop the worker's ~~~ stream fences (they only matter to the web renderer).
44
44
  const isHeartbeatLine = (line) => /…\s?\(\d+s\)\s*$/.test(line);
45
45
  const isFenceLine = (line) => line.trim() === "~~~";
46
+ // The model's own raw Python code blob, delimited by <code>/</code> lines in its
47
+ // Thought+Code output. It's redundant with the step summary that follows it (e.g.
48
+ // "Downloading → url"), so we don't print it — only the "Thought:" prose survives.
49
+ const isCodeOpenLine = (line) => line.trim() === "<code>";
50
+ const isCodeCloseLine = (line) => line.trim() === "</code>";
46
51
 
47
52
  // Playful words for the local "thinking…" ticker, reused verbatim from the worker's
48
53
  // thinking_words.txt sibling (falls back to a tiny built-in list if it's missing).
@@ -290,7 +295,10 @@ async function runAgentTurn(history) {
290
295
  };
291
296
 
292
297
  // Split newly-arrived text into lines: heartbeats + ~~~ fences are swallowed (the ticker
293
- // shows progress); blank lines keep spacing; everything else commits dim to scrollback.
298
+ // shows progress); the model's raw <code>…</code> blob is swallowed too (redundant with
299
+ // the step summary that follows it, e.g. "Downloading → url"); blank lines keep spacing;
300
+ // everything else (the "Thought:" prose) commits dim to scrollback.
301
+ let inCode = false;
294
302
  const consume = (chunk) => {
295
303
  carry += stripThinkTags(chunk);
296
304
  let nl;
@@ -298,6 +306,18 @@ async function runAgentTurn(history) {
298
306
  const line = carry.slice(0, nl);
299
307
  carry = carry.slice(nl + 1);
300
308
  if (isHeartbeatLine(line) || isFenceLine(line)) continue; // swallow
309
+ if (!inCode && isCodeOpenLine(line)) {
310
+ // Reasoning just ended and code is about to run — stamp the thought complete,
311
+ // then suppress the code body itself.
312
+ onContent();
313
+ inCode = true;
314
+ continue;
315
+ }
316
+ if (inCode) {
317
+ lastContentAt = Date.now(); // content IS arriving, just not printed
318
+ if (isCodeCloseLine(line)) inCode = false;
319
+ continue;
320
+ }
301
321
  if (line.trim() === "") {
302
322
  if (!thinking && !statusShown) process.stdout.write("\n");
303
323
  continue;
@@ -488,8 +488,14 @@ def _summarise_step(step_log):
488
488
  name = getattr(tc, "name", "")
489
489
  args = getattr(tc, "arguments", None)
490
490
 
491
- if name == "python_interpreter" and isinstance(args, dict):
492
- code = args.get("code", "")
491
+ if name == "python_interpreter":
492
+ # smolagents' CodeAgent passes the raw code STRING as `arguments` (NOT a
493
+ # dict — only ToolCallingAgent's structured calls use {"code": ...}). Handle
494
+ # both shapes, else this always fell through to the useless "python_interpreter"
495
+ # label below and never showed what was actually called.
496
+ code = args if isinstance(args, str) else (
497
+ args.get("code", "") if isinstance(args, dict) else ""
498
+ )
493
499
  # Show the http_request call if present, else first meaningful line
494
500
  m = re.search(r'http_request\s*\(\s*(?:method\s*=\s*)?[\'"]?(\w+)[\'"]?\s*,\s*(?:url\s*=\s*)?[\'"]([^\'"]+)', code)
495
501
  if m:
@@ -514,9 +520,13 @@ def _summarise_step(step_log):
514
520
 
515
521
  if observations:
516
522
  obs = str(observations).strip()
517
- # smolagents prefixes output with "Execution logs:" skip that header line
518
- # and show the first line of actual content.
519
- lines = [l for l in obs.splitlines() if l.strip() and l.strip() != "Execution logs:"]
523
+ # smolagents wraps observations as "Execution logs:\n<print output>\nLast output
524
+ # from code snippet:\n<return value>" both header lines are pure boilerplate.
525
+ # Without filtering "Last output from code snippet:" too, a call with no print()
526
+ # output (most of our @tool functions just `return`, not print) surfaced that
527
+ # HEADER as the shown text instead of the actual return value on the next line.
528
+ _OBS_BOILERPLATE = ("Execution logs:", "Last output from code snippet:")
529
+ lines = [l for l in obs.splitlines() if l.strip() and l.strip() not in _OBS_BOILERPLATE]
520
530
  if lines:
521
531
  parts.append(f"→ {_clip(lines[0])}")
522
532
 
@@ -3277,8 +3287,10 @@ def run_agent_chat(cfg):
3277
3287
  for dirpath, dirnames, filenames in os.walk(root):
3278
3288
  dirnames[:] = [d for d in dirnames if d not in _RAG_SKIP_DIRS]
3279
3289
  for fn in filenames:
3280
- rel = os.path.relpath(os.path.join(dirpath, fn), root)
3281
- entries.append(rel)
3290
+ # ABSOLUTE path read_file_lines/read_text_file resolve relative
3291
+ # paths against the WORKSPACE root, not whatever subfolder was
3292
+ # listed here, so a name relative to `root` could resolve wrong.
3293
+ entries.append(os.path.join(dirpath, fn))
3282
3294
  if len(entries) >= 300:
3283
3295
  break
3284
3296
  if len(entries) >= 300:
@@ -3447,7 +3459,11 @@ def run_agent_chat(cfg):
3447
3459
  with open(abs_path, "r", encoding="utf-8", errors="replace") as fh:
3448
3460
  for i, line in enumerate(fh, 1):
3449
3461
  if rx.search(line):
3450
- hits.append(f"{rel}:{i}: {line.rstrip()[:200]}")
3462
+ # ABSOLUTE path — read_file_lines/read_text_file resolve
3463
+ # relative paths against the WORKSPACE root, not this
3464
+ # search root, so a path relative to `root` (e.g. when
3465
+ # searching a subfolder) would be silently wrong there.
3466
+ hits.append(f"{abs_path}:{i}: {line.rstrip()[:200]}")
3451
3467
  if len(hits) >= 100:
3452
3468
  break
3453
3469
  except OSError:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.184",
3
+ "version": "1.0.186",
4
4
  "description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
5
5
  "type": "module",
6
6
  "license": "MIT",