@tiens.nguyen/gonext-local-worker 1.0.136 → 1.0.138

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.
@@ -369,12 +369,16 @@ def _web_search_impl(query):
369
369
  )
370
370
 
371
371
 
372
- def _detect_model_id(base_url, api_key=""):
373
- """Ask an OpenAI-compatible server which model it serves.
372
+ class _AgentConfigError(RuntimeError):
373
+ """Deterministic setup error (e.g. wrong model name/URL). Not retryable and not
374
+ worth a plain-reply degrade — the user needs the message itself to fix Settings."""
375
+
376
+
377
+ def _list_model_ids(base_url, api_key=""):
378
+ """Return the model ids an OpenAI-compatible server reports at {base_url}/models.
374
379
 
375
- Queries GET {base_url}/models and returns the first reported model id.
376
- `base_url` already ends with /v1. Returns "" on any failure so callers can
377
- fall back. Used when the user supplies a coding-model URL but no model name.
380
+ `base_url` already ends with /v1. Returns [] on any failure so callers can
381
+ fall back.
378
382
  """
379
383
  url = base_url.rstrip("/") + "/models"
380
384
  headers = {"Accept": "application/json"}
@@ -385,21 +389,31 @@ def _detect_model_id(base_url, api_key=""):
385
389
  with urllib.request.urlopen(req, timeout=10, context=_ssl_context()) as resp:
386
390
  payload = json.loads(resp.read().decode("utf-8", errors="replace"))
387
391
  except Exception as e: # noqa: BLE001
388
- _log(f"model detect failed {url}: {e}")
389
- return ""
392
+ _log(f"model list failed {url}: {e}")
393
+ return []
390
394
  data = payload.get("data") if isinstance(payload, dict) else None
391
- if isinstance(data, list) and data:
392
- ids = [d["id"].strip() for d in data
393
- if isinstance(d, dict) and isinstance(d.get("id"), str) and d["id"].strip()]
394
- if ids:
395
- if len(ids) > 1:
396
- # Ollama servers list every pulled model; "first" is arbitrary and may
397
- # be a huge/slow one (seen live: picked gemma4:31b over qwen3:14b).
398
- _log(f"model detect: server hosts {len(ids)} models {ids} using "
399
- f"{ids[0]!r}. Set the coding model NAME in Settings to choose "
400
- "a specific one.")
401
- return ids[0]
402
- return ""
395
+ if not isinstance(data, list):
396
+ return []
397
+ return [d["id"].strip() for d in data
398
+ if isinstance(d, dict) and isinstance(d.get("id"), str) and d["id"].strip()]
399
+
400
+
401
+ def _detect_model_id(base_url, api_key=""):
402
+ """Ask an OpenAI-compatible server which model it serves (first reported id).
403
+
404
+ Returns "" on any failure so callers can fall back. Used when the user supplies
405
+ a coding-model URL but no model name.
406
+ """
407
+ ids = _list_model_ids(base_url, api_key)
408
+ if not ids:
409
+ return ""
410
+ if len(ids) > 1:
411
+ # Ollama servers list every pulled model; "first" is arbitrary and may be a
412
+ # huge/slow one (seen live: picked gemma4:31b over qwen3:14b).
413
+ _log(f"model detect: server hosts {len(ids)} models {ids} — using "
414
+ f"{ids[0]!r}. Set the coding model NAME in Settings to choose "
415
+ "a specific one.")
416
+ return ids[0]
403
417
 
404
418
 
405
419
  def _summarise_step(step_log):
@@ -1782,6 +1796,20 @@ def run_agent_chat(cfg):
1782
1796
  msg = super().generate(*args, **kwargs)
1783
1797
  break
1784
1798
  except Exception as e: # noqa: BLE001
1799
+ emsg = str(e)
1800
+ # A 404 "model not found" is a config error (wrong model NAME
1801
+ # for this server, e.g. an MLX-style name against Ollama) —
1802
+ # deterministic, so retrying is pointless. Fail fast with the
1803
+ # server's actual model list so the user can fix Settings.
1804
+ if "404" in emsg and "not found" in emsg.lower():
1805
+ ids = _list_model_ids(coding_base_url, agent_api_key)
1806
+ have = f" This server has: {', '.join(ids)}." if ids else ""
1807
+ raise _AgentConfigError(
1808
+ f"The agent coding model {coding_model_id!r} does not "
1809
+ f"exist on {coding_base_url}.{have} Set 'Agent coding "
1810
+ "model name' in Settings → Agent to one of these exact "
1811
+ "names (for Ollama use the tag, e.g. qwen3:14b)."
1812
+ ) from e
1785
1813
  last_err = e
1786
1814
  if attempt < 2:
1787
1815
  _log(f"generate transient error (attempt {attempt + 1}/3): {e} — retrying")
@@ -1963,6 +1991,23 @@ def run_agent_chat(cfg):
1963
1991
  _log(f"done (deterministic, no summarizer call): {len(final_text)} chars")
1964
1992
  _emit({"type": "final", "text": final_text})
1965
1993
  except Exception as e: # noqa: BLE001
1994
+ # Config errors (wrong coding-model name/URL) must reach the user VERBATIM —
1995
+ # they contain the fix (the server's real model list). smolagents wraps model
1996
+ # exceptions in AgentGenerationError, so walk the cause chain to find ours.
1997
+ cfg_err = None
1998
+ cur, depth = e, 0
1999
+ while cur is not None and depth < 6:
2000
+ if isinstance(cur, _AgentConfigError):
2001
+ cfg_err = cur
2002
+ break
2003
+ cur, depth = (getattr(cur, "__cause__", None)
2004
+ or getattr(cur, "__context__", None)), depth + 1
2005
+ if cfg_err is None and "Settings → Agent" in str(e):
2006
+ cfg_err = e # wrapped without a cause chain; message survived
2007
+ if cfg_err is not None:
2008
+ _log(f"agent config error (not degrading): {cfg_err}")
2009
+ _emit({"type": "final", "text": f"⚠️ {cfg_err}"})
2010
+ return
1966
2011
  # An unexpected failure inside the agent loop should still return a useful
1967
2012
  # answer from the conversation rather than surfacing a raw error to the user.
1968
2013
  _log(f"agent error: {e} — degrading to plain reply")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.136",
3
+ "version": "1.0.138",
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",