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:
|
||||
logger.debug("wl-paste not installed — Wayland clipboard unavailable")
|
||||
except ImportError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.debug("wl-paste clipboard extraction failed: %s", e)
|
||||
dest.unlink(missing_ok=True)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import sys
|
|||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
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__)
|
||||
|
||||
|
|
@ -343,358 +343,7 @@ def _ensure_hermes_home_managed(home: Path):
|
|||
# Config loading/saving
|
||||
# =============================================================================
|
||||
|
||||
class _AgentConfig(TypedDict):
|
||||
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 = {
|
||||
DEFAULT_CONFIG = {
|
||||
"model": "",
|
||||
"providers": {},
|
||||
"fallback_providers": [],
|
||||
|
|
@ -1305,7 +954,7 @@ ENV_VARS_BY_VERSION: Dict[int, List[str]] = {
|
|||
REQUIRED_ENV_VARS = {}
|
||||
|
||||
# Optional environment variables that enhance functionality
|
||||
OPTIONAL_ENV_VARS: Dict[str, _EnvVarInfo] = {
|
||||
OPTIONAL_ENV_VARS = {
|
||||
# ── Provider (handled in provider selection, not shown in checklists) ──
|
||||
"NOUS_BASE_URL": {
|
||||
"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):
|
||||
_check(default_value, current[key], full_key)
|
||||
|
||||
_check(dict(DEFAULT_CONFIG), config)
|
||||
_check(DEFAULT_CONFIG, config)
|
||||
return missing
|
||||
|
||||
|
||||
|
|
@ -3407,7 +3056,7 @@ def load_config() -> Dict[str, Any]:
|
|||
ensure_hermes_home()
|
||||
config_path = get_config_path()
|
||||
|
||||
config: Dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
|
||||
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||
|
||||
if config_path.exists():
|
||||
try:
|
||||
|
|
@ -4083,7 +3732,7 @@ def edit_config():
|
|||
|
||||
# Ensure config exists
|
||||
if not config_path.exists():
|
||||
save_config(dict(DEFAULT_CONFIG))
|
||||
save_config(DEFAULT_CONFIG)
|
||||
print(f"Created {config_path}")
|
||||
|
||||
# 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]
|
||||
exclude-newer = "2026-04-16T12:11:13.647742Z"
|
||||
exclude-newer = "2026-04-16T12:11:21.909555Z"
|
||||
exclude-newer-span = "P7D"
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue