mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
refactor(restructure): rewrite all imports for hermes_agent package
Rewrite all import statements, patch() targets, sys.modules keys, importlib.import_module() strings, and subprocess -m references to use hermes_agent.* paths. Strip sys.path.insert hacks from production code (rely on editable install). Update COMPONENT_PREFIXES for logger filtering. Fix 3 hardcoded getLogger() calls to use __name__. Update transport and tool registry discovery paths. Update plugin module path strings. Add legacy process-name patterns for gateway PID detection. Add main() to skills_sync for console_script entry point. Fix _get_bundled_dir() path traversal after move. Part of #14182, #14183
This commit is contained in:
parent
65ca3ba93b
commit
4b16341975
898 changed files with 12494 additions and 12019 deletions
|
|
@ -21,11 +21,11 @@ from dataclasses import dataclass, field
|
|||
from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from tools.budget_config import BudgetConfig
|
||||
from hermes_agent.tools.budget_config import BudgetConfig
|
||||
|
||||
from model_tools import handle_function_call
|
||||
from tools.terminal_tool import get_active_env
|
||||
from tools.tool_result_storage import maybe_persist_tool_result, enforce_turn_budget
|
||||
from hermes_agent.tools.dispatch import handle_function_call
|
||||
from hermes_agent.tools.terminal import get_active_env
|
||||
from hermes_agent.tools.result_storage import maybe_persist_tool_result, enforce_turn_budget
|
||||
|
||||
# Thread pool for running sync tool calls that internally use asyncio.run()
|
||||
# (e.g., the Modal/Docker/Daytona terminal backends). Running them in a separate
|
||||
|
|
@ -164,7 +164,7 @@ class HermesAgentLoop:
|
|||
thresholds, per-turn aggregate budget, and preview size.
|
||||
If None, uses DEFAULT_BUDGET (current hardcoded values).
|
||||
"""
|
||||
from tools.budget_config import DEFAULT_BUDGET
|
||||
from hermes_agent.tools.budget_config import DEFAULT_BUDGET
|
||||
self.server = server
|
||||
self.tool_schemas = tool_schemas
|
||||
self.valid_tool_names = valid_tool_names
|
||||
|
|
@ -190,7 +190,7 @@ class HermesAgentLoop:
|
|||
tool_errors: List[ToolError] = []
|
||||
|
||||
# Per-loop TodoStore for the todo tool (ephemeral, dies with the loop)
|
||||
from tools.todo_tool import TodoStore, todo_tool as _todo_tool
|
||||
from hermes_agent.tools.todo import TodoStore, todo_tool as _todo_tool
|
||||
_todo_store = TodoStore()
|
||||
|
||||
# Extract user task from first user message for browser_snapshot context
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ from atroposlib.envs.server_handling.server_manager import APIServerConfig
|
|||
from environments.agent_loop import AgentResult, HermesAgentLoop
|
||||
from environments.hermes_base_env import HermesAgentBaseEnv, HermesAgentEnvConfig
|
||||
from environments.tool_context import ToolContext
|
||||
from tools.terminal_tool import (
|
||||
from hermes_agent.tools.terminal import (
|
||||
register_task_env_overrides,
|
||||
clear_task_env_overrides,
|
||||
cleanup_vm,
|
||||
|
|
@ -876,7 +876,7 @@ class TerminalBench2EvalEnv(HermesAgentBaseEnv):
|
|||
# Let cancellations propagate (finally blocks run cleanup_vm)
|
||||
await asyncio.gather(*eval_tasks, return_exceptions=True)
|
||||
# Belt-and-suspenders: clean up any remaining sandboxes
|
||||
from tools.terminal_tool import cleanup_all_environments
|
||||
from hermes_agent.tools.terminal import cleanup_all_environments
|
||||
cleanup_all_environments()
|
||||
print("All sandboxes cleaned up.")
|
||||
return
|
||||
|
|
@ -984,7 +984,7 @@ class TerminalBench2EvalEnv(HermesAgentBaseEnv):
|
|||
|
||||
# Kill all remaining sandboxes. Timed-out tasks leave orphaned thread
|
||||
# pool workers still executing commands -- cleanup_all stops them.
|
||||
from tools.terminal_tool import cleanup_all_environments
|
||||
from hermes_agent.tools.terminal import cleanup_all_environments
|
||||
print("\nCleaning up all sandboxes...")
|
||||
cleanup_all_environments()
|
||||
|
||||
|
|
|
|||
|
|
@ -709,7 +709,7 @@ class YCBenchEvalEnv(HermesAgentBaseEnv):
|
|||
tqdm.write("\n[INTERRUPTED] Stopping evaluation...")
|
||||
pbar.close()
|
||||
try:
|
||||
from tools.terminal_tool import cleanup_all_environments
|
||||
from hermes_agent.tools.terminal import cleanup_all_environments
|
||||
cleanup_all_environments()
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -819,7 +819,7 @@ class YCBenchEvalEnv(HermesAgentBaseEnv):
|
|||
print(f"Results saved to: {self._streaming_path}")
|
||||
|
||||
try:
|
||||
from tools.terminal_tool import cleanup_all_environments
|
||||
from hermes_agent.tools.terminal import cleanup_all_environments
|
||||
cleanup_all_environments()
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -62,15 +62,15 @@ from atroposlib.type_definitions import Item
|
|||
|
||||
from environments.agent_loop import AgentResult, HermesAgentLoop
|
||||
from environments.tool_context import ToolContext
|
||||
from tools.budget_config import (
|
||||
from hermes_agent.tools.budget_config import (
|
||||
DEFAULT_RESULT_SIZE_CHARS,
|
||||
DEFAULT_TURN_BUDGET_CHARS,
|
||||
DEFAULT_PREVIEW_SIZE_CHARS,
|
||||
)
|
||||
|
||||
# Import hermes-agent toolset infrastructure
|
||||
from model_tools import get_tool_definitions
|
||||
from toolset_distributions import sample_toolsets_from_distribution
|
||||
from hermes_agent.tools.dispatch import get_tool_definitions
|
||||
from hermes_agent.tools.distributions import sample_toolsets_from_distribution
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ class HermesAgentEnvConfig(BaseEnvConfig):
|
|||
|
||||
def build_budget_config(self):
|
||||
"""Build a BudgetConfig from env config fields."""
|
||||
from tools.budget_config import BudgetConfig
|
||||
from hermes_agent.tools.budget_config import BudgetConfig
|
||||
return BudgetConfig(
|
||||
default_result_size=self.default_result_size_chars,
|
||||
turn_budget=self.turn_budget_chars,
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ from typing import Any, Dict, List, Optional
|
|||
import asyncio
|
||||
import concurrent.futures
|
||||
|
||||
from model_tools import handle_function_call
|
||||
from tools.terminal_tool import cleanup_vm
|
||||
from tools.browser_tool import cleanup_browser
|
||||
from hermes_agent.tools.dispatch import handle_function_call
|
||||
from hermes_agent.tools.terminal import cleanup_vm
|
||||
from hermes_agent.tools.browser.tool import cleanup_browser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -446,7 +446,7 @@ class ToolContext:
|
|||
"""
|
||||
# Kill any background processes from this rollout (safety net)
|
||||
try:
|
||||
from tools.process_registry import process_registry
|
||||
from hermes_agent.tools.process_registry import process_registry
|
||||
killed = process_registry.kill_all(task_id=self.task_id)
|
||||
if killed:
|
||||
logger.debug("Process cleanup for task %s: killed %d process(es)", self.task_id, killed)
|
||||
|
|
|
|||
2
hermes
2
hermes
|
|
@ -7,5 +7,5 @@ subcommands such as `gateway`, `cron`, and `doctor`.
|
|||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
from hermes_cli.main import main
|
||||
from hermes_agent.cli.main import main
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from typing import Optional
|
|||
def detect_provider() -> Optional[str]:
|
||||
"""Resolve the active Hermes runtime provider, or None if unavailable."""
|
||||
try:
|
||||
from hermes_cli.runtime_provider import resolve_runtime_provider
|
||||
from hermes_agent.cli.runtime_provider import resolve_runtime_provider
|
||||
runtime = resolve_runtime_provider()
|
||||
api_key = runtime.get("api_key")
|
||||
provider = runtime.get("provider")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import asyncio
|
|||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
|
||||
# Methods clients send as periodic liveness probes. They are not part of the
|
||||
|
|
@ -83,7 +83,7 @@ def _setup_logging() -> None:
|
|||
|
||||
def _load_env() -> None:
|
||||
"""Load .env from HERMES_HOME (default ``~/.hermes``)."""
|
||||
from hermes_cli.env_loader import load_hermes_dotenv
|
||||
from hermes_agent.cli.env_loader import load_hermes_dotenv
|
||||
|
||||
hermes_home = get_hermes_home()
|
||||
loaded = load_hermes_dotenv(hermes_home=hermes_home)
|
||||
|
|
@ -104,11 +104,6 @@ def main() -> None:
|
|||
logger = logging.getLogger(__name__)
|
||||
logger.info("Starting hermes-agent ACP adapter")
|
||||
|
||||
# Ensure the project root is on sys.path so ``from run_agent import AIAgent`` works
|
||||
project_root = str(Path(__file__).resolve().parent.parent)
|
||||
if project_root not in sys.path:
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
import acp
|
||||
from .server import HermesACPAgent
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ def make_tool_progress_cb(
|
|||
snapshot = None
|
||||
if name in {"write_file", "patch", "skill_manage"}:
|
||||
try:
|
||||
from agent.display import capture_local_edit_snapshot
|
||||
from hermes_agent.agent.display import capture_local_edit_snapshot
|
||||
|
||||
snapshot = capture_local_edit_snapshot(name, args)
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -52,20 +52,20 @@ try:
|
|||
except ImportError:
|
||||
from acp.schema import AuthMethod as AuthMethodAgent # type: ignore[attr-defined]
|
||||
|
||||
from acp_adapter.auth import detect_provider
|
||||
from acp_adapter.events import (
|
||||
from hermes_agent.acp.auth import detect_provider
|
||||
from hermes_agent.acp.events import (
|
||||
make_message_cb,
|
||||
make_step_cb,
|
||||
make_thinking_cb,
|
||||
make_tool_progress_cb,
|
||||
)
|
||||
from acp_adapter.permissions import make_approval_callback
|
||||
from acp_adapter.session import SessionManager, SessionState
|
||||
from hermes_agent.acp.permissions import make_approval_callback
|
||||
from hermes_agent.acp.session import SessionManager, SessionState
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
from hermes_cli import __version__ as HERMES_VERSION
|
||||
from hermes_agent.cli import __version__ as HERMES_VERSION
|
||||
except Exception:
|
||||
HERMES_VERSION = "0.0.0"
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ class HermesACPAgent(acp.Agent):
|
|||
provider = getattr(state.agent, "provider", None) or detect_provider() or "openrouter"
|
||||
|
||||
try:
|
||||
from hermes_cli.models import curated_models_for_provider, normalize_provider, provider_label
|
||||
from hermes_agent.cli.models.models import curated_models_for_provider, normalize_provider, provider_label
|
||||
|
||||
normalized_provider = normalize_provider(provider)
|
||||
provider_name = provider_label(normalized_provider)
|
||||
|
|
@ -235,7 +235,7 @@ class HermesACPAgent(acp.Agent):
|
|||
new_model = raw_model.strip()
|
||||
|
||||
try:
|
||||
from hermes_cli.models import detect_provider_for_model, parse_model_input
|
||||
from hermes_agent.cli.models.models import detect_provider_for_model, parse_model_input
|
||||
|
||||
target_provider, new_model = parse_model_input(new_model, current_provider)
|
||||
if target_provider == current_provider:
|
||||
|
|
@ -257,7 +257,7 @@ class HermesACPAgent(acp.Agent):
|
|||
return
|
||||
|
||||
try:
|
||||
from tools.mcp_tool import register_mcp_servers
|
||||
from hermes_agent.tools.mcp.tool import register_mcp_servers
|
||||
|
||||
config_map: dict[str, dict] = {}
|
||||
for server in mcp_servers:
|
||||
|
|
@ -285,7 +285,7 @@ class HermesACPAgent(acp.Agent):
|
|||
return
|
||||
|
||||
try:
|
||||
from model_tools import get_tool_definitions
|
||||
from hermes_agent.tools.dispatch import get_tool_definitions
|
||||
|
||||
enabled_toolsets = getattr(state.agent, "enabled_toolsets", None) or ["hermes-acp"]
|
||||
disabled_toolsets = getattr(state.agent, "disabled_toolsets", None)
|
||||
|
|
@ -572,7 +572,7 @@ class HermesACPAgent(acp.Agent):
|
|||
nonlocal previous_approval_cb, previous_interactive
|
||||
if approval_cb:
|
||||
try:
|
||||
from tools import terminal_tool as _terminal_tool
|
||||
from hermes_agent.tools import terminal_tool as _terminal_tool
|
||||
previous_approval_cb = _terminal_tool._get_approval_callback()
|
||||
_terminal_tool.set_approval_callback(approval_cb)
|
||||
except Exception:
|
||||
|
|
@ -599,7 +599,7 @@ class HermesACPAgent(acp.Agent):
|
|||
os.environ["HERMES_INTERACTIVE"] = previous_interactive
|
||||
if approval_cb:
|
||||
try:
|
||||
from tools import terminal_tool as _terminal_tool
|
||||
from hermes_agent.tools import terminal_tool as _terminal_tool
|
||||
_terminal_tool.set_approval_callback(previous_approval_cb)
|
||||
except Exception:
|
||||
logger.debug("Could not restore approval callback", exc_info=True)
|
||||
|
|
@ -618,7 +618,7 @@ class HermesACPAgent(acp.Agent):
|
|||
final_response = result.get("final_response", "")
|
||||
if final_response:
|
||||
try:
|
||||
from agent.title_generator import maybe_auto_title
|
||||
from hermes_agent.agent.title_generator import maybe_auto_title
|
||||
|
||||
maybe_auto_title(
|
||||
self.session_manager._get_db(),
|
||||
|
|
@ -753,7 +753,7 @@ class HermesACPAgent(acp.Agent):
|
|||
|
||||
def _cmd_tools(self, args: str, state: SessionState) -> str:
|
||||
try:
|
||||
from model_tools import get_tool_definitions
|
||||
from hermes_agent.tools.dispatch import get_tool_definitions
|
||||
toolsets = getattr(state.agent, "enabled_toolsets", None) or ["hermes-acp"]
|
||||
tools = get_tool_definitions(enabled_toolsets=toolsets, quiet_mode=True)
|
||||
if not tools:
|
||||
|
|
@ -804,7 +804,7 @@ class HermesACPAgent(acp.Agent):
|
|||
if not hasattr(agent, "_compress_context"):
|
||||
return "Context compression not available for this agent."
|
||||
|
||||
from agent.model_metadata import estimate_messages_tokens_rough
|
||||
from hermes_agent.providers.metadata import estimate_messages_tokens_rough
|
||||
|
||||
original_count = len(state.history)
|
||||
approx_tokens = estimate_messages_tokens_rough(state.history)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ history.
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
|
@ -100,7 +100,7 @@ def _register_task_cwd(task_id: str, cwd: str) -> None:
|
|||
if not task_id:
|
||||
return
|
||||
try:
|
||||
from tools.terminal_tool import register_task_env_overrides
|
||||
from hermes_agent.tools.terminal import register_task_env_overrides
|
||||
register_task_env_overrides(task_id, {"cwd": cwd})
|
||||
except Exception:
|
||||
logger.debug("Failed to register ACP task cwd override", exc_info=True)
|
||||
|
|
@ -111,7 +111,7 @@ def _clear_task_cwd(task_id: str) -> None:
|
|||
if not task_id:
|
||||
return
|
||||
try:
|
||||
from tools.terminal_tool import clear_task_env_overrides
|
||||
from hermes_agent.tools.terminal import clear_task_env_overrides
|
||||
clear_task_env_overrides(task_id)
|
||||
except Exception:
|
||||
logger.debug("Failed to clear ACP task cwd override", exc_info=True)
|
||||
|
|
@ -355,7 +355,7 @@ class SessionManager:
|
|||
if self._db_instance is not None:
|
||||
return self._db_instance
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
hermes_home = get_hermes_home()
|
||||
self._db_instance = SessionDB(db_path=hermes_home / "state.db")
|
||||
return self._db_instance
|
||||
|
|
@ -523,9 +523,9 @@ class SessionManager:
|
|||
if self._agent_factory is not None:
|
||||
return self._agent_factory()
|
||||
|
||||
from run_agent import AIAgent
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_cli.runtime_provider import resolve_runtime_provider
|
||||
from hermes_agent.agent.loop import AIAgent
|
||||
from hermes_agent.cli.config import load_config
|
||||
from hermes_agent.cli.runtime_provider import resolve_runtime_provider
|
||||
|
||||
config = load_config()
|
||||
model_cfg = config.get("model")
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ def _build_patch_mode_content(patch_text: str) -> List[Any]:
|
|||
return [acp.tool_content(acp.text_block(""))]
|
||||
|
||||
try:
|
||||
from tools.patch_parser import OperationType, parse_v4a_patch
|
||||
from hermes_agent.tools.patch_parser import OperationType, parse_v4a_patch
|
||||
|
||||
operations, error = parse_v4a_patch(patch_text)
|
||||
if error or not operations:
|
||||
|
|
@ -243,7 +243,7 @@ def _build_tool_complete_content(
|
|||
|
||||
if tool_name in {"write_file", "patch", "skill_manage"}:
|
||||
try:
|
||||
from agent.display import extract_edit_diff
|
||||
from hermes_agent.agent.display import extract_edit_diff
|
||||
|
||||
diff_text = extract_edit_diff(
|
||||
tool_name,
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ import re
|
|||
import time
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from agent.auxiliary_client import call_llm
|
||||
from agent.context_engine import ContextEngine
|
||||
from agent.model_metadata import (
|
||||
from hermes_agent.providers.auxiliary import call_llm
|
||||
from hermes_agent.agent.context.engine import ContextEngine
|
||||
from hermes_agent.providers.metadata import (
|
||||
MINIMUM_CONTEXT_LENGTH,
|
||||
get_model_context_length,
|
||||
estimate_messages_tokens_rough,
|
||||
)
|
||||
from agent.redact import redact_sensitive_text
|
||||
from hermes_agent.agent.redact import redact_sensitive_text
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from dataclasses import dataclass, field
|
|||
from pathlib import Path
|
||||
from typing import Awaitable, Callable
|
||||
|
||||
from agent.model_metadata import estimate_tokens_rough
|
||||
from hermes_agent.providers.metadata import estimate_tokens_rough
|
||||
|
||||
_QUOTED_REFERENCE_VALUE = r'(?:`[^`\n]+`|"[^"\n]+"|\'[^\'\n]+\')'
|
||||
REFERENCE_PATTERN = re.compile(
|
||||
|
|
@ -315,7 +315,7 @@ async def _fetch_url_content(
|
|||
|
||||
|
||||
async def _default_url_fetcher(url: str) -> str:
|
||||
from tools.web_tools import web_extract_tool
|
||||
from hermes_agent.tools.web import web_extract_tool
|
||||
|
||||
raw = await web_extract_tool([url], format="markdown", use_llm_processing=True)
|
||||
payload = json.loads(raw)
|
||||
|
|
@ -340,7 +340,7 @@ def _resolve_path(cwd: Path, target: str, *, allowed_root: Path | None = None) -
|
|||
|
||||
|
||||
def _ensure_reference_path_allowed(path: Path) -> None:
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
home = Path(os.path.expanduser("~")).resolve()
|
||||
hermes_home = get_hermes_home().resolve()
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ from pathlib import Path
|
|||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
|
||||
from agent.file_safety import get_read_block_error, is_write_denied
|
||||
from agent.redact import redact_sensitive_text
|
||||
from hermes_agent.agent.file_safety import get_read_block_error, is_write_denied
|
||||
from hermes_agent.agent.redact import redact_sensitive_text
|
||||
|
||||
ACP_MARKER_BASE_URL = "acp://copilot"
|
||||
_DEFAULT_TIMEOUT_SECONDS = 900.0
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from dataclasses import dataclass, field
|
|||
from difflib import unified_diff
|
||||
from pathlib import Path
|
||||
|
||||
from utils import safe_json_loads
|
||||
from hermes_agent.utils import safe_json_loads
|
||||
|
||||
# ANSI escape codes for coloring tool failure indicators
|
||||
_RED = "\033[31m"
|
||||
|
|
@ -43,7 +43,7 @@ def _diff_ansi() -> dict[str, str]:
|
|||
plus = "\033[38;2;255;255;255;48;2;20;90;20m"
|
||||
|
||||
try:
|
||||
from hermes_cli.skin_engine import get_active_skin
|
||||
from hermes_agent.cli.ui.skin_engine import get_active_skin
|
||||
skin = get_active_skin()
|
||||
|
||||
def _hex_fg(key: str, fallback_rgb: tuple[int, int, int]) -> str:
|
||||
|
|
@ -118,7 +118,7 @@ def get_tool_preview_max_len() -> int:
|
|||
def _get_skin():
|
||||
"""Get the active skin config, or None if not available."""
|
||||
try:
|
||||
from hermes_cli.skin_engine import get_active_skin
|
||||
from hermes_agent.cli.ui.skin_engine import get_active_skin
|
||||
return get_active_skin()
|
||||
except Exception:
|
||||
return None
|
||||
|
|
@ -148,7 +148,7 @@ def get_tool_emoji(tool_name: str, default: str = "⚡") -> str:
|
|||
return override
|
||||
# 2. Registry default
|
||||
try:
|
||||
from tools.registry import registry
|
||||
from hermes_agent.tools.registry import registry
|
||||
emoji = registry.get_emoji(tool_name, default="")
|
||||
if emoji:
|
||||
return emoji
|
||||
|
|
@ -311,7 +311,7 @@ def _resolve_skill_manage_paths(args: dict) -> list[Path]:
|
|||
if not action or not name:
|
||||
return []
|
||||
|
||||
from tools.skill_manager_tool import _find_skill, _resolve_skill_dir
|
||||
from hermes_agent.tools.skills.manager import _find_skill, _resolve_skill_dir
|
||||
|
||||
if action == "create":
|
||||
skill_dir = _resolve_skill_dir(name, args.get("category"))
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from typing import Optional
|
|||
def _hermes_home_path() -> Path:
|
||||
"""Resolve the active HERMES_HOME (profile-aware) without circular imports."""
|
||||
try:
|
||||
from hermes_constants import get_hermes_home # local import to avoid cycles
|
||||
from hermes_agent.constants import get_hermes_home # local import to avoid cycles
|
||||
return get_hermes_home()
|
||||
except Exception:
|
||||
return Path(os.path.expanduser("~/.hermes"))
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ def resolve_aspect_ratio(value: Optional[str]) -> str:
|
|||
|
||||
def _images_cache_dir() -> Path:
|
||||
"""Return ``$HERMES_HOME/cache/images/``, creating parents as needed."""
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
path = get_hermes_home() / "cache" / "images"
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import logging
|
|||
import threading
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from agent.image_gen_provider import ImageGenProvider
|
||||
from hermes_agent.agent.image_gen.provider import ImageGenProvider
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ def get_active_provider() -> Optional[ImageGenProvider]:
|
|||
"""
|
||||
configured: Optional[str] = None
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
|
||||
cfg = load_config()
|
||||
section = cfg.get("image_gen") if isinstance(cfg, dict) else None
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ multi-platform architecture with additional cost estimation and platform
|
|||
breakdown capabilities.
|
||||
|
||||
Usage:
|
||||
from agent.insights import InsightsEngine
|
||||
from hermes_agent.agent.insights import InsightsEngine
|
||||
engine = InsightsEngine(db)
|
||||
report = engine.generate(days=30)
|
||||
print(engine.format_terminal(report))
|
||||
|
|
@ -22,7 +22,7 @@ from collections import Counter, defaultdict
|
|||
from datetime import datetime
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from agent.usage_pricing import (
|
||||
from hermes_agent.providers.pricing import (
|
||||
CanonicalUsage,
|
||||
DEFAULT_PRICING,
|
||||
estimate_usage_cost,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Features:
|
|||
- Support for multiple model providers
|
||||
|
||||
Usage:
|
||||
from run_agent import AIAgent
|
||||
from hermes_agent.agent.loop import AIAgent
|
||||
|
||||
agent = AIAgent(base_url="http://localhost:30000/v1", model="claude-opus-4-20250514")
|
||||
response = agent.run_conversation("Tell me about the latest Python updates")
|
||||
|
|
@ -40,18 +40,18 @@ import uuid
|
|||
from typing import Callable, List, Dict, Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agent.rate_limit_tracker import RateLimitState
|
||||
from hermes_agent.providers.rate_limiting import RateLimitState
|
||||
from openai import OpenAI
|
||||
import fire
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
# Load .env from ~/.hermes/.env first, then project root as dev fallback.
|
||||
# User-managed env files should override stale shell exports on restart.
|
||||
from hermes_cli.env_loader import load_hermes_dotenv
|
||||
from hermes_cli.timeouts import (
|
||||
from hermes_agent.cli.env_loader import load_hermes_dotenv
|
||||
from hermes_agent.cli.timeouts import (
|
||||
get_provider_request_timeout,
|
||||
get_provider_stale_timeout,
|
||||
)
|
||||
|
|
@ -67,30 +67,30 @@ else:
|
|||
|
||||
|
||||
# Import our tool system
|
||||
from model_tools import (
|
||||
from hermes_agent.tools.dispatch import (
|
||||
get_tool_definitions,
|
||||
get_toolset_for_tool,
|
||||
handle_function_call,
|
||||
check_toolset_requirements,
|
||||
)
|
||||
from tools.terminal_tool import cleanup_vm, get_active_env, is_persistent_env
|
||||
from tools.tool_result_storage import maybe_persist_tool_result, enforce_turn_budget
|
||||
from tools.interrupt import set_interrupt as _set_interrupt
|
||||
from tools.browser_tool import cleanup_browser
|
||||
from hermes_agent.tools.terminal import cleanup_vm, get_active_env, is_persistent_env
|
||||
from hermes_agent.tools.result_storage import maybe_persist_tool_result, enforce_turn_budget
|
||||
from hermes_agent.tools.interrupt import set_interrupt as _set_interrupt
|
||||
from hermes_agent.tools.browser.tool import cleanup_browser
|
||||
|
||||
|
||||
from hermes_constants import OPENROUTER_BASE_URL
|
||||
from hermes_agent.constants import OPENROUTER_BASE_URL
|
||||
|
||||
# Agent internals extracted to agent/ package for modularity
|
||||
from agent.memory_manager import build_memory_context_block, sanitize_context
|
||||
from agent.retry_utils import jittered_backoff
|
||||
from agent.error_classifier import classify_api_error, FailoverReason
|
||||
from agent.prompt_builder import (
|
||||
from hermes_agent.agent.memory.manager import build_memory_context_block, sanitize_context
|
||||
from hermes_agent.providers.retry import jittered_backoff
|
||||
from hermes_agent.providers.errors import classify_api_error, FailoverReason
|
||||
from hermes_agent.agent.prompt_builder import (
|
||||
DEFAULT_AGENT_IDENTITY, PLATFORM_HINTS,
|
||||
MEMORY_GUIDANCE, SESSION_SEARCH_GUIDANCE, SKILLS_GUIDANCE,
|
||||
build_nous_subscription_prompt,
|
||||
)
|
||||
from agent.model_metadata import (
|
||||
from hermes_agent.providers.metadata import (
|
||||
fetch_model_metadata,
|
||||
estimate_tokens_rough, estimate_messages_tokens_rough, estimate_request_tokens_rough,
|
||||
get_next_probe_tier, parse_context_limit_from_error,
|
||||
|
|
@ -98,12 +98,12 @@ from agent.model_metadata import (
|
|||
save_context_length, is_local_endpoint,
|
||||
query_ollama_num_ctx,
|
||||
)
|
||||
from agent.context_compressor import ContextCompressor
|
||||
from agent.subdirectory_hints import SubdirectoryHintTracker
|
||||
from agent.prompt_caching import apply_anthropic_cache_control
|
||||
from agent.prompt_builder import build_skills_system_prompt, build_context_files_prompt, build_environment_hints, load_soul_md, TOOL_USE_ENFORCEMENT_GUIDANCE, TOOL_USE_ENFORCEMENT_MODELS, DEVELOPER_ROLE_MODELS, GOOGLE_MODEL_OPERATIONAL_GUIDANCE, OPENAI_MODEL_EXECUTION_GUIDANCE
|
||||
from agent.usage_pricing import estimate_usage_cost, normalize_usage
|
||||
from agent.codex_responses_adapter import (
|
||||
from hermes_agent.agent.context.compressor import ContextCompressor
|
||||
from hermes_agent.agent.subdirectory_hints import SubdirectoryHintTracker
|
||||
from hermes_agent.providers.caching import apply_anthropic_cache_control
|
||||
from hermes_agent.agent.prompt_builder import build_skills_system_prompt, build_context_files_prompt, build_environment_hints, load_soul_md, TOOL_USE_ENFORCEMENT_GUIDANCE, TOOL_USE_ENFORCEMENT_MODELS, DEVELOPER_ROLE_MODELS, GOOGLE_MODEL_OPERATIONAL_GUIDANCE, OPENAI_MODEL_EXECUTION_GUIDANCE
|
||||
from hermes_agent.providers.pricing import estimate_usage_cost, normalize_usage
|
||||
from hermes_agent.providers.codex_adapter import (
|
||||
_chat_content_to_responses_parts,
|
||||
_chat_messages_to_responses_input as _codex_chat_messages_to_responses_input,
|
||||
_derive_responses_function_call_id as _codex_derive_responses_function_call_id,
|
||||
|
|
@ -117,17 +117,17 @@ from agent.codex_responses_adapter import (
|
|||
_split_responses_tool_id as _codex_split_responses_tool_id,
|
||||
_summarize_user_message_for_log,
|
||||
)
|
||||
from agent.display import (
|
||||
from hermes_agent.agent.display import (
|
||||
KawaiiSpinner, build_tool_preview as _build_tool_preview,
|
||||
get_cute_tool_message as _get_cute_tool_message_impl,
|
||||
_detect_tool_failure,
|
||||
get_tool_emoji as _get_tool_emoji,
|
||||
)
|
||||
from agent.trajectory import (
|
||||
from hermes_agent.agent.trajectory import (
|
||||
convert_scratchpad_to_think, has_incomplete_scratchpad,
|
||||
save_trajectory as _save_trajectory_to_file,
|
||||
)
|
||||
from utils import atomic_json_write, base_url_host_matches, base_url_hostname, env_var_enabled, normalize_proxy_url
|
||||
from hermes_agent.utils import atomic_json_write, base_url_host_matches, base_url_hostname, env_var_enabled, normalize_proxy_url
|
||||
|
||||
|
||||
|
||||
|
|
@ -876,7 +876,7 @@ class AIAgent:
|
|||
self.api_mode = "chat_completions"
|
||||
|
||||
try:
|
||||
from hermes_cli.model_normalize import (
|
||||
from hermes_agent.cli.models.normalize import (
|
||||
_AGGREGATOR_PROVIDERS,
|
||||
normalize_model_for_provider,
|
||||
)
|
||||
|
|
@ -1026,7 +1026,7 @@ class AIAgent:
|
|||
# Centralized logging — agent.log (INFO+) and errors.log (WARNING+)
|
||||
# both live under ~/.hermes/logs/. Idempotent, so gateway mode
|
||||
# (which creates a new AIAgent per message) won't duplicate handlers.
|
||||
from hermes_logging import setup_logging, setup_verbose_logging
|
||||
from hermes_agent.logging import setup_logging, setup_verbose_logging
|
||||
setup_logging(hermes_home=_hermes_home)
|
||||
|
||||
if self.verbose_logging:
|
||||
|
|
@ -1040,10 +1040,10 @@ class AIAgent:
|
|||
# File handlers (agent.log, errors.log) still capture everything.
|
||||
for quiet_logger in [
|
||||
'tools', # all tools.* (terminal, browser, web, file, etc.)
|
||||
'run_agent', # agent runner internals
|
||||
'hermes_agent.agent.loop', # agent runner internals
|
||||
'scripts.trajectory_compressor',
|
||||
'cron', # scheduler (only relevant in daemon mode)
|
||||
'hermes_cli', # CLI helpers
|
||||
'hermes_agent.cli', # CLI helpers
|
||||
]:
|
||||
logging.getLogger(quiet_logger).setLevel(logging.ERROR)
|
||||
|
||||
|
|
@ -1085,12 +1085,12 @@ class AIAgent:
|
|||
_provider_timeout = get_provider_request_timeout(self.provider, self.model)
|
||||
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client, resolve_anthropic_token
|
||||
# Bedrock + Claude → use AnthropicBedrock SDK for full feature parity
|
||||
# (prompt caching, thinking budgets, adaptive thinking).
|
||||
_is_bedrock_anthropic = self.provider == "bedrock"
|
||||
if _is_bedrock_anthropic:
|
||||
from agent.anthropic_adapter import build_anthropic_bedrock_client
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_bedrock_client
|
||||
_region_match = re.search(r"bedrock-runtime\.([a-z0-9-]+)\.", base_url or "")
|
||||
_br_region = _region_match.group(1) if _region_match else "us-east-1"
|
||||
self._bedrock_region = _br_region
|
||||
|
|
@ -1119,7 +1119,7 @@ class AIAgent:
|
|||
# so injects Claude-Code identity headers and system prompts
|
||||
# that cause 401/403 on their endpoints. Guards #1739 and
|
||||
# the third-party identity-injection bug.
|
||||
from agent.anthropic_adapter import _is_oauth_token as _is_oat
|
||||
from hermes_agent.providers.anthropic_adapter import _is_oauth_token as _is_oat
|
||||
self._is_anthropic_oauth = _is_oat(effective_key) if _is_native_anthropic else False
|
||||
self._anthropic_client = build_anthropic_client(effective_key, base_url, timeout=_provider_timeout)
|
||||
# No OpenAI client needed for Anthropic mode
|
||||
|
|
@ -1137,7 +1137,7 @@ class AIAgent:
|
|||
# Guardrail config — read from config.yaml at init time.
|
||||
self._bedrock_guardrail_config = None
|
||||
try:
|
||||
from hermes_cli.config import load_config as _load_br_cfg
|
||||
from hermes_agent.cli.config import load_config as _load_br_cfg
|
||||
_gr = _load_br_cfg().get("bedrock", {}).get("guardrail", {})
|
||||
if _gr.get("guardrail_identifier") and _gr.get("guardrail_version"):
|
||||
self._bedrock_guardrail_config = {
|
||||
|
|
@ -1173,7 +1173,7 @@ class AIAgent:
|
|||
"X-OpenRouter-Categories": "productivity,cli-agent",
|
||||
}
|
||||
elif base_url_host_matches(effective_base, "api.githubcopilot.com"):
|
||||
from hermes_cli.models import copilot_default_headers
|
||||
from hermes_agent.cli.models.models import copilot_default_headers
|
||||
|
||||
client_kwargs["default_headers"] = copilot_default_headers()
|
||||
elif base_url_host_matches(effective_base, "api.kimi.com"):
|
||||
|
|
@ -1183,11 +1183,11 @@ class AIAgent:
|
|||
elif base_url_host_matches(effective_base, "portal.qwen.ai"):
|
||||
client_kwargs["default_headers"] = _qwen_portal_headers()
|
||||
elif base_url_host_matches(effective_base, "chatgpt.com"):
|
||||
from agent.auxiliary_client import _codex_cloudflare_headers
|
||||
from hermes_agent.providers.auxiliary import _codex_cloudflare_headers
|
||||
client_kwargs["default_headers"] = _codex_cloudflare_headers(api_key)
|
||||
else:
|
||||
# No explicit creds — use the centralized provider router
|
||||
from agent.auxiliary_client import resolve_provider_client
|
||||
from hermes_agent.providers.auxiliary import resolve_provider_client
|
||||
_routed_client, _ = resolve_provider_client(
|
||||
self.provider or "auto", model=self.model, raw_codex=True)
|
||||
if _routed_client is not None:
|
||||
|
|
@ -1211,7 +1211,7 @@ class AIAgent:
|
|||
# (e.g. alibaba → DASHSCOPE_API_KEY, not ALIBABA_API_KEY).
|
||||
_env_hint = f"{_explicit.upper()}_API_KEY"
|
||||
try:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
_pcfg = PROVIDER_REGISTRY.get(_explicit)
|
||||
if _pcfg and _pcfg.api_key_env_vars:
|
||||
_env_hint = _pcfg.api_key_env_vars[0]
|
||||
|
|
@ -1364,7 +1364,7 @@ class AIAgent:
|
|||
self._cached_system_prompt: Optional[str] = None
|
||||
|
||||
# Filesystem checkpoint manager (transparent — not a tool)
|
||||
from tools.checkpoint_manager import CheckpointManager
|
||||
from hermes_agent.tools.checkpoint import CheckpointManager
|
||||
self._checkpoint_mgr = CheckpointManager(
|
||||
enabled=checkpoints_enabled,
|
||||
max_snapshots=checkpoint_max_snapshots,
|
||||
|
|
@ -1400,12 +1400,12 @@ class AIAgent:
|
|||
)
|
||||
|
||||
# In-memory todo list for task planning (one per agent/session)
|
||||
from tools.todo_tool import TodoStore
|
||||
from hermes_agent.tools.todo import TodoStore
|
||||
self._todo_store = TodoStore()
|
||||
|
||||
# Load config once for memory, skills, and compression sections
|
||||
try:
|
||||
from hermes_cli.config import load_config as _load_agent_config
|
||||
from hermes_agent.cli.config import load_config as _load_agent_config
|
||||
_agent_cfg = _load_agent_config()
|
||||
except Exception:
|
||||
_agent_cfg = {}
|
||||
|
|
@ -1430,7 +1430,7 @@ class AIAgent:
|
|||
self._memory_nudge_interval = int(mem_config.get("nudge_interval", 10))
|
||||
self._memory_flush_min_turns = int(mem_config.get("flush_min_turns", 6))
|
||||
if self._memory_enabled or self._user_profile_enabled:
|
||||
from tools.memory_tool import MemoryStore
|
||||
from hermes_agent.tools.memory import MemoryStore
|
||||
self._memory_store = MemoryStore(
|
||||
memory_char_limit=mem_config.get("memory_char_limit", 2200),
|
||||
user_char_limit=mem_config.get("user_char_limit", 1375),
|
||||
|
|
@ -1449,8 +1449,8 @@ class AIAgent:
|
|||
_mem_provider_name = mem_config.get("provider", "") if mem_config else ""
|
||||
|
||||
if _mem_provider_name:
|
||||
from agent.memory_manager import MemoryManager as _MemoryManager
|
||||
from plugins.memory import load_memory_provider as _load_mem
|
||||
from hermes_agent.agent.memory.manager import MemoryManager as _MemoryManager
|
||||
from hermes_agent.plugins.memory import load_memory_provider as _load_mem
|
||||
self._memory_manager = _MemoryManager()
|
||||
_mp = _load_mem(_mem_provider_name)
|
||||
if _mp and _mp.is_available():
|
||||
|
|
@ -1479,7 +1479,7 @@ class AIAgent:
|
|||
_init_kwargs["gateway_session_key"] = self._gateway_session_key
|
||||
# Profile identity for per-profile provider scoping
|
||||
try:
|
||||
from hermes_cli.profiles import get_active_profile_name
|
||||
from hermes_agent.cli.profiles import get_active_profile_name
|
||||
_profile = get_active_profile_name()
|
||||
_init_kwargs["agent_identity"] = _profile
|
||||
_init_kwargs["agent_workspace"] = "hermes"
|
||||
|
|
@ -1590,7 +1590,7 @@ class AIAgent:
|
|||
# Check custom_providers per-model context_length
|
||||
if _config_context_length is None:
|
||||
try:
|
||||
from hermes_cli.config import get_compatible_custom_providers
|
||||
from hermes_agent.cli.config import get_compatible_custom_providers
|
||||
_custom_providers = get_compatible_custom_providers(_agent_cfg)
|
||||
except Exception:
|
||||
_custom_providers = _agent_cfg.get("custom_providers")
|
||||
|
|
@ -1641,7 +1641,7 @@ class AIAgent:
|
|||
if _engine_name != "compressor":
|
||||
# Try loading from plugins/context_engine/<name>/
|
||||
try:
|
||||
from plugins.context_engine import load_context_engine
|
||||
from hermes_agent.plugins.context_engine import load_context_engine
|
||||
_selected_engine = load_context_engine(_engine_name)
|
||||
except Exception as _ce_load_err:
|
||||
logger.debug("Context engine load from plugins/context_engine/: %s", _ce_load_err)
|
||||
|
|
@ -1649,7 +1649,7 @@ class AIAgent:
|
|||
# Try general plugin system as fallback
|
||||
if _selected_engine is None:
|
||||
try:
|
||||
from hermes_cli.plugins import get_plugin_context_engine
|
||||
from hermes_agent.cli.plugins import get_plugin_context_engine
|
||||
_candidate = get_plugin_context_engine()
|
||||
if _candidate and _candidate.name == _engine_name:
|
||||
_selected_engine = _candidate
|
||||
|
|
@ -1666,7 +1666,7 @@ class AIAgent:
|
|||
if _selected_engine is not None:
|
||||
self.context_compressor = _selected_engine
|
||||
# Resolve context_length for plugin engines — mirrors switch_model() path
|
||||
from agent.model_metadata import get_model_context_length
|
||||
from hermes_agent.providers.metadata import get_model_context_length
|
||||
_plugin_ctx_len = get_model_context_length(
|
||||
self.model,
|
||||
base_url=self.base_url,
|
||||
|
|
@ -1702,7 +1702,7 @@ class AIAgent:
|
|||
|
||||
# Reject models whose context window is below the minimum required
|
||||
# for reliable tool-calling workflows (64K tokens).
|
||||
from agent.model_metadata import MINIMUM_CONTEXT_LENGTH
|
||||
from hermes_agent.providers.metadata import MINIMUM_CONTEXT_LENGTH
|
||||
_ctx = getattr(self.context_compressor, "context_length", 0)
|
||||
if _ctx and _ctx < MINIMUM_CONTEXT_LENGTH:
|
||||
raise ValueError(
|
||||
|
|
@ -1879,7 +1879,7 @@ class AIAgent:
|
|||
change persists across turns (unlike fallback which is
|
||||
turn-scoped).
|
||||
"""
|
||||
from hermes_cli.providers import determine_api_mode
|
||||
from hermes_agent.cli.providers import determine_api_mode
|
||||
|
||||
# ── Determine api_mode if not provided ──
|
||||
if not api_mode:
|
||||
|
|
@ -1911,7 +1911,7 @@ class AIAgent:
|
|||
|
||||
# ── Build new client ──
|
||||
if api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import (
|
||||
from hermes_agent.providers.anthropic_adapter import (
|
||||
build_anthropic_client,
|
||||
resolve_anthropic_token,
|
||||
_is_oauth_token,
|
||||
|
|
@ -1959,7 +1959,7 @@ class AIAgent:
|
|||
|
||||
# ── Update context compressor ──
|
||||
if hasattr(self, "context_compressor") and self.context_compressor:
|
||||
from agent.model_metadata import get_model_context_length
|
||||
from hermes_agent.providers.metadata import get_model_context_length
|
||||
new_context_length = get_model_context_length(
|
||||
self.model,
|
||||
base_url=self.base_url,
|
||||
|
|
@ -2154,8 +2154,8 @@ class AIAgent:
|
|||
if not self.compression_enabled:
|
||||
return
|
||||
try:
|
||||
from agent.auxiliary_client import get_text_auxiliary_client
|
||||
from agent.model_metadata import (
|
||||
from hermes_agent.providers.auxiliary import get_text_auxiliary_client
|
||||
from hermes_agent.providers.metadata import (
|
||||
MINIMUM_CONTEXT_LENGTH,
|
||||
get_model_context_length,
|
||||
)
|
||||
|
|
@ -2448,7 +2448,7 @@ class AIAgent:
|
|||
normalized_provider = (provider or "").strip().lower()
|
||||
if normalized_provider == "copilot":
|
||||
try:
|
||||
from hermes_cli.models import _should_use_copilot_responses_api
|
||||
from hermes_agent.cli.models.models import _should_use_copilot_responses_api
|
||||
return _should_use_copilot_responses_api(model)
|
||||
except Exception:
|
||||
# Fall back to the generic GPT-5 rule if Copilot-specific
|
||||
|
|
@ -3756,7 +3756,7 @@ class AIAgent:
|
|||
if not headers:
|
||||
return
|
||||
try:
|
||||
from agent.rate_limit_tracker import parse_rate_limit_headers
|
||||
from hermes_agent.providers.rate_limiting import parse_rate_limit_headers
|
||||
state = parse_rate_limit_headers(headers, provider=self.provider)
|
||||
if state is not None:
|
||||
self._rate_limit_state = state
|
||||
|
|
@ -3888,7 +3888,7 @@ class AIAgent:
|
|||
|
||||
# 1. Kill background processes for this task
|
||||
try:
|
||||
from tools.process_registry import process_registry
|
||||
from hermes_agent.tools.process_registry import process_registry
|
||||
process_registry.kill_all(task_id=task_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -4105,7 +4105,7 @@ class AIAgent:
|
|||
if context_files_prompt:
|
||||
prompt_parts.append(context_files_prompt)
|
||||
|
||||
from hermes_time import now as _hermes_now
|
||||
from hermes_agent.time import now as _hermes_now
|
||||
now = _hermes_now()
|
||||
timestamp_line = f"Conversation started: {now.strftime('%A, %B %d, %Y %I:%M %p')}"
|
||||
if self.pass_session_id and self.session_id:
|
||||
|
|
@ -4233,7 +4233,7 @@ class AIAgent:
|
|||
|
||||
Returns the original list if no truncation was needed.
|
||||
"""
|
||||
from tools.delegate_tool import _get_max_concurrent_children
|
||||
from hermes_agent.tools.delegate import _get_max_concurrent_children
|
||||
max_children = _get_max_concurrent_children()
|
||||
delegate_count = sum(1 for tc in tool_calls if tc.function.name == "delegate_task")
|
||||
if delegate_count <= max_children:
|
||||
|
|
@ -4409,7 +4409,7 @@ class AIAgent:
|
|||
return None
|
||||
|
||||
def _create_openai_client(self, client_kwargs: dict, *, reason: str, shared: bool) -> Any:
|
||||
from agent.auxiliary_client import _validate_base_url, _validate_proxy_env_urls
|
||||
from hermes_agent.providers.auxiliary import _validate_base_url, _validate_proxy_env_urls
|
||||
# Treat client_kwargs as read-only. Callers pass self._client_kwargs (or shallow
|
||||
# copies of it) in; any in-place mutation leaks back into the stored dict and is
|
||||
# reused on subsequent requests. #10933 hit this by injecting an httpx.Client
|
||||
|
|
@ -4422,7 +4422,7 @@ class AIAgent:
|
|||
_validate_proxy_env_urls()
|
||||
_validate_base_url(client_kwargs.get("base_url"))
|
||||
if self.provider == "copilot-acp" or str(client_kwargs.get("base_url", "")).startswith("acp://copilot"):
|
||||
from agent.copilot_acp_client import CopilotACPClient
|
||||
from hermes_agent.agent.copilot_acp_client import CopilotACPClient
|
||||
|
||||
client = CopilotACPClient(**client_kwargs)
|
||||
logger.info(
|
||||
|
|
@ -4433,7 +4433,7 @@ class AIAgent:
|
|||
)
|
||||
return client
|
||||
if self.provider == "google-gemini-cli" or str(client_kwargs.get("base_url", "")).startswith("cloudcode-pa://"):
|
||||
from agent.gemini_cloudcode_adapter import GeminiCloudCodeClient
|
||||
from hermes_agent.providers.gemini_cloudcode_adapter import GeminiCloudCodeClient
|
||||
|
||||
# Strip OpenAI-specific kwargs the Gemini client doesn't accept
|
||||
safe_kwargs = {
|
||||
|
|
@ -4449,7 +4449,7 @@ class AIAgent:
|
|||
)
|
||||
return client
|
||||
if self.provider == "gemini":
|
||||
from agent.gemini_native_adapter import GeminiNativeClient, is_native_gemini_base_url
|
||||
from hermes_agent.providers.gemini_adapter import GeminiNativeClient, is_native_gemini_base_url
|
||||
|
||||
base_url = str(client_kwargs.get("base_url", "") or "")
|
||||
if is_native_gemini_base_url(base_url):
|
||||
|
|
@ -4904,7 +4904,7 @@ class AIAgent:
|
|||
return False
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import resolve_codex_runtime_credentials
|
||||
from hermes_agent.cli.auth.auth import resolve_codex_runtime_credentials
|
||||
|
||||
creds = resolve_codex_runtime_credentials(force_refresh=force)
|
||||
except Exception as exc:
|
||||
|
|
@ -4933,7 +4933,7 @@ class AIAgent:
|
|||
return False
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import resolve_nous_runtime_credentials
|
||||
from hermes_agent.cli.auth.auth import resolve_nous_runtime_credentials
|
||||
|
||||
creds = resolve_nous_runtime_credentials(
|
||||
min_key_ttl_seconds=max(60, int(os.getenv("HERMES_NOUS_MIN_KEY_TTL_SECONDS", "1800"))),
|
||||
|
|
@ -4972,7 +4972,7 @@ class AIAgent:
|
|||
return False
|
||||
|
||||
try:
|
||||
from agent.anthropic_adapter import resolve_anthropic_token, build_anthropic_client
|
||||
from hermes_agent.providers.anthropic_adapter import resolve_anthropic_token, build_anthropic_client
|
||||
|
||||
new_token = resolve_anthropic_token()
|
||||
except Exception as exc:
|
||||
|
|
@ -5005,19 +5005,19 @@ class AIAgent:
|
|||
# Only treat as OAuth on native Anthropic; third-party endpoints using
|
||||
# the Anthropic protocol must not trip OAuth paths (#1739 & third-party
|
||||
# identity-injection guard).
|
||||
from agent.anthropic_adapter import _is_oauth_token
|
||||
from hermes_agent.providers.anthropic_adapter import _is_oauth_token
|
||||
self._is_anthropic_oauth = _is_oauth_token(new_token) if self.provider == "anthropic" else False
|
||||
return True
|
||||
|
||||
def _apply_client_headers_for_base_url(self, base_url: str) -> None:
|
||||
from agent.auxiliary_client import _AI_GATEWAY_HEADERS, _OR_HEADERS
|
||||
from hermes_agent.providers.auxiliary import _AI_GATEWAY_HEADERS, _OR_HEADERS
|
||||
|
||||
if base_url_host_matches(base_url, "openrouter.ai"):
|
||||
self._client_kwargs["default_headers"] = dict(_OR_HEADERS)
|
||||
elif base_url_host_matches(base_url, "ai-gateway.vercel.sh"):
|
||||
self._client_kwargs["default_headers"] = dict(_AI_GATEWAY_HEADERS)
|
||||
elif base_url_host_matches(base_url, "api.githubcopilot.com"):
|
||||
from hermes_cli.models import copilot_default_headers
|
||||
from hermes_agent.cli.models.models import copilot_default_headers
|
||||
|
||||
self._client_kwargs["default_headers"] = copilot_default_headers()
|
||||
elif base_url_host_matches(base_url, "api.kimi.com"):
|
||||
|
|
@ -5025,7 +5025,7 @@ class AIAgent:
|
|||
elif base_url_host_matches(base_url, "portal.qwen.ai"):
|
||||
self._client_kwargs["default_headers"] = _qwen_portal_headers()
|
||||
elif base_url_host_matches(base_url, "chatgpt.com"):
|
||||
from agent.auxiliary_client import _codex_cloudflare_headers
|
||||
from hermes_agent.providers.auxiliary import _codex_cloudflare_headers
|
||||
self._client_kwargs["default_headers"] = _codex_cloudflare_headers(
|
||||
self._client_kwargs.get("api_key", "")
|
||||
)
|
||||
|
|
@ -5037,7 +5037,7 @@ class AIAgent:
|
|||
runtime_base = getattr(entry, "runtime_base_url", None) or getattr(entry, "base_url", None) or self.base_url
|
||||
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client, _is_oauth_token
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client, _is_oauth_token
|
||||
|
||||
try:
|
||||
self._anthropic_client.close()
|
||||
|
|
@ -5181,7 +5181,7 @@ class AIAgent:
|
|||
result["response"] = self._anthropic_messages_create(api_kwargs)
|
||||
elif self.api_mode == "bedrock_converse":
|
||||
# Bedrock uses boto3 directly — no OpenAI client needed.
|
||||
from agent.bedrock_adapter import (
|
||||
from hermes_agent.providers.bedrock_adapter import (
|
||||
_get_bedrock_runtime_client,
|
||||
normalize_converse_response,
|
||||
)
|
||||
|
|
@ -5246,7 +5246,7 @@ class AIAgent:
|
|||
)
|
||||
try:
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client
|
||||
|
||||
self._anthropic_client.close()
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
|
|
@ -5278,7 +5278,7 @@ class AIAgent:
|
|||
# seed future retries.
|
||||
try:
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client
|
||||
|
||||
self._anthropic_client.close()
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
|
|
@ -5439,7 +5439,7 @@ class AIAgent:
|
|||
|
||||
def _bedrock_call():
|
||||
try:
|
||||
from agent.bedrock_adapter import (
|
||||
from hermes_agent.providers.bedrock_adapter import (
|
||||
_get_bedrock_runtime_client,
|
||||
stream_converse_with_callbacks,
|
||||
)
|
||||
|
|
@ -6019,7 +6019,7 @@ class AIAgent:
|
|||
if self._interrupt_requested:
|
||||
try:
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client
|
||||
|
||||
self._anthropic_client.close()
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
|
|
@ -6129,7 +6129,7 @@ class AIAgent:
|
|||
# raw_codex=True because the main agent needs direct responses.stream()
|
||||
# access for Codex providers.
|
||||
try:
|
||||
from agent.auxiliary_client import resolve_provider_client
|
||||
from hermes_agent.providers.auxiliary import resolve_provider_client
|
||||
# Pass base_url and api_key from fallback config so custom
|
||||
# endpoints (e.g. Ollama Cloud) resolve correctly instead of
|
||||
# falling through to OpenRouter defaults.
|
||||
|
|
@ -6150,7 +6150,7 @@ class AIAgent:
|
|||
fb_provider)
|
||||
return self._try_activate_fallback() # try next in chain
|
||||
try:
|
||||
from hermes_cli.model_normalize import normalize_model_for_provider
|
||||
from hermes_agent.cli.models.normalize import normalize_model_for_provider
|
||||
|
||||
fb_model = normalize_model_for_provider(fb_model, fb_provider)
|
||||
except Exception:
|
||||
|
|
@ -6193,7 +6193,7 @@ class AIAgent:
|
|||
|
||||
if fb_api_mode == "anthropic_messages":
|
||||
# Build native Anthropic client instead of using OpenAI client
|
||||
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token
|
||||
effective_key = (fb_client.api_key or resolve_anthropic_token() or "") if fb_provider == "anthropic" else (fb_client.api_key or "")
|
||||
self.api_key = effective_key
|
||||
self._anthropic_api_key = effective_key
|
||||
|
|
@ -6246,7 +6246,7 @@ class AIAgent:
|
|||
# context window (e.g. 200K) instead of the fallback's (e.g. 32K),
|
||||
# causing oversized sessions to overflow the fallback.
|
||||
if hasattr(self, 'context_compressor') and self.context_compressor:
|
||||
from agent.model_metadata import get_model_context_length
|
||||
from hermes_agent.providers.metadata import get_model_context_length
|
||||
fb_context_length = get_model_context_length(
|
||||
self.model, base_url=self.base_url,
|
||||
api_key=self.api_key, provider=self.provider,
|
||||
|
|
@ -6307,7 +6307,7 @@ class AIAgent:
|
|||
|
||||
# ── Rebuild client for the primary provider ──
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client
|
||||
self._anthropic_api_key = rt["anthropic_api_key"]
|
||||
self._anthropic_base_url = rt["anthropic_base_url"]
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
|
|
@ -6404,7 +6404,7 @@ class AIAgent:
|
|||
self.api_key = rt["api_key"]
|
||||
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client
|
||||
from hermes_agent.providers.anthropic_adapter import build_anthropic_client
|
||||
self._anthropic_api_key = rt["anthropic_api_key"]
|
||||
self._anthropic_base_url = rt["anthropic_base_url"]
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
|
|
@ -6487,7 +6487,7 @@ class AIAgent:
|
|||
|
||||
description = ""
|
||||
try:
|
||||
from tools.vision_tools import vision_analyze_tool
|
||||
from hermes_agent.tools.vision import vision_analyze_tool
|
||||
|
||||
result_json = asyncio.run(
|
||||
vision_analyze_tool(image_url=vision_source, user_prompt=analysis_prompt)
|
||||
|
|
@ -6563,7 +6563,7 @@ class AIAgent:
|
|||
"""Return the cached AnthropicTransport instance (lazy singleton)."""
|
||||
t = getattr(self, "_anthropic_transport", None)
|
||||
if t is None:
|
||||
from agent.transports import get_transport
|
||||
from hermes_agent.providers import get_transport
|
||||
t = get_transport("anthropic_messages")
|
||||
self._anthropic_transport = t
|
||||
return t
|
||||
|
|
@ -6572,7 +6572,7 @@ class AIAgent:
|
|||
"""Return the cached ResponsesApiTransport instance (lazy singleton)."""
|
||||
t = getattr(self, "_codex_transport", None)
|
||||
if t is None:
|
||||
from agent.transports import get_transport
|
||||
from hermes_agent.providers import get_transport
|
||||
t = get_transport("codex_responses")
|
||||
self._codex_transport = t
|
||||
return t
|
||||
|
|
@ -6581,7 +6581,7 @@ class AIAgent:
|
|||
"""Return the cached ChatCompletionsTransport instance (lazy singleton)."""
|
||||
t = getattr(self, "_chat_completions_transport", None)
|
||||
if t is None:
|
||||
from agent.transports import get_transport
|
||||
from hermes_agent.providers import get_transport
|
||||
t = get_transport("chat_completions")
|
||||
self._chat_completions_transport = t
|
||||
return t
|
||||
|
|
@ -6590,7 +6590,7 @@ class AIAgent:
|
|||
"""Return the cached BedrockTransport instance (lazy singleton)."""
|
||||
t = getattr(self, "_bedrock_transport", None)
|
||||
if t is None:
|
||||
from agent.transports import get_transport
|
||||
from hermes_agent.providers import get_transport
|
||||
t = get_transport("bedrock_converse")
|
||||
self._bedrock_transport = t
|
||||
return t
|
||||
|
|
@ -6795,7 +6795,7 @@ class AIAgent:
|
|||
# Temperature: _fixed_temperature_for_model may return OMIT_TEMPERATURE
|
||||
# sentinel (temperature omitted entirely), a numeric override, or None.
|
||||
try:
|
||||
from agent.auxiliary_client import _fixed_temperature_for_model, OMIT_TEMPERATURE
|
||||
from hermes_agent.providers.auxiliary import _fixed_temperature_for_model, OMIT_TEMPERATURE
|
||||
_ft = _fixed_temperature_for_model(self.model, self.base_url)
|
||||
_omit_temp = _ft is OMIT_TEMPERATURE
|
||||
_fixed_temp = _ft if not _omit_temp else None
|
||||
|
|
@ -6822,7 +6822,7 @@ class AIAgent:
|
|||
_ant_max = None
|
||||
if (_is_or or _is_nous) and "claude" in (self.model or "").lower():
|
||||
try:
|
||||
from agent.anthropic_adapter import _get_anthropic_max_output
|
||||
from hermes_agent.providers.anthropic_adapter import _get_anthropic_max_output
|
||||
_ant_max = _get_anthropic_max_output(self.model)
|
||||
except Exception:
|
||||
pass # fail open — let the proxy pick its default
|
||||
|
|
@ -6888,7 +6888,7 @@ class AIAgent:
|
|||
or base_url_host_matches(self._base_url_lower, "api.githubcopilot.com")
|
||||
):
|
||||
try:
|
||||
from hermes_cli.models import github_model_reasoning_efforts
|
||||
from hermes_agent.cli.models.models import github_model_reasoning_efforts
|
||||
|
||||
return bool(github_model_reasoning_efforts(self.model))
|
||||
except Exception:
|
||||
|
|
@ -6912,7 +6912,7 @@ class AIAgent:
|
|||
def _github_models_reasoning_extra_body(self) -> dict | None:
|
||||
"""Format reasoning payload for GitHub Models/OpenAI-compatible routes."""
|
||||
try:
|
||||
from hermes_cli.models import github_model_reasoning_efforts
|
||||
from hermes_agent.cli.models.models import github_model_reasoning_efforts
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
|
@ -7191,7 +7191,7 @@ class AIAgent:
|
|||
|
||||
# Use auxiliary client for the flush call when available --
|
||||
# it's cheaper and avoids Codex Responses API incompatibility.
|
||||
from agent.auxiliary_client import (
|
||||
from hermes_agent.providers.auxiliary import (
|
||||
call_llm as _call_llm,
|
||||
_fixed_temperature_for_model,
|
||||
OMIT_TEMPERATURE,
|
||||
|
|
@ -7254,7 +7254,7 @@ class AIAgent:
|
|||
}
|
||||
if _flush_temperature is not None:
|
||||
api_kwargs["temperature"] = _flush_temperature
|
||||
from agent.auxiliary_client import _get_task_timeout
|
||||
from hermes_agent.providers.auxiliary import _get_task_timeout
|
||||
response = self._ensure_primary_openai_client(reason="flush_memories").chat.completions.create(
|
||||
**api_kwargs, timeout=_get_task_timeout("flush_memories")
|
||||
)
|
||||
|
|
@ -7291,7 +7291,7 @@ class AIAgent:
|
|||
try:
|
||||
args = json.loads(tc.function.arguments)
|
||||
flush_target = args.get("target", "memory")
|
||||
from tools.memory_tool import memory_tool as _memory_tool
|
||||
from hermes_agent.tools.memory import memory_tool as _memory_tool
|
||||
_memory_tool(
|
||||
action=args.get("action"),
|
||||
target=flush_target,
|
||||
|
|
@ -7405,7 +7405,7 @@ class AIAgent:
|
|||
# read content is summarised away — if the model re-reads the same
|
||||
# file it needs the full content, not a "file unchanged" stub.
|
||||
try:
|
||||
from tools.file_tools import reset_file_dedup
|
||||
from hermes_agent.tools.files.tools import reset_file_dedup
|
||||
reset_file_dedup(task_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -7446,7 +7446,7 @@ class AIAgent:
|
|||
New DELEGATE_TASK_SCHEMA fields only need to be added here to reach all
|
||||
invocation paths (concurrent, sequential, inline).
|
||||
"""
|
||||
from tools.delegate_tool import delegate_task as _delegate_task
|
||||
from hermes_agent.tools.delegate import delegate_task as _delegate_task
|
||||
return _delegate_task(
|
||||
goal=function_args.get("goal"),
|
||||
context=function_args.get("context"),
|
||||
|
|
@ -7470,7 +7470,7 @@ class AIAgent:
|
|||
# Check plugin hooks for a block directive before executing anything.
|
||||
block_message: Optional[str] = None
|
||||
try:
|
||||
from hermes_cli.plugins import get_pre_tool_call_block_message
|
||||
from hermes_agent.cli.plugins import get_pre_tool_call_block_message
|
||||
block_message = get_pre_tool_call_block_message(
|
||||
function_name, function_args, task_id=effective_task_id or "",
|
||||
)
|
||||
|
|
@ -7480,7 +7480,7 @@ class AIAgent:
|
|||
return json.dumps({"error": block_message}, ensure_ascii=False)
|
||||
|
||||
if function_name == "todo":
|
||||
from tools.todo_tool import todo_tool as _todo_tool
|
||||
from hermes_agent.tools.todo import todo_tool as _todo_tool
|
||||
return _todo_tool(
|
||||
todos=function_args.get("todos"),
|
||||
merge=function_args.get("merge", False),
|
||||
|
|
@ -7489,7 +7489,7 @@ class AIAgent:
|
|||
elif function_name == "session_search":
|
||||
if not self._session_db:
|
||||
return json.dumps({"success": False, "error": "Session database not available."})
|
||||
from tools.session_search_tool import session_search as _session_search
|
||||
from hermes_agent.tools.session_search import session_search as _session_search
|
||||
return _session_search(
|
||||
query=function_args.get("query", ""),
|
||||
role_filter=function_args.get("role_filter"),
|
||||
|
|
@ -7499,7 +7499,7 @@ class AIAgent:
|
|||
)
|
||||
elif function_name == "memory":
|
||||
target = function_args.get("target", "memory")
|
||||
from tools.memory_tool import memory_tool as _memory_tool
|
||||
from hermes_agent.tools.memory import memory_tool as _memory_tool
|
||||
result = _memory_tool(
|
||||
action=function_args.get("action"),
|
||||
target=target,
|
||||
|
|
@ -7521,7 +7521,7 @@ class AIAgent:
|
|||
elif self._memory_manager and self._memory_manager.has_tool(function_name):
|
||||
return self._memory_manager.handle_tool_call(function_name, function_args)
|
||||
elif function_name == "clarify":
|
||||
from tools.clarify_tool import clarify_tool as _clarify_tool
|
||||
from hermes_agent.tools.clarify import clarify_tool as _clarify_tool
|
||||
return _clarify_tool(
|
||||
question=function_args.get("question", ""),
|
||||
choices=function_args.get("choices"),
|
||||
|
|
@ -7684,7 +7684,7 @@ class AIAgent:
|
|||
# The callback is thread-local; the main thread's callback
|
||||
# is invisible to worker threads.
|
||||
try:
|
||||
from tools.environments.base import set_activity_callback
|
||||
from hermes_agent.backends.base import set_activity_callback
|
||||
set_activity_callback(self._touch_activity)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -7899,7 +7899,7 @@ class AIAgent:
|
|||
# Check plugin hooks for a block directive before executing.
|
||||
_block_msg: Optional[str] = None
|
||||
try:
|
||||
from hermes_cli.plugins import get_pre_tool_call_block_message
|
||||
from hermes_agent.cli.plugins import get_pre_tool_call_block_message
|
||||
_block_msg = get_pre_tool_call_block_message(
|
||||
function_name, function_args, task_id=effective_task_id or "",
|
||||
)
|
||||
|
|
@ -7935,7 +7935,7 @@ class AIAgent:
|
|||
# the agent while a command is running.
|
||||
if _block_msg is None:
|
||||
try:
|
||||
from tools.environments.base import set_activity_callback
|
||||
from hermes_agent.backends.base import set_activity_callback
|
||||
set_activity_callback(self._touch_activity)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -7984,7 +7984,7 @@ class AIAgent:
|
|||
function_result = json.dumps({"error": _block_msg}, ensure_ascii=False)
|
||||
tool_duration = 0.0
|
||||
elif function_name == "todo":
|
||||
from tools.todo_tool import todo_tool as _todo_tool
|
||||
from hermes_agent.tools.todo import todo_tool as _todo_tool
|
||||
function_result = _todo_tool(
|
||||
todos=function_args.get("todos"),
|
||||
merge=function_args.get("merge", False),
|
||||
|
|
@ -7997,7 +7997,7 @@ class AIAgent:
|
|||
if not self._session_db:
|
||||
function_result = json.dumps({"success": False, "error": "Session database not available."})
|
||||
else:
|
||||
from tools.session_search_tool import session_search as _session_search
|
||||
from hermes_agent.tools.session_search import session_search as _session_search
|
||||
function_result = _session_search(
|
||||
query=function_args.get("query", ""),
|
||||
role_filter=function_args.get("role_filter"),
|
||||
|
|
@ -8010,7 +8010,7 @@ class AIAgent:
|
|||
self._vprint(f" {_get_cute_tool_message_impl('session_search', function_args, tool_duration, result=function_result)}")
|
||||
elif function_name == "memory":
|
||||
target = function_args.get("target", "memory")
|
||||
from tools.memory_tool import memory_tool as _memory_tool
|
||||
from hermes_agent.tools.memory import memory_tool as _memory_tool
|
||||
function_result = _memory_tool(
|
||||
action=function_args.get("action"),
|
||||
target=target,
|
||||
|
|
@ -8032,7 +8032,7 @@ class AIAgent:
|
|||
if self._should_emit_quiet_tool_messages():
|
||||
self._vprint(f" {_get_cute_tool_message_impl('memory', function_args, tool_duration, result=function_result)}")
|
||||
elif function_name == "clarify":
|
||||
from tools.clarify_tool import clarify_tool as _clarify_tool
|
||||
from hermes_agent.tools.clarify import clarify_tool as _clarify_tool
|
||||
function_result = _clarify_tool(
|
||||
question=function_args.get("question", ""),
|
||||
choices=function_args.get("choices"),
|
||||
|
|
@ -8287,7 +8287,7 @@ class AIAgent:
|
|||
|
||||
summary_extra_body = {}
|
||||
try:
|
||||
from agent.auxiliary_client import _fixed_temperature_for_model, OMIT_TEMPERATURE as _OMIT_TEMP
|
||||
from hermes_agent.providers.auxiliary import _fixed_temperature_for_model, OMIT_TEMPERATURE as _OMIT_TEMP
|
||||
except Exception:
|
||||
_fixed_temperature_for_model = None
|
||||
_OMIT_TEMP = None
|
||||
|
|
@ -8454,7 +8454,7 @@ class AIAgent:
|
|||
|
||||
# Tag all log records on this thread with the session ID so
|
||||
# ``hermes logs --session <id>`` can filter a single conversation.
|
||||
from hermes_logging import set_session_context
|
||||
from hermes_agent.logging import set_session_context
|
||||
set_session_context(self.session_id)
|
||||
|
||||
# If the previous turn activated fallback, restore the primary
|
||||
|
|
@ -8616,7 +8616,7 @@ class AIAgent:
|
|||
# continuation). Plugins can use this to initialise
|
||||
# session-scoped state (e.g. warm a memory cache).
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook as _invoke_hook
|
||||
from hermes_agent.cli.plugins import invoke_hook as _invoke_hook
|
||||
_invoke_hook(
|
||||
"on_session_start",
|
||||
session_id=self.session_id,
|
||||
|
|
@ -8717,7 +8717,7 @@ class AIAgent:
|
|||
# All injected context is ephemeral (not persisted to session DB).
|
||||
_plugin_user_context = ""
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook as _invoke_hook
|
||||
from hermes_agent.cli.plugins import invoke_hook as _invoke_hook
|
||||
_pre_results = _invoke_hook(
|
||||
"pre_llm_call",
|
||||
session_id=self.session_id,
|
||||
|
|
@ -9091,7 +9091,7 @@ class AIAgent:
|
|||
# deepens the rate limit hole.
|
||||
if self.provider == "nous":
|
||||
try:
|
||||
from agent.nous_rate_guard import (
|
||||
from hermes_agent.providers.nous_rate_guard import (
|
||||
nous_rate_limit_remaining,
|
||||
format_remaining as _fmt_nous_remaining,
|
||||
)
|
||||
|
|
@ -9140,7 +9140,7 @@ class AIAgent:
|
|||
api_kwargs = self._get_codex_transport().preflight_kwargs(api_kwargs, allow_stream=False)
|
||||
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook as _invoke_hook
|
||||
from hermes_agent.cli.plugins import invoke_hook as _invoke_hook
|
||||
_invoke_hook(
|
||||
"pre_api_request",
|
||||
task_id=effective_task_id,
|
||||
|
|
@ -9765,7 +9765,7 @@ class AIAgent:
|
|||
# resume hitting Nous.
|
||||
if self.provider == "nous":
|
||||
try:
|
||||
from agent.nous_rate_guard import clear_nous_rate_limit
|
||||
from hermes_agent.providers.nous_rate_guard import clear_nous_rate_limit
|
||||
clear_nous_rate_limit()
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -10013,7 +10013,7 @@ class AIAgent:
|
|||
and not anthropic_auth_retry_attempted
|
||||
):
|
||||
anthropic_auth_retry_attempted = True
|
||||
from agent.anthropic_adapter import _is_oauth_token
|
||||
from hermes_agent.providers.anthropic_adapter import _is_oauth_token
|
||||
if self._try_refresh_anthropic_client_credentials():
|
||||
print(f"{self.log_prefix}🔐 Anthropic credentials refreshed after 401. Retrying request...")
|
||||
continue
|
||||
|
|
@ -10024,7 +10024,7 @@ class AIAgent:
|
|||
print(f"{self.log_prefix} Auth method: {auth_method}")
|
||||
print(f"{self.log_prefix} Token prefix: {str(key)[:12]}..." if key and len(str(key)) > 12 else f"{self.log_prefix} Token: (empty or short)")
|
||||
print(f"{self.log_prefix} Troubleshooting:")
|
||||
from hermes_constants import display_hermes_home as _dhh_fn
|
||||
from hermes_agent.constants import display_hermes_home as _dhh_fn
|
||||
_dhh = _dhh_fn()
|
||||
print(f"{self.log_prefix} • Check ANTHROPIC_TOKEN in {_dhh}/.env for Hermes-managed OAuth/setup tokens")
|
||||
print(f"{self.log_prefix} • Check ANTHROPIC_API_KEY in {_dhh}/.env for API keys or legacy token values")
|
||||
|
|
@ -10233,7 +10233,7 @@ class AIAgent:
|
|||
and not recovered_with_pool
|
||||
):
|
||||
try:
|
||||
from agent.nous_rate_guard import record_nous_rate_limit
|
||||
from hermes_agent.providers.nous_rate_guard import record_nous_rate_limit
|
||||
_err_resp = getattr(api_error, "response", None)
|
||||
_err_hdrs = (
|
||||
getattr(_err_resp, "headers", None)
|
||||
|
|
@ -10776,7 +10776,7 @@ class AIAgent:
|
|||
assistant_message.content = str(raw)
|
||||
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook as _invoke_hook
|
||||
from hermes_agent.cli.plugins import invoke_hook as _invoke_hook
|
||||
_assistant_tool_calls = getattr(assistant_message, "tool_calls", None) or []
|
||||
_assistant_text = assistant_message.content or ""
|
||||
_invoke_hook(
|
||||
|
|
@ -11642,7 +11642,7 @@ class AIAgent:
|
|||
# to an external memory system).
|
||||
if final_response and not interrupted:
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook as _invoke_hook
|
||||
from hermes_agent.cli.plugins import invoke_hook as _invoke_hook
|
||||
_invoke_hook(
|
||||
"post_llm_call",
|
||||
session_id=self.session_id,
|
||||
|
|
@ -11747,7 +11747,7 @@ class AIAgent:
|
|||
# Fired at the very end of every run_conversation call.
|
||||
# Plugins can use this for cleanup, flushing buffers, etc.
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook as _invoke_hook
|
||||
from hermes_agent.cli.plugins import invoke_hook as _invoke_hook
|
||||
_invoke_hook(
|
||||
"on_session_end",
|
||||
session_id=self.session_id,
|
||||
|
|
@ -11817,8 +11817,8 @@ def main(
|
|||
|
||||
# Handle tool listing
|
||||
if list_tools:
|
||||
from model_tools import get_all_tool_names, get_available_toolsets
|
||||
from toolsets import get_all_toolsets, get_toolset_info
|
||||
from hermes_agent.tools.dispatch import get_all_tool_names, get_available_toolsets
|
||||
from hermes_agent.tools.toolsets import get_all_toolsets, get_toolset_info
|
||||
|
||||
print("📋 Available Tools & Toolsets:")
|
||||
print("-" * 50)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import logging
|
|||
import re
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from agent.memory_provider import MemoryProvider
|
||||
from tools.registry import tool_error
|
||||
from hermes_agent.agent.memory.provider import MemoryProvider
|
||||
from hermes_agent.tools.registry import tool_error
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -361,7 +361,7 @@ class MemoryManager:
|
|||
``get_hermes_home()`` themselves.
|
||||
"""
|
||||
if "hermes_home" not in kwargs:
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
kwargs["hermes_home"] = str(get_hermes_home())
|
||||
for provider in self._providers:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import threading
|
|||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_constants import get_hermes_home, get_skills_dir, is_wsl
|
||||
from hermes_agent.constants import get_hermes_home, get_skills_dir, is_wsl
|
||||
from typing import Optional
|
||||
|
||||
from agent.skill_utils import (
|
||||
from hermes_agent.agent.skill_utils import (
|
||||
extract_skill_conditions,
|
||||
extract_skill_description,
|
||||
get_all_skills_dirs,
|
||||
|
|
@ -24,7 +24,7 @@ from agent.skill_utils import (
|
|||
parse_frontmatter,
|
||||
skill_matches_platform,
|
||||
)
|
||||
from utils import atomic_json_write
|
||||
from hermes_agent.utils import atomic_json_write
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -619,7 +619,7 @@ def build_skills_system_prompt(
|
|||
# ── Layer 1: in-process LRU cache ─────────────────────────────────
|
||||
# Include the resolved platform so per-platform disabled-skill lists
|
||||
# produce distinct cache entries (gateway serves multiple platforms).
|
||||
from gateway.session_context import get_session_env
|
||||
from hermes_agent.gateway.session_context import get_session_env
|
||||
_platform_hint = (
|
||||
os.environ.get("HERMES_PLATFORM")
|
||||
or get_session_env("HERMES_SESSION_PLATFORM")
|
||||
|
|
@ -824,8 +824,8 @@ def build_skills_system_prompt(
|
|||
def build_nous_subscription_prompt(valid_tool_names: "set[str] | None" = None) -> str:
|
||||
"""Build a compact Nous subscription capability block for the system prompt."""
|
||||
try:
|
||||
from hermes_cli.nous_subscription import get_nous_subscription_features
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled
|
||||
from hermes_agent.cli.nous_subscription import get_nous_subscription_features
|
||||
from hermes_agent.tools.backend_helpers import managed_nous_tools_enabled
|
||||
except Exception as exc:
|
||||
logger.debug("Failed to import Nous subscription helper: %s", exc)
|
||||
return ""
|
||||
|
|
@ -911,7 +911,7 @@ def load_soul_md() -> Optional[str]:
|
|||
``skip_soul=True`` so SOUL.md isn't injected twice.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import ensure_hermes_home
|
||||
from hermes_agent.cli.config import ensure_hermes_home
|
||||
ensure_hermes_home()
|
||||
except Exception as e:
|
||||
logger.debug("Could not ensure HERMES_HOME before loading SOUL.md: %s", e)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ try:
|
|||
except ImportError: # pragma: no cover
|
||||
fcntl = None # type: ignore[assignment]
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -177,7 +177,7 @@ def register_from_config(
|
|||
registered: List[ShellHookSpec] = []
|
||||
|
||||
# Import lazily — avoids circular imports at module-load time.
|
||||
from hermes_cli.plugins import get_plugin_manager
|
||||
from hermes_agent.cli.plugins import get_plugin_manager
|
||||
|
||||
manager = get_plugin_manager()
|
||||
|
||||
|
|
@ -243,7 +243,7 @@ def _parse_hooks_block(hooks_cfg: Any) -> List[ShellHookSpec]:
|
|||
Malformed entries warn-and-skip — we never raise from config parsing
|
||||
because a broken hook must not crash the agent.
|
||||
"""
|
||||
from hermes_cli.plugins import VALID_HOOKS
|
||||
from hermes_agent.cli.plugins import VALID_HOOKS
|
||||
|
||||
if not isinstance(hooks_cfg, dict):
|
||||
return []
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from datetime import datetime
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ _INLINE_SHELL_MAX_OUTPUT = 4000
|
|||
def _load_skills_config() -> dict:
|
||||
"""Load the ``skills`` section of config.yaml (best-effort)."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
|
||||
cfg = load_config() or {}
|
||||
skills_cfg = cfg.get("skills")
|
||||
|
|
@ -156,7 +156,7 @@ def _load_skill_payload(skill_identifier: str, task_id: str | None = None) -> tu
|
|||
return None
|
||||
|
||||
try:
|
||||
from tools.skills_tool import SKILLS_DIR, skill_view
|
||||
from hermes_agent.tools.skills.tool import SKILLS_DIR, skill_view
|
||||
|
||||
identifier_path = Path(raw_identifier).expanduser()
|
||||
if identifier_path.is_absolute():
|
||||
|
|
@ -202,7 +202,7 @@ def _inject_skill_config(loaded_skill: dict[str, Any], parts: list[str]) -> None
|
|||
without needing to read config.yaml itself.
|
||||
"""
|
||||
try:
|
||||
from agent.skill_utils import (
|
||||
from hermes_agent.agent.skill_utils import (
|
||||
extract_skill_config_vars,
|
||||
parse_frontmatter,
|
||||
resolve_skill_config_values,
|
||||
|
|
@ -241,7 +241,7 @@ def _build_skill_message(
|
|||
session_id: str | None = None,
|
||||
) -> str:
|
||||
"""Format a loaded skill into a user/system message payload."""
|
||||
from tools.skills_tool import SKILLS_DIR
|
||||
from hermes_agent.tools.skills.tool import SKILLS_DIR
|
||||
|
||||
content = str(loaded_skill.get("content") or "")
|
||||
|
||||
|
|
@ -344,8 +344,8 @@ def scan_skill_commands() -> Dict[str, Dict[str, Any]]:
|
|||
global _skill_commands
|
||||
_skill_commands = {}
|
||||
try:
|
||||
from tools.skills_tool import SKILLS_DIR, _parse_frontmatter, skill_matches_platform, _get_disabled_skill_names
|
||||
from agent.skill_utils import get_external_skills_dirs
|
||||
from hermes_agent.tools.skills.tool import SKILLS_DIR, _parse_frontmatter, skill_matches_platform, _get_disabled_skill_names
|
||||
from hermes_agent.agent.skill_utils import get_external_skills_dirs
|
||||
disabled = _get_disabled_skill_names()
|
||||
seen_names: set = set()
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import sys
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple
|
||||
|
||||
from hermes_constants import get_config_path, get_skills_dir
|
||||
from hermes_agent.constants import get_config_path, get_skills_dir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ def get_disabled_skill_names(platform: str | None = None) -> Set[str]:
|
|||
if not isinstance(skills_cfg, dict):
|
||||
return set()
|
||||
|
||||
from gateway.session_context import get_session_env
|
||||
from hermes_agent.gateway.session_context import get_session_env
|
||||
resolved_platform = (
|
||||
platform
|
||||
or os.getenv("HERMES_PLATFORM")
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import shlex
|
|||
from pathlib import Path
|
||||
from typing import Dict, Any, Optional, Set
|
||||
|
||||
from agent.prompt_builder import _scan_context_content
|
||||
from hermes_agent.agent.prompt_builder import _scan_context_content
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import logging
|
|||
import threading
|
||||
from typing import Optional
|
||||
|
||||
from agent.auxiliary_client import call_llm
|
||||
from hermes_agent.providers.auxiliary import call_llm
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@ The terminal_tool.py factory (_create_environment) selects the backend
|
|||
based on the TERMINAL_ENV configuration.
|
||||
"""
|
||||
|
||||
from tools.environments.base import BaseEnvironment
|
||||
from hermes_agent.backends.base import BaseEnvironment
|
||||
|
||||
__all__ = ["BaseEnvironment"]
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ from abc import ABC, abstractmethod
|
|||
from pathlib import Path
|
||||
from typing import IO, Callable, Protocol
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from tools.interrupt import is_interrupted
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from hermes_agent.tools.interrupt import is_interrupted
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -710,7 +710,7 @@ class BaseEnvironment(ABC):
|
|||
# server, `yes > /dev/null`, etc.), leaking the subshell forever.
|
||||
# Rewriting to `A && { B & }` runs B as a plain background in the
|
||||
# current shell — no subshell wait.
|
||||
from tools.terminal_tool import _rewrite_compound_background
|
||||
from hermes_agent.tools.terminal import _rewrite_compound_background
|
||||
exec_command = _rewrite_compound_background(exec_command)
|
||||
effective_timeout = timeout or self.timeout
|
||||
effective_cwd = cwd or self.cwd
|
||||
|
|
@ -757,7 +757,7 @@ class BaseEnvironment(ABC):
|
|||
|
||||
def _prepare_command(self, command: str) -> tuple[str | None, str | None]:
|
||||
"""Transform sudo commands if SUDO_PASSWORD is available."""
|
||||
from tools.terminal_tool import _transform_sudo_command
|
||||
from hermes_agent.tools.terminal import _transform_sudo_command
|
||||
|
||||
return _transform_sudo_command(command)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import shlex
|
|||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
from tools.environments.base import (
|
||||
from hermes_agent.backends.base import (
|
||||
BaseEnvironment,
|
||||
_ThreadedProcessHandle,
|
||||
)
|
||||
from tools.environments.file_sync import (
|
||||
from hermes_agent.backends.file_sync import (
|
||||
FileSyncManager,
|
||||
iter_sync_files,
|
||||
quoted_mkdir_command,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import sys
|
|||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from tools.environments.base import BaseEnvironment, _popen_bash
|
||||
from tools.environments.local import _HERMES_PROVIDER_ENV_BLOCKLIST
|
||||
from hermes_agent.backends.base import BaseEnvironment, _popen_bash
|
||||
from hermes_agent.backends.local import _HERMES_PROVIDER_ENV_BLOCKLIST
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ def _normalize_env_dict(env: dict | None) -> dict[str, str]:
|
|||
def _load_hermes_env_vars() -> dict[str, str]:
|
||||
"""Load ~/.hermes/.env values without failing Docker command execution."""
|
||||
try:
|
||||
from hermes_cli.config import load_env
|
||||
from hermes_agent.cli.config import load_env
|
||||
|
||||
return load_env() or {}
|
||||
except Exception:
|
||||
|
|
@ -298,7 +298,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
# Persistent workspace via bind mounts from a configurable host directory
|
||||
# (TERMINAL_SANDBOX_DIR, default ~/.hermes/sandboxes/). Non-persistent
|
||||
# mode uses tmpfs (ephemeral, fast, gone on cleanup).
|
||||
from tools.environments.base import get_sandbox_dir
|
||||
from hermes_agent.backends.base import get_sandbox_dir
|
||||
|
||||
# User-configured volume mounts (from config.yaml docker_volumes)
|
||||
volume_args = []
|
||||
|
|
@ -362,7 +362,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
# Mount credential files (OAuth tokens, etc.) declared by skills.
|
||||
# Read-only so the container can authenticate but not modify host creds.
|
||||
try:
|
||||
from tools.credential_files import (
|
||||
from hermes_agent.tools.credential_files import (
|
||||
get_credential_file_mounts,
|
||||
get_skills_directory_mount,
|
||||
get_cache_directory_mounts,
|
||||
|
|
@ -464,7 +464,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
explicit_forward_keys = set(self._forward_env)
|
||||
passthrough_keys: set[str] = set()
|
||||
try:
|
||||
from tools.env_passthrough import get_all_passthrough
|
||||
from hermes_agent.tools.env_passthrough import get_all_passthrough
|
||||
passthrough_keys = set(get_all_passthrough())
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ except ImportError:
|
|||
from pathlib import Path
|
||||
from typing import Callable
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from tools.environments.base import _file_mtime_key
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from hermes_agent.backends.base import _file_mtime_key
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ def iter_sync_files(container_base: str = "/root/.hermes") -> list[tuple[str, st
|
|||
"""
|
||||
# Late import: credential_files imports agent modules that create
|
||||
# circular dependencies if loaded at file_sync module level.
|
||||
from tools.credential_files import (
|
||||
from hermes_agent.tools.credential_files import (
|
||||
get_credential_file_mounts,
|
||||
iter_cache_files,
|
||||
iter_skills_files,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import signal
|
|||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from tools.environments.base import BaseEnvironment, _pipe_stdin
|
||||
from hermes_agent.backends.base import BaseEnvironment, _pipe_stdin
|
||||
|
||||
_IS_WINDOWS = platform.system() == "Windows"
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ def _build_provider_env_blocklist() -> frozenset:
|
|||
blocked: set[str] = set()
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
for pconfig in PROVIDER_REGISTRY.values():
|
||||
blocked.update(pconfig.api_key_env_vars)
|
||||
if pconfig.base_url_env_var:
|
||||
|
|
@ -30,7 +30,7 @@ def _build_provider_env_blocklist() -> frozenset:
|
|||
pass
|
||||
|
||||
try:
|
||||
from hermes_cli.config import OPTIONAL_ENV_VARS
|
||||
from hermes_agent.cli.config import OPTIONAL_ENV_VARS
|
||||
for name, metadata in OPTIONAL_ENV_VARS.items():
|
||||
category = metadata.get("category")
|
||||
if category in {"tool", "messaging"}:
|
||||
|
|
@ -110,7 +110,7 @@ _HERMES_PROVIDER_ENV_BLOCKLIST = _build_provider_env_blocklist()
|
|||
def _sanitize_subprocess_env(base_env: dict | None, extra_env: dict | None = None) -> dict:
|
||||
"""Filter Hermes-managed secrets from a subprocess environment."""
|
||||
try:
|
||||
from tools.env_passthrough import is_env_passthrough as _is_passthrough
|
||||
from hermes_agent.tools.env_passthrough import is_env_passthrough as _is_passthrough
|
||||
except Exception:
|
||||
_is_passthrough = lambda _: False # noqa: E731
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ def _sanitize_subprocess_env(base_env: dict | None, extra_env: dict | None = Non
|
|||
sanitized[key] = value
|
||||
|
||||
# Per-profile HOME isolation for background processes (same as _make_run_env).
|
||||
from hermes_constants import get_subprocess_home
|
||||
from hermes_agent.constants import get_subprocess_home
|
||||
_profile_home = get_subprocess_home()
|
||||
if _profile_home:
|
||||
sanitized["HOME"] = _profile_home
|
||||
|
|
@ -186,7 +186,7 @@ _SANE_PATH = (
|
|||
def _make_run_env(env: dict) -> dict:
|
||||
"""Build a run environment with a sane PATH and provider-var stripping."""
|
||||
try:
|
||||
from tools.env_passthrough import is_env_passthrough as _is_passthrough
|
||||
from hermes_agent.tools.env_passthrough import is_env_passthrough as _is_passthrough
|
||||
except Exception:
|
||||
_is_passthrough = lambda _: False # noqa: E731
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ def _make_run_env(env: dict) -> dict:
|
|||
# Per-profile HOME isolation: redirect system tool configs (git, ssh, gh,
|
||||
# npm …) into {HERMES_HOME}/home/ when that directory exists. Only the
|
||||
# subprocess sees the override — the Python process keeps the real HOME.
|
||||
from hermes_constants import get_subprocess_home
|
||||
from hermes_agent.constants import get_subprocess_home
|
||||
_profile_home = get_subprocess_home()
|
||||
if _profile_home:
|
||||
run_env["HOME"] = _profile_home
|
||||
|
|
@ -220,7 +220,7 @@ def _read_terminal_shell_init_config() -> tuple[list[str], bool]:
|
|||
execution never breaks because the config file is unreadable.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
|
||||
cfg = load_config() or {}
|
||||
terminal_cfg = cfg.get("terminal") or {}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import uuid
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from tools.environments.modal_utils import (
|
||||
from hermes_agent.backends.modal_utils import (
|
||||
BaseModalExecutionEnvironment,
|
||||
ModalExecStart,
|
||||
PreparedModalExec,
|
||||
)
|
||||
from tools.managed_tool_gateway import resolve_managed_tool_gateway
|
||||
from hermes_agent.tools.managed_gateway import resolve_managed_tool_gateway
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ class ManagedModalEnvironment(BaseModalExecutionEnvironment):
|
|||
def _guard_unsupported_credential_passthrough(self) -> None:
|
||||
"""Managed Modal does not sync or mount host credential files."""
|
||||
try:
|
||||
from tools.credential_files import get_credential_file_mounts
|
||||
from hermes_agent.tools.credential_files import get_credential_file_mounts
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ import threading
|
|||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from tools.environments.base import (
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from hermes_agent.backends.base import (
|
||||
BaseEnvironment,
|
||||
_ThreadedProcessHandle,
|
||||
_load_json_store,
|
||||
_save_json_store,
|
||||
)
|
||||
from tools.environments.file_sync import (
|
||||
from hermes_agent.backends.file_sync import (
|
||||
FileSyncManager,
|
||||
iter_sync_files,
|
||||
quoted_mkdir_command,
|
||||
|
|
@ -187,7 +187,7 @@ class ModalEnvironment(BaseEnvironment):
|
|||
|
||||
cred_mounts = []
|
||||
try:
|
||||
from tools.credential_files import (
|
||||
from hermes_agent.tools.credential_files import (
|
||||
get_credential_file_mounts,
|
||||
iter_skills_files,
|
||||
iter_cache_files,
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ from abc import abstractmethod
|
|||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from tools.environments.base import BaseEnvironment
|
||||
from tools.interrupt import is_interrupted
|
||||
from hermes_agent.backends.base import BaseEnvironment
|
||||
from hermes_agent.tools.interrupt import is_interrupted
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
@ -136,7 +136,7 @@ class BaseModalExecutionEnvironment(BaseEnvironment):
|
|||
|
||||
# Periodic activity touch so the gateway knows we're alive
|
||||
try:
|
||||
from tools.environments.base import touch_activity_if_due
|
||||
from hermes_agent.backends.base import touch_activity_if_due
|
||||
touch_activity_if_due(_activity_state, "modal command running")
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import uuid
|
|||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from tools.environments.base import (
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from hermes_agent.backends.base import (
|
||||
BaseEnvironment,
|
||||
_load_json_store,
|
||||
_popen_bash,
|
||||
|
|
@ -75,7 +75,7 @@ def _get_scratch_dir() -> Path:
|
|||
scratch_path.mkdir(parents=True, exist_ok=True)
|
||||
return scratch_path
|
||||
|
||||
from tools.environments.base import get_sandbox_dir
|
||||
from hermes_agent.backends.base import get_sandbox_dir
|
||||
sandbox = get_sandbox_dir() / "singularity"
|
||||
|
||||
scratch = Path("/scratch")
|
||||
|
|
@ -202,7 +202,7 @@ class SingularityEnvironment(BaseEnvironment):
|
|||
cmd.append("--writable-tmpfs")
|
||||
|
||||
try:
|
||||
from tools.credential_files import get_credential_file_mounts, get_skills_directory_mount
|
||||
from hermes_agent.tools.credential_files import get_credential_file_mounts, get_skills_directory_mount
|
||||
for mount_entry in get_credential_file_mounts():
|
||||
cmd.extend(["--bind", f"{mount_entry['host_path']}:{mount_entry['container_path']}:ro"])
|
||||
for skills_mount in get_skills_directory_mount():
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import subprocess
|
|||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from tools.environments.base import BaseEnvironment, _popen_bash
|
||||
from tools.environments.file_sync import (
|
||||
from hermes_agent.backends.base import BaseEnvironment, _popen_bash
|
||||
from hermes_agent.backends.file_sync import (
|
||||
FileSyncManager,
|
||||
iter_sync_files,
|
||||
quoted_mkdir_command,
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ from typing import Any, Dict, List, Optional
|
|||
import httpx
|
||||
import yaml
|
||||
|
||||
from hermes_cli.config import get_hermes_home, get_config_path, read_raw_config
|
||||
from hermes_constants import OPENROUTER_BASE_URL
|
||||
from hermes_agent.cli.config import get_hermes_home, get_config_path, read_raw_config
|
||||
from hermes_agent.constants import OPENROUTER_BASE_URL
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ def get_anthropic_key() -> str:
|
|||
|
||||
ANTHROPIC_API_KEY -> ANTHROPIC_TOKEN -> CLAUDE_CODE_OAUTH_TOKEN
|
||||
"""
|
||||
from hermes_cli.config import get_env_value
|
||||
from hermes_agent.cli.config import get_env_value
|
||||
|
||||
for var in PROVIDER_REGISTRY["anthropic"].api_key_env_vars:
|
||||
value = get_env_value(var) or os.getenv(var, "")
|
||||
|
|
@ -406,7 +406,7 @@ def _resolve_api_key_provider_secret(
|
|||
if provider_id == "copilot":
|
||||
# Use the dedicated copilot auth module for proper token validation
|
||||
try:
|
||||
from hermes_cli.copilot_auth import resolve_copilot_token
|
||||
from hermes_agent.cli.auth.copilot import resolve_copilot_token
|
||||
token, source = resolve_copilot_token()
|
||||
if token:
|
||||
return token, source
|
||||
|
|
@ -866,7 +866,7 @@ def is_provider_explicitly_configured(provider_id: str) -> bool:
|
|||
|
||||
# 2. Check config.yaml model.provider
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
cfg = load_config()
|
||||
model_cfg = cfg.get("model")
|
||||
if isinstance(model_cfg, dict):
|
||||
|
|
@ -953,7 +953,7 @@ def _get_config_hint_for_unknown_provider(provider_name: str) -> str:
|
|||
and returns a human-readable diagnostic, or empty string if nothing found.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import validate_config_structure
|
||||
from hermes_agent.cli.config import validate_config_structure
|
||||
issues = validate_config_structure()
|
||||
if not issues:
|
||||
return ""
|
||||
|
|
@ -1068,7 +1068,7 @@ def resolve_provider(
|
|||
# AWS Bedrock — detect via boto3 credential chain (IAM roles, SSO, env vars).
|
||||
# This runs after API-key providers so explicit keys always win.
|
||||
try:
|
||||
from agent.bedrock_adapter import has_aws_credentials
|
||||
from hermes_agent.providers.bedrock_adapter import has_aws_credentials
|
||||
if has_aws_credentials():
|
||||
return "bedrock"
|
||||
except ImportError:
|
||||
|
|
@ -1331,7 +1331,7 @@ def resolve_gemini_oauth_runtime_credentials(
|
|||
) -> Dict[str, Any]:
|
||||
"""Resolve runtime OAuth creds for google-gemini-cli."""
|
||||
try:
|
||||
from agent.google_oauth import (
|
||||
from hermes_agent.providers.google_oauth import (
|
||||
GoogleOAuthError,
|
||||
_credentials_path,
|
||||
get_valid_access_token,
|
||||
|
|
@ -1370,7 +1370,7 @@ def resolve_gemini_oauth_runtime_credentials(
|
|||
def get_gemini_oauth_auth_status() -> Dict[str, Any]:
|
||||
"""Return a status dict for `hermes auth list` / `hermes status`."""
|
||||
try:
|
||||
from agent.google_oauth import _credentials_path, load_credentials
|
||||
from hermes_agent.providers.google_oauth import _credentials_path, load_credentials
|
||||
except ImportError:
|
||||
return {"logged_in": False, "error": "agent.google_oauth unavailable"}
|
||||
auth_path = _credentials_path()
|
||||
|
|
@ -2159,7 +2159,7 @@ def persist_nous_credentials(
|
|||
Returns the upserted :class:`PooledCredential` entry (or ``None`` if
|
||||
seeding somehow produced no match — shouldn't happen).
|
||||
"""
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
|
||||
state = dict(creds)
|
||||
if label and str(label).strip():
|
||||
|
|
@ -2440,7 +2440,7 @@ def get_nous_auth_status() -> Dict[str, Any]:
|
|||
# Check credential pool first — the dashboard device-code flow saves
|
||||
# here but may not have written to the auth store yet.
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
pool = load_pool("nous")
|
||||
if pool and pool.has_credentials():
|
||||
entry = pool.select()
|
||||
|
|
@ -2494,7 +2494,7 @@ def get_codex_auth_status() -> Dict[str, Any]:
|
|||
# Check credential pool first — this is where `hermes auth` and
|
||||
# `hermes model` store device_code tokens.
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
pool = load_pool("openai-codex")
|
||||
if pool and pool.has_credentials():
|
||||
entry = pool.select()
|
||||
|
|
@ -2615,7 +2615,7 @@ def get_auth_status(provider_id: Optional[str] = None) -> Dict[str, Any]:
|
|||
# AWS SDK providers (Bedrock) — check via boto3 credential chain
|
||||
if pconfig and pconfig.auth_type == "aws_sdk":
|
||||
try:
|
||||
from agent.bedrock_adapter import has_aws_credentials
|
||||
from hermes_agent.providers.bedrock_adapter import has_aws_credentials
|
||||
return {"logged_in": has_aws_credentials(), "provider": target}
|
||||
except ImportError:
|
||||
return {"logged_in": False, "provider": target, "error": "boto3 not installed"}
|
||||
|
|
@ -2804,7 +2804,7 @@ def _prompt_model_selection(
|
|||
If *unavailable_models* is provided, those models are shown grayed out
|
||||
and unselectable, with an upgrade link to *portal_url*.
|
||||
"""
|
||||
from hermes_cli.models import _format_price_per_mtok
|
||||
from hermes_agent.cli.models.models import _format_price_per_mtok
|
||||
|
||||
_unavailable = unavailable_models or []
|
||||
|
||||
|
|
@ -2914,7 +2914,7 @@ def _prompt_model_selection(
|
|||
title=effective_title,
|
||||
)
|
||||
idx = menu.show()
|
||||
from hermes_cli.curses_ui import flush_stdin
|
||||
from hermes_agent.cli.ui.curses import flush_stdin
|
||||
flush_stdin()
|
||||
if idx is None:
|
||||
return None
|
||||
|
|
@ -2971,7 +2971,7 @@ def _save_model_choice(model_id: str) -> None:
|
|||
The model is stored in config.yaml only — NOT in .env. This avoids
|
||||
conflicts in multi-agent setups where env vars would stomp each other.
|
||||
"""
|
||||
from hermes_cli.config import save_config, load_config
|
||||
from hermes_agent.cli.config import save_config, load_config
|
||||
|
||||
config = load_config()
|
||||
# Always use dict format so provider/base_url can be stored alongside
|
||||
|
|
@ -3050,7 +3050,7 @@ def _login_openai_codex(args, pconfig: ProviderConfig) -> None:
|
|||
config_path = _update_config_for_provider("openai-codex", creds.get("base_url", DEFAULT_CODEX_BASE_URL))
|
||||
print()
|
||||
print("Login successful!")
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print(f" Auth state: {_dhh()}/auth.json")
|
||||
print(f" Config updated: {config_path} (model.provider=openai-codex)")
|
||||
|
||||
|
|
@ -3387,7 +3387,7 @@ def _login_nous(args, pconfig: ProviderConfig) -> None:
|
|||
code="invalid_token",
|
||||
)
|
||||
|
||||
from hermes_cli.models import (
|
||||
from hermes_agent.cli.models.models import (
|
||||
_PROVIDER_MODELS, get_pricing_for_provider,
|
||||
check_nous_free_tier, partition_nous_models_by_tier,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import time
|
|||
from types import SimpleNamespace
|
||||
import uuid
|
||||
|
||||
from agent.credential_pool import (
|
||||
from hermes_agent.providers.credential_pool import (
|
||||
AUTH_TYPE_API_KEY,
|
||||
AUTH_TYPE_OAUTH,
|
||||
CUSTOM_POOL_PREFIX,
|
||||
|
|
@ -27,9 +27,9 @@ from agent.credential_pool import (
|
|||
list_custom_pool_providers,
|
||||
load_pool,
|
||||
)
|
||||
import hermes_cli.auth as auth_mod
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_constants import OPENROUTER_BASE_URL
|
||||
import hermes_agent.cli.auth.auth as auth_mod
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.constants import OPENROUTER_BASE_URL
|
||||
|
||||
|
||||
# Providers that support OAuth login in addition to API keys.
|
||||
|
|
@ -39,7 +39,7 @@ _OAUTH_CAPABLE_PROVIDERS = {"anthropic", "nous", "openai-codex", "qwen-oauth", "
|
|||
def _get_custom_provider_names() -> list:
|
||||
"""Return list of (display_name, pool_key, provider_key) tuples."""
|
||||
try:
|
||||
from hermes_cli.config import get_compatible_custom_providers, load_config
|
||||
from hermes_agent.cli.config import get_compatible_custom_providers, load_config
|
||||
|
||||
config = load_config()
|
||||
except Exception:
|
||||
|
|
@ -88,7 +88,7 @@ def _provider_base_url(provider: str) -> str:
|
|||
if provider == "openrouter":
|
||||
return OPENROUTER_BASE_URL
|
||||
if provider.startswith(CUSTOM_POOL_PREFIX):
|
||||
from agent.credential_pool import _get_custom_provider_config
|
||||
from hermes_agent.providers.credential_pool import _get_custom_provider_config
|
||||
|
||||
cp_config = _get_custom_provider_config(provider)
|
||||
if cp_config:
|
||||
|
|
@ -159,7 +159,7 @@ def auth_add_command(args) -> None:
|
|||
# Matches the Codex device_code re-link pattern that predates this.
|
||||
if not provider.startswith(CUSTOM_POOL_PREFIX):
|
||||
try:
|
||||
from hermes_cli.auth import (
|
||||
from hermes_agent.cli.auth.auth import (
|
||||
_load_auth_store,
|
||||
unsuppress_credential_source,
|
||||
)
|
||||
|
|
@ -197,7 +197,7 @@ def auth_add_command(args) -> None:
|
|||
return
|
||||
|
||||
if provider == "anthropic":
|
||||
from agent import anthropic_adapter as anthropic_mod
|
||||
from hermes_agent.agent import anthropic_adapter as anthropic_mod
|
||||
|
||||
creds = anthropic_mod.run_hermes_oauth_login_pure()
|
||||
if not creds:
|
||||
|
|
@ -271,7 +271,7 @@ def auth_add_command(args) -> None:
|
|||
return
|
||||
|
||||
if provider == "google-gemini-cli":
|
||||
from agent.google_oauth import run_gemini_oauth_login_pure
|
||||
from hermes_agent.providers.google_oauth import run_gemini_oauth_login_pure
|
||||
|
||||
creds = run_gemini_oauth_login_pure()
|
||||
label = (getattr(args, "label", None) or "").strip() or (
|
||||
|
|
@ -361,8 +361,8 @@ def auth_remove_command(args) -> None:
|
|||
# handles its source-specific cleanup and we centralise suppression +
|
||||
# user-facing output here so every source behaves identically from
|
||||
# the user's perspective.
|
||||
from agent.credential_sources import find_removal_step
|
||||
from hermes_cli.auth import suppress_credential_source
|
||||
from hermes_agent.providers.credential_sources import find_removal_step
|
||||
from hermes_agent.cli.auth.auth import suppress_credential_source
|
||||
|
||||
step = find_removal_step(provider, removed.source)
|
||||
if step is None:
|
||||
|
|
@ -396,7 +396,7 @@ def _interactive_auth() -> None:
|
|||
|
||||
# Show AWS Bedrock credential status (not in the pool — uses boto3 chain)
|
||||
try:
|
||||
from agent.bedrock_adapter import has_aws_credentials, resolve_aws_auth_env_var, resolve_bedrock_region
|
||||
from hermes_agent.providers.bedrock_adapter import has_aws_credentials, resolve_aws_auth_env_var, resolve_bedrock_region
|
||||
if has_aws_credentials():
|
||||
auth_source = resolve_aws_auth_env_var() or "unknown"
|
||||
region = resolve_bedrock_region()
|
||||
|
|
@ -558,7 +558,7 @@ def _interactive_strategy() -> None:
|
|||
print("Invalid choice.")
|
||||
return
|
||||
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
cfg = load_config()
|
||||
pool_strategies = cfg.get("credential_pool_strategies") or {}
|
||||
if not isinstance(pool_strategies, dict):
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ def dingtalk_qr_auth() -> Optional[Tuple[str, str]]:
|
|||
Returns (client_id, client_secret) on success, or None if the user
|
||||
cancelled or the flow failed.
|
||||
"""
|
||||
from hermes_cli.setup import print_info, print_success, print_warning, print_error
|
||||
from hermes_agent.cli.setup_wizard import print_info, print_success, print_warning, print_error
|
||||
|
||||
print()
|
||||
print_info(" Initializing DingTalk device authorization...")
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from datetime import datetime, timezone
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from hermes_constants import get_default_hermes_root, get_hermes_home, display_hermes_home
|
||||
from hermes_agent.constants import get_default_hermes_root, get_hermes_home, display_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ def run_import(args) -> None:
|
|||
restored_profiles = []
|
||||
if profiles_dir.is_dir():
|
||||
try:
|
||||
from hermes_cli.profiles import (
|
||||
from hermes_agent.cli.profiles import (
|
||||
create_wrapper_script, check_alias_collision,
|
||||
_is_wrapper_dir_in_path, _get_wrapper_dir,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ import sys
|
|||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_cli.config import get_hermes_home, get_config_path, load_config, save_config
|
||||
from hermes_constants import get_optional_skills_dir
|
||||
from hermes_cli.setup import (
|
||||
from hermes_agent.cli.config import get_hermes_home, get_config_path, load_config, save_config
|
||||
from hermes_agent.constants import get_optional_skills_dir
|
||||
from hermes_agent.cli.setup_wizard import (
|
||||
Colors,
|
||||
color,
|
||||
print_header,
|
||||
|
|
@ -153,7 +153,7 @@ def _warn_if_gateway_running(auto_yes: bool) -> None:
|
|||
(e.g. Telegram 409 "terminated by other getUpdates request"). Warn the
|
||||
user and let them decide whether to continue.
|
||||
"""
|
||||
from gateway.status import get_running_pid, read_runtime_status
|
||||
from hermes_agent.gateway.status import get_running_pid, read_runtime_status
|
||||
|
||||
if not get_running_pid():
|
||||
return
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import subprocess
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_constants import is_wsl as _is_wsl
|
||||
from hermes_agent.constants import is_wsl as _is_wsl
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ COMMAND_REGISTRY: list[CommandDef] = [
|
|||
# Tools & Skills
|
||||
CommandDef("tools", "Manage tools: /tools [list|disable|enable] [name...]", "Tools & Skills",
|
||||
args_hint="[list|disable|enable] [name...]", cli_only=True),
|
||||
CommandDef("toolsets", "List available toolsets", "Tools & Skills",
|
||||
CommandDef("hermes_agent.tools.toolsets", "List available toolsets", "Tools & Skills",
|
||||
cli_only=True),
|
||||
CommandDef("skills", "Search, install, inspect, or manage skills",
|
||||
"Tools & Skills", cli_only=True,
|
||||
|
|
@ -318,7 +318,7 @@ def _resolve_config_gates() -> set[str]:
|
|||
if not gated:
|
||||
return set()
|
||||
try:
|
||||
from hermes_cli.config import read_raw_config
|
||||
from hermes_agent.cli.config import read_raw_config
|
||||
cfg = read_raw_config()
|
||||
except Exception:
|
||||
return set()
|
||||
|
|
@ -497,7 +497,7 @@ def _collect_gateway_skill_entries(
|
|||
# --- Tier 1: Plugin slash commands (never trimmed) ---------------------
|
||||
plugin_pairs: list[tuple[str, str]] = []
|
||||
try:
|
||||
from hermes_cli.plugins import get_plugin_commands
|
||||
from hermes_agent.cli.plugins import get_plugin_commands
|
||||
plugin_cmds = get_plugin_commands()
|
||||
for cmd_name in sorted(plugin_cmds):
|
||||
name = sanitize_name(cmd_name) if sanitize_name else cmd_name
|
||||
|
|
@ -519,15 +519,15 @@ def _collect_gateway_skill_entries(
|
|||
# --- Tier 2: Built-in skill commands (trimmed at cap) -----------------
|
||||
_platform_disabled: set[str] = set()
|
||||
try:
|
||||
from agent.skill_utils import get_disabled_skill_names
|
||||
from hermes_agent.agent.skill_utils import get_disabled_skill_names
|
||||
_platform_disabled = get_disabled_skill_names(platform=platform)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
skill_triples: list[tuple[str, str, str]] = []
|
||||
try:
|
||||
from agent.skill_commands import get_skill_commands
|
||||
from tools.skills_tool import SKILLS_DIR
|
||||
from hermes_agent.agent.skill_commands import get_skill_commands
|
||||
from hermes_agent.tools.skills.tool import SKILLS_DIR
|
||||
_skills_dir = str(SKILLS_DIR.resolve())
|
||||
_hub_dir = str((SKILLS_DIR / ".hub").resolve())
|
||||
skill_cmds = get_skill_commands()
|
||||
|
|
@ -661,7 +661,7 @@ def discord_skill_commands_by_category(
|
|||
|
||||
_platform_disabled: set[str] = set()
|
||||
try:
|
||||
from agent.skill_utils import get_disabled_skill_names
|
||||
from hermes_agent.agent.skill_utils import get_disabled_skill_names
|
||||
_platform_disabled = get_disabled_skill_names(platform="discord")
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -673,8 +673,8 @@ def discord_skill_commands_by_category(
|
|||
hidden = 0
|
||||
|
||||
try:
|
||||
from agent.skill_commands import get_skill_commands
|
||||
from tools.skills_tool import SKILLS_DIR
|
||||
from hermes_agent.agent.skill_commands import get_skill_commands
|
||||
from hermes_agent.tools.skills.tool import SKILLS_DIR
|
||||
_skills_dir = SKILLS_DIR.resolve()
|
||||
_hub_dir = (SKILLS_DIR / ".hub").resolve()
|
||||
skill_cmds = get_skill_commands()
|
||||
|
|
@ -1116,7 +1116,7 @@ class SlashCommandCompleter(Completer):
|
|||
def _skin_completions(sub_text: str, sub_lower: str):
|
||||
"""Yield completions for /skin from available skins."""
|
||||
try:
|
||||
from hermes_cli.skin_engine import list_skins
|
||||
from hermes_agent.cli.ui.skin_engine import list_skins
|
||||
for s in list_skins():
|
||||
name = s["name"]
|
||||
if name.startswith(sub_lower) and name != sub_lower:
|
||||
|
|
@ -1133,7 +1133,7 @@ class SlashCommandCompleter(Completer):
|
|||
def _personality_completions(sub_text: str, sub_lower: str):
|
||||
"""Yield completions for /personality from configured personalities."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
personalities = load_config().get("agent", {}).get("personalities", {})
|
||||
if "none".startswith(sub_lower) and "none" != sub_lower:
|
||||
yield Completion(
|
||||
|
|
@ -1162,7 +1162,7 @@ class SlashCommandCompleter(Completer):
|
|||
seen = set()
|
||||
# Config-based direct aliases (preferred — include provider info)
|
||||
try:
|
||||
from hermes_cli.model_switch import (
|
||||
from hermes_agent.cli.models.switch import (
|
||||
_ensure_direct_aliases, DIRECT_ALIASES, MODEL_ALIASES,
|
||||
)
|
||||
_ensure_direct_aliases()
|
||||
|
|
@ -1262,7 +1262,7 @@ class SlashCommandCompleter(Completer):
|
|||
|
||||
# Plugin-registered slash commands
|
||||
try:
|
||||
from hermes_cli.plugins import get_plugin_commands
|
||||
from hermes_agent.cli.plugins import get_plugin_commands
|
||||
for cmd_name, cmd_info in get_plugin_commands().items():
|
||||
if cmd_name.startswith(word):
|
||||
desc = str(cmd_info.get("description", "Plugin command"))
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ _EXTRA_ENV_KEYS = frozenset({
|
|||
})
|
||||
import yaml
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_cli.default_soul import DEFAULT_SOUL_MD
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
from hermes_agent.cli.default_soul import DEFAULT_SOUL_MD
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
|
@ -169,7 +169,7 @@ def get_container_exec_info() -> Optional[dict]:
|
|||
if os.environ.get("HERMES_DEV") == "1":
|
||||
return None
|
||||
|
||||
from hermes_constants import is_container
|
||||
from hermes_agent.constants import is_container
|
||||
if is_container():
|
||||
return None
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ def get_container_exec_info() -> Optional[dict]:
|
|||
# =============================================================================
|
||||
|
||||
# Re-export from hermes_constants — canonical definition lives there.
|
||||
from hermes_constants import get_hermes_home # noqa: F811,E402
|
||||
from hermes_agent.constants import get_hermes_home # noqa: F811,E402
|
||||
|
||||
def get_config_path() -> Path:
|
||||
"""Get the main config file path."""
|
||||
|
|
@ -699,7 +699,7 @@ DEFAULT_CONFIG: _DefaultConfig = {
|
|||
"providers": {},
|
||||
"fallback_providers": [],
|
||||
"credential_pool_strategies": {},
|
||||
"toolsets": ["hermes-cli"],
|
||||
"hermes_agent.tools.toolsets": ["hermes-cli"],
|
||||
"agent": {
|
||||
"max_turns": 90,
|
||||
# Inactivity timeout for gateway agent execution (seconds).
|
||||
|
|
@ -2230,7 +2230,7 @@ def get_missing_skill_config_vars() -> List[Dict[str, Any]]:
|
|||
config.yaml. Returns a list of dicts suitable for prompting.
|
||||
"""
|
||||
try:
|
||||
from agent.skill_utils import discover_all_skill_config_vars, SKILL_CONFIG_PREFIX
|
||||
from hermes_agent.agent.skill_utils import discover_all_skill_config_vars, SKILL_CONFIG_PREFIX
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
|
@ -2450,7 +2450,7 @@ def check_config_version() -> Tuple[int, int]:
|
|||
# Fields that are valid at root level of config.yaml
|
||||
_KNOWN_ROOT_KEYS = {
|
||||
"_config_version", "model", "providers", "fallback_model",
|
||||
"fallback_providers", "credential_pool_strategies", "toolsets",
|
||||
"fallback_providers", "credential_pool_strategies", "hermes_agent.tools.toolsets",
|
||||
"agent", "terminal", "display", "compression", "delegation",
|
||||
"auxiliary", "custom_providers", "context", "memory", "gateway",
|
||||
}
|
||||
|
|
@ -3132,7 +3132,7 @@ def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, A
|
|||
print()
|
||||
config = load_config()
|
||||
try:
|
||||
from agent.skill_utils import SKILL_CONFIG_PREFIX
|
||||
from hermes_agent.agent.skill_utils import SKILL_CONFIG_PREFIX
|
||||
except Exception:
|
||||
SKILL_CONFIG_PREFIX = "skills.config"
|
||||
for var in missing_skill_config:
|
||||
|
|
@ -3447,7 +3447,7 @@ def save_config(config: Dict[str, Any]):
|
|||
if is_managed():
|
||||
managed_error("save configuration")
|
||||
return
|
||||
from utils import atomic_yaml_write
|
||||
from hermes_agent.utils import atomic_yaml_write
|
||||
|
||||
ensure_hermes_home()
|
||||
config_path = get_config_path()
|
||||
|
|
@ -3883,7 +3883,7 @@ def show_config():
|
|||
for env_key, name in keys:
|
||||
value = get_env_value(env_key)
|
||||
print(f" {name:<14} {redact_key(value)}")
|
||||
from hermes_cli.auth import get_anthropic_key
|
||||
from hermes_agent.cli.auth.auth import get_anthropic_key
|
||||
anthropic_value = get_anthropic_key()
|
||||
print(f" {'Anthropic':<14} {redact_key(anthropic_value)}")
|
||||
|
||||
|
|
@ -3991,7 +3991,7 @@ def show_config():
|
|||
|
||||
# Skill config
|
||||
try:
|
||||
from agent.skill_utils import discover_all_skill_config_vars, resolve_skill_config_values
|
||||
from hermes_agent.agent.skill_utils import discover_all_skill_config_vars, resolve_skill_config_values
|
||||
skill_vars = discover_all_skill_config_vars()
|
||||
if skill_vars:
|
||||
resolved = resolve_skill_config_values(skill_vars)
|
||||
|
|
@ -4105,7 +4105,7 @@ def set_config_value(key: str, value: str):
|
|||
|
||||
# Write only user config back (not the full merged defaults)
|
||||
ensure_hermes_home()
|
||||
from utils import atomic_yaml_write
|
||||
from hermes_agent.utils import atomic_yaml_write
|
||||
atomic_yaml_write(config_path, user_config, sort_keys=False)
|
||||
|
||||
# Keep .env in sync for keys that terminal_tool reads directly from env vars.
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@ from pathlib import Path
|
|||
from typing import Iterable, List, Optional
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent.resolve()
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
|
||||
def _normalize_skills(single_skill=None, skills: Optional[Iterable[str]] = None) -> Optional[List[str]]:
|
||||
|
|
@ -33,14 +32,14 @@ def _normalize_skills(single_skill=None, skills: Optional[Iterable[str]] = None)
|
|||
|
||||
|
||||
def _cron_api(**kwargs):
|
||||
from tools.cronjob_tools import cronjob as cronjob_tool
|
||||
from hermes_agent.tools.cronjob import cronjob as cronjob_tool
|
||||
|
||||
return json.loads(cronjob_tool(**kwargs))
|
||||
|
||||
|
||||
def cron_list(show_all: bool = False):
|
||||
"""List all scheduled jobs."""
|
||||
from cron.jobs import list_jobs
|
||||
from hermes_agent.cron.jobs import list_jobs
|
||||
|
||||
jobs = list_jobs(include_disabled=show_all)
|
||||
|
||||
|
|
@ -110,7 +109,7 @@ def cron_list(show_all: bool = False):
|
|||
|
||||
print()
|
||||
|
||||
from hermes_cli.gateway import find_gateway_pids
|
||||
from hermes_agent.cli.gateway import find_gateway_pids
|
||||
if not find_gateway_pids():
|
||||
print(color(" ⚠ Gateway is not running — jobs won't fire automatically.", Colors.YELLOW))
|
||||
print(color(" Start it with: hermes gateway install", Colors.DIM))
|
||||
|
|
@ -120,14 +119,14 @@ def cron_list(show_all: bool = False):
|
|||
|
||||
def cron_tick():
|
||||
"""Run due jobs once and exit."""
|
||||
from cron.scheduler import tick
|
||||
from hermes_agent.cron.scheduler import tick
|
||||
tick(verbose=True)
|
||||
|
||||
|
||||
def cron_status():
|
||||
"""Show cron execution status."""
|
||||
from cron.jobs import list_jobs
|
||||
from hermes_cli.gateway import find_gateway_pids
|
||||
from hermes_agent.cron.jobs import list_jobs
|
||||
from hermes_agent.cli.gateway import find_gateway_pids
|
||||
|
||||
print()
|
||||
|
||||
|
|
@ -185,7 +184,7 @@ def cron_create(args):
|
|||
|
||||
|
||||
def cron_edit(args):
|
||||
from cron.jobs import get_job
|
||||
from hermes_agent.cron.jobs import get_job
|
||||
|
||||
job = get_job(args.job_id)
|
||||
if not job:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import urllib.request
|
|||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -319,7 +319,7 @@ def _resolve_log_path(log_name: str) -> Optional[Path]:
|
|||
|
||||
Returns the path if found, or None.
|
||||
"""
|
||||
from hermes_cli.logs import LOG_FILES
|
||||
from hermes_agent.cli.logs import LOG_FILES
|
||||
|
||||
filename = LOG_FILES.get(log_name)
|
||||
if not filename:
|
||||
|
|
@ -340,7 +340,7 @@ def _resolve_log_path(log_name: str) -> Optional[Path]:
|
|||
|
||||
def _read_log_tail(log_name: str, num_lines: int) -> str:
|
||||
"""Read the last *num_lines* from a log file, or return a placeholder."""
|
||||
from hermes_cli.logs import _read_last_n_lines
|
||||
from hermes_agent.cli.logs import _read_last_n_lines
|
||||
|
||||
log_path = _resolve_log_path(log_name)
|
||||
if log_path is None:
|
||||
|
|
@ -388,7 +388,7 @@ def _read_full_log(log_name: str, max_bytes: int = _MAX_LOG_BYTES) -> Optional[s
|
|||
|
||||
def _capture_dump() -> str:
|
||||
"""Run ``hermes dump`` and return its stdout as a string."""
|
||||
from hermes_cli.dump import run_dump
|
||||
from hermes_agent.cli.dump import run_dump
|
||||
|
||||
class _FakeArgs:
|
||||
show_keys = False
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import subprocess
|
|||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_cli.config import get_project_root, get_hermes_home, get_env_path
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.cli.config import get_project_root, get_hermes_home, get_env_path
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
PROJECT_ROOT = get_project_root()
|
||||
HERMES_HOME = get_hermes_home()
|
||||
|
|
@ -28,9 +28,9 @@ if _env_path.exists():
|
|||
# Also try project .env as dev fallback
|
||||
load_dotenv(PROJECT_ROOT / ".env", override=False, encoding="utf-8")
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_constants import OPENROUTER_MODELS_URL
|
||||
from utils import base_url_host_matches
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
from hermes_agent.constants import OPENROUTER_MODELS_URL
|
||||
from hermes_agent.utils import base_url_host_matches
|
||||
|
||||
|
||||
_PROVIDER_ENV_HINTS = (
|
||||
|
|
@ -58,7 +58,7 @@ _PROVIDER_ENV_HINTS = (
|
|||
)
|
||||
|
||||
|
||||
from hermes_constants import is_termux as _is_termux
|
||||
from hermes_agent.constants import is_termux as _is_termux
|
||||
|
||||
|
||||
def _python_install_cmd() -> str:
|
||||
|
|
@ -92,7 +92,7 @@ def _has_provider_env_config(content: str) -> bool:
|
|||
def _honcho_is_configured_for_doctor() -> bool:
|
||||
"""Return True when Honcho is configured, even if this process has no active session."""
|
||||
try:
|
||||
from plugins.memory.honcho.client import HonchoClientConfig
|
||||
from hermes_agent.plugins.memory.honcho.client import HonchoClientConfig
|
||||
|
||||
cfg = HonchoClientConfig.from_global_config()
|
||||
return bool(cfg.enabled and (cfg.api_key or cfg.base_url))
|
||||
|
|
@ -132,7 +132,7 @@ def check_info(text: str):
|
|||
def _check_gateway_service_linger(issues: list[str]) -> None:
|
||||
"""Warn when a systemd user gateway service will stop after logout."""
|
||||
try:
|
||||
from hermes_cli.gateway import (
|
||||
from hermes_agent.cli.gateway import (
|
||||
get_systemd_linger_status,
|
||||
get_systemd_unit_path,
|
||||
is_linux,
|
||||
|
|
@ -290,12 +290,12 @@ def run_doctor(args):
|
|||
|
||||
known_providers: set = set()
|
||||
try:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
known_providers = set(PROVIDER_REGISTRY.keys()) | {"openrouter", "custom", "auto"}
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from hermes_cli.auth import resolve_provider as _resolve_provider
|
||||
from hermes_agent.cli.auth.auth import resolve_provider as _resolve_provider
|
||||
except Exception:
|
||||
_resolve_provider = None
|
||||
|
||||
|
|
@ -338,7 +338,7 @@ def run_doctor(args):
|
|||
# explicitly dispatch, which would produce false positives.
|
||||
if canonical_provider and canonical_provider not in ("auto", "custom", "openrouter"):
|
||||
try:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY, get_auth_status
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY, get_auth_status
|
||||
pconfig = PROVIDER_REGISTRY.get(canonical_provider)
|
||||
if pconfig and getattr(pconfig, "auth_type", "") == "api_key":
|
||||
status = get_auth_status(canonical_provider) or {}
|
||||
|
|
@ -379,7 +379,7 @@ def run_doctor(args):
|
|||
config_path = HERMES_HOME / 'config.yaml'
|
||||
if config_path.exists():
|
||||
try:
|
||||
from hermes_cli.config import check_config_version, migrate_config
|
||||
from hermes_agent.cli.config import check_config_version, migrate_config
|
||||
current_ver, latest_ver = check_config_version()
|
||||
if current_ver < latest_ver:
|
||||
check_warn(
|
||||
|
|
@ -419,7 +419,7 @@ def run_doctor(args):
|
|||
model_section[k] = raw_config.pop(k)
|
||||
else:
|
||||
raw_config.pop(k)
|
||||
from utils import atomic_yaml_write
|
||||
from hermes_agent.utils import atomic_yaml_write
|
||||
atomic_yaml_write(config_path, raw_config)
|
||||
check_ok("Migrated stale root-level keys into model section")
|
||||
fixed_count += 1
|
||||
|
|
@ -430,7 +430,7 @@ def run_doctor(args):
|
|||
|
||||
# Validate config structure (catches malformed custom_providers, etc.)
|
||||
try:
|
||||
from hermes_cli.config import validate_config_structure
|
||||
from hermes_agent.cli.config import validate_config_structure
|
||||
config_issues = validate_config_structure()
|
||||
if config_issues:
|
||||
print()
|
||||
|
|
@ -454,7 +454,7 @@ def run_doctor(args):
|
|||
print(color("◆ Auth Providers", Colors.CYAN, Colors.BOLD))
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import (
|
||||
from hermes_agent.cli.auth.auth import (
|
||||
get_nous_auth_status,
|
||||
get_codex_auth_status,
|
||||
get_gemini_oauth_auth_status,
|
||||
|
|
@ -877,13 +877,13 @@ def run_doctor(args):
|
|||
else:
|
||||
check_warn("OpenRouter API", "(not configured)")
|
||||
|
||||
from hermes_cli.auth import get_anthropic_key
|
||||
from hermes_agent.cli.auth.auth import get_anthropic_key
|
||||
anthropic_key = get_anthropic_key()
|
||||
if anthropic_key:
|
||||
print(" Checking Anthropic API...", end="", flush=True)
|
||||
try:
|
||||
import httpx
|
||||
from agent.anthropic_adapter import _is_oauth_token, _COMMON_BETAS, _OAUTH_ONLY_BETAS
|
||||
from hermes_agent.providers.anthropic_adapter import _is_oauth_token, _COMMON_BETAS, _OAUTH_ONLY_BETAS
|
||||
|
||||
headers = {"anthropic-version": "2023-06-01"}
|
||||
if _is_oauth_token(anthropic_key):
|
||||
|
|
@ -951,7 +951,7 @@ def run_doctor(args):
|
|||
# with no /v1) don't support /models. Rewrite to the OpenAI-compat
|
||||
# /v1 surface for health checks.
|
||||
if _base and _base.rstrip("/").endswith("/anthropic"):
|
||||
from agent.auxiliary_client import _to_openai_base_url
|
||||
from hermes_agent.providers.auxiliary import _to_openai_base_url
|
||||
_base = _to_openai_base_url(_base)
|
||||
if base_url_host_matches(_base, "api.kimi.com") and _base.rstrip("/").endswith("/coding"):
|
||||
_base = _base.rstrip("/") + "/v1"
|
||||
|
|
@ -977,7 +977,7 @@ def run_doctor(args):
|
|||
# -- AWS Bedrock --
|
||||
# Bedrock uses the AWS SDK credential chain, not API keys.
|
||||
try:
|
||||
from agent.bedrock_adapter import has_aws_credentials, resolve_aws_auth_env_var, resolve_bedrock_region
|
||||
from hermes_agent.providers.bedrock_adapter import has_aws_credentials, resolve_aws_auth_env_var, resolve_bedrock_region
|
||||
if has_aws_credentials():
|
||||
_auth_var = resolve_aws_auth_env_var()
|
||||
_region = resolve_bedrock_region()
|
||||
|
|
@ -1028,9 +1028,7 @@ def run_doctor(args):
|
|||
print(color("◆ Tool Availability", Colors.CYAN, Colors.BOLD))
|
||||
|
||||
try:
|
||||
# Add project root to path for imports
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
from model_tools import check_tool_availability, TOOLSET_REQUIREMENTS
|
||||
from hermes_agent.tools.dispatch import check_tool_availability, TOOLSET_REQUIREMENTS
|
||||
|
||||
available, unavailable = check_tool_availability()
|
||||
available, unavailable = _apply_doctor_tool_availability_overrides(available, unavailable)
|
||||
|
|
@ -1079,7 +1077,7 @@ def run_doctor(args):
|
|||
else:
|
||||
check_warn("Skills Hub directory not initialized", "(run: hermes skills list)")
|
||||
|
||||
from hermes_cli.config import get_env_value
|
||||
from hermes_agent.cli.config import get_env_value
|
||||
github_token = get_env_value("GITHUB_TOKEN") or get_env_value("GH_TOKEN")
|
||||
if github_token:
|
||||
check_ok("GitHub token configured (authenticated API access)")
|
||||
|
|
@ -1107,7 +1105,7 @@ def run_doctor(args):
|
|||
check_ok("Built-in memory active", "(no external provider configured — this is fine)")
|
||||
elif _active_memory_provider == "honcho":
|
||||
try:
|
||||
from plugins.memory.honcho.client import HonchoClientConfig, resolve_config_path
|
||||
from hermes_agent.plugins.memory.honcho.client import HonchoClientConfig, resolve_config_path
|
||||
hcfg = HonchoClientConfig.from_global_config()
|
||||
_honcho_cfg_path = resolve_config_path()
|
||||
|
||||
|
|
@ -1119,7 +1117,7 @@ def run_doctor(args):
|
|||
check_fail("Honcho API key or base URL not set", "run: hermes memory setup")
|
||||
issues.append("No Honcho API key — run 'hermes memory setup'")
|
||||
else:
|
||||
from plugins.memory.honcho.client import get_honcho_client, reset_honcho_client
|
||||
from hermes_agent.plugins.memory.honcho.client import get_honcho_client, reset_honcho_client
|
||||
reset_honcho_client()
|
||||
try:
|
||||
get_honcho_client(hcfg)
|
||||
|
|
@ -1137,7 +1135,7 @@ def run_doctor(args):
|
|||
check_warn("Honcho check failed", str(_e))
|
||||
elif _active_memory_provider == "mem0":
|
||||
try:
|
||||
from plugins.memory.mem0 import _load_config as _load_mem0_config
|
||||
from hermes_agent.plugins.memory.mem0 import _load_config as _load_mem0_config
|
||||
mem0_cfg = _load_mem0_config()
|
||||
mem0_key = mem0_cfg.get("api_key", "")
|
||||
if mem0_key:
|
||||
|
|
@ -1154,7 +1152,7 @@ def run_doctor(args):
|
|||
else:
|
||||
# Generic check for other memory providers (openviking, hindsight, etc.)
|
||||
try:
|
||||
from plugins.memory import load_memory_provider
|
||||
from hermes_agent.plugins.memory import load_memory_provider
|
||||
_provider = load_memory_provider(_active_memory_provider)
|
||||
if _provider and _provider.is_available():
|
||||
check_ok(f"{_active_memory_provider} provider active")
|
||||
|
|
@ -1169,7 +1167,7 @@ def run_doctor(args):
|
|||
# Profiles
|
||||
# =========================================================================
|
||||
try:
|
||||
from hermes_cli.profiles import list_profiles, _get_wrapper_dir, profile_exists
|
||||
from hermes_agent.cli.profiles import list_profiles, _get_wrapper_dir, profile_exists
|
||||
import re as _re
|
||||
|
||||
named_profiles = [p for p in list_profiles() if not p.is_default]
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ import subprocess
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_cli.config import get_hermes_home, get_env_path, get_project_root, load_config
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.cli.config import get_hermes_home, get_env_path, get_project_root, load_config
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
|
||||
def _get_git_commit(project_root: Path) -> str:
|
||||
|
|
@ -44,7 +44,7 @@ def _redact(value: str) -> str:
|
|||
def _gateway_status() -> str:
|
||||
"""Return a short gateway status string."""
|
||||
try:
|
||||
from hermes_cli.gateway import get_gateway_runtime_snapshot
|
||||
from hermes_agent.cli.gateway import get_gateway_runtime_snapshot
|
||||
|
||||
snapshot = get_gateway_runtime_snapshot()
|
||||
if snapshot.running:
|
||||
|
|
@ -142,7 +142,7 @@ def _config_overrides(config: dict) -> dict[str, str]:
|
|||
|
||||
Returns a flat dict of dotpath -> value for interesting overrides.
|
||||
"""
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
from hermes_agent.cli.config import DEFAULT_CONFIG
|
||||
|
||||
overrides = {}
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ def _config_overrides(config: dict) -> dict[str, str]:
|
|||
default_toolsets = DEFAULT_CONFIG.get("toolsets", [])
|
||||
user_toolsets = config.get("toolsets", [])
|
||||
if user_toolsets != default_toolsets:
|
||||
overrides["toolsets"] = str(user_toolsets)
|
||||
overrides["hermes_agent.tools.toolsets"] = str(user_toolsets)
|
||||
|
||||
# Fallback providers
|
||||
fallbacks = config.get("fallback_providers", [])
|
||||
|
|
@ -207,7 +207,7 @@ def run_dump(args):
|
|||
hermes_home = get_hermes_home()
|
||||
|
||||
try:
|
||||
from hermes_cli import __version__, __release_date__
|
||||
from hermes_agent.cli import __version__, __release_date__
|
||||
except ImportError:
|
||||
__version__ = "(unknown)"
|
||||
__release_date__ = ""
|
||||
|
|
@ -223,7 +223,7 @@ def run_dump(args):
|
|||
|
||||
# Profile
|
||||
try:
|
||||
from hermes_cli.profiles import get_active_profile_name
|
||||
from hermes_agent.cli.profiles import get_active_profile_name
|
||||
profile = get_active_profile_name() or "(default)"
|
||||
except Exception:
|
||||
profile = "(default)"
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ def _sanitize_env_file_if_needed(path: Path) -> None:
|
|||
if not path.exists():
|
||||
return
|
||||
try:
|
||||
from hermes_cli.config import _sanitize_env_lines
|
||||
from hermes_agent.cli.config import _sanitize_env_lines
|
||||
except ImportError:
|
||||
return # early bootstrap — config module not available yet
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ from pathlib import Path
|
|||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent.resolve()
|
||||
|
||||
from gateway.status import terminate_pid
|
||||
from gateway.restart import (
|
||||
from hermes_agent.gateway.status import terminate_pid
|
||||
from hermes_agent.gateway.restart import (
|
||||
DEFAULT_GATEWAY_RESTART_DRAIN_TIMEOUT,
|
||||
GATEWAY_SERVICE_RESTART_EXIT_CODE,
|
||||
parse_restart_drain_timeout,
|
||||
)
|
||||
from hermes_cli.config import (
|
||||
from hermes_agent.cli.config import (
|
||||
get_env_value,
|
||||
get_hermes_home,
|
||||
is_managed,
|
||||
|
|
@ -31,11 +31,11 @@ from hermes_cli.config import (
|
|||
)
|
||||
# display_hermes_home is imported lazily at call sites to avoid ImportError
|
||||
# when hermes_constants is cached from a pre-update version during `hermes update`.
|
||||
from hermes_cli.setup import (
|
||||
from hermes_agent.cli.setup_wizard import (
|
||||
print_header, print_info, print_success, print_warning, print_error,
|
||||
prompt, prompt_choice, prompt_yes_no,
|
||||
)
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
|
@ -192,6 +192,12 @@ def _scan_gateway_pids(exclude_pids: set[int], all_profiles: bool = False) -> li
|
|||
"""
|
||||
pids: list[int] = []
|
||||
patterns = [
|
||||
"hermes_agent.cli.main gateway",
|
||||
"hermes_agent.cli.main --profile",
|
||||
"hermes_agent.cli.main -p",
|
||||
"hermes_agent/cli/main.py gateway",
|
||||
"hermes_agent/cli/main.py --profile",
|
||||
"hermes_agent/cli/main.py -p",
|
||||
"hermes_cli.main gateway",
|
||||
"hermes_cli.main --profile",
|
||||
"hermes_cli.main -p",
|
||||
|
|
@ -303,7 +309,7 @@ def find_gateway_pids(exclude_pids: set | None = None, all_profiles: bool = Fals
|
|||
pids: list[int] = []
|
||||
if not all_profiles:
|
||||
try:
|
||||
from gateway.status import get_running_pid
|
||||
from hermes_agent.gateway.status import get_running_pid
|
||||
|
||||
_append_unique_pid(pids, get_running_pid(), _exclude)
|
||||
except Exception:
|
||||
|
|
@ -357,7 +363,7 @@ def get_gateway_runtime_snapshot(system: bool = False) -> GatewayRuntimeSnapshot
|
|||
gateway_pids=gateway_pids,
|
||||
)
|
||||
|
||||
from hermes_constants import is_container
|
||||
from hermes_agent.constants import is_container
|
||||
|
||||
if is_linux() and is_container():
|
||||
return GatewayRuntimeSnapshot(
|
||||
|
|
@ -445,7 +451,7 @@ def stop_profile_gateway() -> bool:
|
|||
Returns True if a process was stopped, False if none was found.
|
||||
"""
|
||||
try:
|
||||
from gateway.status import get_running_pid, remove_pid_file
|
||||
from hermes_agent.gateway.status import get_running_pid, remove_pid_file
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
|
@ -478,7 +484,7 @@ def is_linux() -> bool:
|
|||
return sys.platform.startswith('linux')
|
||||
|
||||
|
||||
from hermes_constants import is_container, is_termux, is_wsl
|
||||
from hermes_agent.constants import is_container, is_termux, is_wsl
|
||||
|
||||
|
||||
def _wsl_systemd_operational() -> bool:
|
||||
|
|
@ -552,7 +558,7 @@ def _profile_suffix() -> str:
|
|||
"""
|
||||
import hashlib
|
||||
import re
|
||||
from hermes_constants import get_default_hermes_root
|
||||
from hermes_agent.constants import get_default_hermes_root
|
||||
home = get_hermes_home().resolve()
|
||||
default = get_default_hermes_root().resolve()
|
||||
if home == default:
|
||||
|
|
@ -582,7 +588,7 @@ def _profile_arg(hermes_home: str | None = None) -> str:
|
|||
service definition for a different user (e.g. system service).
|
||||
"""
|
||||
import re
|
||||
from hermes_constants import get_default_hermes_root
|
||||
from hermes_agent.constants import get_default_hermes_root
|
||||
home = Path(hermes_home or str(get_hermes_home())).resolve()
|
||||
default = get_default_hermes_root().resolve()
|
||||
if home == default:
|
||||
|
|
@ -696,6 +702,8 @@ _LEGACY_SERVICE_NAMES: tuple[str, ...] = ("hermes.service",)
|
|||
# ExecStart content markers that identify a unit as running our gateway.
|
||||
# A legacy unit is only flagged when its file contains one of these.
|
||||
_LEGACY_UNIT_EXECSTART_MARKERS: tuple[str, ...] = (
|
||||
"hermes_agent.cli.main gateway",
|
||||
"hermes_agent/cli/main.py gateway",
|
||||
"hermes_cli.main gateway",
|
||||
"hermes_cli/main.py gateway",
|
||||
"gateway/run.py",
|
||||
|
|
@ -1221,7 +1229,7 @@ StartLimitBurst=5
|
|||
Type=simple
|
||||
User={username}
|
||||
Group={group_name}
|
||||
ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
|
||||
ExecStart={python_path} -m hermes_agent.cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
|
||||
WorkingDirectory={working_dir}
|
||||
Environment="HOME={home_dir}"
|
||||
Environment="USER={username}"
|
||||
|
|
@ -1256,7 +1264,7 @@ StartLimitBurst=5
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
|
||||
ExecStart={python_path} -m hermes_agent.cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
|
||||
WorkingDirectory={working_dir}
|
||||
Environment="PATH={sane_path}"
|
||||
Environment="VIRTUAL_ENV={venv_dir}"
|
||||
|
|
@ -1501,7 +1509,7 @@ def systemd_restart(system: bool = False):
|
|||
if system:
|
||||
_require_root_for_system_service("restart")
|
||||
refresh_systemd_unit_if_needed(system=system)
|
||||
from gateway.status import get_running_pid
|
||||
from hermes_agent.gateway.status import get_running_pid
|
||||
|
||||
pid = get_running_pid()
|
||||
if pid is not None and _request_gateway_self_restart(pid):
|
||||
|
|
@ -1689,7 +1697,7 @@ def generate_launchd_plist() -> str:
|
|||
prog_args = [
|
||||
f"<string>{python_path}</string>",
|
||||
"<string>-m</string>",
|
||||
"<string>hermes_cli.main</string>",
|
||||
"<string>hermes_agent.cli.main</string>",
|
||||
]
|
||||
if profile_arg:
|
||||
for part in profile_arg.split():
|
||||
|
|
@ -1799,7 +1807,7 @@ def launchd_install(force: bool = False):
|
|||
print()
|
||||
print("Next steps:")
|
||||
print(" hermes gateway status # Check status")
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print(f" tail -f {_dhh()}/logs/gateway.log # View logs")
|
||||
|
||||
def launchd_uninstall():
|
||||
|
|
@ -1867,7 +1875,7 @@ def _wait_for_gateway_exit(timeout: float = 10.0, force_after: float | None = 5.
|
|||
force_after: Seconds of graceful waiting before escalating to force-kill.
|
||||
"""
|
||||
import time
|
||||
from gateway.status import get_running_pid
|
||||
from hermes_agent.gateway.status import get_running_pid
|
||||
|
||||
deadline = time.monotonic() + timeout
|
||||
force_deadline = (time.monotonic() + force_after) if force_after is not None else None
|
||||
|
|
@ -1901,7 +1909,7 @@ def launchd_restart():
|
|||
label = get_launchd_label()
|
||||
target = f"{_launchd_domain()}/{label}"
|
||||
drain_timeout = _get_restart_drain_timeout()
|
||||
from gateway.status import get_running_pid
|
||||
from hermes_agent.gateway.status import get_running_pid
|
||||
|
||||
try:
|
||||
pid = get_running_pid()
|
||||
|
|
@ -1982,9 +1990,7 @@ def run_gateway(verbose: int = 0, quiet: bool = False, replace: bool = False):
|
|||
This prevents systemd restart loops when the old process
|
||||
hasn't fully exited yet.
|
||||
"""
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from gateway.run import start_gateway
|
||||
from hermes_agent.gateway.run import start_gateway
|
||||
|
||||
print("┌─────────────────────────────────────────────────────────┐")
|
||||
print("│ ⚕ Hermes Gateway Starting... │")
|
||||
|
|
@ -2430,7 +2436,7 @@ def _platform_status(platform: dict) -> str:
|
|||
def _runtime_health_lines() -> list[str]:
|
||||
"""Summarize the latest persisted gateway runtime health state."""
|
||||
try:
|
||||
from gateway.status import read_runtime_status
|
||||
from hermes_agent.gateway.status import read_runtime_status
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
|
@ -2562,7 +2568,7 @@ def _setup_standard_platform(platform: dict):
|
|||
|
||||
def _setup_whatsapp():
|
||||
"""Delegate to the existing WhatsApp setup flow."""
|
||||
from hermes_cli.main import cmd_whatsapp
|
||||
from hermes_agent.cli.main import cmd_whatsapp
|
||||
import argparse
|
||||
cmd_whatsapp(argparse.Namespace())
|
||||
|
||||
|
|
@ -2581,7 +2587,7 @@ def _setup_sms():
|
|||
|
||||
def _setup_dingtalk():
|
||||
"""Configure DingTalk — QR scan (recommended) or manual credential entry."""
|
||||
from hermes_cli.setup import (
|
||||
from hermes_agent.cli.setup_wizard import (
|
||||
prompt_choice, prompt_yes_no, print_info, print_success, print_warning,
|
||||
)
|
||||
|
||||
|
|
@ -2612,7 +2618,7 @@ def _setup_dingtalk():
|
|||
if method == 0:
|
||||
# ── QR-code device-flow authorization ──
|
||||
try:
|
||||
from hermes_cli.dingtalk_auth import dingtalk_qr_auth
|
||||
from hermes_agent.cli.auth.dingtalk import dingtalk_qr_auth
|
||||
except ImportError as exc:
|
||||
print_warning(f" QR auth module failed to load ({exc}), falling back to manual input.")
|
||||
_setup_standard_platform(dingtalk_platform)
|
||||
|
|
@ -2720,7 +2726,7 @@ def _setup_weixin():
|
|||
return
|
||||
|
||||
try:
|
||||
from gateway.platforms.weixin import check_weixin_requirements, qr_login
|
||||
from hermes_agent.gateway.platforms.weixin import check_weixin_requirements, qr_login
|
||||
except Exception as exc:
|
||||
print_error(f" Weixin adapter import failed: {exc}")
|
||||
print_info(" Install gateway dependencies first, then retry.")
|
||||
|
|
@ -2855,7 +2861,7 @@ def _setup_feishu():
|
|||
if method_idx == 0:
|
||||
# ── QR scan-to-create ──
|
||||
try:
|
||||
from gateway.platforms.feishu import qr_register
|
||||
from hermes_agent.gateway.platforms.feishu import qr_register
|
||||
except Exception as exc:
|
||||
print_error(f" Feishu / Lark onboard import failed: {exc}")
|
||||
qr_register = None
|
||||
|
|
@ -2896,7 +2902,7 @@ def _setup_feishu():
|
|||
# Try to probe the bot with manual credentials
|
||||
bot_name = None
|
||||
try:
|
||||
from gateway.platforms.feishu import probe_bot
|
||||
from hermes_agent.gateway.platforms.feishu import probe_bot
|
||||
bot_info = probe_bot(app_id, app_secret, domain)
|
||||
if bot_info:
|
||||
bot_name = bot_info.get("bot_name")
|
||||
|
|
@ -3129,11 +3135,11 @@ def _qqbot_qr_flow():
|
|||
or None on failure/cancel.
|
||||
"""
|
||||
try:
|
||||
from gateway.platforms.qqbot import (
|
||||
from hermes_agent.gateway.platforms.qqbot import (
|
||||
create_bind_task, poll_bind_result, build_connect_url,
|
||||
decrypt_secret, BindStatus,
|
||||
)
|
||||
from gateway.platforms.qqbot.constants import ONBOARD_POLL_INTERVAL
|
||||
from hermes_agent.gateway.platforms.qqbot.constants import ONBOARD_POLL_INTERVAL
|
||||
except Exception as exc:
|
||||
print_error(f" QQBot onboard import failed: {exc}")
|
||||
return None
|
||||
|
|
@ -3471,7 +3477,7 @@ def gateway_setup():
|
|||
print_info(" To enable systemd: add systemd=true to /etc/wsl.conf, then 'wsl --shutdown'")
|
||||
else:
|
||||
if is_termux():
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print_info(" Termux does not use systemd/launchd services.")
|
||||
print_info(" Run in foreground: hermes gateway run")
|
||||
print_info(f" Or start it manually in the background (best effort): nohup hermes gateway run >{_dhh()}/logs/gateway.log 2>&1 &")
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ def hooks_command(args) -> None:
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _cmd_list(_args) -> None:
|
||||
from hermes_cli.config import load_config
|
||||
from agent import shell_hooks
|
||||
from hermes_agent.cli.config import load_config
|
||||
from hermes_agent.agent import shell_hooks
|
||||
|
||||
specs = shell_hooks.iter_configured_hooks(load_config())
|
||||
|
||||
|
|
@ -186,9 +186,9 @@ _DEFAULT_PAYLOADS = {
|
|||
|
||||
|
||||
def _cmd_test(args) -> None:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_cli.plugins import VALID_HOOKS
|
||||
from agent import shell_hooks
|
||||
from hermes_agent.cli.config import load_config
|
||||
from hermes_agent.cli.plugins import VALID_HOOKS
|
||||
from hermes_agent.agent import shell_hooks
|
||||
|
||||
event = args.event
|
||||
if event not in VALID_HOOKS:
|
||||
|
|
@ -273,7 +273,7 @@ def _truncate(s: str, n: int) -> str:
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _cmd_revoke(args) -> None:
|
||||
from agent import shell_hooks
|
||||
from hermes_agent.agent import shell_hooks
|
||||
|
||||
removed = shell_hooks.revoke(args.command)
|
||||
if removed == 0:
|
||||
|
|
@ -291,8 +291,8 @@ def _cmd_revoke(args) -> None:
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _cmd_doctor(_args) -> None:
|
||||
from hermes_cli.config import load_config
|
||||
from agent import shell_hooks
|
||||
from hermes_agent.cli.config import load_config
|
||||
from hermes_agent.agent import shell_hooks
|
||||
|
||||
specs = shell_hooks.iter_configured_hooks(load_config())
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ from datetime import datetime, timedelta
|
|||
from pathlib import Path
|
||||
from typing import Optional, Sequence
|
||||
|
||||
from hermes_constants import get_hermes_home, display_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home, display_hermes_home
|
||||
|
||||
# Known log files (name → filename)
|
||||
LOG_FILES = {
|
||||
|
|
@ -191,7 +191,7 @@ def tail_log(
|
|||
# Resolve component to logger name prefixes
|
||||
component_prefixes = None
|
||||
if component:
|
||||
from hermes_logging import COMPONENT_PREFIXES
|
||||
from hermes_agent.logging import COMPONENT_PREFIXES
|
||||
component_lower = component.lower()
|
||||
if component_lower not in COMPONENT_PREFIXES:
|
||||
available = ", ".join(sorted(COMPONENT_PREFIXES))
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -15,15 +15,15 @@ import re
|
|||
import time
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from hermes_cli.config import (
|
||||
from hermes_agent.cli.config import (
|
||||
load_config,
|
||||
save_config,
|
||||
get_env_value,
|
||||
save_env_value,
|
||||
get_hermes_home, # noqa: F401 — used by test mocks
|
||||
)
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ def _confirm(question: str, default: bool = True) -> bool:
|
|||
|
||||
|
||||
def _prompt(question: str, *, password: bool = False, default: str = "") -> str:
|
||||
from hermes_cli.cli_output import prompt as _shared_prompt
|
||||
from hermes_agent.cli.ui.output import prompt as _shared_prompt
|
||||
return _shared_prompt(question, default=default, password=password)
|
||||
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ def _probe_single_server(
|
|||
Returns list of ``(tool_name, description)`` tuples.
|
||||
Raises on connection failure.
|
||||
"""
|
||||
from tools.mcp_tool import (
|
||||
from hermes_agent.tools.mcp.tool import (
|
||||
_ensure_mcp_loop,
|
||||
_run_on_mcp_loop,
|
||||
_connect_server,
|
||||
|
|
@ -279,7 +279,7 @@ def cmd_mcp_add(args):
|
|||
_info(f"Starting OAuth flow for '{name}'...")
|
||||
oauth_ok = False
|
||||
try:
|
||||
from tools.mcp_oauth_manager import get_manager
|
||||
from hermes_agent.tools.mcp.oauth_manager import get_manager
|
||||
oauth_auth = get_manager().get_or_build_provider(name, url, None)
|
||||
if oauth_auth:
|
||||
server_config["auth"] = "oauth"
|
||||
|
|
@ -372,7 +372,7 @@ def cmd_mcp_add(args):
|
|||
|
||||
if choice in ("s", "select"):
|
||||
# Interactive tool selection
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
|
||||
labels = [f"{t[0]} — {t[1]}" for t in tools]
|
||||
pre_selected = set(range(len(tools)))
|
||||
|
|
@ -432,7 +432,7 @@ def cmd_mcp_remove(args):
|
|||
# any provider instance cached in the current process (e.g. from an
|
||||
# earlier `hermes mcp test` in the same session) is evicted too.
|
||||
try:
|
||||
from tools.mcp_oauth_manager import get_manager
|
||||
from hermes_agent.tools.mcp.oauth_manager import get_manager
|
||||
get_manager().remove(name)
|
||||
_success("Cleaned up OAuth tokens")
|
||||
except Exception:
|
||||
|
|
@ -616,7 +616,7 @@ def cmd_mcp_login(args):
|
|||
# Wipe both disk and in-memory cache so the next probe forces a fresh
|
||||
# OAuth flow.
|
||||
try:
|
||||
from tools.mcp_oauth_manager import get_manager
|
||||
from hermes_agent.tools.mcp.oauth_manager import get_manager
|
||||
mgr = get_manager()
|
||||
mgr.remove(name)
|
||||
except Exception as exc:
|
||||
|
|
@ -700,7 +700,7 @@ def cmd_mcp_configure(args):
|
|||
print()
|
||||
|
||||
# Interactive checklist
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
|
||||
labels = [f"{t[0]} — {t[1]}" for t in all_tools]
|
||||
|
||||
|
|
@ -742,7 +742,7 @@ def mcp_command(args):
|
|||
action = getattr(args, "mcp_action", None)
|
||||
|
||||
if action == "serve":
|
||||
from mcp_serve import run_mcp_server
|
||||
from hermes_agent.tools.mcp.serve import run_mcp_server
|
||||
run_mcp_server(verbose=getattr(args, "verbose", False))
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import os
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -25,7 +25,7 @@ def _curses_select(title: str, items: list[tuple[str, str]], default: int = 0) -
|
|||
items: list of (label, description) tuples.
|
||||
Returns selected index, or default on escape/quit.
|
||||
"""
|
||||
from hermes_cli.curses_ui import curses_radiolist
|
||||
from hermes_agent.cli.ui.curses import curses_radiolist
|
||||
# Format (label, desc) tuples into display strings
|
||||
display_items = [
|
||||
f"{label} {desc}" if desc else label
|
||||
|
|
@ -58,7 +58,7 @@ def _prompt(label: str, default: str | None = None, secret: bool = False) -> str
|
|||
def _install_dependencies(provider_name: str) -> None:
|
||||
"""Install pip dependencies declared in plugin.yaml."""
|
||||
import subprocess
|
||||
from plugins.memory import find_provider_dir
|
||||
from hermes_agent.plugins.memory import find_provider_dir
|
||||
|
||||
plugin_dir = find_provider_dir(provider_name)
|
||||
if not plugin_dir:
|
||||
|
|
@ -148,7 +148,7 @@ def _get_available_providers() -> list:
|
|||
Returns list of (name, description, provider_instance) tuples.
|
||||
"""
|
||||
try:
|
||||
from plugins.memory import discover_memory_providers, load_memory_provider
|
||||
from hermes_agent.plugins.memory import discover_memory_providers, load_memory_provider
|
||||
raw = discover_memory_providers()
|
||||
except Exception:
|
||||
raw = []
|
||||
|
|
@ -184,7 +184,7 @@ def _get_available_providers() -> list:
|
|||
|
||||
def cmd_setup_provider(provider_name: str) -> None:
|
||||
"""Run memory setup for a specific provider, skipping the picker."""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
|
||||
providers = _get_available_providers()
|
||||
match = None
|
||||
|
|
@ -220,7 +220,7 @@ def cmd_setup_provider(provider_name: str) -> None:
|
|||
|
||||
def cmd_setup(args) -> None:
|
||||
"""Interactive memory provider setup wizard."""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
|
||||
providers = _get_available_providers()
|
||||
|
||||
|
|
@ -386,7 +386,7 @@ def _write_env_vars(env_path: Path, env_writes: dict) -> None:
|
|||
|
||||
def cmd_status(args) -> None:
|
||||
"""Show current memory provider config."""
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
|
||||
config = load_config()
|
||||
mem_config = config.get("memory", {})
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from difflib import get_close_matches
|
|||
from pathlib import Path
|
||||
from typing import Any, NamedTuple, Optional
|
||||
|
||||
from hermes_cli import __version__ as _HERMES_VERSION
|
||||
from hermes_agent.cli import __version__ as _HERMES_VERSION
|
||||
|
||||
# Identify ourselves so endpoints fronted by Cloudflare's Browser Integrity
|
||||
# Check (error 1010) don't reject the default ``Python-urllib/*`` signature.
|
||||
|
|
@ -101,7 +101,7 @@ def _codex_curated_models() -> list[str]:
|
|||
This keeps the gateway /model picker in sync with the CLI `hermes model`
|
||||
flow without maintaining a separate static list.
|
||||
"""
|
||||
from hermes_cli.codex_models import DEFAULT_CODEX_MODELS, _add_forward_compat_models
|
||||
from hermes_agent.cli.models.codex import DEFAULT_CODEX_MODELS, _add_forward_compat_models
|
||||
return _add_forward_compat_models(list(DEFAULT_CODEX_MODELS))
|
||||
|
||||
|
||||
|
|
@ -488,7 +488,7 @@ def check_nous_free_tier() -> bool:
|
|||
return cached_result
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import get_provider_auth_state, resolve_nous_runtime_credentials
|
||||
from hermes_agent.cli.auth.auth import get_provider_auth_state, resolve_nous_runtime_credentials
|
||||
|
||||
# Ensure we have a fresh token (triggers refresh if needed)
|
||||
resolve_nous_runtime_credentials(min_key_ttl_seconds=60)
|
||||
|
|
@ -583,7 +583,7 @@ def fetch_nous_recommended_models(
|
|||
def _resolve_nous_portal_url() -> str:
|
||||
"""Best-effort lookup of the Portal base URL the user is authed against."""
|
||||
try:
|
||||
from hermes_cli.auth import (
|
||||
from hermes_agent.cli.auth.auth import (
|
||||
DEFAULT_NOUS_PORTAL_URL,
|
||||
get_provider_auth_state,
|
||||
)
|
||||
|
|
@ -912,7 +912,7 @@ def fetch_ai_gateway_models(
|
|||
if _ai_gateway_catalog_cache is not None and not force_refresh:
|
||||
return list(_ai_gateway_catalog_cache)
|
||||
|
||||
from hermes_constants import AI_GATEWAY_BASE_URL
|
||||
from hermes_agent.constants import AI_GATEWAY_BASE_URL
|
||||
|
||||
fallback = list(VERCEL_AI_GATEWAY_MODELS)
|
||||
preferred_ids = [mid for mid, _ in fallback]
|
||||
|
|
@ -1133,7 +1133,7 @@ def fetch_ai_gateway_pricing(
|
|||
``prompt`` / ``completion``. This translates. Cache read/write field names
|
||||
already match.
|
||||
"""
|
||||
from hermes_constants import AI_GATEWAY_BASE_URL
|
||||
from hermes_agent.constants import AI_GATEWAY_BASE_URL
|
||||
|
||||
cache_key = AI_GATEWAY_BASE_URL.rstrip("/")
|
||||
if not force_refresh and cache_key in _pricing_cache:
|
||||
|
|
@ -1180,7 +1180,7 @@ def _resolve_openrouter_api_key() -> str:
|
|||
def _resolve_nous_pricing_credentials() -> tuple[str, str]:
|
||||
"""Return ``(api_key, base_url)`` for Nous Portal pricing, or empty strings."""
|
||||
try:
|
||||
from hermes_cli.auth import resolve_nous_runtime_credentials
|
||||
from hermes_agent.cli.auth.auth import resolve_nous_runtime_credentials
|
||||
creds = resolve_nous_runtime_credentials()
|
||||
if creds:
|
||||
return (creds.get("api_key", ""), creds.get("base_url", ""))
|
||||
|
|
@ -1248,7 +1248,7 @@ def list_available_providers() -> list[dict[str, str]]:
|
|||
# Check if this provider has credentials available
|
||||
has_creds = False
|
||||
try:
|
||||
from hermes_cli.auth import get_auth_status, has_usable_secret
|
||||
from hermes_agent.cli.auth.auth import get_auth_status, has_usable_secret
|
||||
if pid == "custom":
|
||||
custom_base_url = _get_custom_base_url() or ""
|
||||
has_creds = bool(custom_base_url.strip())
|
||||
|
|
@ -1307,7 +1307,7 @@ def parse_model_input(raw: str, current_provider: str) -> tuple[str, str]:
|
|||
def _get_custom_base_url() -> str:
|
||||
"""Get the custom endpoint base_url from config.yaml."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
model_cfg = config.get("model", {})
|
||||
if isinstance(model_cfg, dict):
|
||||
|
|
@ -1401,7 +1401,7 @@ def detect_provider_for_model(
|
|||
# credential pool, or auth store entries.
|
||||
has_creds = False
|
||||
try:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
pconfig = PROVIDER_REGISTRY.get(direct_match)
|
||||
if pconfig:
|
||||
for env_var in pconfig.api_key_env_vars:
|
||||
|
|
@ -1414,7 +1414,7 @@ def detect_provider_for_model(
|
|||
# Claude Code tokens, and other non-env-var credentials (#10300).
|
||||
if not has_creds:
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
pool = load_pool(direct_match)
|
||||
if pool.has_credentials():
|
||||
has_creds = True
|
||||
|
|
@ -1422,7 +1422,7 @@ def detect_provider_for_model(
|
|||
pass
|
||||
if not has_creds:
|
||||
try:
|
||||
from hermes_cli.auth import _load_auth_store
|
||||
from hermes_agent.cli.auth.auth import _load_auth_store
|
||||
store = _load_auth_store()
|
||||
if direct_match in store.get("providers", {}) or direct_match in store.get("credential_pool", {}):
|
||||
has_creds = True
|
||||
|
|
@ -1572,7 +1572,7 @@ def resolve_fast_mode_overrides(model_id: Optional[str]) -> dict[str, Any] | Non
|
|||
def _resolve_copilot_catalog_api_key() -> str:
|
||||
"""Best-effort GitHub token for fetching the Copilot model catalog."""
|
||||
try:
|
||||
from hermes_cli.auth import resolve_api_key_provider_credentials
|
||||
from hermes_agent.cli.auth.auth import resolve_api_key_provider_credentials
|
||||
|
||||
creds = resolve_api_key_provider_credentials("copilot")
|
||||
return str(creds.get("api_key") or "").strip()
|
||||
|
|
@ -1590,7 +1590,7 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)
|
|||
if normalized == "openrouter":
|
||||
return model_ids(force_refresh=force_refresh)
|
||||
if normalized == "openai-codex":
|
||||
from hermes_cli.codex_models import get_codex_model_ids
|
||||
from hermes_agent.cli.models.codex import get_codex_model_ids
|
||||
|
||||
return get_codex_model_ids()
|
||||
if normalized in {"copilot", "copilot-acp"}:
|
||||
|
|
@ -1605,7 +1605,7 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)
|
|||
if normalized == "nous":
|
||||
# Try live Nous Portal /models endpoint
|
||||
try:
|
||||
from hermes_cli.auth import fetch_nous_models, resolve_nous_runtime_credentials
|
||||
from hermes_agent.cli.auth.auth import fetch_nous_models, resolve_nous_runtime_credentials
|
||||
creds = resolve_nous_runtime_credentials()
|
||||
if creds:
|
||||
live = fetch_nous_models(api_key=creds.get("api_key", ""), inference_base_url=creds.get("base_url", ""))
|
||||
|
|
@ -1647,7 +1647,7 @@ def _fetch_anthropic_models(timeout: float = 5.0) -> Optional[list[str]]:
|
|||
Claude Code auto-discovery). Returns sorted model IDs or None.
|
||||
"""
|
||||
try:
|
||||
from agent.anthropic_adapter import resolve_anthropic_token, _is_oauth_token
|
||||
from hermes_agent.providers.anthropic_adapter import resolve_anthropic_token, _is_oauth_token
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
|
|
@ -1658,7 +1658,7 @@ def _fetch_anthropic_models(timeout: float = 5.0) -> Optional[list[str]]:
|
|||
headers: dict[str, str] = {"anthropic-version": "2023-06-01"}
|
||||
if _is_oauth_token(token):
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
from agent.anthropic_adapter import _COMMON_BETAS, _OAUTH_ONLY_BETAS
|
||||
from hermes_agent.providers.anthropic_adapter import _COMMON_BETAS, _OAUTH_ONLY_BETAS
|
||||
headers["anthropic-beta"] = ",".join(_COMMON_BETAS + _OAUTH_ONLY_BETAS)
|
||||
else:
|
||||
headers["x-api-key"] = token
|
||||
|
|
@ -1701,7 +1701,7 @@ def copilot_default_headers() -> dict[str, str]:
|
|||
Copilot CLI send on every request.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.copilot_auth import copilot_request_headers
|
||||
from hermes_agent.cli.auth.copilot import copilot_request_headers
|
||||
return copilot_request_headers(is_agent_turn=True)
|
||||
except ImportError:
|
||||
return {
|
||||
|
|
@ -2117,7 +2117,7 @@ def _fetch_ai_gateway_models(timeout: float = 5.0) -> Optional[list[str]]:
|
|||
return None
|
||||
base_url = os.getenv("AI_GATEWAY_BASE_URL", "").strip()
|
||||
if not base_url:
|
||||
from hermes_constants import AI_GATEWAY_BASE_URL
|
||||
from hermes_agent.constants import AI_GATEWAY_BASE_URL
|
||||
base_url = AI_GATEWAY_BASE_URL
|
||||
|
||||
url = base_url.rstrip("/") + "/models"
|
||||
|
|
@ -2161,7 +2161,7 @@ _OLLAMA_CLOUD_CACHE_TTL = 3600 # 1 hour
|
|||
|
||||
def _ollama_cloud_cache_path() -> Path:
|
||||
"""Return the path for the Ollama Cloud model cache."""
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
return get_hermes_home() / "ollama_cloud_models_cache.json"
|
||||
|
||||
|
||||
|
|
@ -2195,7 +2195,7 @@ def _load_ollama_cloud_cache(*, ignore_ttl: bool = False) -> Optional[dict]:
|
|||
def _save_ollama_cloud_cache(models: list[str]) -> None:
|
||||
"""Persist the merged Ollama Cloud model list to disk."""
|
||||
try:
|
||||
from utils import atomic_json_write
|
||||
from hermes_agent.utils import atomic_json_write
|
||||
cache_path = _ollama_cloud_cache_path()
|
||||
cache_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
atomic_json_write(cache_path, {"models": models, "cached_at": time.time()}, indent=None)
|
||||
|
|
@ -2240,7 +2240,7 @@ def fetch_ollama_cloud_models(
|
|||
# 3. models.dev registry
|
||||
mdev_models: list[str] = []
|
||||
try:
|
||||
from agent.models_dev import list_agentic_models
|
||||
from hermes_agent.providers.metadata_dev import list_agentic_models
|
||||
mdev_models = list_agentic_models("ollama-cloud")
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -2510,7 +2510,7 @@ def validate_requested_model(
|
|||
# AWS SDK control plane (ListFoundationModels + ListInferenceProfiles).
|
||||
if normalized == "bedrock":
|
||||
try:
|
||||
from agent.bedrock_adapter import discover_bedrock_models, resolve_bedrock_region
|
||||
from hermes_agent.providers.bedrock_adapter import discover_bedrock_models, resolve_bedrock_region
|
||||
region = resolve_bedrock_region()
|
||||
discovered = discover_bedrock_models(region)
|
||||
discovered_ids = {m["id"] for m in discovered}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ def _normalize_provider_alias(provider_name: str) -> str:
|
|||
if not raw:
|
||||
return raw
|
||||
try:
|
||||
from hermes_cli.models import normalize_provider
|
||||
from hermes_agent.cli.models.models import normalize_provider
|
||||
|
||||
return normalize_provider(raw)
|
||||
except Exception:
|
||||
|
|
@ -382,7 +382,7 @@ def normalize_model_for_provider(model_input: str, target_provider: str) -> str:
|
|||
# HTTP 400 "model_not_supported". See issue #6879.
|
||||
if provider in {"copilot", "copilot-acp"}:
|
||||
try:
|
||||
from hermes_cli.models import normalize_copilot_model_id
|
||||
from hermes_agent.cli.models.models import normalize_copilot_model_id
|
||||
|
||||
normalized = normalize_copilot_model_id(name)
|
||||
if normalized:
|
||||
|
|
|
|||
|
|
@ -25,17 +25,17 @@ import re
|
|||
from dataclasses import dataclass
|
||||
from typing import List, NamedTuple, Optional
|
||||
|
||||
from hermes_cli.providers import (
|
||||
from hermes_agent.cli.providers import (
|
||||
custom_provider_slug,
|
||||
determine_api_mode,
|
||||
get_label,
|
||||
is_aggregator,
|
||||
resolve_provider_full,
|
||||
)
|
||||
from hermes_cli.model_normalize import (
|
||||
from hermes_agent.cli.models.normalize import (
|
||||
normalize_model_for_provider,
|
||||
)
|
||||
from agent.models_dev import (
|
||||
from hermes_agent.providers.metadata_dev import (
|
||||
ModelCapabilities,
|
||||
ModelInfo,
|
||||
get_model_capabilities,
|
||||
|
|
@ -193,7 +193,7 @@ def _load_direct_aliases() -> dict[str, DirectAlias]:
|
|||
"""
|
||||
merged = dict(_BUILTIN_DIRECT_ALIASES)
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
cfg = load_config()
|
||||
user_aliases = cfg.get("model_aliases")
|
||||
if isinstance(user_aliases, dict):
|
||||
|
|
@ -456,13 +456,13 @@ def switch_model(
|
|||
Returns:
|
||||
ModelSwitchResult with all information the caller needs.
|
||||
"""
|
||||
from hermes_cli.models import (
|
||||
from hermes_agent.cli.models.models import (
|
||||
copilot_model_api_mode,
|
||||
detect_provider_for_model,
|
||||
validate_requested_model,
|
||||
opencode_model_api_mode,
|
||||
)
|
||||
from hermes_cli.runtime_provider import resolve_runtime_provider
|
||||
from hermes_agent.cli.runtime_provider import resolve_runtime_provider
|
||||
|
||||
resolved_alias = ""
|
||||
new_model = raw_input.strip()
|
||||
|
|
@ -486,7 +486,7 @@ def switch_model(
|
|||
)
|
||||
# Check for common config issues that cause provider resolution failures
|
||||
try:
|
||||
from hermes_cli.config import validate_config_structure
|
||||
from hermes_agent.cli.config import validate_config_structure
|
||||
_cfg_issues = validate_config_structure()
|
||||
if _cfg_issues:
|
||||
_switch_err += "\n\nRun 'hermes doctor' — config issues detected:"
|
||||
|
|
@ -505,7 +505,7 @@ def switch_model(
|
|||
# If no model specified, try auto-detect from endpoint
|
||||
if not new_model:
|
||||
if pdef.base_url:
|
||||
from hermes_cli.runtime_provider import _auto_detect_local_model
|
||||
from hermes_agent.cli.runtime_provider import _auto_detect_local_model
|
||||
detected = _auto_detect_local_model(pdef.base_url)
|
||||
if detected:
|
||||
new_model = detected
|
||||
|
|
@ -804,13 +804,13 @@ def list_authenticated_providers(
|
|||
Only includes providers that have API keys set or are user-defined endpoints.
|
||||
"""
|
||||
import os
|
||||
from agent.models_dev import (
|
||||
from hermes_agent.providers.metadata_dev import (
|
||||
PROVIDER_TO_MODELS_DEV,
|
||||
fetch_models_dev,
|
||||
get_provider_info as _mdev_pinfo,
|
||||
)
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_cli.models import OPENROUTER_MODELS, _PROVIDER_MODELS
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.models.models import OPENROUTER_MODELS, _PROVIDER_MODELS
|
||||
|
||||
results: List[dict] = []
|
||||
seen_slugs: set = set() # lowercase-normalized to catch case variants (#9545)
|
||||
|
|
@ -826,7 +826,7 @@ def list_authenticated_providers(
|
|||
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
|
||||
from hermes_agent.cli.models.models import fetch_ollama_cloud_models
|
||||
curated["ollama-cloud"] = fetch_ollama_cloud_models()
|
||||
|
||||
# --- 1. Check Hermes-mapped providers ---
|
||||
|
|
@ -878,8 +878,8 @@ def list_authenticated_providers(
|
|||
seen_mdev_ids.add(mdev_id)
|
||||
|
||||
# --- 2. Check Hermes-only providers (nous, openai-codex, copilot, opencode-go) ---
|
||||
from hermes_cli.providers import HERMES_OVERLAYS
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY as _auth_registry
|
||||
from hermes_agent.cli.providers import HERMES_OVERLAYS
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY as _auth_registry
|
||||
|
||||
# Build reverse mapping: models.dev ID → Hermes provider ID.
|
||||
# HERMES_OVERLAYS keys may be models.dev IDs (e.g. "github-copilot")
|
||||
|
|
@ -913,7 +913,7 @@ def list_authenticated_providers(
|
|||
# OAuth via external credential files).
|
||||
if not has_creds:
|
||||
try:
|
||||
from hermes_cli.auth import _load_auth_store
|
||||
from hermes_agent.cli.auth.auth import _load_auth_store
|
||||
store = _load_auth_store()
|
||||
providers_store = store.get("providers", {})
|
||||
pool_store = store.get("credential_pool", {})
|
||||
|
|
@ -930,7 +930,7 @@ def list_authenticated_providers(
|
|||
# imports on demand but aren't in the raw auth.json yet.
|
||||
if not has_creds:
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
pool = load_pool(hermes_slug)
|
||||
if pool.has_credentials():
|
||||
has_creds = True
|
||||
|
|
@ -945,7 +945,7 @@ def list_authenticated_providers(
|
|||
# configured.
|
||||
if not has_creds and hermes_slug == "anthropic":
|
||||
try:
|
||||
from agent.anthropic_adapter import (
|
||||
from hermes_agent.providers.anthropic_adapter import (
|
||||
read_claude_code_credentials,
|
||||
read_hermes_oauth_credentials,
|
||||
)
|
||||
|
|
@ -981,7 +981,7 @@ def list_authenticated_providers(
|
|||
# in PROVIDER_TO_MODELS_DEV or HERMES_OVERLAYS (keeps /model in sync
|
||||
# with `hermes model`).
|
||||
try:
|
||||
from hermes_cli.models import CANONICAL_PROVIDERS as _canon_provs
|
||||
from hermes_agent.cli.models.models import CANONICAL_PROVIDERS as _canon_provs
|
||||
except ImportError:
|
||||
_canon_provs = []
|
||||
|
||||
|
|
@ -997,7 +997,7 @@ def list_authenticated_providers(
|
|||
# Also check auth store and credential pool
|
||||
if not _cp_has_creds:
|
||||
try:
|
||||
from hermes_cli.auth import _load_auth_store
|
||||
from hermes_agent.cli.auth.auth import _load_auth_store
|
||||
_cp_store = _load_auth_store()
|
||||
_cp_providers_store = _cp_store.get("providers", {})
|
||||
_cp_pool_store = _cp_store.get("credential_pool", {})
|
||||
|
|
@ -1010,7 +1010,7 @@ def list_authenticated_providers(
|
|||
pass
|
||||
if not _cp_has_creds:
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
_cp_pool = load_pool(_cp.slug)
|
||||
if _cp_pool.has_credentials():
|
||||
_cp_has_creds = True
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ from dataclasses import dataclass
|
|||
from pathlib import Path
|
||||
from typing import Dict, Iterable, Optional, Set
|
||||
|
||||
from hermes_cli.auth import get_nous_auth_status
|
||||
from hermes_cli.config import get_env_value, load_config
|
||||
from tools.managed_tool_gateway import is_managed_tool_gateway_ready
|
||||
from tools.tool_backend_helpers import (
|
||||
from hermes_agent.cli.auth.auth import get_nous_auth_status
|
||||
from hermes_agent.cli.config import get_env_value, load_config
|
||||
from hermes_agent.tools.managed_gateway import is_managed_tool_gateway_ready
|
||||
from hermes_agent.tools.backend_helpers import (
|
||||
fal_key_is_configured,
|
||||
has_direct_modal_credentials,
|
||||
managed_nous_tools_enabled,
|
||||
|
|
@ -82,7 +82,7 @@ def _model_config_dict(config: Dict[str, object]) -> Dict[str, object]:
|
|||
|
||||
|
||||
def _toolset_enabled(config: Dict[str, object], toolset_key: str) -> bool:
|
||||
from toolsets import resolve_toolset
|
||||
from hermes_agent.tools.toolsets import resolve_toolset
|
||||
|
||||
platform_toolsets = config.get("platform_toolsets")
|
||||
if not isinstance(platform_toolsets, dict) or not platform_toolsets:
|
||||
|
|
@ -688,7 +688,7 @@ def prompt_enable_tool_gateway(config: Dict[str, object]) -> set[str]:
|
|||
return set()
|
||||
|
||||
try:
|
||||
from hermes_cli.setup import prompt_choice
|
||||
from hermes_agent.cli.setup_wizard import prompt_choice
|
||||
except Exception:
|
||||
return set()
|
||||
|
||||
|
|
@ -766,7 +766,7 @@ def prompt_enable_tool_gateway(config: Dict[str, object]) -> set[str]:
|
|||
|
||||
changed = apply_gateway_defaults(config, to_apply)
|
||||
if changed:
|
||||
from hermes_cli.config import save_config
|
||||
from hermes_agent.cli.config import save_config
|
||||
save_config(config)
|
||||
# Only report the tools that actually switched (not already-managed ones)
|
||||
newly_switched = changed - set(already_managed)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Usage:
|
|||
|
||||
def pairing_command(args):
|
||||
"""Handle hermes pairing subcommands."""
|
||||
from gateway.pairing import PairingStore
|
||||
from hermes_agent.gateway.pairing import PairingStore
|
||||
|
||||
store = PairingStore()
|
||||
action = getattr(args, "pairing_action", None)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ from dataclasses import dataclass, field
|
|||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional, Set, Union
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from utils import env_var_enabled
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from hermes_agent.utils import env_var_enabled
|
||||
|
||||
try:
|
||||
import yaml
|
||||
|
|
@ -73,7 +73,7 @@ VALID_HOOKS: Set[str] = {
|
|||
"subagent_stop",
|
||||
}
|
||||
|
||||
ENTRY_POINTS_GROUP = "hermes_agent.plugins"
|
||||
ENTRY_POINTS_GROUP = "plugins"
|
||||
|
||||
_NS_PARENT = "hermes_plugins"
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ def _get_disabled_plugins() -> set:
|
|||
``plugins.enabled``.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
disabled = config.get("plugins", {}).get("disabled", [])
|
||||
return set(disabled) if isinstance(disabled, list) else set()
|
||||
|
|
@ -114,7 +114,7 @@ def _get_enabled_plugins() -> Optional[set]:
|
|||
* ``set(...)`` — the concrete allow-list.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
plugins_cfg = config.get("plugins")
|
||||
if not isinstance(plugins_cfg, dict):
|
||||
|
|
@ -207,7 +207,7 @@ class PluginContext:
|
|||
emoji: str = "",
|
||||
) -> None:
|
||||
"""Register a tool in the global registry **and** track it as plugin-provided."""
|
||||
from tools.registry import registry
|
||||
from hermes_agent.tools.registry import registry
|
||||
|
||||
registry.register(
|
||||
name=name,
|
||||
|
|
@ -305,7 +305,7 @@ class PluginContext:
|
|||
|
||||
# Reject if it conflicts with a built-in command
|
||||
try:
|
||||
from hermes_cli.commands import resolve_command
|
||||
from hermes_agent.cli.commands import resolve_command
|
||||
if resolve_command(clean) is not None:
|
||||
logger.warning(
|
||||
"Plugin '%s' tried to register command '/%s' which conflicts "
|
||||
|
|
@ -341,7 +341,7 @@ class PluginContext:
|
|||
Returns:
|
||||
JSON string from the tool handler (same format as model tool calls).
|
||||
"""
|
||||
from tools.registry import registry
|
||||
from hermes_agent.tools.registry import registry
|
||||
|
||||
# Wire up parent agent context when available (CLI mode).
|
||||
# In gateway mode _cli_ref is None — tools degrade gracefully
|
||||
|
|
@ -372,7 +372,7 @@ class PluginContext:
|
|||
)
|
||||
return
|
||||
# Defer the import to avoid circular deps at module level
|
||||
from agent.context_engine import ContextEngine
|
||||
from hermes_agent.agent.context.engine import ContextEngine
|
||||
if not isinstance(engine, ContextEngine):
|
||||
logger.warning(
|
||||
"Plugin '%s' tried to register a context engine that does not "
|
||||
|
|
@ -397,8 +397,8 @@ class PluginContext:
|
|||
``config.yaml`` matches against when routing ``image_generate``
|
||||
tool calls.
|
||||
"""
|
||||
from agent.image_gen_provider import ImageGenProvider
|
||||
from agent.image_gen_registry import register_provider
|
||||
from hermes_agent.agent.image_gen.provider import ImageGenProvider
|
||||
from hermes_agent.agent.image_gen.registry import register_provider
|
||||
|
||||
if not isinstance(provider, ImageGenProvider):
|
||||
logger.warning(
|
||||
|
|
@ -452,7 +452,7 @@ class PluginContext:
|
|||
ValueError: if *name* contains ``':'`` or invalid characters.
|
||||
FileNotFoundError: if *path* does not exist.
|
||||
"""
|
||||
from agent.skill_utils import _NAMESPACE_RE
|
||||
from hermes_agent.agent.skill_utils import _NAMESPACE_RE
|
||||
|
||||
if ":" in name:
|
||||
raise ValueError(
|
||||
|
|
@ -1087,7 +1087,7 @@ def get_plugin_toolsets() -> List[tuple]:
|
|||
return []
|
||||
|
||||
try:
|
||||
from tools.registry import registry
|
||||
from hermes_agent.tools.registry import registry
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import sys
|
|||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -173,8 +173,8 @@ def _prompt_plugin_env_vars(manifest: dict, console) -> None:
|
|||
if not requires_env:
|
||||
return
|
||||
|
||||
from hermes_cli.config import get_env_value, save_env_value # noqa: F811
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.cli.config import get_env_value, save_env_value # noqa: F811
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
# Normalise to list-of-dicts
|
||||
env_specs: list[dict] = []
|
||||
|
|
@ -360,7 +360,7 @@ def cmd_install(
|
|||
)
|
||||
sys.exit(1)
|
||||
if mv_int > _SUPPORTED_MANIFEST_VERSION:
|
||||
from hermes_cli.config import recommended_update_command
|
||||
from hermes_agent.cli.config import recommended_update_command
|
||||
console.print(
|
||||
f"[red]Error:[/red] Plugin '{plugin_name}' requires manifest_version "
|
||||
f"{mv}, but this installer only supports up to {_SUPPORTED_MANIFEST_VERSION}.\n"
|
||||
|
|
@ -517,7 +517,7 @@ def _get_disabled_set() -> set:
|
|||
listed in ``plugins.enabled``.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
disabled = config.get("plugins", {}).get("disabled", [])
|
||||
return set(disabled) if isinstance(disabled, list) else set()
|
||||
|
|
@ -527,7 +527,7 @@ def _get_disabled_set() -> set:
|
|||
|
||||
def _save_disabled_set(disabled: set) -> None:
|
||||
"""Write the disabled plugins list to config.yaml."""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
config = load_config()
|
||||
if "plugins" not in config:
|
||||
config["plugins"] = {}
|
||||
|
|
@ -542,7 +542,7 @@ def _get_enabled_set() -> set:
|
|||
the key is missing (same behaviour as "nothing enabled yet").
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
plugins_cfg = config.get("plugins", {})
|
||||
if not isinstance(plugins_cfg, dict):
|
||||
|
|
@ -555,7 +555,7 @@ def _get_enabled_set() -> set:
|
|||
|
||||
def _save_enabled_set(enabled: set) -> None:
|
||||
"""Write the enabled plugins list to config.yaml."""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
config = load_config()
|
||||
if "plugins" not in config:
|
||||
config["plugins"] = {}
|
||||
|
|
@ -631,7 +631,7 @@ def _plugin_exists(name: str) -> bool:
|
|||
return True
|
||||
# Bundled: <repo>/plugins/<name>/
|
||||
from pathlib import Path as _P
|
||||
import hermes_cli
|
||||
import hermes_agent.cli
|
||||
repo_plugins = _P(hermes_cli.__file__).resolve().parent.parent / "plugins"
|
||||
if repo_plugins.is_dir():
|
||||
candidate = repo_plugins / name
|
||||
|
|
@ -659,7 +659,7 @@ def _discover_all_plugins() -> list:
|
|||
seen: dict = {} # name -> (name, version, description, source, path)
|
||||
|
||||
# Bundled (<repo>/plugins/<name>/), excluding memory/ and context_engine/
|
||||
import hermes_cli
|
||||
import hermes_agent.cli
|
||||
repo_plugins = Path(hermes_cli.__file__).resolve().parent.parent / "plugins"
|
||||
for base, source in ((repo_plugins, "bundled"), (_plugins_dir(), "user")):
|
||||
if not base.is_dir():
|
||||
|
|
@ -743,7 +743,7 @@ def cmd_list() -> None:
|
|||
def _discover_memory_providers() -> list[tuple[str, str]]:
|
||||
"""Return [(name, description), ...] for available memory providers."""
|
||||
try:
|
||||
from plugins.memory import discover_memory_providers
|
||||
from hermes_agent.plugins.memory import discover_memory_providers
|
||||
return [(name, desc) for name, desc, _avail in discover_memory_providers()]
|
||||
except Exception:
|
||||
return []
|
||||
|
|
@ -752,7 +752,7 @@ def _discover_memory_providers() -> list[tuple[str, str]]:
|
|||
def _discover_context_engines() -> list[tuple[str, str]]:
|
||||
"""Return [(name, description), ...] for available context engines."""
|
||||
try:
|
||||
from plugins.context_engine import discover_context_engines
|
||||
from hermes_agent.plugins.context_engine import discover_context_engines
|
||||
return [(name, desc) for name, desc, _avail in discover_context_engines()]
|
||||
except Exception:
|
||||
return []
|
||||
|
|
@ -761,7 +761,7 @@ def _discover_context_engines() -> list[tuple[str, str]]:
|
|||
def _get_current_memory_provider() -> str:
|
||||
"""Return the current memory.provider from config (empty = built-in)."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
return config.get("memory", {}).get("provider", "") or ""
|
||||
except Exception:
|
||||
|
|
@ -771,7 +771,7 @@ def _get_current_memory_provider() -> str:
|
|||
def _get_current_context_engine() -> str:
|
||||
"""Return the current context.engine from config."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
config = load_config()
|
||||
return config.get("context", {}).get("engine", "compressor") or "compressor"
|
||||
except Exception:
|
||||
|
|
@ -780,7 +780,7 @@ def _get_current_context_engine() -> str:
|
|||
|
||||
def _save_memory_provider(name: str) -> None:
|
||||
"""Persist memory.provider to config.yaml."""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
config = load_config()
|
||||
if "memory" not in config:
|
||||
config["memory"] = {}
|
||||
|
|
@ -790,7 +790,7 @@ def _save_memory_provider(name: str) -> None:
|
|||
|
||||
def _save_context_engine(name: str) -> None:
|
||||
"""Persist context.engine to config.yaml."""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
config = load_config()
|
||||
if "context" not in config:
|
||||
config["context"] = {}
|
||||
|
|
@ -800,7 +800,7 @@ def _save_context_engine(name: str) -> None:
|
|||
|
||||
def _configure_memory_provider() -> bool:
|
||||
"""Launch a radio picker for memory providers. Returns True if changed."""
|
||||
from hermes_cli.curses_ui import curses_radiolist
|
||||
from hermes_agent.cli.ui.curses import curses_radiolist
|
||||
|
||||
current = _get_current_memory_provider()
|
||||
providers = _discover_memory_providers()
|
||||
|
|
@ -838,7 +838,7 @@ def _configure_memory_provider() -> bool:
|
|||
|
||||
def _configure_context_engine() -> bool:
|
||||
"""Launch a radio picker for context engines. Returns True if changed."""
|
||||
from hermes_cli.curses_ui import curses_radiolist
|
||||
from hermes_agent.cli.ui.curses import curses_radiolist
|
||||
|
||||
current = _get_current_context_engine()
|
||||
engines = _discover_context_engines()
|
||||
|
|
@ -938,7 +938,7 @@ def cmd_toggle() -> None:
|
|||
def _run_composite_ui(curses, plugin_names, plugin_labels, plugin_selected,
|
||||
disabled, categories, console):
|
||||
"""Custom curses screen with checkboxes + category action rows."""
|
||||
from hermes_cli.curses_ui import flush_stdin
|
||||
from hermes_agent.cli.ui.curses import flush_stdin
|
||||
|
||||
chosen = set(plugin_selected)
|
||||
n_plugins = len(plugin_names)
|
||||
|
|
@ -1188,7 +1188,7 @@ def _run_composite_ui(curses, plugin_names, plugin_labels, plugin_selected,
|
|||
def _run_composite_fallback(plugin_names, plugin_labels, plugin_selected,
|
||||
disabled, categories, console):
|
||||
"""Text-based fallback for the composite plugins UI."""
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
print(color("\n Plugins", Colors.YELLOW))
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ _DEFAULT_EXPORT_EXCLUDE_ROOT = frozenset({
|
|||
"node_modules", # npm packages
|
||||
# Databases & runtime state
|
||||
"state.db", "state.db-shm", "state.db-wal",
|
||||
"hermes_state.db",
|
||||
"state.db",
|
||||
"response_store.db", "response_store.db-shm", "response_store.db-wal",
|
||||
"gateway.pid", "gateway_state.json", "processes.json",
|
||||
"auth.json", # API keys, OAuth tokens, credential pools
|
||||
|
|
@ -138,7 +138,7 @@ def _get_default_hermes_home() -> Path:
|
|||
In Docker/custom deployments where HERMES_HOME is outside ``~/.hermes``
|
||||
(e.g. ``/opt/data``), returns HERMES_HOME directly.
|
||||
"""
|
||||
from hermes_constants import get_default_hermes_root
|
||||
from hermes_agent.constants import get_default_hermes_root
|
||||
return get_default_hermes_root()
|
||||
|
||||
|
||||
|
|
@ -301,7 +301,7 @@ def _read_config_model(profile_dir: Path) -> tuple:
|
|||
def _check_gateway_running(profile_dir: Path) -> bool:
|
||||
"""Check if a gateway is running for a given profile directory."""
|
||||
try:
|
||||
from gateway.status import get_running_pid
|
||||
from hermes_agent.gateway.status import get_running_pid
|
||||
return get_running_pid(profile_dir / "gateway.pid", cleanup_stale=False) is not None
|
||||
except Exception:
|
||||
return False
|
||||
|
|
@ -413,7 +413,7 @@ def create_profile(
|
|||
if clone_from is not None or clone_all or clone_config:
|
||||
if clone_from is None:
|
||||
# Default: clone from active profile
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
source_dir = get_hermes_home()
|
||||
else:
|
||||
validate_profile_name(clone_from)
|
||||
|
|
@ -455,7 +455,7 @@ def create_profile(
|
|||
soul_path = profile_dir / "SOUL.md"
|
||||
if not soul_path.exists():
|
||||
try:
|
||||
from hermes_cli.default_soul import DEFAULT_SOUL_MD
|
||||
from hermes_agent.cli.default_soul import DEFAULT_SOUL_MD
|
||||
soul_path.write_text(DEFAULT_SOUL_MD, encoding="utf-8")
|
||||
except Exception:
|
||||
pass # best-effort — don't fail profile creation over this
|
||||
|
|
@ -597,7 +597,7 @@ def _cleanup_gateway_service(name: str, profile_dir: Path) -> None:
|
|||
old_home = os.environ.get("HERMES_HOME")
|
||||
try:
|
||||
os.environ["HERMES_HOME"] = str(profile_dir)
|
||||
from hermes_cli.gateway import get_service_name, get_launchd_plist_path
|
||||
from hermes_agent.cli.gateway import get_service_name, get_launchd_plist_path
|
||||
|
||||
if _platform.system() == "Linux":
|
||||
svc_name = get_service_name()
|
||||
|
|
@ -720,7 +720,7 @@ def get_active_profile_name() -> str:
|
|||
Returns the profile name if HERMES_HOME points into ``~/.hermes/profiles/<name>``.
|
||||
Returns ``"custom"`` if HERMES_HOME is set to an unrecognized path.
|
||||
"""
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
hermes_home = get_hermes_home()
|
||||
resolved = hermes_home.resolve()
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import logging
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from utils import base_url_host_matches, base_url_hostname
|
||||
from hermes_agent.utils import base_url_host_matches, base_url_hostname
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ def get_provider(name: str) -> Optional[ProviderDef]:
|
|||
|
||||
# Try to get models.dev data
|
||||
try:
|
||||
from agent.models_dev import get_provider_info as _mdev_provider
|
||||
from hermes_agent.providers.metadata_dev import get_provider_info as _mdev_provider
|
||||
mdev_info = _mdev_provider(canonical)
|
||||
except Exception:
|
||||
mdev_info = None
|
||||
|
|
@ -596,7 +596,7 @@ def resolve_provider_full(
|
|||
|
||||
# 3. Try models.dev directly (for providers not in our ALIASES)
|
||||
try:
|
||||
from agent.models_dev import get_provider_info as _mdev_provider
|
||||
from hermes_agent.providers.metadata_dev import get_provider_info as _mdev_provider
|
||||
mdev_info = _mdev_provider(canonical)
|
||||
if mdev_info is not None:
|
||||
return ProviderDef(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -9,9 +9,9 @@ from typing import Any, Dict, Optional
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from hermes_cli import auth as auth_mod
|
||||
from agent.credential_pool import CredentialPool, PooledCredential, get_custom_provider_pool_key, load_pool
|
||||
from hermes_cli.auth import (
|
||||
from hermes_agent.cli import auth as auth_mod
|
||||
from hermes_agent.providers.credential_pool import CredentialPool, PooledCredential, get_custom_provider_pool_key, load_pool
|
||||
from hermes_agent.cli.auth.auth import (
|
||||
AuthError,
|
||||
DEFAULT_CODEX_BASE_URL,
|
||||
DEFAULT_QWEN_BASE_URL,
|
||||
|
|
@ -27,9 +27,9 @@ from hermes_cli.auth import (
|
|||
resolve_external_process_provider_credentials,
|
||||
has_usable_secret,
|
||||
)
|
||||
from hermes_cli.config import get_compatible_custom_providers, load_config
|
||||
from hermes_constants import OPENROUTER_BASE_URL
|
||||
from utils import base_url_host_matches, base_url_hostname
|
||||
from hermes_agent.cli.config import get_compatible_custom_providers, load_config
|
||||
from hermes_agent.constants import OPENROUTER_BASE_URL
|
||||
from hermes_agent.utils import base_url_host_matches, base_url_hostname
|
||||
|
||||
|
||||
def _normalize_custom_provider_name(value: str) -> str:
|
||||
|
|
@ -134,7 +134,7 @@ def _copilot_runtime_api_mode(model_cfg: Dict[str, Any], api_key: str) -> str:
|
|||
return "chat_completions"
|
||||
|
||||
try:
|
||||
from hermes_cli.models import copilot_model_api_mode
|
||||
from hermes_agent.cli.models.models import copilot_model_api_mode
|
||||
|
||||
return copilot_model_api_mode(model_name, api_key=api_key)
|
||||
except Exception:
|
||||
|
|
@ -206,7 +206,7 @@ def _resolve_runtime_from_pool_entry(
|
|||
if configured_mode and _provider_supports_explicit_api_mode(provider, configured_provider):
|
||||
api_mode = configured_mode
|
||||
elif provider in ("opencode-zen", "opencode-go"):
|
||||
from hermes_cli.models import opencode_model_api_mode
|
||||
from hermes_agent.cli.models.models import opencode_model_api_mode
|
||||
api_mode = opencode_model_api_mode(provider, model_cfg.get("default", ""))
|
||||
else:
|
||||
# Auto-detect Anthropic-compatible endpoints (/anthropic suffix,
|
||||
|
|
@ -567,7 +567,7 @@ def _resolve_explicit_runtime(
|
|||
base_url = explicit_base_url or cfg_base_url or "https://api.anthropic.com"
|
||||
api_key = explicit_api_key
|
||||
if not api_key:
|
||||
from agent.anthropic_adapter import resolve_anthropic_token
|
||||
from hermes_agent.providers.anthropic_adapter import resolve_anthropic_token
|
||||
|
||||
api_key = resolve_anthropic_token()
|
||||
if not api_key:
|
||||
|
|
@ -870,7 +870,7 @@ def resolve_runtime_provider(
|
|||
|
||||
# Anthropic (native Messages API)
|
||||
if provider == "anthropic":
|
||||
from agent.anthropic_adapter import resolve_anthropic_token
|
||||
from hermes_agent.providers.anthropic_adapter import resolve_anthropic_token
|
||||
token = resolve_anthropic_token()
|
||||
if not token:
|
||||
raise AuthError(
|
||||
|
|
@ -896,7 +896,7 @@ def resolve_runtime_provider(
|
|||
|
||||
# AWS Bedrock (native Converse API via boto3)
|
||||
if provider == "bedrock":
|
||||
from agent.bedrock_adapter import (
|
||||
from hermes_agent.providers.bedrock_adapter import (
|
||||
has_aws_credentials,
|
||||
resolve_aws_auth_env_var,
|
||||
resolve_bedrock_region,
|
||||
|
|
@ -989,7 +989,7 @@ def resolve_runtime_provider(
|
|||
if configured_mode and _provider_supports_explicit_api_mode(provider, configured_provider):
|
||||
api_mode = configured_mode
|
||||
elif provider in ("opencode-zen", "opencode-go"):
|
||||
from hermes_cli.models import opencode_model_api_mode
|
||||
from hermes_agent.cli.models.models import opencode_model_api_mode
|
||||
api_mode = opencode_model_api_mode(provider, model_cfg.get("default", ""))
|
||||
else:
|
||||
# Auto-detect Anthropic-compatible endpoints by URL convention
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ import copy
|
|||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from hermes_cli.nous_subscription import get_nous_subscription_features
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled
|
||||
from utils import base_url_hostname
|
||||
from hermes_constants import get_optional_skills_dir
|
||||
from hermes_agent.cli.nous_subscription import get_nous_subscription_features
|
||||
from hermes_agent.tools.backend_helpers import managed_nous_tools_enabled
|
||||
from hermes_agent.utils import base_url_hostname
|
||||
from hermes_agent.constants import get_optional_skills_dir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ def _supports_same_provider_pool_setup(provider: str) -> bool:
|
|||
return False
|
||||
if provider == "openrouter":
|
||||
return True
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
|
||||
pconfig = PROVIDER_REGISTRY.get(provider)
|
||||
if not pconfig:
|
||||
|
|
@ -129,7 +129,7 @@ def _set_reasoning_effort(config: Dict[str, Any], effort: str) -> None:
|
|||
|
||||
|
||||
# Import config helpers
|
||||
from hermes_cli.config import (
|
||||
from hermes_agent.cli.config import (
|
||||
DEFAULT_CONFIG,
|
||||
get_hermes_home,
|
||||
get_config_path,
|
||||
|
|
@ -142,7 +142,7 @@ from hermes_cli.config import (
|
|||
)
|
||||
# display_hermes_home imported lazily at call sites (stale-module safety during hermes update)
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
|
||||
def print_header(title: str):
|
||||
|
|
@ -151,7 +151,7 @@ def print_header(title: str):
|
|||
print(color(f"◆ {title}", Colors.CYAN, Colors.BOLD))
|
||||
|
||||
|
||||
from hermes_cli.cli_output import ( # noqa: E402
|
||||
from hermes_agent.cli.ui.output import ( # noqa: E402
|
||||
print_error,
|
||||
print_info,
|
||||
print_success,
|
||||
|
|
@ -212,7 +212,7 @@ def prompt(question: str, default: str = None, password: bool = False) -> str:
|
|||
|
||||
def _curses_prompt_choice(question: str, choices: list, default: int = 0, description: str | None = None) -> int:
|
||||
"""Single-select menu using curses. Delegates to curses_radiolist."""
|
||||
from hermes_cli.curses_ui import curses_radiolist
|
||||
from hermes_agent.cli.ui.curses import curses_radiolist
|
||||
return curses_radiolist(question, choices, selected=default, cancel_returns=-1, description=description)
|
||||
|
||||
|
||||
|
|
@ -302,7 +302,7 @@ def prompt_checklist(title: str, items: list, pre_selected: list = None) -> list
|
|||
if pre_selected is None:
|
||||
pre_selected = []
|
||||
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
|
||||
chosen = curses_checklist(
|
||||
title,
|
||||
|
|
@ -352,7 +352,7 @@ def _print_setup_summary(config: dict, hermes_home):
|
|||
|
||||
# Vision — use the same runtime resolver as the actual vision tools
|
||||
try:
|
||||
from agent.auxiliary_client import get_available_vision_backends
|
||||
from hermes_agent.providers.auxiliary import get_available_vision_backends
|
||||
|
||||
_vision_backends = get_available_vision_backends()
|
||||
except Exception:
|
||||
|
|
@ -419,8 +419,8 @@ def _print_setup_summary(config: dict, hermes_home):
|
|||
# setups don't show as "missing FAL_KEY".
|
||||
_img_backend = None
|
||||
try:
|
||||
from agent.image_gen_registry import list_providers
|
||||
from hermes_cli.plugins import _ensure_plugins_discovered
|
||||
from hermes_agent.agent.image_gen.registry import list_providers
|
||||
from hermes_agent.cli.plugins import _ensure_plugins_discovered
|
||||
|
||||
_ensure_plugins_discovered()
|
||||
for _p in list_providers():
|
||||
|
|
@ -536,7 +536,7 @@ def _print_setup_summary(config: dict, hermes_home):
|
|||
print_warning(
|
||||
"Some tools are disabled. Run 'hermes setup tools' to configure them,"
|
||||
)
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print_warning(f"or edit {_dhh()}/.env directly to add the missing API keys.")
|
||||
print()
|
||||
|
||||
|
|
@ -560,7 +560,7 @@ def _print_setup_summary(config: dict, hermes_home):
|
|||
print()
|
||||
|
||||
# Show file locations prominently
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print(color(f"📁 All your files are in {_dhh()}/:", Colors.CYAN, Colors.BOLD))
|
||||
print()
|
||||
print(f" {color('Settings:', Colors.YELLOW)} {get_config_path()}")
|
||||
|
|
@ -665,7 +665,7 @@ def setup_model_provider(config: dict, *, quick: bool = False):
|
|||
When *quick* is True, skips credential rotation, vision, and TTS
|
||||
configuration — used by the streamlined first-time quick setup.
|
||||
"""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
|
||||
print_header("Inference Provider")
|
||||
print_info("Choose how to connect to your main chat model.")
|
||||
|
|
@ -674,7 +674,7 @@ def setup_model_provider(config: dict, *, quick: bool = False):
|
|||
|
||||
# Delegate to the shared hermes model flow — handles provider picker,
|
||||
# credential prompting, model selection, and config persistence.
|
||||
from hermes_cli.main import select_provider_and_model
|
||||
from hermes_agent.cli.main import select_provider_and_model
|
||||
try:
|
||||
select_provider_and_model()
|
||||
except (SystemExit, KeyboardInterrupt):
|
||||
|
|
@ -708,8 +708,8 @@ def setup_model_provider(config: dict, *, quick: bool = False):
|
|||
if not quick and _supports_same_provider_pool_setup(selected_provider):
|
||||
try:
|
||||
from types import SimpleNamespace
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_cli.auth_commands import auth_add_command
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
from hermes_agent.cli.auth.commands import auth_add_command
|
||||
|
||||
pool = load_pool(selected_provider)
|
||||
entries = pool.entries()
|
||||
|
|
@ -786,7 +786,7 @@ def setup_model_provider(config: dict, *, quick: bool = False):
|
|||
_vision_needs_setup = False
|
||||
else:
|
||||
try:
|
||||
from agent.auxiliary_client import get_available_vision_backends
|
||||
from hermes_agent.providers.auxiliary import get_available_vision_backends
|
||||
_vision_backends = set(get_available_vision_backends())
|
||||
except Exception:
|
||||
_vision_backends = set()
|
||||
|
|
@ -1075,7 +1075,7 @@ def _setup_tts_provider(config: dict):
|
|||
save_env_value("XAI_API_KEY", api_key)
|
||||
print_success("xAI TTS API key saved")
|
||||
else:
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print_warning(
|
||||
"No xAI API key provided for TTS. Configure XAI_API_KEY via "
|
||||
f"hermes setup model or {_dhh()}/.env to use xAI TTS. "
|
||||
|
|
@ -1284,8 +1284,8 @@ def setup_terminal_backend(config: dict):
|
|||
elif selected_backend == "modal":
|
||||
print_success("Terminal backend: Modal")
|
||||
print_info("Serverless cloud sandboxes. Each session gets its own container.")
|
||||
from tools.managed_tool_gateway import is_managed_tool_gateway_ready
|
||||
from tools.tool_backend_helpers import normalize_modal_mode
|
||||
from hermes_agent.tools.managed_gateway import is_managed_tool_gateway_ready
|
||||
from hermes_agent.tools.backend_helpers import normalize_modal_mode
|
||||
|
||||
managed_modal_available = bool(
|
||||
managed_nous_tools_enabled()
|
||||
|
|
@ -2040,49 +2040,49 @@ def _setup_whatsapp():
|
|||
|
||||
def _setup_weixin():
|
||||
"""Configure Weixin (personal WeChat) via iLink Bot API QR login."""
|
||||
from hermes_cli.gateway import _setup_weixin as _gateway_setup_weixin
|
||||
from hermes_agent.cli.gateway import _setup_weixin as _gateway_setup_weixin
|
||||
_gateway_setup_weixin()
|
||||
|
||||
|
||||
def _setup_signal():
|
||||
"""Configure Signal via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_signal as _gateway_setup_signal
|
||||
from hermes_agent.cli.gateway import _setup_signal as _gateway_setup_signal
|
||||
_gateway_setup_signal()
|
||||
|
||||
|
||||
def _setup_email():
|
||||
"""Configure Email via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_email as _gateway_setup_email
|
||||
from hermes_agent.cli.gateway import _setup_email as _gateway_setup_email
|
||||
_gateway_setup_email()
|
||||
|
||||
|
||||
def _setup_sms():
|
||||
"""Configure SMS (Twilio) via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_sms as _gateway_setup_sms
|
||||
from hermes_agent.cli.gateway import _setup_sms as _gateway_setup_sms
|
||||
_gateway_setup_sms()
|
||||
|
||||
|
||||
def _setup_dingtalk():
|
||||
"""Configure DingTalk via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_dingtalk as _gateway_setup_dingtalk
|
||||
from hermes_agent.cli.gateway import _setup_dingtalk as _gateway_setup_dingtalk
|
||||
_gateway_setup_dingtalk()
|
||||
|
||||
|
||||
def _setup_feishu():
|
||||
"""Configure Feishu / Lark via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_feishu as _gateway_setup_feishu
|
||||
from hermes_agent.cli.gateway import _setup_feishu as _gateway_setup_feishu
|
||||
_gateway_setup_feishu()
|
||||
|
||||
|
||||
def _setup_wecom():
|
||||
"""Configure WeCom (Enterprise WeChat) via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_wecom as _gateway_setup_wecom
|
||||
from hermes_agent.cli.gateway import _setup_wecom as _gateway_setup_wecom
|
||||
_gateway_setup_wecom()
|
||||
|
||||
|
||||
def _setup_wecom_callback():
|
||||
"""Configure WeCom Callback (self-built app) via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_wecom_callback as _gw_setup
|
||||
from hermes_agent.cli.gateway import _setup_wecom_callback as _gw_setup
|
||||
_gw_setup()
|
||||
|
||||
|
||||
|
|
@ -2155,7 +2155,7 @@ def _setup_bluebubbles():
|
|||
|
||||
def _setup_qqbot():
|
||||
"""Configure QQ Bot (Official API v2) via gateway setup."""
|
||||
from hermes_cli.gateway import _setup_qqbot as _gateway_setup_qqbot
|
||||
from hermes_agent.cli.gateway import _setup_qqbot as _gateway_setup_qqbot
|
||||
_gateway_setup_qqbot()
|
||||
|
||||
|
||||
|
|
@ -2194,7 +2194,7 @@ def _setup_webhooks():
|
|||
save_env_value("WEBHOOK_ENABLED", "true")
|
||||
print()
|
||||
print_success("Webhooks enabled! Next steps:")
|
||||
from hermes_constants import display_hermes_home as _dhh
|
||||
from hermes_agent.constants import display_hermes_home as _dhh
|
||||
print_info(f" 1. Define webhook routes in {_dhh()}/config.yaml")
|
||||
print_info(" 2. Point your service (GitHub, GitLab, etc.) at:")
|
||||
print_info(" http://your-server:8644/webhooks/<route-name>")
|
||||
|
|
@ -2318,7 +2318,7 @@ def setup_gateway(config: dict):
|
|||
_is_linux = _platform.system() == "Linux"
|
||||
_is_macos = _platform.system() == "Darwin"
|
||||
|
||||
from hermes_cli.gateway import (
|
||||
from hermes_agent.cli.gateway import (
|
||||
_is_service_installed,
|
||||
_is_service_running,
|
||||
supports_systemd_services,
|
||||
|
|
@ -2398,7 +2398,7 @@ def setup_gateway(config: dict):
|
|||
print_info(" Or as a boot-time service: sudo hermes gateway install --system")
|
||||
print_info(" Or run in foreground: hermes gateway")
|
||||
else:
|
||||
from hermes_constants import is_container
|
||||
from hermes_agent.constants import is_container
|
||||
if is_container():
|
||||
print_info("Start the gateway to bring your bots online:")
|
||||
print_info(" hermes gateway run # Run as container main process")
|
||||
|
|
@ -2428,7 +2428,7 @@ def setup_tools(config: dict, first_install: bool = False):
|
|||
first_install: When True, uses the simplified first-install flow
|
||||
(no platform menu, prompts for all unconfigured API keys).
|
||||
"""
|
||||
from hermes_cli.tools_config import tools_command
|
||||
from hermes_agent.cli.tools_config import tools_command
|
||||
|
||||
tools_command(first_install=first_install, config=config)
|
||||
|
||||
|
|
@ -2450,14 +2450,14 @@ def _model_section_has_credentials(config: dict) -> bool:
|
|||
``OPENAI_API_KEY`` / ``OPENROUTER_API_KEY`` values through OpenRouter.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.auth import get_active_provider
|
||||
from hermes_agent.cli.auth.auth import get_active_provider
|
||||
if get_active_provider():
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import PROVIDER_REGISTRY
|
||||
except Exception:
|
||||
PROVIDER_REGISTRY = {} # type: ignore[assignment]
|
||||
|
||||
|
|
@ -2863,7 +2863,7 @@ def run_setup_wizard(args):
|
|||
hermes setup tools — just tool configuration
|
||||
hermes setup agent — just agent settings
|
||||
"""
|
||||
from hermes_cli.config import is_managed, managed_error
|
||||
from hermes_agent.cli.config import is_managed, managed_error
|
||||
if is_managed():
|
||||
managed_error("run setup wizard")
|
||||
return
|
||||
|
|
@ -2918,7 +2918,7 @@ def run_setup_wizard(args):
|
|||
return
|
||||
|
||||
# Check if this is an existing installation with a provider configured
|
||||
from hermes_cli.auth import get_active_provider
|
||||
from hermes_agent.cli.auth.auth import get_active_provider
|
||||
|
||||
active_provider = get_active_provider()
|
||||
is_existing = (
|
||||
|
|
@ -3072,8 +3072,8 @@ def _resolve_hermes_chat_argv() -> Optional[list[str]]:
|
|||
return [hermes_bin, "chat"]
|
||||
|
||||
try:
|
||||
if importlib.util.find_spec("hermes_cli") is not None:
|
||||
return [sys.executable, "-m", "hermes_cli.main", "chat"]
|
||||
if importlib.util.find_spec("hermes_agent.cli") is not None:
|
||||
return [sys.executable, "-m", "hermes_agent.cli.main", "chat"]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
@ -3140,7 +3140,7 @@ def _run_first_time_quick_setup(config: dict, hermes_home, is_existing: bool):
|
|||
|
||||
def _run_quick_setup(config: dict, hermes_home):
|
||||
"""Quick setup — only configure items that are missing."""
|
||||
from hermes_cli.config import (
|
||||
from hermes_agent.cli.config import (
|
||||
get_missing_env_vars,
|
||||
get_missing_config_fields,
|
||||
check_config_version,
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ Config stored in ~/.hermes/config.yaml under:
|
|||
"""
|
||||
from typing import List, Optional, Set
|
||||
|
||||
from hermes_cli.config import load_config, save_config
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_cli.platforms import PLATFORMS as _PLATFORMS
|
||||
from hermes_agent.cli.config import load_config, save_config
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
from hermes_agent.cli.platforms import PLATFORMS as _PLATFORMS
|
||||
|
||||
# Backward-compatible view: {key: label_string} so existing code that
|
||||
# iterates ``PLATFORMS.items()`` or calls ``PLATFORMS.get(key)`` keeps
|
||||
|
|
@ -52,7 +52,7 @@ def save_disabled_skills(config: dict, disabled: Set[str], platform: Optional[st
|
|||
def _list_all_skills() -> List[dict]:
|
||||
"""Return all installed skills (ignoring disabled state)."""
|
||||
try:
|
||||
from tools.skills_tool import _find_all_skills
|
||||
from hermes_agent.tools.skills.tool import _find_all_skills
|
||||
return _find_all_skills(skip_disabled=True)
|
||||
except Exception:
|
||||
return []
|
||||
|
|
@ -93,7 +93,7 @@ def _select_platform() -> Optional[str]:
|
|||
|
||||
def _toggle_by_category(skills: List[dict], disabled: Set[str]) -> Set[str]:
|
||||
"""Toggle all skills in a category at once."""
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
|
||||
categories = _get_categories(skills)
|
||||
cat_labels = []
|
||||
|
|
@ -124,7 +124,7 @@ def _toggle_by_category(skills: List[dict], disabled: Set[str]) -> Set[str]:
|
|||
|
||||
def skills_command(args=None):
|
||||
"""Entry point for `hermes skills`."""
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
|
||||
config = load_config()
|
||||
skills = _list_all_skills()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from rich.table import Table
|
|||
|
||||
# Lazy imports to avoid circular dependencies and slow startup.
|
||||
# tools.skills_hub and tools.skills_guard are imported inside functions.
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
_console = Console()
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ def _resolve_short_name(name: str, sources, console: Console) -> str:
|
|||
matches exist, shows them and asks the user to use the full identifier.
|
||||
Returns empty string if nothing found or ambiguous.
|
||||
"""
|
||||
from tools.skills_hub import unified_search
|
||||
from hermes_agent.tools.skills.hub import unified_search
|
||||
|
||||
c = console or _console
|
||||
c.print(f"[dim]Resolving '{name}'...[/]")
|
||||
|
|
@ -144,7 +144,7 @@ def _derive_category_from_install_path(install_path: str) -> str:
|
|||
def do_search(query: str, source: str = "all", limit: int = 10,
|
||||
console: Optional[Console] = None) -> None:
|
||||
"""Search registries and display results as a Rich table."""
|
||||
from tools.skills_hub import GitHubAuth, create_source_router, unified_search
|
||||
from hermes_agent.tools.skills.hub import GitHubAuth, create_source_router, unified_search
|
||||
|
||||
c = console or _console
|
||||
c.print(f"\n[bold]Searching for:[/] {query}")
|
||||
|
|
@ -187,7 +187,7 @@ def do_browse(page: int = 1, page_size: int = 20, source: str = "all",
|
|||
|
||||
Official skills are always shown first, regardless of source filter.
|
||||
"""
|
||||
from tools.skills_hub import (
|
||||
from hermes_agent.tools.skills.hub import (
|
||||
GitHubAuth, create_source_router, parallel_search_sources,
|
||||
)
|
||||
|
||||
|
|
@ -311,11 +311,11 @@ def do_install(identifier: str, category: str = "", force: bool = False,
|
|||
console: Optional[Console] = None, skip_confirm: bool = False,
|
||||
invalidate_cache: bool = True) -> None:
|
||||
"""Fetch, quarantine, scan, confirm, and install a skill."""
|
||||
from tools.skills_hub import (
|
||||
from hermes_agent.tools.skills.hub import (
|
||||
GitHubAuth, create_source_router, ensure_hub_dirs,
|
||||
quarantine_bundle, install_from_quarantine, HubLockFile,
|
||||
)
|
||||
from tools.skills_guard import scan_skill, should_allow_install, format_scan_report
|
||||
from hermes_agent.tools.skills.guard import scan_skill, should_allow_install, format_scan_report
|
||||
|
||||
c = console or _console
|
||||
ensure_hub_dirs()
|
||||
|
|
@ -377,7 +377,7 @@ def do_install(identifier: str, category: str = "", force: bool = False,
|
|||
q_path = quarantine_bundle(bundle)
|
||||
except ValueError as exc:
|
||||
c.print(f"[bold red]Installation blocked:[/] {exc}\n")
|
||||
from tools.skills_hub import append_audit_log
|
||||
from hermes_agent.tools.skills.hub import append_audit_log
|
||||
append_audit_log("BLOCKED", bundle.name, bundle.source,
|
||||
bundle.trust_level, "invalid_path", str(exc))
|
||||
return
|
||||
|
|
@ -395,7 +395,7 @@ def do_install(identifier: str, category: str = "", force: bool = False,
|
|||
c.print(f"\n[bold red]Installation blocked:[/] {reason}")
|
||||
# Clean up quarantine
|
||||
shutil.rmtree(q_path, ignore_errors=True)
|
||||
from tools.skills_hub import append_audit_log
|
||||
from hermes_agent.tools.skills.hub import append_audit_log
|
||||
append_audit_log("BLOCKED", bundle.name, bundle.source,
|
||||
bundle.trust_level, result.verdict,
|
||||
f"{len(result.findings)}_findings")
|
||||
|
|
@ -445,18 +445,18 @@ def do_install(identifier: str, category: str = "", force: bool = False,
|
|||
except ValueError as exc:
|
||||
c.print(f"[bold red]Installation blocked:[/] {exc}\n")
|
||||
shutil.rmtree(q_path, ignore_errors=True)
|
||||
from tools.skills_hub import append_audit_log
|
||||
from hermes_agent.tools.skills.hub import append_audit_log
|
||||
append_audit_log("BLOCKED", bundle.name, bundle.source,
|
||||
bundle.trust_level, "invalid_path", str(exc))
|
||||
return
|
||||
from tools.skills_hub import SKILLS_DIR
|
||||
from hermes_agent.tools.skills.hub import SKILLS_DIR
|
||||
c.print(f"[bold green]Installed:[/] {install_dir.relative_to(SKILLS_DIR)}")
|
||||
c.print(f"[dim]Files: {', '.join(bundle.files.keys())}[/]\n")
|
||||
|
||||
if invalidate_cache:
|
||||
# Invalidate the skills prompt cache so the new skill appears immediately
|
||||
try:
|
||||
from agent.prompt_builder import clear_skills_system_prompt_cache
|
||||
from hermes_agent.agent.prompt_builder import clear_skills_system_prompt_cache
|
||||
clear_skills_system_prompt_cache(clear_snapshot=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -467,7 +467,7 @@ def do_install(identifier: str, category: str = "", force: bool = False,
|
|||
|
||||
def do_inspect(identifier: str, console: Optional[Console] = None) -> None:
|
||||
"""Preview a skill's SKILL.md content without installing."""
|
||||
from tools.skills_hub import GitHubAuth, create_source_router
|
||||
from hermes_agent.tools.skills.hub import GitHubAuth, create_source_router
|
||||
|
||||
c = console or _console
|
||||
auth = GitHubAuth()
|
||||
|
|
@ -520,7 +520,7 @@ def browse_skills(page: int = 1, page_size: int = 20, source: str = "all") -> di
|
|||
|
||||
Returns ``{"items": [...], "page": int, "total_pages": int, "total": int}``.
|
||||
"""
|
||||
from tools.skills_hub import GitHubAuth, create_source_router
|
||||
from hermes_agent.tools.skills.hub import GitHubAuth, create_source_router
|
||||
|
||||
page_size = max(1, min(page_size, 100))
|
||||
_TRUST_RANK = {"builtin": 3, "trusted": 2, "community": 1}
|
||||
|
|
@ -563,7 +563,7 @@ def browse_skills(page: int = 1, page_size: int = 20, source: str = "all") -> di
|
|||
|
||||
def inspect_skill(identifier: str) -> Optional[dict]:
|
||||
"""Skill metadata (+ SKILL.md preview) for programmatic callers."""
|
||||
from tools.skills_hub import GitHubAuth, create_source_router
|
||||
from hermes_agent.tools.skills.hub import GitHubAuth, create_source_router
|
||||
|
||||
class _Q:
|
||||
def print(self, *a, **k):
|
||||
|
|
@ -601,9 +601,9 @@ def inspect_skill(identifier: str) -> Optional[dict]:
|
|||
|
||||
def do_list(source_filter: str = "all", console: Optional[Console] = None) -> None:
|
||||
"""List installed skills, distinguishing hub, builtin, and local skills."""
|
||||
from tools.skills_hub import HubLockFile, ensure_hub_dirs
|
||||
from tools.skills_sync import _read_manifest
|
||||
from tools.skills_tool import _find_all_skills
|
||||
from hermes_agent.tools.skills.hub import HubLockFile, ensure_hub_dirs
|
||||
from hermes_agent.tools.skills.sync import _read_manifest
|
||||
from hermes_agent.tools.skills.tool import _find_all_skills
|
||||
|
||||
c = console or _console
|
||||
ensure_hub_dirs()
|
||||
|
|
@ -659,7 +659,7 @@ def do_list(source_filter: str = "all", console: Optional[Console] = None) -> No
|
|||
|
||||
def do_check(name: Optional[str] = None, console: Optional[Console] = None) -> None:
|
||||
"""Check hub-installed skills for upstream updates."""
|
||||
from tools.skills_hub import check_for_skill_updates
|
||||
from hermes_agent.tools.skills.hub import check_for_skill_updates
|
||||
|
||||
c = console or _console
|
||||
results = check_for_skill_updates(name=name)
|
||||
|
|
@ -682,7 +682,7 @@ def do_check(name: Optional[str] = None, console: Optional[Console] = None) -> N
|
|||
|
||||
def do_update(name: Optional[str] = None, console: Optional[Console] = None) -> None:
|
||||
"""Update hub-installed skills with upstream changes."""
|
||||
from tools.skills_hub import HubLockFile, check_for_skill_updates
|
||||
from hermes_agent.tools.skills.hub import HubLockFile, check_for_skill_updates
|
||||
|
||||
c = console or _console
|
||||
lock = HubLockFile()
|
||||
|
|
@ -702,8 +702,8 @@ def do_update(name: Optional[str] = None, console: Optional[Console] = None) ->
|
|||
|
||||
def do_audit(name: Optional[str] = None, console: Optional[Console] = None) -> None:
|
||||
"""Re-run security scan on installed hub skills."""
|
||||
from tools.skills_hub import HubLockFile, SKILLS_DIR
|
||||
from tools.skills_guard import scan_skill, format_scan_report
|
||||
from hermes_agent.tools.skills.hub import HubLockFile, SKILLS_DIR
|
||||
from hermes_agent.tools.skills.guard import scan_skill, format_scan_report
|
||||
|
||||
c = console or _console
|
||||
lock = HubLockFile()
|
||||
|
|
@ -737,7 +737,7 @@ def do_uninstall(name: str, console: Optional[Console] = None,
|
|||
skip_confirm: bool = False,
|
||||
invalidate_cache: bool = True) -> None:
|
||||
"""Remove a hub-installed skill with confirmation."""
|
||||
from tools.skills_hub import uninstall_skill
|
||||
from hermes_agent.tools.skills.hub import uninstall_skill
|
||||
|
||||
c = console or _console
|
||||
|
||||
|
|
@ -757,7 +757,7 @@ def do_uninstall(name: str, console: Optional[Console] = None,
|
|||
c.print(f"[bold green]{msg}[/]\n")
|
||||
if invalidate_cache:
|
||||
try:
|
||||
from agent.prompt_builder import clear_skills_system_prompt_cache
|
||||
from hermes_agent.agent.prompt_builder import clear_skills_system_prompt_cache
|
||||
clear_skills_system_prompt_cache(clear_snapshot=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -773,7 +773,7 @@ def do_reset(name: str, restore: bool = False,
|
|||
skip_confirm: bool = False,
|
||||
invalidate_cache: bool = True) -> None:
|
||||
"""Reset a bundled skill's manifest tracking (+ optionally restore from bundled)."""
|
||||
from tools.skills_sync import reset_bundled_skill
|
||||
from hermes_agent.tools.skills.sync import reset_bundled_skill
|
||||
|
||||
c = console or _console
|
||||
|
||||
|
|
@ -804,7 +804,7 @@ def do_reset(name: str, restore: bool = False,
|
|||
|
||||
if invalidate_cache:
|
||||
try:
|
||||
from agent.prompt_builder import clear_skills_system_prompt_cache
|
||||
from hermes_agent.agent.prompt_builder import clear_skills_system_prompt_cache
|
||||
clear_skills_system_prompt_cache(clear_snapshot=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -815,7 +815,7 @@ def do_reset(name: str, restore: bool = False,
|
|||
|
||||
def do_tap(action: str, repo: str = "", console: Optional[Console] = None) -> None:
|
||||
"""Manage taps (custom GitHub repo sources)."""
|
||||
from tools.skills_hub import TapsManager
|
||||
from hermes_agent.tools.skills.hub import TapsManager
|
||||
|
||||
c = console or _console
|
||||
mgr = TapsManager()
|
||||
|
|
@ -859,8 +859,8 @@ def do_tap(action: str, repo: str = "", console: Optional[Console] = None) -> No
|
|||
def do_publish(skill_path: str, target: str = "github", repo: str = "",
|
||||
console: Optional[Console] = None) -> None:
|
||||
"""Publish a local skill to a registry (GitHub PR or ClawHub submission)."""
|
||||
from tools.skills_hub import GitHubAuth, SKILLS_DIR
|
||||
from tools.skills_guard import scan_skill, format_scan_report
|
||||
from hermes_agent.tools.skills.hub import GitHubAuth, SKILLS_DIR
|
||||
from hermes_agent.tools.skills.guard import scan_skill, format_scan_report
|
||||
|
||||
c = console or _console
|
||||
path = Path(skill_path)
|
||||
|
|
@ -1024,7 +1024,7 @@ def _github_publish(skill_path: Path, skill_name: str, target_repo: str,
|
|||
|
||||
def do_snapshot_export(output_path: str, console: Optional[Console] = None) -> None:
|
||||
"""Export current hub skill configuration to a portable JSON file."""
|
||||
from tools.skills_hub import HubLockFile, TapsManager
|
||||
from hermes_agent.tools.skills.hub import HubLockFile, TapsManager
|
||||
|
||||
c = console or _console
|
||||
lock = HubLockFile()
|
||||
|
|
@ -1065,7 +1065,7 @@ def do_snapshot_export(output_path: str, console: Optional[Console] = None) -> N
|
|||
def do_snapshot_import(input_path: str, force: bool = False,
|
||||
console: Optional[Console] = None) -> None:
|
||||
"""Re-install skills from a snapshot file."""
|
||||
from tools.skills_hub import TapsManager
|
||||
from hermes_agent.tools.skills.hub import TapsManager
|
||||
|
||||
c = console or _console
|
||||
inp = Path(input_path)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ def get_provider_request_timeout(
|
|||
return None
|
||||
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ def get_provider_stale_timeout(
|
|||
return None
|
||||
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@ from pathlib import Path
|
|||
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypedDict
|
||||
|
||||
|
||||
from hermes_cli.config import (
|
||||
from hermes_agent.cli.config import (
|
||||
load_config, save_config, get_env_value, save_env_value,
|
||||
)
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_cli.nous_subscription import (
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
from hermes_agent.cli.nous_subscription import (
|
||||
apply_nous_managed_defaults,
|
||||
get_nous_subscription_features,
|
||||
)
|
||||
from tools.tool_backend_helpers import fal_key_is_configured, managed_nous_tools_enabled
|
||||
from utils import base_url_hostname
|
||||
from hermes_agent.tools.backend_helpers import fal_key_is_configured, managed_nous_tools_enabled
|
||||
from hermes_agent.utils import base_url_hostname
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ PROJECT_ROOT = Path(__file__).parent.parent.resolve()
|
|||
|
||||
# ─── UI Helpers (shared with setup.py) ────────────────────────────────────────
|
||||
|
||||
from hermes_cli.cli_output import ( # noqa: E402 — late import block
|
||||
from hermes_agent.cli.ui.output import ( # noqa: E402 — late import block
|
||||
print_error as _print_error,
|
||||
print_info as _print_info,
|
||||
print_success as _print_success,
|
||||
|
|
@ -83,7 +83,7 @@ def _get_effective_configurable_toolsets():
|
|||
"""
|
||||
result = list(CONFIGURABLE_TOOLSETS)
|
||||
try:
|
||||
from hermes_cli.plugins import discover_plugins, get_plugin_toolsets
|
||||
from hermes_agent.cli.plugins import discover_plugins, get_plugin_toolsets
|
||||
discover_plugins() # idempotent — ensures plugins are loaded
|
||||
result.extend(get_plugin_toolsets())
|
||||
except Exception:
|
||||
|
|
@ -94,7 +94,7 @@ def _get_effective_configurable_toolsets():
|
|||
def _get_plugin_toolset_keys() -> set:
|
||||
"""Return the set of toolset keys provided by plugins."""
|
||||
try:
|
||||
from hermes_cli.plugins import discover_plugins, get_plugin_toolsets
|
||||
from hermes_agent.cli.plugins import discover_plugins, get_plugin_toolsets
|
||||
discover_plugins() # idempotent — ensures plugins are loaded
|
||||
return {ts_key for ts_key, _, _ in get_plugin_toolsets()}
|
||||
except Exception:
|
||||
|
|
@ -103,7 +103,7 @@ def _get_plugin_toolset_keys() -> set:
|
|||
# Platform display config — derived from the canonical registry so every
|
||||
# module shares the same data. Kept as dict-of-dicts for backward
|
||||
# compatibility with existing ``PLATFORMS[key]["label"]`` access patterns.
|
||||
from hermes_cli.platforms import PLATFORMS as _PLATFORMS_REGISTRY
|
||||
from hermes_agent.cli.platforms import PLATFORMS as _PLATFORMS_REGISTRY
|
||||
|
||||
PLATFORMS = {
|
||||
k: {"label": info.label, "default_toolset": info.default_toolset}
|
||||
|
|
@ -404,7 +404,7 @@ def _run_post_setup(post_setup_key: str):
|
|||
if result.returncode == 0:
|
||||
_print_success(" Node.js dependencies installed")
|
||||
else:
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
_print_warning(f" npm install failed - run manually: cd {display_hermes_home()}/hermes-agent && npm install")
|
||||
elif not node_modules.exists():
|
||||
_print_warning(" Node.js not found - browser tools require: npm install (in hermes-agent directory)")
|
||||
|
|
@ -549,7 +549,7 @@ def _get_platform_tools(
|
|||
include_default_mcp_servers: bool = True,
|
||||
) -> Set[str]:
|
||||
"""Resolve which individual toolset names are enabled for a platform."""
|
||||
from toolsets import resolve_toolset
|
||||
from hermes_agent.tools.toolsets import resolve_toolset
|
||||
|
||||
platform_toolsets = config.get("platform_toolsets") or {}
|
||||
toolset_names = platform_toolsets.get(platform)
|
||||
|
|
@ -696,7 +696,7 @@ def _toolset_has_keys(ts_key: str, config: dict = None) -> bool:
|
|||
|
||||
if ts_key == "vision":
|
||||
try:
|
||||
from agent.auxiliary_client import resolve_vision_provider_client
|
||||
from hermes_agent.providers.auxiliary import resolve_vision_provider_client
|
||||
|
||||
_provider, client, _model = resolve_vision_provider_client()
|
||||
return client is not None
|
||||
|
|
@ -731,7 +731,7 @@ def _toolset_has_keys(ts_key: str, config: dict = None) -> bool:
|
|||
|
||||
def _prompt_choice(question: str, choices: list, default: int = 0) -> int:
|
||||
"""Single-select menu (arrow keys). Delegates to curses_radiolist."""
|
||||
from hermes_cli.curses_ui import curses_radiolist
|
||||
from hermes_agent.cli.ui.curses import curses_radiolist
|
||||
return curses_radiolist(question, choices, selected=default, cancel_returns=default)
|
||||
|
||||
|
||||
|
|
@ -765,8 +765,8 @@ def _estimate_tool_tokens() -> Dict[str, int]:
|
|||
|
||||
try:
|
||||
# Trigger full tool discovery (imports all tool modules).
|
||||
import model_tools # noqa: F401
|
||||
from tools.registry import registry
|
||||
import hermes_agent.tools.dispatch # noqa: F401
|
||||
from hermes_agent.tools.registry import registry
|
||||
except Exception:
|
||||
logger.debug("Tool registry unavailable; skipping token estimation")
|
||||
_tool_token_cache = {}
|
||||
|
|
@ -786,8 +786,8 @@ def _estimate_tool_tokens() -> Dict[str, int]:
|
|||
|
||||
def _prompt_toolset_checklist(platform_label: str, enabled: Set[str]) -> Set[str]:
|
||||
"""Multi-select checklist of toolsets. Returns set of selected toolset keys."""
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from toolsets import resolve_toolset
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
from hermes_agent.tools.toolsets import resolve_toolset
|
||||
|
||||
# Pre-compute per-tool token counts (cached after first call).
|
||||
tool_tokens = _estimate_tool_tokens()
|
||||
|
|
@ -862,8 +862,8 @@ def _plugin_image_gen_providers() -> list[dict]:
|
|||
function surfaces it alongside OpenAI automatically.
|
||||
"""
|
||||
try:
|
||||
from agent.image_gen_registry import list_providers
|
||||
from hermes_cli.plugins import _ensure_plugins_discovered
|
||||
from hermes_agent.agent.image_gen.registry import list_providers
|
||||
from hermes_agent.cli.plugins import _ensure_plugins_discovered
|
||||
|
||||
_ensure_plugins_discovered()
|
||||
providers = list_providers()
|
||||
|
|
@ -933,8 +933,8 @@ def _toolset_needs_configuration_prompt(ts_key: str, config: dict) -> bool:
|
|||
if fal_key_is_configured():
|
||||
return False
|
||||
try:
|
||||
from agent.image_gen_registry import list_providers
|
||||
from hermes_cli.plugins import _ensure_plugins_discovered
|
||||
from hermes_agent.agent.image_gen.registry import list_providers
|
||||
from hermes_agent.cli.plugins import _ensure_plugins_discovered
|
||||
|
||||
_ensure_plugins_discovered()
|
||||
for provider in list_providers():
|
||||
|
|
@ -1085,7 +1085,7 @@ class _ImagegenBackend(TypedDict):
|
|||
|
||||
def _fal_model_catalog() -> Tuple[Dict[str, Dict[str, Any]], str]:
|
||||
"""Lazy-load the FAL model catalog from the tool module."""
|
||||
from tools.image_generation_tool import FAL_MODELS, DEFAULT_MODEL
|
||||
from hermes_agent.tools.media.image_gen import FAL_MODELS, DEFAULT_MODEL
|
||||
return FAL_MODELS, DEFAULT_MODEL
|
||||
|
||||
|
||||
|
|
@ -1179,8 +1179,8 @@ def _plugin_image_gen_catalog(plugin_name: str):
|
|||
``({}, None)`` if the provider isn't registered or has no models.
|
||||
"""
|
||||
try:
|
||||
from agent.image_gen_registry import get_provider
|
||||
from hermes_cli.plugins import _ensure_plugins_discovered
|
||||
from hermes_agent.agent.image_gen.registry import get_provider
|
||||
from hermes_agent.cli.plugins import _ensure_plugins_discovered
|
||||
|
||||
_ensure_plugins_discovered()
|
||||
provider = get_provider(plugin_name)
|
||||
|
|
@ -1836,7 +1836,7 @@ def tools_command(args=None, first_install: bool = False, config: dict = None):
|
|||
platform_choices[idx] = f"Configure {pinfo['label']} ({new_count}/{total} enabled)"
|
||||
|
||||
print()
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
print(color(f" Tool configuration saved to {display_hermes_home()}/config.yaml", Colors.DIM))
|
||||
print(color(" Changes take effect on next 'hermes' or gateway restart.", Colors.DIM))
|
||||
print()
|
||||
|
|
@ -1852,7 +1852,7 @@ def _configure_mcp_tools_interactive(config: dict):
|
|||
a per-server curses checklist. Writes changes back as ``tools.exclude``
|
||||
entries in config.yaml.
|
||||
"""
|
||||
from hermes_cli.curses_ui import curses_checklist
|
||||
from hermes_agent.cli.ui.curses import curses_checklist
|
||||
|
||||
mcp_servers = config.get("mcp_servers") or {}
|
||||
if not mcp_servers:
|
||||
|
|
@ -1873,7 +1873,7 @@ def _configure_mcp_tools_interactive(config: dict):
|
|||
print(color(f" Connecting to {len(enabled_names)} server(s): {', '.join(enabled_names)}", Colors.DIM))
|
||||
|
||||
try:
|
||||
from tools.mcp_tool import probe_mcp_server_tools
|
||||
from hermes_agent.tools.mcp.tool import probe_mcp_server_tools
|
||||
server_tools = probe_mcp_server_tools()
|
||||
except Exception as exc:
|
||||
_print_error(f"Failed to probe MCP servers: {exc}")
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import subprocess
|
|||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from rich.console import Console
|
||||
|
|
@ -45,7 +45,7 @@ def cprint(text: str):
|
|||
def _skin_color(key: str, fallback: str) -> str:
|
||||
"""Get a color from the active skin, or return fallback."""
|
||||
try:
|
||||
from hermes_cli.skin_engine import get_active_skin
|
||||
from hermes_agent.cli.ui.skin_engine import get_active_skin
|
||||
return get_active_skin().get_color(key, fallback)
|
||||
except Exception:
|
||||
return fallback
|
||||
|
|
@ -54,7 +54,7 @@ def _skin_color(key: str, fallback: str) -> str:
|
|||
def _skin_branding(key: str, fallback: str) -> str:
|
||||
"""Get a branding string from the active skin, or return fallback."""
|
||||
try:
|
||||
from hermes_cli.skin_engine import get_active_skin
|
||||
from hermes_agent.cli.ui.skin_engine import get_active_skin
|
||||
return get_active_skin().get_branding(key, fallback)
|
||||
except Exception:
|
||||
return fallback
|
||||
|
|
@ -64,7 +64,7 @@ def _skin_branding(key: str, fallback: str) -> str:
|
|||
# ASCII Art & Branding
|
||||
# =========================================================================
|
||||
|
||||
from hermes_cli import __version__ as VERSION, __release_date__ as RELEASE_DATE
|
||||
from hermes_agent.cli import __version__ as VERSION, __release_date__ as RELEASE_DATE
|
||||
|
||||
HERMES_AGENT_LOGO = """[bold #FFD700]██╗ ██╗███████╗██████╗ ███╗ ███╗███████╗███████╗ █████╗ ██████╗ ███████╗███╗ ██╗████████╗[/]
|
||||
[bold #FFD700]██║ ██║██╔════╝██╔══██╗████╗ ████║██╔════╝██╔════╝ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝[/]
|
||||
|
|
@ -103,7 +103,7 @@ def get_available_skills() -> Dict[str, List[str]]:
|
|||
user's ``skills.disabled`` config list.
|
||||
"""
|
||||
try:
|
||||
from tools.skills_tool import _find_all_skills
|
||||
from hermes_agent.tools.skills.tool import _find_all_skills
|
||||
all_skills = _find_all_skills() # already filtered
|
||||
except Exception:
|
||||
return {}
|
||||
|
|
@ -330,9 +330,9 @@ def build_welcome_banner(console: Console, model: str, cwd: str,
|
|||
get_toolset_for_tool: Callable to map tool name -> toolset name.
|
||||
context_length: Model's context window size in tokens.
|
||||
"""
|
||||
from model_tools import check_tool_availability, TOOLSET_REQUIREMENTS
|
||||
from hermes_agent.tools.dispatch import check_tool_availability, TOOLSET_REQUIREMENTS
|
||||
if get_toolset_for_tool is None:
|
||||
from model_tools import get_toolset_for_tool
|
||||
from hermes_agent.tools.dispatch import get_toolset_for_tool
|
||||
|
||||
tools = tools or []
|
||||
enabled_toolsets = enabled_toolsets or []
|
||||
|
|
@ -364,7 +364,7 @@ def build_welcome_banner(console: Console, model: str, cwd: str,
|
|||
|
||||
# Use skin's custom caduceus art if provided
|
||||
try:
|
||||
from hermes_cli.skin_engine import get_active_skin
|
||||
from hermes_agent.cli.ui.skin_engine import get_active_skin
|
||||
_bskin = get_active_skin()
|
||||
_hero = _bskin.banner_hero if hasattr(_bskin, 'banner_hero') and _bskin.banner_hero else HERMES_CADUCEUS
|
||||
except Exception:
|
||||
|
|
@ -444,7 +444,7 @@ def build_welcome_banner(console: Console, model: str, cwd: str,
|
|||
|
||||
# MCP Servers section (only if configured)
|
||||
try:
|
||||
from tools.mcp_tool import get_mcp_status
|
||||
from hermes_agent.tools.mcp.tool import get_mcp_status
|
||||
mcp_status = get_mcp_status()
|
||||
except Exception:
|
||||
mcp_status = []
|
||||
|
|
@ -491,7 +491,7 @@ def build_welcome_banner(console: Console, model: str, cwd: str,
|
|||
summary_parts.append("/help for commands")
|
||||
# Show active profile name when not 'default'
|
||||
try:
|
||||
from hermes_cli.profiles import get_active_profile_name
|
||||
from hermes_agent.cli.profiles import get_active_profile_name
|
||||
_profile_name = get_active_profile_name()
|
||||
if _profile_name and _profile_name != "default":
|
||||
right_lines.append(f"[bold {accent}]Profile:[/] [{text}]{_profile_name}[/]")
|
||||
|
|
@ -504,7 +504,7 @@ def build_welcome_banner(console: Console, model: str, cwd: str,
|
|||
try:
|
||||
behind = get_update_result(timeout=0.5)
|
||||
if behind and behind > 0:
|
||||
from hermes_cli.config import recommended_update_command
|
||||
from hermes_agent.cli.config import recommended_update_command
|
||||
commits_word = "commit" if behind == 1 else "commits"
|
||||
right_lines.append(
|
||||
f"[bold yellow]⚠ {behind} {commits_word} behind[/]"
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import queue
|
|||
import time as _time
|
||||
import getpass
|
||||
|
||||
from hermes_cli.banner import cprint, _DIM, _RST
|
||||
from hermes_cli.config import save_env_value_secure
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.cli.ui.banner import cprint, _DIM, _RST
|
||||
from hermes_agent.cli.config import save_env_value_secure
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
|
||||
def clarify_callback(cli, question, choices):
|
||||
|
|
@ -21,7 +21,7 @@ def clarify_callback(cli, question, choices):
|
|||
Sets up the interactive selection UI, then blocks until the user
|
||||
responds. Returns the user's choice or a timeout message.
|
||||
"""
|
||||
from cli import CLI_CONFIG
|
||||
from hermes_agent.cli.repl import CLI_CONFIG
|
||||
|
||||
timeout = CLI_CONFIG.get("clarify", {}).get("timeout", 120)
|
||||
response_queue = queue.Queue()
|
||||
|
|
@ -200,7 +200,7 @@ def approval_callback(cli, command: str, description: str) -> str:
|
|||
lock = cli._approval_lock
|
||||
|
||||
with lock:
|
||||
from cli import CLI_CONFIG
|
||||
from hermes_agent.cli.repl import CLI_CONFIG
|
||||
timeout = CLI_CONFIG.get("approvals", {}).get("timeout", 60)
|
||||
response_queue = queue.Queue()
|
||||
choices = ["once", "session", "always", "deny"]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ text-based numbered fallback for terminals without curses support.
|
|||
import sys
|
||||
from typing import Callable, List, Optional, Set
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
|
||||
def flush_stdin() -> None:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ mcp_config.py, and memory_setup.py.
|
|||
|
||||
import getpass
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
|
||||
# ─── Print Helpers ────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ USAGE
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
from hermes_cli.skin_engine import get_active_skin, list_skins, set_active_skin
|
||||
from hermes_agent.cli.ui.skin_engine import get_active_skin, list_skins, set_active_skin
|
||||
|
||||
skin = get_active_skin()
|
||||
print(skin.colors["banner_title"]) # "#FFD700"
|
||||
|
|
@ -108,7 +108,7 @@ from dataclasses import dataclass, field
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ from pathlib import Path
|
|||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent.resolve()
|
||||
|
||||
from hermes_cli.auth import AuthError, resolve_provider
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_cli.config import get_env_path, get_env_value, get_hermes_home, load_config
|
||||
from hermes_cli.models import provider_label
|
||||
from hermes_cli.nous_subscription import get_nous_subscription_features
|
||||
from hermes_cli.runtime_provider import resolve_requested_provider
|
||||
from hermes_constants import OPENROUTER_MODELS_URL
|
||||
from tools.tool_backend_helpers import managed_nous_tools_enabled
|
||||
from hermes_agent.cli.auth.auth import AuthError, resolve_provider
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
from hermes_agent.cli.config import get_env_path, get_env_value, get_hermes_home, load_config
|
||||
from hermes_agent.cli.models.models import provider_label
|
||||
from hermes_agent.cli.nous_subscription import get_nous_subscription_features
|
||||
from hermes_agent.cli.runtime_provider import resolve_requested_provider
|
||||
from hermes_agent.constants import OPENROUTER_MODELS_URL
|
||||
from hermes_agent.tools.backend_helpers import managed_nous_tools_enabled
|
||||
|
||||
def check_mark(ok: bool) -> str:
|
||||
if ok:
|
||||
|
|
@ -79,7 +79,7 @@ def _effective_provider_label() -> str:
|
|||
return provider_label(effective)
|
||||
|
||||
|
||||
from hermes_constants import is_termux as _is_termux
|
||||
from hermes_agent.constants import is_termux as _is_termux
|
||||
|
||||
|
||||
def show_status(args):
|
||||
|
|
@ -141,7 +141,7 @@ def show_status(args):
|
|||
display = redact_key(value) if not show_all else value
|
||||
print(f" {name:<12} {check_mark(has_key)} {display}")
|
||||
|
||||
from hermes_cli.auth import get_anthropic_key
|
||||
from hermes_agent.cli.auth.auth import get_anthropic_key
|
||||
anthropic_value = get_anthropic_key()
|
||||
anthropic_display = redact_key(anthropic_value) if not show_all else anthropic_value
|
||||
print(f" {'Anthropic':<12} {check_mark(bool(anthropic_value))} {anthropic_display}")
|
||||
|
|
@ -153,7 +153,7 @@ def show_status(args):
|
|||
print(color("◆ Auth Providers", Colors.CYAN, Colors.BOLD))
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import get_nous_auth_status, get_codex_auth_status, get_qwen_auth_status
|
||||
from hermes_agent.cli.auth.auth import get_nous_auth_status, get_codex_auth_status, get_qwen_auth_status
|
||||
nous_status = get_nous_auth_status()
|
||||
codex_status = get_codex_auth_status()
|
||||
qwen_status = get_qwen_auth_status()
|
||||
|
|
@ -344,7 +344,7 @@ def show_status(args):
|
|||
print(color("◆ Gateway Service", Colors.CYAN, Colors.BOLD))
|
||||
|
||||
try:
|
||||
from hermes_cli.gateway import get_gateway_runtime_snapshot, _format_gateway_pids
|
||||
from hermes_agent.cli.gateway import get_gateway_runtime_snapshot, _format_gateway_pids
|
||||
|
||||
snapshot = get_gateway_runtime_snapshot()
|
||||
is_running = snapshot.running
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import shutil
|
|||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
from hermes_cli.colors import Colors, color
|
||||
from hermes_agent.cli.ui.colors import Colors, color
|
||||
|
||||
def log_info(msg: str):
|
||||
print(f"{color('→', Colors.CYAN)} {msg}")
|
||||
|
|
@ -108,7 +108,7 @@ def remove_wrapper_script():
|
|||
try:
|
||||
# Check if it's our wrapper (contains hermes_cli reference)
|
||||
content = wrapper.read_text()
|
||||
if 'hermes_cli' in content or 'hermes-agent' in content:
|
||||
if 'hermes_agent.cli' in content or 'hermes-agent' in content:
|
||||
wrapper.unlink()
|
||||
removed.append(wrapper)
|
||||
except Exception as e:
|
||||
|
|
@ -132,7 +132,7 @@ def uninstall_gateway_service():
|
|||
|
||||
# 1. Kill any standalone gateway processes (all platforms, including Termux)
|
||||
try:
|
||||
from hermes_cli.gateway import kill_gateway_processes, find_gateway_pids
|
||||
from hermes_agent.cli.gateway import kill_gateway_processes, find_gateway_pids
|
||||
pids = find_gateway_pids()
|
||||
if pids:
|
||||
killed = kill_gateway_processes()
|
||||
|
|
@ -153,7 +153,7 @@ def uninstall_gateway_service():
|
|||
# 2. Linux: uninstall systemd services (both user and system scopes)
|
||||
if system == "Linux":
|
||||
try:
|
||||
from hermes_cli.gateway import (
|
||||
from hermes_agent.cli.gateway import (
|
||||
get_systemd_unit_path,
|
||||
get_service_name,
|
||||
_systemctl_cmd,
|
||||
|
|
@ -190,7 +190,7 @@ def uninstall_gateway_service():
|
|||
# 3. macOS: uninstall launchd plist
|
||||
elif system == "Darwin":
|
||||
try:
|
||||
from hermes_cli.gateway import get_launchd_plist_path
|
||||
from hermes_agent.cli.gateway import get_launchd_plist_path
|
||||
plist_path = get_launchd_plist_path()
|
||||
if plist_path.exists():
|
||||
subprocess.run(["launchctl", "unload", str(plist_path)],
|
||||
|
|
@ -207,7 +207,7 @@ def uninstall_gateway_service():
|
|||
def _is_default_hermes_home(hermes_home: Path) -> bool:
|
||||
"""Return True when ``hermes_home`` points at the default (non-profile) root."""
|
||||
try:
|
||||
from hermes_constants import get_default_hermes_root
|
||||
from hermes_agent.constants import get_default_hermes_root
|
||||
return hermes_home.resolve() == get_default_hermes_root().resolve()
|
||||
except Exception:
|
||||
return False
|
||||
|
|
@ -218,7 +218,7 @@ def _discover_named_profiles():
|
|||
if profile support is unavailable or nothing is installed beyond the
|
||||
default root."""
|
||||
try:
|
||||
from hermes_cli.profiles import list_profiles
|
||||
from hermes_agent.cli.profiles import list_profiles
|
||||
except Exception:
|
||||
return []
|
||||
try:
|
||||
|
|
@ -243,9 +243,9 @@ def _uninstall_profile(profile) -> None:
|
|||
log_info(f"Uninstalling profile '{name}'...")
|
||||
|
||||
# 1. Stop and remove this profile's gateway service.
|
||||
# Use `python -m hermes_cli.main` so we don't depend on a `hermes`
|
||||
# Use `python -m hermes_agent.cli.main` so we don't depend on a `hermes`
|
||||
# wrapper that may be half-removed mid-uninstall.
|
||||
hermes_invocation = [_sys.executable, "-m", "hermes_cli.main", "--profile", name]
|
||||
hermes_invocation = [_sys.executable, "-m", "hermes_agent.cli.main", "--profile", name]
|
||||
for subcmd in ("stop", "uninstall"):
|
||||
try:
|
||||
subprocess.run(
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ Provides a FastAPI backend serving the Vite/React frontend and REST API
|
|||
endpoints for managing configuration, environment variables, and sessions.
|
||||
|
||||
Usage:
|
||||
python -m hermes_cli.main web # Start on http://127.0.0.1:9119
|
||||
python -m hermes_cli.main web --port 8080
|
||||
python -m hermes_agent.cli.main web # Start on http://127.0.0.1:9119
|
||||
python -m hermes_agent.cli.main web --port 8080
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
|
@ -28,11 +28,9 @@ from typing import Any, Dict, List, Optional
|
|||
import yaml
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent.resolve()
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from hermes_cli import __version__, __release_date__
|
||||
from hermes_cli.config import (
|
||||
from hermes_agent.cli import __version__, __release_date__
|
||||
from hermes_agent.cli.config import (
|
||||
DEFAULT_CONFIG,
|
||||
OPTIONAL_ENV_VARS,
|
||||
get_config_path,
|
||||
|
|
@ -46,7 +44,7 @@ from hermes_cli.config import (
|
|||
check_config_version,
|
||||
redact_key,
|
||||
)
|
||||
from gateway.status import get_running_pid, read_runtime_status
|
||||
from hermes_agent.gateway.status import get_running_pid, read_runtime_status
|
||||
|
||||
try:
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
|
|
@ -296,7 +294,7 @@ _SCHEMA_OVERRIDES: Dict[str, Dict[str, Any]] = {
|
|||
"description": "Log level for agent.log",
|
||||
"options": ["DEBUG", "INFO", "WARNING", "ERROR"],
|
||||
},
|
||||
"agent.service_tier": {
|
||||
"hermes_agent.agent.service_tier": {
|
||||
"type": "select",
|
||||
"description": "API service tier (OpenAI/Anthropic)",
|
||||
"options": ["", "auto", "default", "flex"],
|
||||
|
|
@ -485,7 +483,7 @@ async def get_status():
|
|||
gateway_updated_at = None
|
||||
configured_gateway_platforms: set[str] | None = None
|
||||
try:
|
||||
from gateway.config import load_gateway_config
|
||||
from hermes_agent.gateway.config import load_gateway_config
|
||||
|
||||
gateway_config = load_gateway_config()
|
||||
configured_gateway_platforms = {
|
||||
|
|
@ -528,7 +526,7 @@ async def get_status():
|
|||
|
||||
active_sessions = 0
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
sessions = db.list_sessions_rich(limit=50)
|
||||
|
|
@ -588,7 +586,7 @@ _ACTION_PROCS: Dict[str, subprocess.Popen] = {}
|
|||
def _spawn_hermes_action(subcommand: List[str], name: str) -> subprocess.Popen:
|
||||
"""Spawn ``hermes <subcommand>`` detached and record the Popen handle.
|
||||
|
||||
Uses the running interpreter's ``hermes_cli.main`` module so the action
|
||||
Uses the running interpreter's ``hermes_agent.cli.main`` module so the action
|
||||
inherits the same venv/PYTHONPATH the web server is using.
|
||||
"""
|
||||
log_file_name = _ACTION_LOG_FILES[name]
|
||||
|
|
@ -599,7 +597,7 @@ def _spawn_hermes_action(subcommand: List[str], name: str) -> subprocess.Popen:
|
|||
f"\n=== {name} started {time.strftime('%Y-%m-%d %H:%M:%S')} ===\n".encode()
|
||||
)
|
||||
|
||||
cmd = [sys.executable, "-m", "hermes_cli.main", *subcommand]
|
||||
cmd = [sys.executable, "-m", "hermes_agent.cli.main", *subcommand]
|
||||
|
||||
popen_kwargs: Dict[str, Any] = {
|
||||
"cwd": str(PROJECT_ROOT),
|
||||
|
|
@ -697,7 +695,7 @@ async def get_action_status(name: str, lines: int = 200):
|
|||
@app.get("/api/sessions")
|
||||
async def get_sessions(limit: int = 20, offset: int = 0):
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
sessions = db.list_sessions_rich(limit=limit, offset=offset)
|
||||
|
|
@ -722,7 +720,7 @@ async def search_sessions(q: str = "", limit: int = 20):
|
|||
if not q or not q.strip():
|
||||
return {"results": []}
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
# Auto-add prefix wildcards so partial words match
|
||||
|
|
@ -838,7 +836,7 @@ def get_model_info():
|
|||
# Resolve auto-detected context length (pass config_ctx=None to get
|
||||
# purely auto-detected value, then separately report the override)
|
||||
try:
|
||||
from agent.model_metadata import get_model_context_length
|
||||
from hermes_agent.providers.metadata import get_model_context_length
|
||||
auto_ctx = get_model_context_length(
|
||||
model=model_name,
|
||||
base_url=base_url,
|
||||
|
|
@ -858,7 +856,7 @@ def get_model_info():
|
|||
# Try to get model capabilities from models.dev
|
||||
caps = {}
|
||||
try:
|
||||
from agent.models_dev import get_model_capabilities
|
||||
from hermes_agent.providers.metadata_dev import get_model_capabilities
|
||||
mc = get_model_capabilities(provider=provider, model=model_name)
|
||||
if mc is not None:
|
||||
caps = {
|
||||
|
|
@ -1062,7 +1060,7 @@ def _anthropic_oauth_status() -> Dict[str, Any]:
|
|||
The dashboard reports the highest-priority source that's actually present.
|
||||
"""
|
||||
try:
|
||||
from agent.anthropic_adapter import (
|
||||
from hermes_agent.providers.anthropic_adapter import (
|
||||
read_hermes_oauth_credentials,
|
||||
read_claude_code_credentials,
|
||||
_HERMES_OAUTH_FILE,
|
||||
|
|
@ -1125,7 +1123,7 @@ def _claude_code_only_status() -> Dict[str, Any]:
|
|||
when they also have a separate Hermes-managed PKCE login.
|
||||
"""
|
||||
try:
|
||||
from agent.anthropic_adapter import read_claude_code_credentials
|
||||
from hermes_agent.providers.anthropic_adapter import read_claude_code_credentials
|
||||
creds = read_claude_code_credentials()
|
||||
except Exception:
|
||||
creds = None
|
||||
|
|
@ -1200,7 +1198,7 @@ def _resolve_provider_status(provider_id: str, status_fn) -> Dict[str, Any]:
|
|||
except Exception as e:
|
||||
return {"logged_in": False, "error": str(e)}
|
||||
try:
|
||||
from hermes_cli import auth as hauth
|
||||
from hermes_agent.cli import auth as hauth
|
||||
if provider_id == "nous":
|
||||
raw = hauth.get_nous_auth_status()
|
||||
return {
|
||||
|
|
@ -1288,14 +1286,14 @@ async def disconnect_oauth_provider(provider_id: str, request: Request):
|
|||
# want to undo a disconnect.
|
||||
if provider_id in ("anthropic", "claude-code"):
|
||||
try:
|
||||
from agent.anthropic_adapter import _HERMES_OAUTH_FILE
|
||||
from hermes_agent.providers.anthropic_adapter import _HERMES_OAUTH_FILE
|
||||
if _HERMES_OAUTH_FILE.exists():
|
||||
_HERMES_OAUTH_FILE.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
# Also clear the credential pool entry if present.
|
||||
try:
|
||||
from hermes_cli.auth import clear_provider_auth
|
||||
from hermes_agent.cli.auth.auth import clear_provider_auth
|
||||
clear_provider_auth("anthropic")
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -1303,7 +1301,7 @@ async def disconnect_oauth_provider(provider_id: str, request: Request):
|
|||
return {"ok": True, "provider": provider_id}
|
||||
|
||||
try:
|
||||
from hermes_cli.auth import clear_provider_auth
|
||||
from hermes_agent.cli.auth.auth import clear_provider_auth
|
||||
cleared = clear_provider_auth(provider_id)
|
||||
_log.info("oauth/disconnect: %s (cleared=%s)", provider_id, cleared)
|
||||
return {"ok": bool(cleared), "provider": provider_id}
|
||||
|
|
@ -1356,7 +1354,7 @@ _oauth_sessions_lock = threading.Lock()
|
|||
# Guarded so hermes web still starts if anthropic_adapter is unavailable;
|
||||
# Phase 2 endpoints will return 501 in that case.
|
||||
try:
|
||||
from agent.anthropic_adapter import (
|
||||
from hermes_agent.providers.anthropic_adapter import (
|
||||
_OAUTH_CLIENT_ID as _ANTHROPIC_OAUTH_CLIENT_ID,
|
||||
_OAUTH_TOKEN_URL as _ANTHROPIC_OAUTH_TOKEN_URL,
|
||||
_OAUTH_REDIRECT_URI as _ANTHROPIC_OAUTH_REDIRECT_URI,
|
||||
|
|
@ -1400,7 +1398,7 @@ def _save_anthropic_oauth_creds(access_token: str, refresh_token: str, expires_a
|
|||
Mirrors what auth_commands.add_command does so the dashboard flow leaves
|
||||
the system in the same state as ``hermes auth add anthropic``.
|
||||
"""
|
||||
from agent.anthropic_adapter import _HERMES_OAUTH_FILE
|
||||
from hermes_agent.providers.anthropic_adapter import _HERMES_OAUTH_FILE
|
||||
payload = {
|
||||
"accessToken": access_token,
|
||||
"refreshToken": refresh_token,
|
||||
|
|
@ -1412,7 +1410,7 @@ def _save_anthropic_oauth_creds(access_token: str, refresh_token: str, expires_a
|
|||
# the file write — pool registration only matters for the rotation
|
||||
# strategy, not for runtime credential resolution.
|
||||
try:
|
||||
from agent.credential_pool import (
|
||||
from hermes_agent.providers.credential_pool import (
|
||||
PooledCredential,
|
||||
load_pool,
|
||||
AUTH_TYPE_OAUTH,
|
||||
|
|
@ -1539,9 +1537,9 @@ async def _start_device_code_flow(provider_id: str) -> Dict[str, Any]:
|
|||
then spawns a background poller. Returns the user-facing display fields
|
||||
so the UI can render the verification page link + user code.
|
||||
"""
|
||||
from hermes_cli import auth as hauth
|
||||
from hermes_agent.cli import auth as hauth
|
||||
if provider_id == "nous":
|
||||
from hermes_cli.auth import _request_device_code, PROVIDER_REGISTRY
|
||||
from hermes_agent.cli.auth.auth import _request_device_code, PROVIDER_REGISTRY
|
||||
import httpx
|
||||
pconfig = PROVIDER_REGISTRY["nous"]
|
||||
portal_base_url = (
|
||||
|
|
@ -1618,7 +1616,7 @@ async def _start_device_code_flow(provider_id: str) -> Dict[str, Any]:
|
|||
|
||||
def _nous_poller(session_id: str) -> None:
|
||||
"""Background poller that drives a Nous device-code flow to completion."""
|
||||
from hermes_cli.auth import _poll_for_token, refresh_nous_oauth_from_state
|
||||
from hermes_agent.cli.auth.auth import _poll_for_token, refresh_nous_oauth_from_state
|
||||
from datetime import datetime, timezone
|
||||
import httpx
|
||||
with _oauth_sessions_lock:
|
||||
|
|
@ -1662,7 +1660,7 @@ def _nous_poller(session_id: str) -> None:
|
|||
auth_state, min_key_ttl_seconds=300, timeout_seconds=15.0,
|
||||
force_refresh=False, force_mint=True,
|
||||
)
|
||||
from hermes_cli.auth import persist_nous_credentials
|
||||
from hermes_agent.cli.auth.auth import persist_nous_credentials
|
||||
persist_nous_credentials(full_state)
|
||||
with _oauth_sessions_lock:
|
||||
sess["status"] = "approved"
|
||||
|
|
@ -1691,7 +1689,7 @@ def _codex_full_login_worker(session_id: str) -> None:
|
|||
"""
|
||||
try:
|
||||
import httpx
|
||||
from hermes_cli.auth import (
|
||||
from hermes_agent.cli.auth.auth import (
|
||||
CODEX_OAUTH_CLIENT_ID,
|
||||
CODEX_OAUTH_TOKEN_URL,
|
||||
DEFAULT_CODEX_BASE_URL,
|
||||
|
|
@ -1775,7 +1773,7 @@ def _codex_full_login_worker(session_id: str) -> None:
|
|||
raise RuntimeError("token exchange did not return access_token")
|
||||
|
||||
# Persist via credential pool — same shape as auth_commands.add_command
|
||||
from agent.credential_pool import (
|
||||
from hermes_agent.providers.credential_pool import (
|
||||
PooledCredential,
|
||||
load_pool,
|
||||
AUTH_TYPE_OAUTH,
|
||||
|
|
@ -1889,7 +1887,7 @@ async def cancel_oauth_session(session_id: str, request: Request):
|
|||
|
||||
@app.get("/api/sessions/{session_id}")
|
||||
async def get_session_detail(session_id: str):
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
sid = db.resolve_session_id(session_id)
|
||||
|
|
@ -1903,7 +1901,7 @@ async def get_session_detail(session_id: str):
|
|||
|
||||
@app.get("/api/sessions/{session_id}/messages")
|
||||
async def get_session_messages(session_id: str):
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
sid = db.resolve_session_id(session_id)
|
||||
|
|
@ -1917,7 +1915,7 @@ async def get_session_messages(session_id: str):
|
|||
|
||||
@app.delete("/api/sessions/{session_id}")
|
||||
async def delete_session_endpoint(session_id: str):
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
if not db.delete_session(session_id):
|
||||
|
|
@ -1940,7 +1938,7 @@ async def get_logs(
|
|||
component: Optional[str] = None,
|
||||
search: Optional[str] = None,
|
||||
):
|
||||
from hermes_cli.logs import _read_tail, LOG_FILES
|
||||
from hermes_agent.cli.logs import _read_tail, LOG_FILES
|
||||
|
||||
log_name = LOG_FILES.get(file)
|
||||
if not log_name:
|
||||
|
|
@ -1950,7 +1948,7 @@ async def get_logs(
|
|||
return {"file": file, "lines": []}
|
||||
|
||||
try:
|
||||
from hermes_logging import COMPONENT_PREFIXES
|
||||
from hermes_agent.logging import COMPONENT_PREFIXES
|
||||
except ImportError:
|
||||
COMPONENT_PREFIXES = {}
|
||||
|
||||
|
|
@ -2003,13 +2001,13 @@ class CronJobUpdate(BaseModel):
|
|||
|
||||
@app.get("/api/cron/jobs")
|
||||
async def list_cron_jobs():
|
||||
from cron.jobs import list_jobs
|
||||
from hermes_agent.cron.jobs import list_jobs
|
||||
return list_jobs(include_disabled=True)
|
||||
|
||||
|
||||
@app.get("/api/cron/jobs/{job_id}")
|
||||
async def get_cron_job(job_id: str):
|
||||
from cron.jobs import get_job
|
||||
from hermes_agent.cron.jobs import get_job
|
||||
job = get_job(job_id)
|
||||
if not job:
|
||||
raise HTTPException(status_code=404, detail="Job not found")
|
||||
|
|
@ -2018,7 +2016,7 @@ async def get_cron_job(job_id: str):
|
|||
|
||||
@app.post("/api/cron/jobs")
|
||||
async def create_cron_job(body: CronJobCreate):
|
||||
from cron.jobs import create_job
|
||||
from hermes_agent.cron.jobs import create_job
|
||||
try:
|
||||
job = create_job(prompt=body.prompt, schedule=body.schedule,
|
||||
name=body.name, deliver=body.deliver)
|
||||
|
|
@ -2030,7 +2028,7 @@ async def create_cron_job(body: CronJobCreate):
|
|||
|
||||
@app.put("/api/cron/jobs/{job_id}")
|
||||
async def update_cron_job(job_id: str, body: CronJobUpdate):
|
||||
from cron.jobs import update_job
|
||||
from hermes_agent.cron.jobs import update_job
|
||||
job = update_job(job_id, body.updates)
|
||||
if not job:
|
||||
raise HTTPException(status_code=404, detail="Job not found")
|
||||
|
|
@ -2039,7 +2037,7 @@ async def update_cron_job(job_id: str, body: CronJobUpdate):
|
|||
|
||||
@app.post("/api/cron/jobs/{job_id}/pause")
|
||||
async def pause_cron_job(job_id: str):
|
||||
from cron.jobs import pause_job
|
||||
from hermes_agent.cron.jobs import pause_job
|
||||
job = pause_job(job_id)
|
||||
if not job:
|
||||
raise HTTPException(status_code=404, detail="Job not found")
|
||||
|
|
@ -2048,7 +2046,7 @@ async def pause_cron_job(job_id: str):
|
|||
|
||||
@app.post("/api/cron/jobs/{job_id}/resume")
|
||||
async def resume_cron_job(job_id: str):
|
||||
from cron.jobs import resume_job
|
||||
from hermes_agent.cron.jobs import resume_job
|
||||
job = resume_job(job_id)
|
||||
if not job:
|
||||
raise HTTPException(status_code=404, detail="Job not found")
|
||||
|
|
@ -2057,7 +2055,7 @@ async def resume_cron_job(job_id: str):
|
|||
|
||||
@app.post("/api/cron/jobs/{job_id}/trigger")
|
||||
async def trigger_cron_job(job_id: str):
|
||||
from cron.jobs import trigger_job
|
||||
from hermes_agent.cron.jobs import trigger_job
|
||||
job = trigger_job(job_id)
|
||||
if not job:
|
||||
raise HTTPException(status_code=404, detail="Job not found")
|
||||
|
|
@ -2066,7 +2064,7 @@ async def trigger_cron_job(job_id: str):
|
|||
|
||||
@app.delete("/api/cron/jobs/{job_id}")
|
||||
async def delete_cron_job(job_id: str):
|
||||
from cron.jobs import remove_job
|
||||
from hermes_agent.cron.jobs import remove_job
|
||||
if not remove_job(job_id):
|
||||
raise HTTPException(status_code=404, detail="Job not found")
|
||||
return {"ok": True}
|
||||
|
|
@ -2084,8 +2082,8 @@ class SkillToggle(BaseModel):
|
|||
|
||||
@app.get("/api/skills")
|
||||
async def get_skills():
|
||||
from tools.skills_tool import _find_all_skills
|
||||
from hermes_cli.skills_config import get_disabled_skills
|
||||
from hermes_agent.tools.skills.tool import _find_all_skills
|
||||
from hermes_agent.cli.skills_config import get_disabled_skills
|
||||
config = load_config()
|
||||
disabled = get_disabled_skills(config)
|
||||
skills = _find_all_skills(skip_disabled=True)
|
||||
|
|
@ -2096,7 +2094,7 @@ async def get_skills():
|
|||
|
||||
@app.put("/api/skills/toggle")
|
||||
async def toggle_skill(body: SkillToggle):
|
||||
from hermes_cli.skills_config import get_disabled_skills, save_disabled_skills
|
||||
from hermes_agent.cli.skills_config import get_disabled_skills, save_disabled_skills
|
||||
config = load_config()
|
||||
disabled = get_disabled_skills(config)
|
||||
if body.enabled:
|
||||
|
|
@ -2109,12 +2107,12 @@ async def toggle_skill(body: SkillToggle):
|
|||
|
||||
@app.get("/api/tools/toolsets")
|
||||
async def get_toolsets():
|
||||
from hermes_cli.tools_config import (
|
||||
from hermes_agent.cli.tools_config import (
|
||||
_get_effective_configurable_toolsets,
|
||||
_get_platform_tools,
|
||||
_toolset_has_keys,
|
||||
)
|
||||
from toolsets import resolve_toolset
|
||||
from hermes_agent.tools.toolsets import resolve_toolset
|
||||
|
||||
config = load_config()
|
||||
enabled_toolsets = _get_platform_tools(
|
||||
|
|
@ -2175,8 +2173,8 @@ async def update_config_raw(body: RawConfigUpdate):
|
|||
|
||||
@app.get("/api/analytics/usage")
|
||||
async def get_usage_analytics(days: int = 30):
|
||||
from hermes_state import SessionDB
|
||||
from agent.insights import InsightsEngine
|
||||
from hermes_agent.state import SessionDB
|
||||
from hermes_agent.agent.insights import InsightsEngine
|
||||
|
||||
db = SessionDB()
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ import time
|
|||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_agent.constants import display_hermes_home
|
||||
|
||||
|
||||
_SUBSCRIPTIONS_FILENAME = "webhook_subscriptions.json"
|
||||
|
||||
|
||||
def _hermes_home() -> Path:
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
return get_hermes_home()
|
||||
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ def _save_subscriptions(subs: Dict[str, dict]) -> None:
|
|||
def _get_webhook_config() -> dict:
|
||||
"""Load webhook platform config. Returns {} if not configured."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_agent.cli.config import load_config
|
||||
cfg = load_config()
|
||||
return cfg.get("platforms", {}).get("webhook", {})
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ The gateway ticks the scheduler every 60 seconds. A file lock prevents
|
|||
duplicate execution if multiple processes overlap.
|
||||
"""
|
||||
|
||||
from cron.jobs import (
|
||||
from hermes_agent.cron.jobs import (
|
||||
create_job,
|
||||
get_job,
|
||||
list_jobs,
|
||||
|
|
@ -26,7 +26,7 @@ from cron.jobs import (
|
|||
trigger_job,
|
||||
JOBS_FILE,
|
||||
)
|
||||
from cron.scheduler import tick
|
||||
from hermes_agent.cron.scheduler import tick
|
||||
|
||||
__all__ = [
|
||||
"create_job",
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ import re
|
|||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from typing import Optional, Dict, List, Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from hermes_time import now as _hermes_now
|
||||
from hermes_agent.time import now as _hermes_now
|
||||
|
||||
try:
|
||||
from croniter import croniter
|
||||
|
|
|
|||
|
|
@ -29,14 +29,9 @@ except ImportError:
|
|||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
# Add parent directory to path for imports BEFORE repo-level imports.
|
||||
# Without this, standalone invocations (e.g. after `hermes update` reloads
|
||||
# the module) fail with ModuleNotFoundError for hermes_time et al.
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_cli.config import load_config
|
||||
from hermes_time import now as _hermes_now
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
from hermes_agent.cli.config import load_config
|
||||
from hermes_agent.time import now as _hermes_now
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -76,7 +71,7 @@ _LEGACY_HOME_TARGET_ENV_VARS = {
|
|||
"QQBOT_HOME_CHANNEL": "QQ_HOME_CHANNEL",
|
||||
}
|
||||
|
||||
from cron.jobs import get_due_jobs, mark_job_run, save_job_output, advance_next_run
|
||||
from hermes_agent.cron.jobs import get_due_jobs, mark_job_run, save_job_output, advance_next_run
|
||||
|
||||
# Sentinel: when a cron agent has nothing new to report, it can start its
|
||||
# response with this marker to suppress delivery. Output is still saved
|
||||
|
|
@ -152,7 +147,7 @@ def _resolve_single_delivery_target(job: dict, deliver_value: str) -> Optional[d
|
|||
platform_name, rest = deliver_value.split(":", 1)
|
||||
platform_key = platform_name.lower()
|
||||
|
||||
from tools.send_message_tool import _parse_target_ref
|
||||
from hermes_agent.tools.send_message import _parse_target_ref
|
||||
|
||||
parsed_chat_id, parsed_thread_id, is_explicit = _parse_target_ref(platform_key, rest)
|
||||
if is_explicit:
|
||||
|
|
@ -162,7 +157,7 @@ def _resolve_single_delivery_target(job: dict, deliver_value: str) -> Optional[d
|
|||
|
||||
# Resolve human-friendly labels like "Alice (dm)" to real IDs.
|
||||
try:
|
||||
from gateway.channel_directory import resolve_channel_name
|
||||
from hermes_agent.gateway.channel_directory import resolve_channel_name
|
||||
resolved = resolve_channel_name(platform_key, chat_id)
|
||||
if resolved:
|
||||
parsed_chat_id, parsed_thread_id, resolved_is_explicit = _parse_target_ref(platform_key, resolved)
|
||||
|
|
@ -285,8 +280,8 @@ def _deliver_result(job: dict, content: str, adapters=None, loop=None) -> Option
|
|||
return msg
|
||||
return None # local-only jobs don't deliver — not a failure
|
||||
|
||||
from tools.send_message_tool import _send_to_platform
|
||||
from gateway.config import load_gateway_config, Platform
|
||||
from hermes_agent.tools.send_message import _send_to_platform
|
||||
from hermes_agent.gateway.config import load_gateway_config, Platform
|
||||
|
||||
platform_map = {
|
||||
"telegram": Platform.TELEGRAM,
|
||||
|
|
@ -332,7 +327,7 @@ def _deliver_result(job: dict, content: str, adapters=None, loop=None) -> Option
|
|||
delivery_content = content
|
||||
|
||||
# Extract MEDIA: tags so attachments are forwarded as files, not raw text
|
||||
from gateway.platforms.base import BasePlatformAdapter
|
||||
from hermes_agent.gateway.platforms.base import BasePlatformAdapter
|
||||
media_files, cleaned_delivery_content = BasePlatformAdapter.extract_media(delivery_content)
|
||||
|
||||
try:
|
||||
|
|
@ -508,7 +503,7 @@ def _run_job_script(script_path: str) -> tuple[bool, str]:
|
|||
(success, output) — on failure *output* contains the error message so the
|
||||
LLM can report the problem to the user.
|
||||
"""
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
scripts_dir = get_hermes_home() / "scripts"
|
||||
scripts_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
|
@ -550,7 +545,7 @@ def _run_job_script(script_path: str) -> tuple[bool, str]:
|
|||
|
||||
# Redact secrets from both stdout and stderr before any return path.
|
||||
try:
|
||||
from agent.redact import redact_sensitive_text
|
||||
from hermes_agent.agent.redact import redact_sensitive_text
|
||||
stdout = redact_sensitive_text(stdout)
|
||||
stderr = redact_sensitive_text(stderr)
|
||||
except Exception:
|
||||
|
|
@ -663,7 +658,7 @@ def _build_job_prompt(job: dict, prerun_script: Optional[tuple] = None) -> str:
|
|||
if not skill_names:
|
||||
return prompt
|
||||
|
||||
from tools.skills_tool import skill_view
|
||||
from hermes_agent.tools.skills.tool import skill_view
|
||||
|
||||
parts = []
|
||||
skipped: list[str] = []
|
||||
|
|
@ -707,13 +702,13 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
Returns:
|
||||
Tuple of (success, full_output_doc, final_response, error_message)
|
||||
"""
|
||||
from run_agent import AIAgent
|
||||
from hermes_agent.agent.loop import AIAgent
|
||||
|
||||
# Initialize SQLite session store so cron job messages are persisted
|
||||
# and discoverable via session_search (same pattern as gateway/run.py).
|
||||
_session_db = None
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
_session_db = SessionDB()
|
||||
except Exception as e:
|
||||
logger.debug("Job '%s': SQLite session store not available: %s", job.get("id", "?"), e)
|
||||
|
|
@ -757,7 +752,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
|
||||
# Use ContextVars for per-job session/delivery state so parallel jobs
|
||||
# don't clobber each other's targets (os.environ is process-global).
|
||||
from gateway.session_context import set_session_vars, clear_session_vars, _VAR_MAP
|
||||
from hermes_agent.gateway.session_context import set_session_vars, clear_session_vars, _VAR_MAP
|
||||
|
||||
_ctx_tokens = set_session_vars(
|
||||
platform=origin["platform"] if origin else "",
|
||||
|
|
@ -802,7 +797,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
|
||||
# Apply IPv4 preference if configured.
|
||||
try:
|
||||
from hermes_constants import apply_ipv4_preference
|
||||
from hermes_agent.constants import apply_ipv4_preference
|
||||
_net_cfg = _cfg.get("network", {})
|
||||
if isinstance(_net_cfg, dict) and _net_cfg.get("force_ipv4"):
|
||||
apply_ipv4_preference(force=True)
|
||||
|
|
@ -810,7 +805,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
pass
|
||||
|
||||
# Reasoning config from config.yaml
|
||||
from hermes_constants import parse_reasoning_effort
|
||||
from hermes_agent.constants import parse_reasoning_effort
|
||||
effort = str(_cfg.get("agent", {}).get("reasoning_effort", "")).strip()
|
||||
reasoning_config = parse_reasoning_effort(effort)
|
||||
|
||||
|
|
@ -837,7 +832,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
# Provider routing
|
||||
pr = _cfg.get("provider_routing", {})
|
||||
|
||||
from hermes_cli.runtime_provider import (
|
||||
from hermes_agent.cli.runtime_provider import (
|
||||
resolve_runtime_provider,
|
||||
format_runtime_provider_error,
|
||||
)
|
||||
|
|
@ -857,7 +852,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
runtime_provider = str(runtime.get("provider") or "").strip().lower()
|
||||
if runtime_provider:
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
from hermes_agent.providers.credential_pool import load_pool
|
||||
pool = load_pool(runtime_provider)
|
||||
if pool.has_credentials():
|
||||
credential_pool = pool
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ suppress delivery.
|
|||
import logging
|
||||
import threading
|
||||
|
||||
logger = logging.getLogger("hooks.boot-md")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
HERMES_HOME = get_hermes_home()
|
||||
BOOT_FILE = HERMES_HOME / "BOOT.md"
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ def _build_boot_prompt(content: str) -> str:
|
|||
def _run_boot_agent(content: str) -> None:
|
||||
"""Spawn a one-shot agent session to execute the boot instructions."""
|
||||
try:
|
||||
from run_agent import AIAgent
|
||||
from hermes_agent.agent.loop import AIAgent
|
||||
|
||||
prompt = _build_boot_prompt(content)
|
||||
agent = AIAgent(
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import logging
|
|||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from utils import atomic_json_write
|
||||
from hermes_agent.cli.config import get_hermes_home
|
||||
from hermes_agent.utils import atomic_json_write
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ def build_channel_directory(adapters: Dict[Any, Any]) -> Dict[str, Any]:
|
|||
|
||||
Returns the directory dict and writes it to DIRECTORY_PATH.
|
||||
"""
|
||||
from gateway.config import Platform
|
||||
from hermes_agent.gateway.config import Platform
|
||||
|
||||
platforms: Dict[str, List[Dict[str, str]]] = {}
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ def _build_slack(adapter) -> List[Dict[str, str]]:
|
|||
return _build_from_sessions("slack")
|
||||
|
||||
try:
|
||||
from tools.send_message_tool import _send_slack # noqa: F401
|
||||
from hermes_agent.tools.send_message import _send_slack # noqa: F401
|
||||
# Use the Slack Web API directly if available
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ from dataclasses import dataclass, field
|
|||
from typing import Dict, List, Optional, Any
|
||||
from enum import Enum
|
||||
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from utils import is_truthy_value
|
||||
from hermes_agent.cli.config import get_hermes_home
|
||||
from hermes_agent.utils import is_truthy_value
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -821,7 +821,7 @@ def _validate_gateway_config(config: "GatewayConfig") -> None:
|
|||
# without changing placeholder values get a clear startup error instead
|
||||
# of a confusing "auth failed" from the platform API.
|
||||
try:
|
||||
from hermes_cli.auth import has_usable_secret
|
||||
from hermes_agent.cli.auth.auth import has_usable_secret
|
||||
except ImportError:
|
||||
has_usable_secret = None # type: ignore[assignment]
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from datetime import datetime
|
|||
from dataclasses import dataclass
|
||||
from typing import Dict, List, Optional, Any
|
||||
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from hermes_agent.cli.config import get_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from typing import Any, Callable, Dict, List, Optional
|
|||
|
||||
import yaml
|
||||
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from hermes_agent.cli.config import get_hermes_home
|
||||
|
||||
|
||||
HOOKS_DIR = get_hermes_home() / "hooks"
|
||||
|
|
@ -54,7 +54,7 @@ class HookRegistry:
|
|||
def _register_builtin_hooks(self) -> None:
|
||||
"""Register built-in hooks that are always active."""
|
||||
try:
|
||||
from gateway.builtin_hooks.boot_md import handle as boot_md_handle
|
||||
from hermes_agent.gateway.builtin_hooks.boot_md import handle as boot_md_handle
|
||||
|
||||
self._handlers.setdefault("gateway:startup", []).append(boot_md_handle)
|
||||
self._loaded_hooks.append({
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import logging
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from hermes_agent.cli.config import get_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ def _append_to_sqlite(session_id: str, message: dict) -> None:
|
|||
"""Append a message to the SQLite session database."""
|
||||
db = None
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
db = SessionDB()
|
||||
db.append_message(
|
||||
session_id=session_id,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import time
|
|||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from hermes_constants import get_hermes_dir
|
||||
from hermes_agent.constants import get_hermes_dir
|
||||
|
||||
|
||||
# Unambiguous alphabet -- excludes 0/O, 1/I to prevent confusion
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import time
|
|||
import uuid
|
||||
from typing import Any, Dict, List, Optional
|
||||
from aiohttp import web
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from gateway.platforms.base import (
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
SendResult,
|
||||
is_network_accessible,
|
||||
|
|
@ -279,7 +279,7 @@ class ResponseStore:
|
|||
self._max_size = max_size
|
||||
if db_path is None:
|
||||
try:
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from hermes_agent.cli.config import get_hermes_home
|
||||
db_path = str(get_hermes_home() / "response_store.db")
|
||||
except Exception:
|
||||
db_path = ":memory:"
|
||||
|
|
@ -513,7 +513,7 @@ def _derive_chat_session_id(
|
|||
|
||||
_CRON_AVAILABLE = False
|
||||
try:
|
||||
from cron.jobs import (
|
||||
from hermes_agent.cron.jobs import (
|
||||
list_jobs as _cron_list,
|
||||
get_job as _cron_get,
|
||||
create_job as _cron_create,
|
||||
|
|
@ -592,7 +592,7 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
if explicit and explicit.strip():
|
||||
return explicit.strip()
|
||||
try:
|
||||
from hermes_cli.profiles import get_active_profile_name
|
||||
from hermes_agent.cli.profiles import get_active_profile_name
|
||||
profile = get_active_profile_name()
|
||||
if profile and profile not in ("default", "custom"):
|
||||
return profile
|
||||
|
|
@ -668,7 +668,7 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
"""
|
||||
if self._session_db is None:
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
from hermes_agent.state import SessionDB
|
||||
self._session_db = SessionDB()
|
||||
except Exception as e:
|
||||
logger.debug("SessionDB unavailable for API server: %s", e)
|
||||
|
|
@ -695,9 +695,9 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
from config.yaml platform_toolsets.api_server (same as all other
|
||||
gateway platforms), falling back to the hermes-api-server default.
|
||||
"""
|
||||
from run_agent import AIAgent
|
||||
from gateway.run import _resolve_runtime_agent_kwargs, _resolve_gateway_model, _load_gateway_config
|
||||
from hermes_cli.tools_config import _get_platform_tools
|
||||
from hermes_agent.agent.loop import AIAgent
|
||||
from hermes_agent.gateway.run import _resolve_runtime_agent_kwargs, _resolve_gateway_model, _load_gateway_config
|
||||
from hermes_agent.cli.tools_config import _get_platform_tools
|
||||
|
||||
runtime_kwargs = _resolve_runtime_agent_kwargs()
|
||||
model = _resolve_gateway_model()
|
||||
|
|
@ -709,7 +709,7 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
|
||||
# Load fallback provider chain so the API server platform has the
|
||||
# same fallback behaviour as Telegram/Discord/Slack (fixes #4954).
|
||||
from gateway.run import GatewayRunner
|
||||
from hermes_agent.gateway.run import GatewayRunner
|
||||
fallback_model = GatewayRunner._load_fallback_model()
|
||||
|
||||
agent = AIAgent(
|
||||
|
|
@ -746,7 +746,7 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
dashboard can display full status without needing a shared PID file or
|
||||
/proc access. No authentication required.
|
||||
"""
|
||||
from gateway.status import read_runtime_status
|
||||
from hermes_agent.gateway.status import read_runtime_status
|
||||
|
||||
runtime = read_runtime_status() or {}
|
||||
return web.json_response({
|
||||
|
|
@ -927,7 +927,7 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
return
|
||||
if name.startswith("_"):
|
||||
return
|
||||
from agent.display import get_tool_emoji
|
||||
from hermes_agent.agent.display import get_tool_emoji
|
||||
emoji = get_tool_emoji(name)
|
||||
label = preview or name
|
||||
_stream_q.put(("__tool_progress__", {
|
||||
|
|
@ -2505,7 +2505,7 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
# Ported from openclaw/openclaw#64586.
|
||||
if is_network_accessible(self._host) and self._api_key:
|
||||
try:
|
||||
from hermes_cli.auth import has_usable_secret
|
||||
from hermes_agent.cli.auth.auth import has_usable_secret
|
||||
if not has_usable_secret(self._api_key, min_length=8):
|
||||
logger.error(
|
||||
"[%s] Refusing to start: API_SERVER_KEY is set to a "
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import uuid
|
|||
from abc import ABC, abstractmethod
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
from utils import normalize_proxy_url
|
||||
from hermes_agent.utils import normalize_proxy_url
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -235,12 +235,9 @@ from pathlib import Path
|
|||
from typing import Dict, List, Optional, Any, Callable, Awaitable, Tuple
|
||||
from enum import Enum
|
||||
|
||||
from pathlib import Path as _Path
|
||||
sys.path.insert(0, str(_Path(__file__).resolve().parents[2]))
|
||||
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from gateway.session import SessionSource, build_session_key
|
||||
from hermes_constants import get_hermes_dir
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.session import SessionSource, build_session_key
|
||||
from hermes_agent.constants import get_hermes_dir
|
||||
|
||||
|
||||
GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGE = (
|
||||
|
|
@ -296,7 +293,7 @@ async def _ssrf_redirect_guard(response):
|
|||
"""
|
||||
if response.is_redirect and response.next_request:
|
||||
redirect_url = str(response.next_request.url)
|
||||
from tools.url_safety import is_safe_url
|
||||
from hermes_agent.tools.security.urls import is_safe_url
|
||||
if not is_safe_url(redirect_url):
|
||||
raise ValueError(
|
||||
f"Blocked redirect to private/internal address: {safe_url_for_log(redirect_url)}"
|
||||
|
|
@ -385,7 +382,7 @@ async def cache_image_from_url(url: str, ext: str = ".jpg", retries: int = 2) ->
|
|||
Raises:
|
||||
ValueError: If the URL targets a private/internal network (SSRF protection).
|
||||
"""
|
||||
from tools.url_safety import is_safe_url
|
||||
from hermes_agent.tools.security.urls import is_safe_url
|
||||
if not is_safe_url(url):
|
||||
raise ValueError(f"Blocked unsafe URL (SSRF protection): {safe_url_for_log(url)}")
|
||||
|
||||
|
|
@ -500,7 +497,7 @@ async def cache_audio_from_url(url: str, ext: str = ".ogg", retries: int = 2) ->
|
|||
Raises:
|
||||
ValueError: If the URL targets a private/internal network (SSRF protection).
|
||||
"""
|
||||
from tools.url_safety import is_safe_url
|
||||
from hermes_agent.tools.security.urls import is_safe_url
|
||||
if not is_safe_url(url):
|
||||
raise ValueError(f"Blocked unsafe URL (SSRF protection): {safe_url_for_log(url)}")
|
||||
|
||||
|
|
@ -942,7 +939,7 @@ class BasePlatformAdapter(ABC):
|
|||
self._fatal_error_message = None
|
||||
self._fatal_error_retryable = True
|
||||
try:
|
||||
from gateway.status import write_runtime_status
|
||||
from hermes_agent.gateway.status import write_runtime_status
|
||||
write_runtime_status(platform=self.platform.value, platform_state="connected", error_code=None, error_message=None)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -952,7 +949,7 @@ class BasePlatformAdapter(ABC):
|
|||
if self.has_fatal_error:
|
||||
return
|
||||
try:
|
||||
from gateway.status import write_runtime_status
|
||||
from hermes_agent.gateway.status import write_runtime_status
|
||||
write_runtime_status(platform=self.platform.value, platform_state="disconnected", error_code=None, error_message=None)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -963,7 +960,7 @@ class BasePlatformAdapter(ABC):
|
|||
self._fatal_error_message = message
|
||||
self._fatal_error_retryable = retryable
|
||||
try:
|
||||
from gateway.status import write_runtime_status
|
||||
from hermes_agent.gateway.status import write_runtime_status
|
||||
write_runtime_status(
|
||||
platform=self.platform.value,
|
||||
platform_state="fatal",
|
||||
|
|
@ -983,7 +980,7 @@ class BasePlatformAdapter(ABC):
|
|||
|
||||
def _acquire_platform_lock(self, scope: str, identity: str, resource_desc: str) -> bool:
|
||||
"""Acquire a scoped lock for this adapter. Returns True on success."""
|
||||
from gateway.status import acquire_scoped_lock
|
||||
from hermes_agent.gateway.status import acquire_scoped_lock
|
||||
self._platform_lock_scope = scope
|
||||
self._platform_lock_identity = identity
|
||||
acquired, existing = acquire_scoped_lock(
|
||||
|
|
@ -1006,7 +1003,7 @@ class BasePlatformAdapter(ABC):
|
|||
identity = getattr(self, '_platform_lock_identity', None)
|
||||
if not identity:
|
||||
return
|
||||
from gateway.status import release_scoped_lock
|
||||
from hermes_agent.gateway.status import release_scoped_lock
|
||||
release_scoped_lock(self._platform_lock_scope, identity)
|
||||
self._platform_lock_identity = None
|
||||
|
||||
|
|
@ -1705,7 +1702,7 @@ class BasePlatformAdapter(ABC):
|
|||
# session lifecycle and its cleanup races with the running task
|
||||
# (see PR #4926).
|
||||
cmd = event.get_command()
|
||||
from hermes_cli.commands import should_bypass_active_session
|
||||
from hermes_agent.cli.commands import should_bypass_active_session
|
||||
|
||||
if should_bypass_active_session(cmd):
|
||||
logger.debug(
|
||||
|
|
@ -1879,7 +1876,7 @@ class BasePlatformAdapter(ABC):
|
|||
and not media_files
|
||||
and event.source.chat_id not in self._auto_tts_disabled_chats):
|
||||
try:
|
||||
from tools.tts_tool import text_to_speech_tool, check_tts_requirements
|
||||
from hermes_agent.tools.media.tts import text_to_speech_tool, check_tts_requirements
|
||||
if check_tts_requirements():
|
||||
import json as _json
|
||||
speech_text = re.sub(r'[*_`#\[\]()]', '', text_content)[:4000].strip()
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ from urllib.parse import quote
|
|||
|
||||
import httpx
|
||||
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from gateway.platforms.base import (
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
MessageEvent,
|
||||
MessageType,
|
||||
|
|
@ -30,7 +30,7 @@ from gateway.platforms.base import (
|
|||
cache_audio_from_bytes,
|
||||
cache_document_from_bytes,
|
||||
)
|
||||
from gateway.platforms.helpers import strip_markdown
|
||||
from hermes_agent.gateway.platforms.helpers import strip_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -502,7 +502,7 @@ class BlueBubblesAdapter(BasePlatformAdapter):
|
|||
metadata: Optional[Dict[str, Any]] = None,
|
||||
) -> SendResult:
|
||||
try:
|
||||
from gateway.platforms.base import cache_image_from_url
|
||||
from hermes_agent.gateway.platforms.base import cache_image_from_url
|
||||
|
||||
local_path = await cache_image_from_url(image_url)
|
||||
return await self._send_attachment(chat_id, local_path, caption=caption)
|
||||
|
|
|
|||
|
|
@ -87,9 +87,9 @@ except ImportError:
|
|||
open_api_models = None
|
||||
tea_util_models = None
|
||||
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from gateway.platforms.helpers import MessageDeduplicator
|
||||
from gateway.platforms.base import (
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.platforms.helpers import MessageDeduplicator
|
||||
from hermes_agent.gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
MessageEvent,
|
||||
MessageType,
|
||||
|
|
|
|||
|
|
@ -36,15 +36,11 @@ except ImportError:
|
|||
Intents = Any
|
||||
commands = None
|
||||
|
||||
import sys
|
||||
from pathlib import Path as _Path
|
||||
sys.path.insert(0, str(_Path(__file__).resolve().parents[2]))
|
||||
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
import re
|
||||
|
||||
from gateway.platforms.helpers import MessageDeduplicator, ThreadParticipationTracker
|
||||
from gateway.platforms.base import (
|
||||
from hermes_agent.gateway.platforms.helpers import MessageDeduplicator, ThreadParticipationTracker
|
||||
from hermes_agent.gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
MessageEvent,
|
||||
MessageType,
|
||||
|
|
@ -57,7 +53,7 @@ from gateway.platforms.base import (
|
|||
cache_document_from_bytes,
|
||||
SUPPORTED_DOCUMENT_TYPES,
|
||||
)
|
||||
from tools.url_safety import is_safe_url
|
||||
from hermes_agent.tools.security.urls import is_safe_url
|
||||
|
||||
|
||||
def _clean_discord_id(entry: str) -> str:
|
||||
|
|
@ -601,7 +597,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
intents.voice_states = True
|
||||
|
||||
# Resolve proxy (DISCORD_PROXY > generic env vars > macOS system proxy)
|
||||
from gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_bot
|
||||
from hermes_agent.gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_bot
|
||||
proxy_url = resolve_proxy_url(platform_env_var="DISCORD_PROXY")
|
||||
if proxy_url:
|
||||
logger.info("[%s] Using proxy for Discord: %s", self.name, proxy_url)
|
||||
|
|
@ -970,7 +966,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
reported in ``raw_response['warnings']`` so the caller can surface
|
||||
partial-send issues.
|
||||
"""
|
||||
from tools.send_message_tool import _derive_forum_thread_name
|
||||
from hermes_agent.tools.send_message import _derive_forum_thread_name
|
||||
|
||||
formatted = self.format_message(content)
|
||||
chunks = self.truncate_message(formatted, self.MAX_MESSAGE_LENGTH)
|
||||
|
|
@ -1032,7 +1028,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
ForumChannel accepts the same file/files/content kwargs as
|
||||
``channel.send``, creating the thread and starter message atomically.
|
||||
"""
|
||||
from tools.send_message_tool import _derive_forum_thread_name
|
||||
from hermes_agent.tools.send_message import _derive_forum_thread_name
|
||||
|
||||
if not thread_name:
|
||||
# Prefer the text content, fall back to the first attached
|
||||
|
|
@ -1507,7 +1503,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
|
||||
async def _process_voice_input(self, guild_id: int, user_id: int, pcm_data: bytes):
|
||||
"""Convert PCM -> WAV -> STT -> callback."""
|
||||
from tools.voice_mode import is_whisper_hallucination
|
||||
from hermes_agent.tools.media.voice import is_whisper_hallucination
|
||||
|
||||
tmp_f = tempfile.NamedTemporaryFile(suffix=".wav", prefix="vc_listen_", delete=False)
|
||||
wav_path = tmp_f.name
|
||||
|
|
@ -1515,7 +1511,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
try:
|
||||
await asyncio.to_thread(VoiceReceiver.pcm_to_wav, pcm_data, wav_path)
|
||||
|
||||
from tools.transcription_tools import transcribe_audio
|
||||
from hermes_agent.tools.media.transcription import transcribe_audio
|
||||
result = await asyncio.to_thread(transcribe_audio, wav_path)
|
||||
|
||||
if not result.get("success"):
|
||||
|
|
@ -1627,7 +1623,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
|
||||
# Download the image and send as a Discord file attachment
|
||||
# (Discord renders attachments inline, unlike plain URLs)
|
||||
from gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_aiohttp
|
||||
from hermes_agent.gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_aiohttp
|
||||
_proxy = resolve_proxy_url(platform_env_var="DISCORD_PROXY")
|
||||
_sess_kw, _req_kw = proxy_kwargs_for_aiohttp(_proxy)
|
||||
async with aiohttp.ClientSession(**_sess_kw) as session:
|
||||
|
|
@ -1706,7 +1702,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
|
||||
# Download the GIF and send as a Discord file attachment
|
||||
# (Discord renders .gif attachments as auto-playing animations inline)
|
||||
from gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_aiohttp
|
||||
from hermes_agent.gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_aiohttp
|
||||
_proxy = resolve_proxy_url(platform_env_var="DISCORD_PROXY")
|
||||
_sess_kw, _req_kw = proxy_kwargs_for_aiohttp(_proxy)
|
||||
async with aiohttp.ClientSession(**_sess_kw) as session:
|
||||
|
|
@ -2137,7 +2133,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
# hermes_cli/commands.py automatically appear as Discord slash
|
||||
# commands without needing a manual entry here.
|
||||
try:
|
||||
from hermes_cli.commands import COMMAND_REGISTRY, _is_gateway_available, _resolve_config_gates
|
||||
from hermes_agent.cli.commands import COMMAND_REGISTRY, _is_gateway_available, _resolve_config_gates
|
||||
|
||||
already_registered = set()
|
||||
try:
|
||||
|
|
@ -2227,7 +2223,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
skill name and its description.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.commands import discord_skill_commands_by_category
|
||||
from hermes_agent.cli.commands import discord_skill_commands_by_category
|
||||
|
||||
existing_names = set()
|
||||
try:
|
||||
|
|
@ -2481,7 +2477,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
|
||||
def _resolve_channel_prompt(self, channel_id: str, parent_id: str | None = None) -> str | None:
|
||||
"""Resolve a Discord per-channel prompt, preferring the exact channel over its parent."""
|
||||
from gateway.platforms.base import resolve_channel_prompt
|
||||
from hermes_agent.gateway.platforms.base import resolve_channel_prompt
|
||||
return resolve_channel_prompt(self.config.extra, channel_id, parent_id)
|
||||
|
||||
def _discord_require_mention(self) -> bool:
|
||||
|
|
@ -2747,7 +2743,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
channel = await self._client.fetch_channel(int(target_id))
|
||||
|
||||
try:
|
||||
from hermes_cli.providers import get_label
|
||||
from hermes_agent.cli.providers import get_label
|
||||
provider_label = get_label(current_provider)
|
||||
except Exception:
|
||||
provider_label = current_provider
|
||||
|
|
@ -2932,7 +2928,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
f"Blocked unsafe attachment URL (SSRF protection): {att.url}"
|
||||
)
|
||||
import aiohttp
|
||||
from gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_aiohttp
|
||||
from hermes_agent.gateway.platforms.base import resolve_proxy_url, proxy_kwargs_for_aiohttp
|
||||
_proxy = resolve_proxy_url(platform_env_var="DISCORD_PROXY")
|
||||
_sess_kw, _req_kw = proxy_kwargs_for_aiohttp(_proxy)
|
||||
async with aiohttp.ClientSession(**_sess_kw) as session:
|
||||
|
|
@ -3235,7 +3231,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
|
||||
def _text_batch_key(self, event: MessageEvent) -> str:
|
||||
"""Session-scoped key for text message batching."""
|
||||
from gateway.session import build_session_key
|
||||
from hermes_agent.gateway.session import build_session_key
|
||||
return build_session_key(
|
||||
event.source,
|
||||
group_sessions_per_user=self.config.extra.get("group_sessions_per_user", True),
|
||||
|
|
@ -3372,7 +3368,7 @@ if DISCORD_AVAILABLE:
|
|||
|
||||
# Unblock the waiting agent thread via the gateway approval queue
|
||||
try:
|
||||
from tools.approval import resolve_gateway_approval
|
||||
from hermes_agent.tools.security.approval import resolve_gateway_approval
|
||||
count = resolve_gateway_approval(self.session_key, choice)
|
||||
logger.info(
|
||||
"Discord button resolved %d approval(s) for session %s (choice=%s, user=%s)",
|
||||
|
|
@ -3460,7 +3456,7 @@ if DISCORD_AVAILABLE:
|
|||
|
||||
# Write response file
|
||||
try:
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
home = get_hermes_home()
|
||||
response_path = home / ".update_response"
|
||||
tmp = response_path.with_suffix(".tmp")
|
||||
|
|
@ -3675,7 +3671,7 @@ if DISCORD_AVAILABLE:
|
|||
self._build_provider_select()
|
||||
|
||||
try:
|
||||
from hermes_cli.providers import get_label
|
||||
from hermes_agent.cli.providers import get_label
|
||||
provider_label = get_label(self.current_provider)
|
||||
except Exception:
|
||||
provider_label = self.current_provider
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ from email import encoders
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from gateway.platforms.base import (
|
||||
from hermes_agent.gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
MessageEvent,
|
||||
MessageType,
|
||||
|
|
@ -40,7 +40,7 @@ from gateway.platforms.base import (
|
|||
cache_document_from_bytes,
|
||||
cache_image_from_bytes,
|
||||
)
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
# Automated sender patterns — emails from these are silently ignored
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ except ImportError:
|
|||
FEISHU_WEBSOCKET_AVAILABLE = websockets is not None
|
||||
FEISHU_WEBHOOK_AVAILABLE = aiohttp is not None
|
||||
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from gateway.platforms.base import (
|
||||
from hermes_agent.gateway.config import Platform, PlatformConfig
|
||||
from hermes_agent.gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
MessageEvent,
|
||||
MessageType,
|
||||
|
|
@ -108,8 +108,8 @@ from gateway.platforms.base import (
|
|||
cache_audio_from_bytes,
|
||||
cache_image_from_bytes,
|
||||
)
|
||||
from gateway.status import acquire_scoped_lock, release_scoped_lock
|
||||
from hermes_constants import get_hermes_home
|
||||
from hermes_agent.gateway.status import acquire_scoped_lock, release_scoped_lock
|
||||
from hermes_agent.constants import get_hermes_home
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -414,7 +414,7 @@ def _strip_markdown_to_plain_text(text: str) -> str:
|
|||
Feishu-specific patterns (blockquotes, strikethrough, underline tags,
|
||||
horizontal rules, \\r\\n normalisation).
|
||||
"""
|
||||
from gateway.platforms.helpers import strip_markdown
|
||||
from hermes_agent.gateway.platforms.helpers import strip_markdown
|
||||
plain = text.replace("\r\n", "\n")
|
||||
plain = _MARKDOWN_LINK_RE.sub(lambda m: f"{m.group(1)} ({m.group(2).strip()})", plain)
|
||||
plain = re.sub(r"^>\s?", "", plain, flags=re.MULTILINE)
|
||||
|
|
@ -2039,7 +2039,7 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
logging, and reaction. Scheduling follows the same
|
||||
``run_coroutine_threadsafe`` pattern used by ``_on_message_event``.
|
||||
"""
|
||||
from gateway.platforms.feishu_comment import handle_drive_comment_event
|
||||
from hermes_agent.gateway.platforms.feishu_comment import handle_drive_comment_event
|
||||
|
||||
loop = self._loop
|
||||
if not self._loop_accepts_callbacks(loop):
|
||||
|
|
@ -2151,7 +2151,7 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
logger.debug("[Feishu] Approval %s already resolved or unknown", approval_id)
|
||||
return
|
||||
try:
|
||||
from tools.approval import resolve_gateway_approval
|
||||
from hermes_agent.tools.security.approval import resolve_gateway_approval
|
||||
count = resolve_gateway_approval(state["session_key"], choice)
|
||||
logger.info(
|
||||
"Feishu button resolved %d approval(s) for session %s (choice=%s, user=%s)",
|
||||
|
|
@ -2542,7 +2542,7 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
)
|
||||
|
||||
def _media_batch_key(self, event: MessageEvent) -> str:
|
||||
from gateway.session import build_session_key
|
||||
from hermes_agent.gateway.session import build_session_key
|
||||
|
||||
session_key = build_session_key(
|
||||
event.source,
|
||||
|
|
@ -2619,7 +2619,7 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
default_ext: str,
|
||||
preferred_name: str,
|
||||
) -> tuple[str, str]:
|
||||
from tools.url_safety import is_safe_url
|
||||
from hermes_agent.tools.security.urls import is_safe_url
|
||||
if not is_safe_url(file_url):
|
||||
raise ValueError(f"Blocked unsafe URL (SSRF protection): {file_url[:80]}")
|
||||
|
||||
|
|
@ -2822,7 +2822,7 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
|
||||
def _text_batch_key(self, event: MessageEvent) -> str:
|
||||
"""Return the session-scoped key used for Feishu text aggregation."""
|
||||
from gateway.session import build_session_key
|
||||
from hermes_agent.gateway.session import build_session_key
|
||||
|
||||
return build_session_key(
|
||||
event.source,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue