Merge branch 'main' of github.com:NousResearch/hermes-agent into feat/ink-refactor
This commit is contained in:
@@ -1597,13 +1597,8 @@ OPTIONAL_ENV_VARS = {
|
||||
},
|
||||
|
||||
# ── Agent settings ──
|
||||
"MESSAGING_CWD": {
|
||||
"description": "Working directory for terminal commands via messaging",
|
||||
"prompt": "Messaging working directory (default: home)",
|
||||
"url": None,
|
||||
"password": False,
|
||||
"category": "setting",
|
||||
},
|
||||
# NOTE: MESSAGING_CWD was removed here — use terminal.cwd in config.yaml
|
||||
# instead. The gateway reads TERMINAL_CWD (bridged from terminal.cwd).
|
||||
"SUDO_PASSWORD": {
|
||||
"description": "Sudo password for terminal commands requiring root access; set to an explicit empty string to try empty without prompting",
|
||||
"prompt": "Sudo password",
|
||||
@@ -2082,6 +2077,52 @@ def print_config_warnings(config: Optional[Dict[str, Any]] = None) -> None:
|
||||
sys.stderr.write("\n".join(lines) + "\n\n")
|
||||
|
||||
|
||||
def warn_deprecated_cwd_env_vars(config: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""Warn if MESSAGING_CWD or TERMINAL_CWD is set in .env instead of config.yaml.
|
||||
|
||||
These env vars are deprecated — the canonical setting is terminal.cwd
|
||||
in config.yaml. Prints a migration hint to stderr.
|
||||
"""
|
||||
import os, sys
|
||||
messaging_cwd = os.environ.get("MESSAGING_CWD")
|
||||
terminal_cwd_env = os.environ.get("TERMINAL_CWD")
|
||||
|
||||
if config is None:
|
||||
try:
|
||||
config = load_config()
|
||||
except Exception:
|
||||
return
|
||||
|
||||
terminal_cfg = config.get("terminal", {})
|
||||
config_cwd = terminal_cfg.get("cwd", ".") if isinstance(terminal_cfg, dict) else "."
|
||||
# Only warn if config.yaml doesn't have an explicit path
|
||||
config_has_explicit_cwd = config_cwd not in (".", "auto", "cwd", "")
|
||||
|
||||
lines: list[str] = []
|
||||
if messaging_cwd:
|
||||
lines.append(
|
||||
f" \033[33m⚠\033[0m MESSAGING_CWD={messaging_cwd} found in .env — "
|
||||
f"this is deprecated."
|
||||
)
|
||||
if terminal_cwd_env and not config_has_explicit_cwd:
|
||||
# TERMINAL_CWD in env but not from config bridge — likely from .env
|
||||
lines.append(
|
||||
f" \033[33m⚠\033[0m TERMINAL_CWD={terminal_cwd_env} found in .env — "
|
||||
f"this is deprecated."
|
||||
)
|
||||
if lines:
|
||||
hint_path = os.environ.get("HERMES_HOME", "~/.hermes")
|
||||
lines.insert(0, "\033[33m⚠ Deprecated .env settings detected:\033[0m")
|
||||
lines.append(
|
||||
f" \033[2mMove to config.yaml instead: "
|
||||
f"terminal:\\n cwd: /your/project/path\033[0m"
|
||||
)
|
||||
lines.append(
|
||||
f" \033[2mThen remove the old entries from {hint_path}/.env\033[0m"
|
||||
)
|
||||
sys.stderr.write("\n".join(lines) + "\n\n")
|
||||
|
||||
|
||||
def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, Any]:
|
||||
"""
|
||||
Migrate config to latest version, prompting for new required fields.
|
||||
|
||||
@@ -5998,6 +5998,18 @@ Examples:
|
||||
memory_sub.add_parser("setup", help="Interactive provider selection and configuration")
|
||||
memory_sub.add_parser("status", help="Show current memory provider config")
|
||||
memory_sub.add_parser("off", help="Disable external provider (built-in only)")
|
||||
_reset_parser = memory_sub.add_parser(
|
||||
"reset",
|
||||
help="Erase all built-in memory (MEMORY.md and USER.md)",
|
||||
)
|
||||
_reset_parser.add_argument(
|
||||
"--yes", "-y", action="store_true",
|
||||
help="Skip confirmation prompt",
|
||||
)
|
||||
_reset_parser.add_argument(
|
||||
"--target", choices=["all", "memory", "user"], default="all",
|
||||
help="Which store to reset: 'all' (default), 'memory', or 'user'",
|
||||
)
|
||||
|
||||
def cmd_memory(args):
|
||||
sub = getattr(args, "memory_command", None)
|
||||
@@ -6010,6 +6022,44 @@ Examples:
|
||||
save_config(config)
|
||||
print("\n ✓ Memory provider: built-in only")
|
||||
print(" Saved to config.yaml\n")
|
||||
elif sub == "reset":
|
||||
from hermes_constants import get_hermes_home, display_hermes_home
|
||||
mem_dir = get_hermes_home() / "memories"
|
||||
target = getattr(args, "target", "all")
|
||||
files_to_reset = []
|
||||
if target in ("all", "memory"):
|
||||
files_to_reset.append(("MEMORY.md", "agent notes"))
|
||||
if target in ("all", "user"):
|
||||
files_to_reset.append(("USER.md", "user profile"))
|
||||
|
||||
# Check what exists
|
||||
existing = [(f, desc) for f, desc in files_to_reset if (mem_dir / f).exists()]
|
||||
if not existing:
|
||||
print(f"\n Nothing to reset — no memory files found in {display_hermes_home()}/memories/\n")
|
||||
return
|
||||
|
||||
print(f"\n This will permanently erase the following memory files:")
|
||||
for f, desc in existing:
|
||||
path = mem_dir / f
|
||||
size = path.stat().st_size
|
||||
print(f" ◆ {f} ({desc}) — {size:,} bytes")
|
||||
|
||||
if not getattr(args, "yes", False):
|
||||
try:
|
||||
answer = input("\n Type 'yes' to confirm: ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print("\n Cancelled.\n")
|
||||
return
|
||||
if answer != "yes":
|
||||
print(" Cancelled.\n")
|
||||
return
|
||||
|
||||
for f, desc in existing:
|
||||
(mem_dir / f).unlink()
|
||||
print(f" ✓ Deleted {f} ({desc})")
|
||||
|
||||
print(f"\n Memory reset complete. New sessions will start with a blank slate.")
|
||||
print(f" Files were in: {display_hermes_home()}/memories/\n")
|
||||
else:
|
||||
from hermes_cli.memory_setup import memory_command
|
||||
memory_command(args)
|
||||
|
||||
@@ -807,6 +807,10 @@ def list_authenticated_providers(
|
||||
# "nous" shares OpenRouter's curated list if not separately defined
|
||||
if "nous" not in curated:
|
||||
curated["nous"] = curated["openrouter"]
|
||||
# Ollama Cloud uses dynamic discovery (no static curated list)
|
||||
if "ollama-cloud" not in curated:
|
||||
from hermes_cli.models import fetch_ollama_cloud_models
|
||||
curated["ollama-cloud"] = fetch_ollama_cloud_models()
|
||||
|
||||
# --- 1. Check Hermes-mapped providers ---
|
||||
for hermes_id, mdev_id in PROVIDER_TO_MODELS_DEV.items():
|
||||
|
||||
@@ -1044,7 +1044,7 @@ def detect_provider_for_model(
|
||||
return (resolved_provider, default_models[0])
|
||||
|
||||
# Aggregators list other providers' models — never auto-switch TO them
|
||||
_AGGREGATORS = {"nous", "openrouter"}
|
||||
_AGGREGATORS = {"nous", "openrouter", "ai-gateway", "copilot", "kilocode"}
|
||||
|
||||
# If the model belongs to the current provider's catalog, don't suggest switching
|
||||
current_models = _PROVIDER_MODELS.get(current_provider, [])
|
||||
@@ -1286,6 +1286,10 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)
|
||||
live = _fetch_ai_gateway_models()
|
||||
if live:
|
||||
return live
|
||||
if normalized == "ollama-cloud":
|
||||
live = fetch_ollama_cloud_models(force_refresh=force_refresh)
|
||||
if live:
|
||||
return live
|
||||
if normalized == "custom":
|
||||
base_url = _get_custom_base_url()
|
||||
if base_url:
|
||||
|
||||
@@ -708,7 +708,9 @@ def init_skin_from_config(config: dict) -> None:
|
||||
|
||||
Call this once during CLI init with the loaded config dict.
|
||||
"""
|
||||
display = config.get("display", {})
|
||||
display = config.get("display") or {}
|
||||
if not isinstance(display, dict):
|
||||
display = {}
|
||||
skin_name = display.get("skin", "default")
|
||||
if isinstance(skin_name, str) and skin_name.strip():
|
||||
set_active_skin(skin_name.strip())
|
||||
|
||||
Reference in New Issue
Block a user