mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
refactor: remove config TypedDicts and fix ImportError propagation in clipboard
Remove 44 TypedDict classes from config.py — they were already stale (11 missing keys) and load_config() still returns Dict[str, Any], so they provided zero type-checking value. Keep the int() coercions and Dict[str, Any] annotations which are real fixes. Fix _wayland_save() swallowing ImportError at DEBUG level by adding an explicit except ImportError: raise before the broad except Exception.
This commit is contained in:
parent
98eb32f39a
commit
415043315f
4 changed files with 9 additions and 386 deletions
|
|
@ -387,6 +387,8 @@ def _wayland_save(dest: Path) -> bool:
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.debug("wl-paste not installed — Wayland clipboard unavailable")
|
logger.debug("wl-paste not installed — Wayland clipboard unavailable")
|
||||||
|
except ImportError:
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug("wl-paste clipboard extraction failed: %s", e)
|
logger.debug("wl-paste clipboard extraction failed: %s", e)
|
||||||
dest.unlink(missing_ok=True)
|
dest.unlink(missing_ok=True)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, Optional, List, Tuple, TypedDict, Union
|
from typing import Dict, Any, Optional, List, Tuple
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -343,358 +343,7 @@ def _ensure_hermes_home_managed(home: Path):
|
||||||
# Config loading/saving
|
# Config loading/saving
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
class _AgentConfig(TypedDict):
|
DEFAULT_CONFIG = {
|
||||||
max_turns: int
|
|
||||||
gateway_timeout: int
|
|
||||||
restart_drain_timeout: int
|
|
||||||
service_tier: str
|
|
||||||
tool_use_enforcement: str
|
|
||||||
gateway_timeout_warning: int
|
|
||||||
gateway_notify_interval: int
|
|
||||||
|
|
||||||
class _TerminalConfig(TypedDict):
|
|
||||||
backend: str
|
|
||||||
modal_mode: str
|
|
||||||
cwd: str
|
|
||||||
timeout: int
|
|
||||||
env_passthrough: List[str]
|
|
||||||
docker_image: str
|
|
||||||
docker_forward_env: List[str]
|
|
||||||
docker_env: Dict[str, str]
|
|
||||||
singularity_image: str
|
|
||||||
modal_image: str
|
|
||||||
daytona_image: str
|
|
||||||
container_cpu: int
|
|
||||||
container_memory: int
|
|
||||||
container_disk: int
|
|
||||||
container_persistent: bool
|
|
||||||
docker_volumes: List[str]
|
|
||||||
docker_mount_cwd_to_workspace: bool
|
|
||||||
persistent_shell: bool
|
|
||||||
|
|
||||||
|
|
||||||
class _CamofoxConfig(TypedDict, total=False):
|
|
||||||
managed_persistence: bool
|
|
||||||
|
|
||||||
|
|
||||||
class _BrowserConfig(TypedDict):
|
|
||||||
inactivity_timeout: int
|
|
||||||
command_timeout: int
|
|
||||||
record_sessions: bool
|
|
||||||
allow_private_urls: bool
|
|
||||||
cdp_url: str
|
|
||||||
camofox: _CamofoxConfig
|
|
||||||
|
|
||||||
|
|
||||||
class _CheckpointsConfig(TypedDict):
|
|
||||||
enabled: bool
|
|
||||||
max_snapshots: int
|
|
||||||
|
|
||||||
|
|
||||||
class _CompressionConfig(TypedDict):
|
|
||||||
enabled: bool
|
|
||||||
threshold: float
|
|
||||||
target_ratio: float
|
|
||||||
protect_last_n: int
|
|
||||||
|
|
||||||
|
|
||||||
class _BedrockDiscoveryConfig(TypedDict):
|
|
||||||
enabled: bool
|
|
||||||
provider_filter: List[str]
|
|
||||||
refresh_interval: int
|
|
||||||
|
|
||||||
|
|
||||||
class _BedrockGuardrailConfig(TypedDict):
|
|
||||||
guardrail_identifier: str
|
|
||||||
guardrail_version: str
|
|
||||||
stream_processing_mode: str
|
|
||||||
trace: str
|
|
||||||
|
|
||||||
|
|
||||||
class _BedrockConfig(TypedDict):
|
|
||||||
region: str
|
|
||||||
discovery: _BedrockDiscoveryConfig
|
|
||||||
guardrail: _BedrockGuardrailConfig
|
|
||||||
|
|
||||||
|
|
||||||
class _AuxiliaryTaskConfig(TypedDict, total=False):
|
|
||||||
provider: str
|
|
||||||
model: str
|
|
||||||
base_url: str
|
|
||||||
api_key: str
|
|
||||||
timeout: int
|
|
||||||
extra_body: Dict[str, Any]
|
|
||||||
max_concurrency: int
|
|
||||||
download_timeout: int
|
|
||||||
|
|
||||||
|
|
||||||
class _AuxiliaryConfig(TypedDict):
|
|
||||||
vision: _AuxiliaryTaskConfig
|
|
||||||
web_extract: _AuxiliaryTaskConfig
|
|
||||||
compression: _AuxiliaryTaskConfig
|
|
||||||
session_search: _AuxiliaryTaskConfig
|
|
||||||
skills_hub: _AuxiliaryTaskConfig
|
|
||||||
approval: _AuxiliaryTaskConfig
|
|
||||||
mcp: _AuxiliaryTaskConfig
|
|
||||||
flush_memories: _AuxiliaryTaskConfig
|
|
||||||
title_generation: _AuxiliaryTaskConfig
|
|
||||||
|
|
||||||
|
|
||||||
class _UserMessagePreviewConfig(TypedDict):
|
|
||||||
first_lines: int
|
|
||||||
last_lines: int
|
|
||||||
|
|
||||||
|
|
||||||
class _DisplayConfig(TypedDict):
|
|
||||||
compact: bool
|
|
||||||
personality: str
|
|
||||||
resume_display: str
|
|
||||||
busy_input_mode: str
|
|
||||||
bell_on_complete: bool
|
|
||||||
show_reasoning: bool
|
|
||||||
streaming: bool
|
|
||||||
final_response_markdown: str
|
|
||||||
inline_diffs: bool
|
|
||||||
show_cost: bool
|
|
||||||
skin: str
|
|
||||||
user_message_preview: _UserMessagePreviewConfig
|
|
||||||
interim_assistant_messages: bool
|
|
||||||
tool_progress_command: bool
|
|
||||||
tool_progress_overrides: Dict[str, Any]
|
|
||||||
tool_preview_length: int
|
|
||||||
platforms: Dict[str, Any]
|
|
||||||
|
|
||||||
|
|
||||||
class _DashboardConfig(TypedDict):
|
|
||||||
theme: str
|
|
||||||
|
|
||||||
|
|
||||||
class _PrivacyConfig(TypedDict):
|
|
||||||
redact_pii: bool
|
|
||||||
|
|
||||||
|
|
||||||
class _EdgeTtsConfig(TypedDict):
|
|
||||||
voice: str
|
|
||||||
|
|
||||||
|
|
||||||
class _ElevenlabsTtsConfig(TypedDict):
|
|
||||||
voice_id: str
|
|
||||||
model_id: str
|
|
||||||
|
|
||||||
|
|
||||||
class _OpenaiTtsConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
voice: str
|
|
||||||
|
|
||||||
|
|
||||||
class _XaiTtsConfig(TypedDict):
|
|
||||||
voice_id: str
|
|
||||||
language: str
|
|
||||||
sample_rate: int
|
|
||||||
bit_rate: int
|
|
||||||
|
|
||||||
|
|
||||||
class _MistralTtsConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
voice_id: str
|
|
||||||
|
|
||||||
|
|
||||||
class _NeuttsConfig(TypedDict):
|
|
||||||
ref_audio: str
|
|
||||||
ref_text: str
|
|
||||||
model: str
|
|
||||||
device: str
|
|
||||||
|
|
||||||
|
|
||||||
class _TtsConfig(TypedDict):
|
|
||||||
provider: str
|
|
||||||
edge: _EdgeTtsConfig
|
|
||||||
elevenlabs: _ElevenlabsTtsConfig
|
|
||||||
openai: _OpenaiTtsConfig
|
|
||||||
xai: _XaiTtsConfig
|
|
||||||
mistral: _MistralTtsConfig
|
|
||||||
neutts: _NeuttsConfig
|
|
||||||
|
|
||||||
|
|
||||||
class _LocalSttConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
language: str
|
|
||||||
|
|
||||||
|
|
||||||
class _OpenaiSttConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
|
|
||||||
|
|
||||||
class _MistralSttConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
|
|
||||||
|
|
||||||
class _SttConfig(TypedDict):
|
|
||||||
enabled: bool
|
|
||||||
provider: str
|
|
||||||
local: _LocalSttConfig
|
|
||||||
openai: _OpenaiSttConfig
|
|
||||||
mistral: _MistralSttConfig
|
|
||||||
|
|
||||||
|
|
||||||
class _VoiceConfig(TypedDict):
|
|
||||||
record_key: str
|
|
||||||
max_recording_seconds: int
|
|
||||||
auto_tts: bool
|
|
||||||
silence_threshold: int
|
|
||||||
silence_duration: float
|
|
||||||
|
|
||||||
|
|
||||||
class _HumanDelayConfig(TypedDict):
|
|
||||||
mode: str
|
|
||||||
min_ms: int
|
|
||||||
max_ms: int
|
|
||||||
|
|
||||||
|
|
||||||
class _ContextConfig(TypedDict):
|
|
||||||
engine: str
|
|
||||||
|
|
||||||
|
|
||||||
class _MemoryConfig(TypedDict):
|
|
||||||
memory_enabled: bool
|
|
||||||
user_profile_enabled: bool
|
|
||||||
memory_char_limit: int
|
|
||||||
user_char_limit: int
|
|
||||||
provider: str
|
|
||||||
|
|
||||||
|
|
||||||
class _DelegationConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
provider: str
|
|
||||||
base_url: str
|
|
||||||
api_key: str
|
|
||||||
max_iterations: int
|
|
||||||
reasoning_effort: str
|
|
||||||
|
|
||||||
|
|
||||||
class _SkillsConfig(TypedDict):
|
|
||||||
external_dirs: List[str]
|
|
||||||
|
|
||||||
|
|
||||||
class _ChannelPromptsConfig(TypedDict):
|
|
||||||
channel_prompts: Dict[str, str]
|
|
||||||
|
|
||||||
|
|
||||||
class _DiscordConfig(TypedDict):
|
|
||||||
require_mention: bool
|
|
||||||
free_response_channels: str
|
|
||||||
allowed_channels: str
|
|
||||||
auto_thread: bool
|
|
||||||
reactions: bool
|
|
||||||
channel_prompts: Dict[str, str]
|
|
||||||
server_actions: str
|
|
||||||
|
|
||||||
|
|
||||||
class _ApprovalsConfig(TypedDict):
|
|
||||||
mode: str
|
|
||||||
timeout: int
|
|
||||||
cron_mode: str
|
|
||||||
|
|
||||||
|
|
||||||
class _WebsiteBlocklistConfig(TypedDict):
|
|
||||||
enabled: bool
|
|
||||||
domains: List[str]
|
|
||||||
shared_files: List[str]
|
|
||||||
|
|
||||||
|
|
||||||
class _SecurityConfig(TypedDict):
|
|
||||||
redact_secrets: bool
|
|
||||||
tirith_enabled: bool
|
|
||||||
tirith_path: str
|
|
||||||
tirith_timeout: int
|
|
||||||
tirith_fail_open: bool
|
|
||||||
website_blocklist: _WebsiteBlocklistConfig
|
|
||||||
|
|
||||||
|
|
||||||
class _CronConfig(TypedDict):
|
|
||||||
wrap_response: bool
|
|
||||||
max_parallel_jobs: Optional[int]
|
|
||||||
|
|
||||||
|
|
||||||
class _CodeExecutionConfig(TypedDict):
|
|
||||||
mode: str
|
|
||||||
|
|
||||||
|
|
||||||
class _LoggingConfig(TypedDict):
|
|
||||||
level: str
|
|
||||||
max_size_mb: int
|
|
||||||
backup_count: int
|
|
||||||
|
|
||||||
|
|
||||||
class _NetworkConfig(TypedDict):
|
|
||||||
force_ipv4: bool
|
|
||||||
|
|
||||||
|
|
||||||
class _DefaultConfig(TypedDict):
|
|
||||||
model: str
|
|
||||||
providers: Dict[str, Any]
|
|
||||||
fallback_providers: List[Any]
|
|
||||||
credential_pool_strategies: Dict[str, Any]
|
|
||||||
toolsets: List[str]
|
|
||||||
agent: _AgentConfig
|
|
||||||
terminal: _TerminalConfig
|
|
||||||
browser: _BrowserConfig
|
|
||||||
checkpoints: _CheckpointsConfig
|
|
||||||
file_read_max_chars: int
|
|
||||||
compression: _CompressionConfig
|
|
||||||
bedrock: _BedrockConfig
|
|
||||||
auxiliary: _AuxiliaryConfig
|
|
||||||
display: _DisplayConfig
|
|
||||||
dashboard: _DashboardConfig
|
|
||||||
privacy: _PrivacyConfig
|
|
||||||
tts: _TtsConfig
|
|
||||||
stt: _SttConfig
|
|
||||||
voice: _VoiceConfig
|
|
||||||
human_delay: _HumanDelayConfig
|
|
||||||
context: _ContextConfig
|
|
||||||
memory: _MemoryConfig
|
|
||||||
delegation: _DelegationConfig
|
|
||||||
prefill_messages_file: str
|
|
||||||
skills: _SkillsConfig
|
|
||||||
honcho: Dict[str, Any]
|
|
||||||
timezone: str
|
|
||||||
discord: _DiscordConfig
|
|
||||||
whatsapp: Dict[str, Any]
|
|
||||||
telegram: _ChannelPromptsConfig
|
|
||||||
slack: _ChannelPromptsConfig
|
|
||||||
mattermost: _ChannelPromptsConfig
|
|
||||||
approvals: _ApprovalsConfig
|
|
||||||
command_allowlist: List[str]
|
|
||||||
quick_commands: Dict[str, Any]
|
|
||||||
hooks: Dict[str, Any]
|
|
||||||
hooks_auto_accept: bool
|
|
||||||
personalities: Dict[str, Any]
|
|
||||||
security: _SecurityConfig
|
|
||||||
cron: _CronConfig
|
|
||||||
code_execution: _CodeExecutionConfig
|
|
||||||
logging: _LoggingConfig
|
|
||||||
network: _NetworkConfig
|
|
||||||
_config_version: int
|
|
||||||
|
|
||||||
|
|
||||||
class _EnvVarRequired(TypedDict):
|
|
||||||
description: str
|
|
||||||
prompt: str
|
|
||||||
category: str
|
|
||||||
|
|
||||||
|
|
||||||
class _EnvVarOptional(TypedDict, total=False):
|
|
||||||
url: Optional[str]
|
|
||||||
password: bool
|
|
||||||
tools: List[str]
|
|
||||||
advanced: bool
|
|
||||||
|
|
||||||
|
|
||||||
class _EnvVarInfo(_EnvVarRequired, _EnvVarOptional):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CONFIG: _DefaultConfig = {
|
|
||||||
"model": "",
|
"model": "",
|
||||||
"providers": {},
|
"providers": {},
|
||||||
"fallback_providers": [],
|
"fallback_providers": [],
|
||||||
|
|
@ -1305,7 +954,7 @@ ENV_VARS_BY_VERSION: Dict[int, List[str]] = {
|
||||||
REQUIRED_ENV_VARS = {}
|
REQUIRED_ENV_VARS = {}
|
||||||
|
|
||||||
# Optional environment variables that enhance functionality
|
# Optional environment variables that enhance functionality
|
||||||
OPTIONAL_ENV_VARS: Dict[str, _EnvVarInfo] = {
|
OPTIONAL_ENV_VARS = {
|
||||||
# ── Provider (handled in provider selection, not shown in checklists) ──
|
# ── Provider (handled in provider selection, not shown in checklists) ──
|
||||||
"NOUS_BASE_URL": {
|
"NOUS_BASE_URL": {
|
||||||
"description": "Nous Portal base URL override",
|
"description": "Nous Portal base URL override",
|
||||||
|
|
@ -2269,7 +1918,7 @@ def get_missing_config_fields() -> List[Dict[str, Any]]:
|
||||||
elif isinstance(default_value, dict) and isinstance(current.get(key), dict):
|
elif isinstance(default_value, dict) and isinstance(current.get(key), dict):
|
||||||
_check(default_value, current[key], full_key)
|
_check(default_value, current[key], full_key)
|
||||||
|
|
||||||
_check(dict(DEFAULT_CONFIG), config)
|
_check(DEFAULT_CONFIG, config)
|
||||||
return missing
|
return missing
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3407,7 +3056,7 @@ def load_config() -> Dict[str, Any]:
|
||||||
ensure_hermes_home()
|
ensure_hermes_home()
|
||||||
config_path = get_config_path()
|
config_path = get_config_path()
|
||||||
|
|
||||||
config: Dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
|
||||||
if config_path.exists():
|
if config_path.exists():
|
||||||
try:
|
try:
|
||||||
|
|
@ -4083,7 +3732,7 @@ def edit_config():
|
||||||
|
|
||||||
# Ensure config exists
|
# Ensure config exists
|
||||||
if not config_path.exists():
|
if not config_path.exists():
|
||||||
save_config(dict(DEFAULT_CONFIG))
|
save_config(DEFAULT_CONFIG)
|
||||||
print(f"Created {config_path}")
|
print(f"Created {config_path}")
|
||||||
|
|
||||||
# Find editor
|
# Find editor
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
"""Runtime smoke tests for `_CamofoxConfig` / `_BrowserConfig` TypedDict shapes."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
def test_camofox_config_is_partial_typeddict():
|
|
||||||
from hermes_cli.config import _CamofoxConfig
|
|
||||||
|
|
||||||
cfg_empty: _CamofoxConfig = {}
|
|
||||||
cfg_with_field: _CamofoxConfig = {"managed_persistence": True}
|
|
||||||
|
|
||||||
assert cfg_empty == {}
|
|
||||||
assert cfg_with_field.get("managed_persistence") is True
|
|
||||||
|
|
||||||
|
|
||||||
def test_camofox_config_nested_in_browser_config():
|
|
||||||
from hermes_cli.config import _BrowserConfig
|
|
||||||
|
|
||||||
browser: _BrowserConfig = {
|
|
||||||
"inactivity_timeout": 60,
|
|
||||||
"command_timeout": 10,
|
|
||||||
"record_sessions": False,
|
|
||||||
"allow_private_urls": False,
|
|
||||||
"cdp_url": "http://localhost:9222",
|
|
||||||
"camofox": {"managed_persistence": False},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert browser["camofox"].get("managed_persistence") is False
|
|
||||||
2
uv.lock
generated
2
uv.lock
generated
|
|
@ -9,7 +9,7 @@ resolution-markers = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
exclude-newer = "2026-04-16T12:11:13.647742Z"
|
exclude-newer = "2026-04-16T12:11:21.909555Z"
|
||||||
exclude-newer-span = "P7D"
|
exclude-newer-span = "P7D"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue