@tiens.nguyen/gonext-local-worker 1.0.194 → 1.0.195

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.
@@ -1800,6 +1800,41 @@ def _ws_for_path(path: str):
1800
1800
  return None
1801
1801
 
1802
1802
 
1803
+ def _workspace_overview(roots, max_entries: int = 40) -> str:
1804
+ """Cheap, LOCAL top-level listing of each registered workspace root — a plain
1805
+ os.listdir(), no recursion, no network call, no model call. Used two ways: (1)
1806
+ injected into the task prompt so the agent has upfront grounding that the workspace
1807
+ is non-empty WITHOUT spending its first (possibly failing) tool-call round-trip just
1808
+ discovering that; (2) appended to the degrade-to-plain-reply message so even a TOTAL
1809
+ coding-model outage still shows the user their files are actually there — this is
1810
+ the one piece of workspace context that stays available no matter how badly the
1811
+ model-calling side of the agent is failing, since it never touches a model at all."""
1812
+ import os
1813
+ parts = []
1814
+ for w in roots:
1815
+ root = w["path"]
1816
+ try:
1817
+ entries = sorted(
1818
+ e for e in os.listdir(root) if e not in _RAG_SKIP_DIRS
1819
+ )
1820
+ except OSError as e:
1821
+ parts.append(f"{w['name']} ({root}): could not list ({e})")
1822
+ continue
1823
+ if not entries:
1824
+ parts.append(f"{w['name']} ({root}): EMPTY — no files or folders found.")
1825
+ continue
1826
+ shown = entries[:max_entries]
1827
+ labeled = [
1828
+ f"{e}/" if os.path.isdir(os.path.join(root, e)) else e for e in shown
1829
+ ]
1830
+ more = f" …(+{len(entries) - max_entries} more)" if len(entries) > max_entries else ""
1831
+ parts.append(
1832
+ f"{w['name']} ({root}) — {len(entries)} top-level item(s): "
1833
+ + ", ".join(labeled) + more
1834
+ )
1835
+ return "\n".join(parts)
1836
+
1837
+
1803
1838
  def _ws_write_allowed(path: str) -> str:
1804
1839
  """Resolve `path` for WRITING: must be inside a registered workspace and never
1805
1840
  inside its .git/ internals (agents must not corrupt version control)."""
@@ -2347,8 +2382,15 @@ def run_agent_chat(cfg):
2347
2382
  "If the user adds information, rag_add(source_url=url, text=...).\n"
2348
2383
  ) if _RAG_AVAILABLE else ""
2349
2384
  _ws_names = ", ".join(f"{w['name']} = {w['path']}" for w in _WS_ROOTS)
2385
+ # Upfront, ZERO-COST (no tool call, no model round-trip) top-level listing — so the
2386
+ # agent already knows the workspace is non-empty and roughly what's in it before its
2387
+ # first step, instead of having to spend (and risk losing to a timeout) a whole
2388
+ # round-trip just calling list_dir to discover that.
2389
+ _ws_overview = _workspace_overview(_WS_ROOTS) if _WS_AVAILABLE else ""
2350
2390
  _ws_tool_block = (
2351
2391
  f" WORKSPACES (local code folders you may READ and EDIT): {_ws_names}\n"
2392
+ f" Current contents:\n"
2393
+ + "\n".join(f" {line}" for line in _ws_overview.splitlines()) + "\n"
2352
2394
  " - list_dir(path) / read_text_file(path) — browse and read files.\n"
2353
2395
  " - grep_repo(pattern, path='', glob='') — search code, returns file:line hits. "
2354
2396
  "Use this to find the EXACT lines to change.\n"
@@ -3938,10 +3980,15 @@ def run_agent_chat(cfg):
3938
3980
  # "the real attempt never got to run" (seen live: workspace summarize request →
3939
3981
  # coding model timed out 3x on a slow/unreachable remote Ollama box → silent
3940
3982
  # fallback claimed "no access to your workspace").
3941
- _emit({"type": "final", "text": (
3942
- f"⚠️ I couldn't finish the full investigation ({_clip(str(e), 120)}) — here's "
3943
- f"what I can say without it:\n\n{fallback}"
3944
- )})
3983
+ note = f"⚠️ I couldn't finish the full investigation ({_clip(str(e), 120)}) — here's what I can say without it:\n\n{fallback}"
3984
+ # Append the workspace's ACTUAL top-level contents (computed locally, no model
3985
+ # call see _workspace_overview) so the user sees their files are really there
3986
+ # even during a total coding-model outage, instead of trusting a plain-chat
3987
+ # model's guess that "there's no code or project" (seen live — false: the
3988
+ # workspace had real content the whole time, the model just never reached it).
3989
+ if _WS_AVAILABLE:
3990
+ note += f"\n\n(Your registered workspace:\n{_workspace_overview(_WS_ROOTS)})"
3991
+ _emit({"type": "final", "text": note})
3945
3992
 
3946
3993
 
3947
3994
  def _log(text: str):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.194",
3
+ "version": "1.0.195",
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",