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

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.
@@ -649,6 +649,37 @@ _COMPACT_CODE_SYSTEM_PROMPT = (
649
649
  )
650
650
 
651
651
 
652
+ def _is_model_not_found_err(e) -> bool:
653
+ """True when a chat completion failed because the server didn't recognize the model
654
+ name (mlx_lm.server treats an unknown name as an HF repo to fetch → 'Repository Not
655
+ Found' / 401 / 404), as opposed to a real network/auth failure."""
656
+ s = str(e).lower()
657
+ return ("repository not found" in s or "not found for url" in s
658
+ or "repo_id" in s or "does not exist" in s
659
+ or ("404" in s and "model" in s))
660
+
661
+
662
+ def _chat_create(client, **kwargs):
663
+ """chat.completions.create with an mlx_lm safety net: if the server rejects the model
664
+ NAME as an unknown repo, retry once with 'default_model' — mlx_lm.server maps that
665
+ sentinel to whatever model it was launched with (`--model <path>`), so a server
666
+ started as e.g. `mlx_lm.server --model ~/mlx-models/Qwen3-14B-4bit` answers even when
667
+ we only know the bare name. Non-mlx servers surface their ORIGINAL error unchanged."""
668
+ try:
669
+ return client.chat.completions.create(**kwargs)
670
+ except Exception as e: # noqa: BLE001
671
+ if kwargs.get("model") != "default_model" and _is_model_not_found_err(e):
672
+ _log(f"model {kwargs.get('model')!r} not found on server; retrying as "
673
+ "'default_model' (mlx_lm preloaded model)")
674
+ try:
675
+ kwargs2 = dict(kwargs)
676
+ kwargs2["model"] = "default_model"
677
+ return client.chat.completions.create(**kwargs2)
678
+ except Exception: # noqa: BLE001
679
+ raise e # surface the clearer original error, not the retry's
680
+ raise
681
+
682
+
652
683
  def _route(task_text: str, base_url: str, api_key: str, model_id: str) -> bool:
653
684
  """Decide if the task needs the HTTP agent (True) or a plain chat reply (False).
654
685
 
@@ -668,7 +699,8 @@ def _route(task_text: str, base_url: str, api_key: str, model_id: str) -> bool:
668
699
  from openai import OpenAI
669
700
  client = OpenAI(base_url=base_url, api_key=api_key or "local",
670
701
  max_retries=0, timeout=20)
671
- resp = client.chat.completions.create(
702
+ resp = _chat_create(
703
+ client,
672
704
  model=model_id,
673
705
  messages=[
674
706
  {"role": "system", "content": (
@@ -716,7 +748,8 @@ def _summarize_result(task_text: str, agent_output: str,
716
748
  from openai import OpenAI
717
749
  client = OpenAI(base_url=base_url, api_key=api_key or "local",
718
750
  max_retries=0, timeout=30)
719
- resp = client.chat.completions.create(
751
+ resp = _chat_create(
752
+ client,
720
753
  model=model_id,
721
754
  messages=[
722
755
  {"role": "system", "content": (
@@ -773,7 +806,8 @@ def _plain_reply(messages: list, base_url: str, api_key: str, model_id: str,
773
806
  from openai import OpenAI
774
807
  client = OpenAI(base_url=b, api_key=api_key or "local",
775
808
  max_retries=0, timeout=60)
776
- resp = client.chat.completions.create(
809
+ resp = _chat_create(
810
+ client,
777
811
  model=mid,
778
812
  messages=chat_messages,
779
813
  temperature=0.7,
@@ -783,8 +817,9 @@ def _plain_reply(messages: list, base_url: str, api_key: str, model_id: str,
783
817
  except Exception as e: # noqa: BLE001
784
818
  last_err = e
785
819
  if i + 1 < len(targets):
786
- _log(f"plain reply: primary model failed ({e}); retrying on fallback "
787
- f"{mid} @ {b}")
820
+ nb, nmid = targets[i + 1] # the model we're about to try next
821
+ _log(f"plain reply: {mid} @ {b} failed ({e}); "
822
+ f"falling back to {nmid} @ {nb}")
788
823
  return f"[Error: {last_err}]"
789
824
 
790
825
 
@@ -810,7 +845,8 @@ def _synthesize_document(gathered: list, task: str, base_url: str, api_key: str,
810
845
  from openai import OpenAI
811
846
  client = OpenAI(base_url=base_url, api_key=api_key or "local",
812
847
  max_retries=0, timeout=120)
813
- resp = client.chat.completions.create(
848
+ resp = _chat_create(
849
+ client,
814
850
  model=model_id,
815
851
  messages=[{"role": "system", "content": sys_prompt},
816
852
  {"role": "user", "content": user_prompt}],
@@ -1083,7 +1119,8 @@ def _format_text_for_pdf(text: str, title: str, base_url: str, api_key: str,
1083
1119
  + (f"Requested change: {instruction}\n\n" if instruction else "")
1084
1120
  + f"Content to format:\n{text}"
1085
1121
  )
1086
- resp = client.chat.completions.create(
1122
+ resp = _chat_create(
1123
+ client,
1087
1124
  model=model_id,
1088
1125
  messages=[
1089
1126
  {"role": "system", "content": system_content},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.182",
3
+ "version": "1.0.184",
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",