
    KiR                       U d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
mZmZmZmZmZ ddlmZ  ej                    dk    Z ej        d          Z eh d          ZddlZdd	lmZmZ dd
lmZ dZdddddZ dee!         fdZ"de#fdZ$dee!         fdZ%de!fdZ&dde!de!fdZ'dde!fdZ(ddl)m*Z* de	fdZ+de	fdZ,de	fdZ-d Z.d Z/de	ddfd Z0d! Z1i d"d#d$g d%i d&d'gd(d)d*d+d,i d-d.d/d*d0d1d2d3d4g d5d6d7g d8d9d:d6d;d6d<d=d>d?d@dAdBdCdDg dEdFdGdCdHdIdJdFdFdKdFidLdMdCdNdOdPdQdRdCdSdTdUd#d*ddVdWdFdXdYi dZd[d*d#d#d#dJdJd\d*d#d#d#dJd]d*d#d#d#dId]d*d#d#d#dJd]d*d#d#d#dJd]d*d#d#d#dJd]d*d#d#d#dJd]d*d#d#d#dJd]d^d_dFd`dadbdFdFdFdCdFdcdFddddedfdFidgdhdidjidkdldmdndodpd#d#dqdrdsdtdudCd.d"dvid"dwidxdidydIdFdzd{d|i d}d~dddddCdCddd#ddd#d#d#d#dNddd#ddg idi dd#ddCd#dCdCddi dddddg di di ddCdCdddCdFg g dddddCiddZ2g dddgg ddgdgdZ3ee4ee!         f         e5d<   i Z6i dddddFddCddddddCddgddCddddddCddCddddddCddCddddddCddCddddddFddCddddddCddCddddddFddCddddddCddCddddddFddCddddddCddCddddddFddCddddddCdd؜dddd#dFdd؜dddddCdd؜dddd#dFddCddddddCddCdi dddddFddCddddddCddCddddddFddCddddddCdd؜dddddFddCdddddddgdCdddd ddddgdCddddddddgdCddddd	ddFddCdd
ddddFddCddddddFddCddddddFddCddddddCddCdddddg ddCddddddddgdCddd d!d"dddgdFddd#d$d%d&ddgdCddi d'd(d)d*ddgdFddd+d,d-d.d/gdCddd0d1d2d3g d4dCddd5d6d7d8d9d:gdCdddd;d<d=d>d?gdCdddd@dAdBdCdd؜dCdDdEdFdCdd؜dGdHdIdJdKgdCdddLdMdNddOdPdQdRdSdCdTd؜dUdVdWdXdFdTd؜dYdZd[d\dCdTd؜d]d^d_ddFdTd؜d`dadbdcdCdTd؜dddedfdcdCdTd؜dgdhdidjdFdTd؜dkdldmddCdTd؜i dndodpddFdTd؜dqdrdsddFdTd؜dtdudvddFdTd؜dwdxdydzdFdTd؜d{d|d}ddCdTd؜d~ddddFdTd؜dddddFdTd؜dddddFdTdCddddddFdTdCddddddCdTdCddddddFdTdCddddddFdTdCddddddFdTd؜dddddFdTd؜dddddCdTd؜dddddFdd؜dddddCdd؜ddddFdd؜ddddFdd؜ddddFdd؜ddddFdd؜ddddFdd؜dZ7 e            sdD ]Z8e79                    e8d           dՐde#deee!ef                  fdZ:de;de!fdZ<deee!ef                  fdZ=dee4e4f         fdZ>d֐de#de#dee!ef         fdZ?dve;de;de;fdZ@d ZAdee!ef         dee!ef         fdZBdee!ef         dee!ef         fdZCdee!ef         fdZDdZEdZFdZGdee!ef         fdZHdee!e!f         fdZIdeJdeJfdĄZKde4fdńZLde!de!fdȄZMdאde!fdɄZNdאdʄZOdאde!fd˄ZPde!de!dee!ef         fd̄ZQde!dee!         fd̈́ZRde!de!fd΄ZSdτ ZTdЄ ZUde!de!fdфZVd҄ ZWdS (  a  
Configuration management for Hermes Agent.

Config files are stored in ~/.hermes/ for easy access:
- ~/.hermes/config.yaml  - All settings (model, toolsets, terminal, etc.)
- ~/.hermes/.env         - API keys and secrets

This module provides:
- hermes config          - Show current configuration
- hermes config edit     - Open config in editor
- hermes config set      - Set a specific value
- hermes config wizard   - Re-run setup wizard
    N)Path)DictAnyOptionalListTuple)managed_nous_tools_enabledWindowsz^[A-Za-z_][A-Za-z0-9_]*$>   TERMINAL_ENVWECOM_BOT_IDWECOM_SECRETFEISHU_APP_IDWHATSAPP_MODEOPENAI_API_KEYSIGNAL_ACCOUNTANTHROPIC_TOKENMATRIX_PASSWORDOPENAI_BASE_URLSIGNAL_HTTP_URLMATRIX_HOME_ROOMTERMINAL_SSH_KEYWHATSAPP_ENABLEDANTHROPIC_API_KEYFEISHU_APP_SECRETMATRIX_ENCRYPTIONTERMINAL_SSH_PORTDINGTALK_CLIENT_IDFEISHU_ENCRYPT_KEYDISCORD_HOME_CHANNELSIGNAL_ALLOWED_USERSMATTERMOST_REPLY_MODETELEGRAM_HOME_CHANNELAUXILIARY_VISION_MODELDINGTALK_CLIENT_SECRETMATTERMOST_HOME_CHANNELFEISHU_VERIFICATION_TOKENSIGNAL_GROUP_ALLOWED_USERS)Colorscolor)DEFAULT_SOUL_MD)true1yesHomebrewNixOS)brewhomebrewnixnixosreturnc                     t          j        dd                                          } | r:|                                 }|t          v rdS t
                              ||           S t                      dz  }|                                rdS dS )z7Return the package manager owning this install, if any.HERMES_MANAGED r/   z.managedN)	osgetenvstriplower_MANAGED_TRUE_VALUES_MANAGED_SYSTEM_NAMESgetget_hermes_homeexists)raw
normalizedmanaged_markers      ./home/ubuntu/hermes-agent/hermes_cli/config.pyget_managed_systemrE   A   s    
)$b
)
)
/
/
1
1C
 :YY[[
---7$((S999$&&3N w4    c                  "    t                      duS )a  Check if Hermes is running in package-manager-managed mode.

    Two signals: the HERMES_MANAGED env var (set by the systemd service),
    or a .managed marker file in HERMES_HOME (set by the NixOS activation
    script, so interactive shells also see it).
    NrE    rF   rD   
is_managedrJ   P   s     t++rF   c                  B    t                      } | dk    rdS | dk    rdS dS )z;Return the preferred upgrade command for a managed install.r.   zbrew upgrade hermes-agentr/   zsudo nixos-rebuild switchNrH   )managed_systems    rD   get_managed_update_commandrM   Z   s4    '))N##**  **4rF   c                  "    t                      pdS )z<Return the best update command for the current installation.zhermes update)rM   rI   rF   rD   recommended_update_commandrO   d   s    %'':?:rF   modify this Hermes installationactionc                    t                      pd}t          j        dd                                                                          }|dk    r|t
          v rdn|pd}d|  d| dS |d	k    r|pd
}d|  d| dS d|  d| dS )z/Build a user-facing error for managed installs.za package managerr6   r7   r/   r+   zCannot z?: this Hermes installation is managed by NixOS (HERMES_MANAGED=ze).
Edit services.hermes-agent.settings in your configuration.nix and run:
  sudo nixos-rebuild switchr.   r1   zB: this Hermes installation is managed by Homebrew (HERMES_MANAGED=z#).
Use:
  brew upgrade hermes-agentz): this Hermes installation is managed by z:.
Use your package manager to upgrade or reinstall Hermes.)rE   r8   r9   r:   r;   r<   )rQ   rL   rA   env_hints       rD   format_managed_messagerT   i   s    '))@-@N
)$b
)
)
/
/
1
1
7
7
9
9C   $88866cmV*f * *'* * *	
 ##$**f * *'* * *	
	C& 	C 	C> 	C 	C 	CrF   modify configurationc                 V    t          t          |           t          j                   dS )z+Print user-friendly error for managed mode.)fileN)printrT   sysstderr)rQ   s    rD   managed_errorr[      s&    	
 
(
(sz::::::rF   r?   c                  $    t                      dz  S )zGet the main config file path.zconfig.yamlr\   rI   rF   rD   get_config_pathr^      s    },,rF   c                  $    t                      dz  S )z&Get the .env file path (for API keys).z.envr\   rI   rF   rD   get_env_pathr`      s    v%%rF   c                  b    t          t                    j        j                                        S )z'Get the project installation directory.)r   __file__parentresolverI   rF   rD   get_project_rootre      s     >> '//111rF   c                 b    	 t          j        | d           dS # t          t          f$ r Y dS w xY w)z<Set directory to owner-only access (0700). No-op on Windows.i  N)r8   chmodOSErrorNotImplementedErrorpaths    rD   _secure_dirrl      sG    
u()   s    ..c                     	 t           j                            t          |                     rt          j        | d           dS dS # t
          t          f$ r Y dS w xY w)z;Set file to owner-only read/write (0600). No-op on Windows.i  N)r8   rk   r@   strrg   rh   ri   rj   s    rD   _secure_filero      sm    7>>#d))$$ 	"HT5!!!!!	" 	"()   s   AA AAhomec                     | dz  }|                                 rdS |                    t          d           t          |           dS )zISeed a default SOUL.md into HERMES_HOME if the user doesn't have one yet.zSOUL.mdNutf-8encoding)r@   
write_textr*   ro   )rp   	soul_paths     rD   _ensure_default_soul_mdrw      sR    y I 7;;;rF   c                      t                      } |                     dd           t          |            dD ]-}| |z  }|                    dd           t          |           .t          |            dS )zDEnsure ~/.hermes directory structure exists with secure permissions.T)parentsexist_ok)cronsessionslogsmemoriesN)r?   mkdirrl   rw   )rp   subdirds      rD   ensure_hermes_homer      s    DJJtdJ+++:  6M	t,,,AD!!!!!rF   modelr7   fallback_providerscredential_pool_strategiestoolsetsz
hermes-cliagentZ   auto)	max_turnstool_use_enforcementterminalbackendlocal
modal_modecwd.timeout   env_passthroughdocker_image*nikolaik/python-nodejs:python3.11-nodejs20docker_forward_envsingularity_image3docker://nikolaik/python-nodejs:python3.11-nodejs20modal_imagedaytona_imagecontainer_cpu   container_memoryi   container_diski   container_persistentTdocker_volumesdocker_mount_cwd_to_workspaceFpersistent_shellbrowserx      managed_persistence)inactivity_timeoutcommand_timeoutrecord_sessionsallow_private_urlscamofoxcheckpoints2   )enabledmax_snapshotsfile_read_max_charsi compression      ?皙?   )r   	thresholdtarget_ratioprotect_last_nsummary_modelsummary_providersummary_base_urlsmart_model_routing      )r   max_simple_charsmax_simple_wordscheap_model	auxiliary)providerr   base_urlapi_keyr   download_timeout)r   r   r   r   r   )visionweb_extractr   session_search
skills_hubapprovalmcpflush_memoriesdisplaykawaiifull	interruptdefault)compactpersonalityresume_displaybusy_input_modebell_on_completeshow_reasoning	streaminginline_diffs	show_costskintool_progress_commandtool_preview_lengthprivacy
redact_piittsedgevoicezen-US-AriaNeuralpNInz6obpgDQGcFmaJgBeleven_multilingual_v2)voice_idmodel_idzgpt-4o-mini-ttsalloy)r   r   zneuphonic/neutts-air-q4-ggufcpu)	ref_audioref_textr   device)r   r   
elevenlabsopenaineuttssttbasez	whisper-1)r   r   r   r   zctrl+b   g      @)
record_keymax_recording_secondsauto_ttssilence_thresholdsilence_durationhuman_delayoffi   i	  )modemin_msmax_msmemoryi  i_  )memory_enableduser_profile_enabledmemory_char_limituser_char_limitr   
delegation)r   r   r   r   max_iterationsprefill_messages_fileskillsexternal_dirshonchotimezonediscord)require_mentionfree_response_channelsauto_thread	reactionswhatsapp	approvalsmanual<   )r   r   command_allowlistquick_commandspersonalitiessecuritytirith   )r   domainsshared_files)redact_secretstirith_enabledtirith_pathtirith_timeouttirith_fail_openwebsite_blocklistr{   wrap_response_config_version   )FIRECRAWL_API_KEYBROWSERBASE_API_KEYBROWSERBASE_PROJECT_IDFAL_KEYVOICE_TOOLS_OPENAI_KEYELEVENLABS_API_KEY)r   r   WHATSAPP_ALLOWED_USERSSLACK_BOT_TOKENSLACK_APP_TOKENSLACK_ALLOWED_USERSTAVILY_API_KEYTERMINAL_MODAL_MODE)      r  
   r"  ENV_VARS_BY_VERSIONNOUS_BASE_URLzNous Portal base URL overridez.Nous Portal base URL (leave empty for default)r   )descriptionprompturlpasswordcategoryadvancedOPENROUTER_API_KEYz>OpenRouter API key (for vision, web scraping helpers, and MoA)zOpenRouter API keyzhttps://openrouter.ai/keysvision_analyzemixture_of_agents)r4  r5  r6  r7  toolsr8  r9  GLM_API_KEYzBZ.AI / GLM API key (also recognized as ZAI_API_KEY / Z_AI_API_KEY)zZ.AI / GLM API keyzhttps://z.ai/ZAI_API_KEYz$Z.AI API key (alias for GLM_API_KEY)zZ.AI API keyZ_AI_API_KEYGLM_BASE_URLzZ.AI / GLM base URL overridez-Z.AI / GLM base URL (leave empty for default)KIMI_API_KEYzKimi / Moonshot API keyzKimi API keyzhttps://platform.moonshot.cn/KIMI_BASE_URLz!Kimi / Moonshot base URL overridez'Kimi base URL (leave empty for default)MINIMAX_API_KEYzMiniMax API key (international)zMiniMax API keyzhttps://www.minimax.io/MINIMAX_BASE_URLzMiniMax base URL overridez*MiniMax base URL (leave empty for default)MINIMAX_CN_API_KEYz MiniMax API key (China endpoint)zMiniMax (China) API keyzhttps://www.minimaxi.com/MINIMAX_CN_BASE_URLz!MiniMax (China) base URL overridez2MiniMax (China) base URL (leave empty for default)DEEPSEEK_API_KEYz+DeepSeek API key for direct DeepSeek accesszDeepSeek API Keyz&https://platform.deepseek.com/api_keys)r4  r5  r6  r7  r8  DEEPSEEK_BASE_URLz'Custom DeepSeek API base URL (advanced)zDeepSeek Base URLDASHSCOPE_API_KEYz>Alibaba Cloud DashScope API key (Qwen + multi-provider models)zDashScope API Keyz-https://modelstudio.console.alibabacloud.com/DASHSCOPE_BASE_URLzGCustom DashScope base URL (default: coding-intl OpenAI-compat endpoint)zDashScope Base URLOPENCODE_ZEN_API_KEYz=OpenCode Zen API key (pay-as-you-go access to curated models)zOpenCode Zen API keyzhttps://opencode.ai/authOPENCODE_ZEN_BASE_URLzOpenCode Zen base URL overridez/OpenCode Zen base URL (leave empty for default)OPENCODE_GO_API_KEYz<OpenCode Go API key ($10/month subscription for open models)zOpenCode Go API keyOPENCODE_GO_BASE_URLzOpenCode Go base URL overridez.OpenCode Go base URL (leave empty for default)HF_TOKENzVHugging Face token for Inference Providers (20+ open models via router.huggingface.co)zHugging Face Tokenz&https://huggingface.co/settings/tokensHF_BASE_URLz2Hugging Face Inference Providers base URL overridez%HF base URL (leave empty for default)EXA_API_KEYz1Exa API key for AI-native web search and contentszExa API keyzhttps://exa.ai/
web_searchr   tool)r4  r5  r6  r=  r7  r8  PARALLEL_API_KEYz5Parallel API key for AI-native web search and extractzParallel API keyzhttps://parallel.ai/r#  z-Firecrawl API key for web search and scrapingzFirecrawl API keyzhttps://firecrawl.dev/FIRECRAWL_API_URLz6Firecrawl API URL for self-hosted instances (optional)z)Firecrawl API URL (leave empty for cloud)FIRECRAWL_GATEWAY_URLzQExact Firecrawl tool-gateway origin override for Nous Subscribers only (optional)z9Firecrawl gateway URL (leave empty to derive from domain)TOOL_GATEWAY_DOMAINzShared tool-gateway domain suffix for Nous Subscribers only, used to derive vendor hosts, e.g. nousresearch.com -> firecrawl-gateway.nousresearch.comzTool-gateway domain suffixTOOL_GATEWAY_SCHEMEzShared tool-gateway URL scheme for Nous Subscribers only, used to derive vendor hosts (`https` by default, set `http` for local gateway testing)zTool-gateway URL schemeTOOL_GATEWAY_USER_TOKENzuExplicit Nous Subscriber access token for tool-gateway requests (optional; otherwise read from the Hermes auth store)zTool-gateway user tokenz;Tavily API key for AI-native web search, extract, and crawlzTavily API keyzhttps://app.tavily.com/home)rS  r   	web_crawlr$  uU   Browserbase API key for cloud browser (optional — local browser works without this)zBrowserbase API keyzhttps://browserbase.com/browser_navigatebrowser_clickr%  uC   Browserbase project ID (optional — only needed for cloud browser)zBrowserbase project IDBROWSER_USE_API_KEYuU   Browser Use API key for cloud browser (optional — local browser works without this)zBrowser Use API keyzhttps://browser-use.com/CAMOFOX_URLzYCamofox browser server URL for local anti-detection browsing (e.g. http://localhost:9377)zCamofox server URLz)https://github.com/jo-inc/camofox-browserr&  z FAL API key for image generationzFAL API keyzhttps://fal.ai/image_generateTINKER_API_KEYzTinker API key for RL trainingzTinker API keyz/https://tinker-console.thinkingmachines.ai/keys)rl_start_trainingrl_check_statusrl_stop_trainingWANDB_API_KEYz0Weights & Biases API key for experiment trackingzWandB API keyzhttps://wandb.ai/authorizerl_get_resultsrc  z?OpenAI API key for voice transcription (Whisper) and OpenAI TTSz&OpenAI API Key (for Whisper STT + TTS)z$https://platform.openai.com/api-keysvoice_transcription
openai_ttsz4ElevenLabs API key for premium text-to-speech voiceszElevenLabs API keyzhttps://elevenlabs.io/GITHUB_TOKENzCGitHub token for Skills Hub (higher API rate limits, skill publish)zGitHub Tokenz"https://github.com/settings/tokensHONCHO_API_KEYz.Honcho API key for AI-native persistent memoryzHoncho API keyzhttps://app.honcho.devhoncho_contextHONCHO_BASE_URLz=Base URL for self-hosted Honcho instances (no API key needed)z,Honcho base URL (e.g. http://localhost:8000))r4  r5  r8  TELEGRAM_BOT_TOKENz"Telegram bot token from @BotFatherzTelegram bot tokenzhttps://t.me/BotFather	messagingTELEGRAM_ALLOWED_USERSzSComma-separated Telegram user IDs allowed to use the bot (get ID from @userinfobot)z+Allowed Telegram user IDs (comma-separated)zhttps://t.me/userinfobotDISCORD_BOT_TOKENz'Discord bot token from Developer PortalzDiscord bot tokenz+https://discord.com/developers/applicationsDISCORD_ALLOWED_USERSz7Comma-separated Discord user IDs allowed to use the botz*Allowed Discord user IDs (comma-separated)r*  zSlack bot token (xoxb-). Get from OAuth & Permissions after installing your app. Required scopes: chat:write, app_mentions:read, channels:history, groups:history, im:history, im:read, im:write, users:read, files:writezSlack Bot Token (xoxb-...)zhttps://api.slack.com/appsr+  u   Slack app-level token (xapp-) for Socket Mode. Get from Basic Information → App-Level Tokens. Also ensure Event Subscriptions include: message.im, message.channels, message.groups, app_mentionzSlack App Token (xapp-...)MATTERMOST_URLz3Mattermost server URL (e.g. https://mm.example.com)zMattermost server URLzhttps://mattermost.com/deploy/MATTERMOST_TOKENz-Mattermost bot token or personal access tokenzMattermost bot tokenMATTERMOST_ALLOWED_USERSz:Comma-separated Mattermost user IDs allowed to use the botz-Allowed Mattermost user IDs (comma-separated)MATTERMOST_REQUIRE_MENTIONzaRequire @mention in Mattermost channels (default: true). Set to false to respond to all messages.zRequire @mention in channels!MATTERMOST_FREE_RESPONSE_CHANNELSzJComma-separated Mattermost channel IDs where bot responds without @mentionz+Free-response channel IDs (comma-separated)MATRIX_HOMESERVERz7Matrix homeserver URL (e.g. https://matrix.example.org)zMatrix homeserver URLz%https://matrix.org/ecosystem/servers/MATRIX_ACCESS_TOKENz3Matrix access token (preferred over password login)zMatrix access tokenMATRIX_USER_IDz)Matrix user ID (e.g. @hermes:example.org)zMatrix user ID (@user:server)MATRIX_ALLOWED_USERSzLComma-separated Matrix user IDs allowed to use the bot (@user:server format)z)Allowed Matrix user IDs (comma-separated)GATEWAY_ALLOW_ALL_USERSzMAllow all users to interact with messaging bots (true/false). Default: false.zAllow all users (true/false)API_SERVER_ENABLEDzrEnable the OpenAI-compatible API server (true/false). Allows frontends like Open WebUI, LobeChat, etc. to connect.zEnable API server (true/false)API_SERVER_KEYz`Bearer token for API server authentication. If empty, all requests are allowed (local use only).zAPI server auth key (optional)API_SERVER_PORTz(Port for the API server (default: 8642).zAPI server portAPI_SERVER_HOSTu   Host/bind address for the API server (default: 127.0.0.1). Use 0.0.0.0 for network access — requires API_SERVER_KEY for security.zAPI server hostWEBHOOK_ENABLEDzREnable the webhook platform adapter for receiving events from GitHub, GitLab, etc.zEnable webhooks (true/false)WEBHOOK_PORTz1Port for the webhook HTTP server (default: 8644).zWebhook portWEBHOOK_SECRETz[Global HMAC secret for webhook signature validation (overridable per route in config.yaml).zWebhook secretMESSAGING_CWDz5Working directory for terminal commands via messagingz+Messaging working directory (default: home)settingSUDO_PASSWORDz9Sudo password for terminal commands requiring root accesszSudo passwordz>Maximum tool-calling iterations per conversation (default: 90)zMax iterationsz=(deprecated) Use display.tool_progress in config.yaml insteadu.   Tool progress (deprecated — use config.yaml)u.   Progress mode (deprecated — use config.yaml)zFPath to JSON file with ephemeral prefill messages for few-shot primingzPrefill messages file pathzOEphemeral system prompt injected at API-call time (never persisted to sessions)zEphemeral system prompt)HERMES_MAX_ITERATIONSHERMES_TOOL_PROGRESSHERMES_TOOL_PROGRESS_MODEHERMES_PREFILL_MESSAGES_FILEHERMES_EPHEMERAL_SYSTEM_PROMPT)rW  rX  rY  rZ  required_onlyc                 :   g }t                                           D ]1\  }}t          |          s|                    d|i|ddi           2| sKt                                          D ]1\  }}t          |          s|                    d|i|ddi           2|S )z|
    Check which environment variables are missing.
    
    Returns list of dicts with var info for missing variables.
    nameis_requiredTF)REQUIRED_ENV_VARSitemsget_env_valueappendOPTIONAL_ENV_VARS)r  missingvar_nameinfos       rD   get_missing_env_varsr  l  s     G ,1133 L L$X&& 	LNNFHJJmTJJKKK  Q/5577 	Q 	QNHd ** QODO-OOPPPNrF   config
dotted_keyc                     |                     d          }| }|dd         D ];}||vs(t          |                    |          t                    si ||<   ||         }<|||d         <   dS )zSet a value at an arbitrarily nested dotted key path.

    Creates intermediate dicts as needed, e.g. ``_set_nested(c, "a.b.c", 1)``
    ensures ``c["a"]["b"]["c"] == 1``.
    r   N)split
isinstancer>   dict)r  r  valuepartscurrentparts         rD   _set_nestedr    s     S!!EGcrc
    wjT1B1BD&I&IGDM$-GE"IrF   c                      t                      } g ddt          dt          dt          ffd t          |            S )z
    Check which config fields are missing or outdated (recursive).
    
    Walks the DEFAULT_CONFIG tree at arbitrary depth and reports any keys
    present in defaults but absent from the user's loaded config.
    r7   defaultsr  prefixc                 `   |                                  D ]\  }}|                    d          r|s|n| d| }||vr                    ||d| d           Gt          |t                    r;t          |                    |          t                    r |||         |           d S )N_r   zNew config option: )keyr   r4  )r  
startswithr  r  r  r>   )r  r  r  r  default_valuefull_key_checkr  s         rD   r  z)get_missing_config_fields.<locals>._check  s    "*.."2"2 	> 	>C~~c"" "(?ss.?.?#.?.?H'!!#,#C#C#C       
 M400 >ZC@P@PRV5W5W >}gclH===	> 	>rF   )r7   )load_configr  rn   DEFAULT_CONFIG)r  r  r  s    @@rD   get_missing_config_fieldsr    sj     ]]FG> > > >c > > > > > > > F>6"""NrF   c                      t                      } |                     dd          }t                              dd          }||fS )zS
    Check config version.
    
    Returns (current_version, latest_version).
    r!  r   r   )r  r>   r  )r  r  latests      rD   check_config_versionr    sA     ]]Fjj*A..G 1155FF?rF   interactivequietc           
         g g g d}	 t                      }|r|st          d| d           n# t          $ r Y nw xY wt                      \  }}|dk     rFt	                      }|                    di           }t          |t                    si }d|vrt          d          }t          d          }	|r7|	                                d	v r!d
|d<   |d         
                    d           n|	r_|		                                dv rI|		                                |d<   |d         
                    d|		                                 d           n d|d<   |d         
                    d           ||d<   t          |           |st          d|d                     |dk     rt	                      }d|vrt          j        dd          }
|
r]|
                                rI|
                                |d<   |d         
                    d|
                                 d           n d|d<   |d         
                    d           t          |           |s|d         pd}t          d|            |dk     rD	 t          d          }|r!t          dd           |st          d           n# t          $ r Y nw xY w||k     r|st          d| d |            t!          d!"          }|r7|s5t          d#           |D ]#}t          d$|d%          d&|d'                     $| r/|r,t          d(           |D ]}|                    d)          rt          d*|d)                     |                    d+          r$d,d-l}|                    d.|d/          d&          }n+t%          d.|d/          d&                                          }|rPt          |d%         |           |d0         
                    |d%                    t          d1|d%                     n%|d2         
                    d3|d%          d4           t                       t!          d5"          }|rd6 |D             nt'                      fd7|D             }t'                      }t)          |d8z   |d8z             D ]0}|                    t,                              |g                      1|rC| r@|s=d9 t/          |          D             }|r!t          d:t1          |           d;           |D ].\  }}t          d<| d=|                    d'd                      /t                       	 t%          d>                                          	                                }n# t2          t4          f$ r d?}Y nw xY w|d@v r`t                       |D ]M\  }}|                    d)          r?t          d.|                    d'|                      t          d*|d)                     n&t          d.|                    d'|                      |                    d+          r2d,d-l}|                    d.|                    d/|           dA          }n9t%          d.|                    d/|           dA                                          }|r=t          ||           |d0         
                    |           t          d1|            t                       Ont          dB           t7                      }|r{t	                      }|D ]U}|dC         }|dD         }t9          |||           |d         
                    |           |st          dE| dF|            V||dG<   t          |           n(||k     r"t	                      }||dG<   t          |           |S )Ha<  
    Migrate config to latest version, prompting for new required fields.
    
    Args:
        interactive: If True, prompt user for missing values
        quiet: If True, suppress output
        
    Returns:
        Dict with migration results: {"env_added": [...], "config_added": [...], "warnings": [...]}
    )	env_addedconfig_addedwarningsu     ✓ Repaired .env file (z corrupted entries fixed)r0  r   tool_progressr  r  )false0nor   r  z;display.tool_progress=off (from HERMES_TOOL_PROGRESS=false))newallzdisplay.tool_progress=z! (from HERMES_TOOL_PROGRESS_MODE)r  z#display.tool_progress=all (default)u-     ✓ Migrated tool progress to config.yaml: r  r  HERMES_TIMEZONEr7   z	timezone=z (from HERMES_TIMEZONE)z$timezone= (empty, uses server-local)(server-local)u%     ✓ Added timezone to config.yaml: 	   r   u8     ✓ Cleared ANTHROPIC_TOKEN from .env (no longer used)zConfig version:     → Tr  u0   
⚠️  Missing required environment variables:u      • r  z: r4  z
Let's configure them now:
r6  z  Get your key at: r7  r   N  r5  r  u     ✓ Saved r  zSkipped z - some features may not workFc                     h | ]
}|d          S )r  rI   .0vs     rD   	<setcomp>z!migrate_config.<locals>.<setcomp>&  s    555Aai555rF   c                 R    g | ]#}|d          v|                     d          !|$S )r  r9  r>   )r  r  required_namess     rD   
<listcomp>z"migrate_config.<locals>.<listcomp>'  sC       V9N**1553D3D* 	
***rF   r   c                 \    g | ])}t          |          s|t          v |t          |         f*S rI   )r  r  )r  r  s     rD   r  z"migrate_config.<locals>.<listcomp>2  sK     
 
 
 &&
 ,03D+D+D $T*++D+D+DrF   
  z$ new optional key(s) in this update:u       • u    — z  Configure new keys? [y/N]: n)yr-   z (Enter to skip): z1  Set later with: hermes config set <key> <value>r  r   u     ✓ Added  = r!  )sanitize_env_filerX   	Exceptionr  r  r>   r  r  r  r;   r  save_configr8   r9   r:   save_env_valuer  getpassinputsetrangeupdater2  sortedlenEOFErrorKeyboardInterruptr  r  )r  r  resultsfixescurrent_ver
latest_verr  r   old_enabledold_modeold_tz
tz_display	old_tokenmissing_envvarr  r  missing_optionalnew_var_namesvernew_and_unsetr  r  answermissing_configfieldr  r   r  s                               @rD   migrate_configr    sp	    CCG!## 	Q 	QOuOOOPPP    344K Q**Y++'4(( 	G'))'(>??K$%@AAH V{00226JJJ+0('../lmmmm Vhnn...@@+3>>+;+;('../{HXHX/{/{/{||||+0('../TUUU 'F9 b`goF^``aaa QV##Y0"55F W&,,.. W%+\\^^z"'../b6<<>>/b/b/bcccc%'z"'../UVVV L#J/C3C
JjJJKKK Q	%&788I V0"555 VTUUU 	 	 	D	 Z???:??@@@ 'T:::K A5 AABBB 	A 	AC?CK??3}+=??@@@@ { -... 	 	Cwwu~~ :8CJ88999wwz"" >(>S](>(>(>??43x=44455;;== bs6{E222$++CK8882S[223333
#**+`c&k+`+`+`aaaGGGG ,%@@@9DO555555#%%N   #   EEM[1_j1n55 ? ?044S"==>>>> #K #KU #K
 
}--
 
 

  	KQ]++QQQRRR+ K K
dIIIDHH]B,G,GIIJJJJGGG>??EEGGMMOO/0    %%"/  JD$xx DB488M4#@#@BBCCCADKAABBBBB488M4#@#@BBCCCxx
++ a& '0aTXXh5M5M0a0a0a b b %&W488Hd+C+C&W&W&W X X ^ ^ ` ` 5&tU333,33D9993T33444GGGG" IJJJ /00N # 	8 	8E,CI&GW---N#**3/// 86S66W66777 %/ !F	z	!	!$. !FNs0   %/ 
<<=2J0 0
J=<J=,3V   V65V6overridec                    |                                  }|                                D ]X\  }}||v rJt          ||         t                    r/t          |t                    rt	          ||         |          ||<   S|||<   Y|S )a  Recursively merge *override* into *base*, preserving nested defaults.

    Keys in *override* take precedence. If both values are dicts the merge
    recurses, so a user who overrides only ``tts.elevenlabs.voice_id`` will
    keep the default ``tts.elevenlabs.model_id`` intact.
    )copyr  r  r  _deep_merge)r   r  resultr  r  s        rD   r  r  q  s     YY[[Fnn&&    
U6MM6#;-- 5$''  &fSk599F3KKF3KKMrF   c                    t          | t                    rt          j        dd |           S t          | t                    rd |                                 D             S t          | t                    rd | D             S | S )a  Recursively expand ``${VAR}`` references in config values.

    Only string values are processed; dict keys, numbers, booleans, and
    None are left untouched.  Unresolved references (variable not in
    ``os.environ``) are kept verbatim so callers can detect them.
    z\${([^}]+)}c                     t           j                            |                     d          |                     d                    S )Nr   r   )r8   environr>   group)ms    rD   <lambda>z"_expand_env_vars.<locals>.<lambda>  s*    bjnnQWWQZZ<< rF   c                 4    i | ]\  }}|t          |          S rI   _expand_env_vars)r  kr  s      rD   
<dictcomp>z$_expand_env_vars.<locals>.<dictcomp>  s'    ???41a#A&&???rF   c                 ,    g | ]}t          |          S rI   r   )r  items     rD   r  z$_expand_env_vars.<locals>.<listcomp>  s!    7774 &&777rF   )r  rn   resubr  r  list)objs    rD   r  r    s     #s 
v<<
 
 	

 #t @??399;;????#t 87737777JrF   c                 j    t           fddD                       }|s S t                                           d          }t          |t                    s|rd|ini }| d<   dD ]I}                     |          }|r|                    |          s|||<                        |d           J S )u  Move stale root-level provider/base_url into model section.

    Some users (or older code) placed ``provider:`` and ``base_url:`` at the
    config root instead of inside ``model:``.  These root-level keys are only
    used as a fallback when the corresponding ``model.*`` key is empty — they
    never override an existing ``model.provider`` or ``model.base_url``.
    After migration the root-level keys are removed so they can't cause
    confusion on subsequent loads.
    c              3   B   K   | ]}                     |          V  d S Nr  )r  r  r  s     rD   	<genexpr>z-_normalize_root_model_keys.<locals>.<genexpr>  s-      CCQ6::a==CCCCCCrF   )r   r   r   r   N)anyr  r>   r  pop)r  has_rootr   r  root_vals   `    rD   _normalize_root_model_keysr    s     CCCC*BCCCCCH &\\FJJwEeT""  &+3E""w'  ::c?? 	"EIIcNN 	"!E#J

3MrF   c                     t          |           } t          |                     d          pi           }d| v rd|vr| d         |d<   d|vrt          d         d         |d<   || d<   |                     dd           | S )z;Normalize legacy root-level max_turns into agent.max_turns.r   r   N)r  r>   r  r  )r  agent_configs     rD   _normalize_max_turns_configr    s    &\\F

7++1r22LfL!@!@$*;$7[!,&&$27$;K$H[!"F7O
JJ{D!!!MrF   c                     ddl } t                       t                      }|                     t                    }|                                r	 t          |d          5 }t          j        |          pi }ddd           n# 1 swxY w Y   d|v r_t          |
                    d          pi           }|
                    d          |d         |d<   ||d<   |                    dd           t          ||          }n)# t          $ r}t          d|            Y d}~nd}~ww xY wt          t!          t#          |                              S )z.Load configuration from ~/.hermes/config.yaml.r   Nrr   rs   r   r   z Warning: Failed to load config: )r  r   r^   deepcopyr  r@   openyaml	safe_loadr  r>   r  r  r  rX   r  r  r  )r  config_pathr  fuser_configagent_user_configes          rD   r  r    s   KKK!##K]]>**F :	:kG444 6"nQ//526 6 6 6 6 6 6 6 6 6 6 6 6 6 6 k))$()A)A)GR$H$H!$((55=5@5M%k2'8G$T222 55FF 	: 	: 	:8Q8899999999	: 67RSY7Z7Z[[\\\s=   D !B8D BD BA6D 
D)D$$D)u  
# ── Security ──────────────────────────────────────────────────────────
# API keys, tokens, and passwords are redacted from tool output by default.
# Set to false to see full values (useful for debugging auth issues).
# tirith pre-exec scanning is enabled by default when the tirith binary
# is available. Configure via security.tirith_* keys or env vars
# (TIRITH_ENABLED, TIRITH_BIN, TIRITH_TIMEOUT, TIRITH_FAIL_OPEN).
#
# security:
#   redact_secrets: false
#   tirith_enabled: true
#   tirith_path: "tirith"
#   tirith_timeout: 5
#   tirith_fail_open: true
u  
# ── Fallback Model ────────────────────────────────────────────────────
# Automatic provider failover when primary is unavailable.
# Uncomment and configure to enable. Triggers on rate limits (429),
# overload (529), service errors (503), or connection failures.
#
# Supported providers:
#   openrouter   (OPENROUTER_API_KEY)  — routes to any model
#   openai-codex (OAuth — hermes login) — OpenAI Codex
#   nous         (OAuth — hermes login) — Nous Portal
#   zai          (ZAI_API_KEY)         — Z.AI / GLM
#   kimi-coding  (KIMI_API_KEY)        — Kimi / Moonshot
#   minimax      (MINIMAX_API_KEY)     — MiniMax
#   minimax-cn   (MINIMAX_CN_API_KEY)  — MiniMax (China)
#
# For custom OpenAI-compatible endpoints, add base_url and api_key_env.
#
# fallback_model:
#   provider: openrouter
#   model: anthropic/claude-sonnet-4
#
# ── Smart Model Routing ────────────────────────────────────────────────
# Optional cheap-vs-strong routing for simple turns.
# Keeps the primary model for complex work, but can route short/simple
# messages to a cheaper model across providers.
#
# smart_model_routing:
#   enabled: true
#   max_simple_chars: 160
#   max_simple_words: 28
#   cheap_model:
#     provider: openrouter
#     model: google/gemini-2.5-flash
uD  
# ── Security ──────────────────────────────────────────────────────────
# API keys, tokens, and passwords are redacted from tool output by default.
# Set to false to see full values (useful for debugging auth issues).
#
# security:
#   redact_secrets: false

# ── Fallback Model ────────────────────────────────────────────────────
# Automatic provider failover when primary is unavailable.
# Uncomment and configure to enable. Triggers on rate limits (429),
# overload (529), service errors (503), or connection failures.
#
# Supported providers:
#   openrouter   (OPENROUTER_API_KEY)  — routes to any model
#   openai-codex (OAuth — hermes login) — OpenAI Codex
#   nous         (OAuth — hermes login) — Nous Portal
#   zai          (ZAI_API_KEY)         — Z.AI / GLM
#   kimi-coding  (KIMI_API_KEY)        — Kimi / Moonshot
#   minimax      (MINIMAX_API_KEY)     — MiniMax
#   minimax-cn   (MINIMAX_CN_API_KEY)  — MiniMax (China)
#
# For custom OpenAI-compatible endpoints, add base_url and api_key_env.
#
# fallback_model:
#   provider: openrouter
#   model: anthropic/claude-sonnet-4
#
# ── Smart Model Routing ────────────────────────────────────────────────
# Optional cheap-vs-strong routing for simple turns.
# Keeps the primary model for complex work, but can route short/simple
# messages to a cheaper model across providers.
#
# smart_model_routing:
#   enabled: true
#   max_simple_chars: 160
#   max_simple_words: 28
#   cheap_model:
#     provider: openrouter
#     model: google/gemini-2.5-flash
c                 r   t                      rt          d           dS ddlm} t	                       t                      }t          t          |                     }g }|                    di           }|r|                    d          |	                    t                     |                    di           }|r*|                    d          r|                    d	          s|	                    t                      ||||rd
                    |          nd           t          |           dS )z,Save configuration to ~/.hermes/config.yaml.zsave configurationNr   )atomic_yaml_writer  r  fallback_modelr   r   r7   )extra_content)rJ   r[   utilsr!  r   r^   r  r  r>   r  _SECURITY_COMMENT_FALLBACK_COMMENTjoinro   )r  r!  r  rB   r  secfbs          rD   r  r  B  sG   || *+++''''''!##K+,G,O,OPPJ E
..R
(
(C (#''*++3&'''	("	-	-B (bffZ(( (RVVG__ (&'''(-7bggennn4   
 rF   c                     t                      } i }|                                 rt          rdddni }t          | fi |5 }|D ]}|                                }|rn|                    d          sYd|v rU|                    d          \  }}}|                                                    d          ||                                <   	 ddd           n# 1 swxY w Y   |S )z/Load environment variables from ~/.hermes/.env.rr   replacert   errors#=z"'N)r`   r@   _IS_WINDOWSr  r:   r  	partition)env_pathenv_varsopen_kwr  liner  r  r  s           rD   load_envr6  _  sG   ~~HH 	G ALSw)<<<QS(&&g&& 	G! G Gzz|| G 4 4 G$(NN3$7$7MCE,1KKMM,?,?,F,FHSYY[[)	G	G 	G 	G 	G 	G 	G 	G 	G 	G 	G 	G 	G 	G 	G 	G Os    B
CCClinesc           	         t          t                                                    t          z  }g }| D ]}|                    d          }|                                }|r|                    d          r|                    |dz              \g }|D ]c}|dz   }|                    |          }	|	dk    rA|                    |	           |                    ||	t          |          z             }	|	dk    Adt          |          dk    r|
                                 t          t          |                    }t          |          D ]k\  }
}|
dz   t          |          k     r||
dz            nt          |          }|||                                         }|r|                    |dz              l|                    |dz              |S )a  Fix corrupted .env lines before writing.

    Handles two known corruption patterns:
    1. Concatenated KEY=VALUE pairs on a single line (missing newline between
       entries, e.g. ``ANTHROPIC_API_KEY=sk-...OPENAI_BASE_URL=https://...``).
    2. Stale ``KEY=***`` placeholder entries left by incomplete setup runs.

    Uses a known-keys set (OPTIONAL_ENV_VARS + _EXTRA_ENV_KEYS) so we only
    split on real Hermes env var names, avoiding false positives from values
    that happen to contain uppercase text with ``=``.
    z
r.  
r/  r   r   )r  r  keys_EXTRA_ENV_KEYSrstripr:   r  r  findr  sortr  	enumerate)r7  
known_keys	sanitizedr5  rA   strippedsplit_positionskey_nameneedleidxiposendr  s                 rD   _sanitize_env_linesrJ  r  s    &++--..@JI . .kk&!!99;;  	8..s33 	S4Z((( " 	? 	?H^F--''C((&&s+++mmFC#f++,=>> (( !##  """$S%9%9::O#O44 2 2301AO8L8L0L0Loa!e,,RUV^R_R_C(..00 2$$TD[111	2 X_----rF   c                  6   t                      } |                                 sdS t          rdddni }t          rddini }t          | fi |5 }|                                }ddd           n# 1 swxY w Y   t          |          }||k    rdS t          t          |          t          |          z
            }|dk    rVt          d t          ||          D                       }|t          t          |          t          |          z
            z  }t          j        t          | j                  dd	
          \  }}	 t          j        |dfi |5 }|                    |           |                                 t          j        |                                           ddd           n# 1 swxY w Y   t          j        ||            n5# t*          $ r( 	 t          j        |           n# t.          $ r Y nw xY w w xY wt1          |            |S )zRead, sanitize, and rewrite ~/.hermes/.env in place.

    Returns the number of lines that were fixed (concatenation splits +
    placeholder removals).  Returns 0 when no changes are needed.
    r   rr   r+  r,  rt   Nc              3   ,   K   | ]\  }}||k    d V  dS )r   NrI   )r  abs      rD   r  z$sanitize_env_file.<locals>.<genexpr>  s*      KK$!QAFFAFFFFKKrF   .tmp.env_dirsuffixr  w)r`   r@   r0  r  	readlinesrJ  absr  sumziptempfilemkstemprn   rc   r8   fdopen
writelinesflushfsyncfilenor+  BaseExceptionunlinkrh   ro   )	r2  read_kwwrite_kwr  original_linesrA  r  fdtmp_paths	            rD   r  r    s    ~~H?? q<GO7i888RG(3;
G$$H	h	"	"'	"	" 'a' ' ' ' ' ' ' ' ' ' ' ' ' ' ' $N33IN""q I^!4!4455EzzKK#ni"@"@KKKKKS^^c.&9&99:::#HO(<(<VT[\\\LBYr3++(++ 	!qLL###GGIIIHQXXZZ   	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	
8X&&&&   	Ih 	 	 	D	 Lsg   A..A25A2G AF4(G 4F88G ;F8<G 
H G54H5
H?HHHr  r  c                    t                      rt          d|             dS t                              |           st	          d|           |                    dd                              dd          }t                       t                      }t          rddd	ni }t          rd
dini }g }|	                                rHt          |fi |5 }|                                }ddd           n# 1 swxY w Y   t          |          }d}t          |          D ]>\  }}	|	                                                    |  d          r|  d| d||<   d} n?|sH|r+|d                             d          s|dxx         dz  cc<   |                    |  d| d           t%          j        t)          |j                  dd          \  }
}	 t-          j        |
dfi |5 }|                    |           |                                 t-          j        |                                           ddd           n# 1 swxY w Y   t-          j        ||           n5# t8          $ r( 	 t-          j        |           n# t<          $ r Y nw xY w w xY wt?          |           |t,          j         | <   t          s@	 t-          j!        |tD          j#        tD          j$        z             dS # t<          $ r Y dS w xY wdS )z)Save or update a value in ~/.hermes/.env.zset Nz#Invalid environment variable name: r9  r7   rr   r+  r,  rt   Fr/  Tr  rO  rP  rQ  rT  )%rJ   r[   _ENV_VAR_NAME_REmatch
ValueErrorr+  r   r`   r0  r@   r  rU  rJ  r?  r:   r  endswithr  rY  rZ  rn   rc   r8   r[  r\  r]  r^  r_  r`  ra  rh   ro   r  rg   statS_IRUSRS_IWUSR)r  r  r2  rb  rc  r7  r  foundrG  r5  re  rf  s               rD   r  r    s   || lSll###!!#&& HFsFFGGGMM$##++D"55E~~H =HO7i888RG(3;
G$$HE +(&&g&& 	"!KKMME	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" $E** EU##  4::<<""c999-- 	)))))E!HEE	
  ) 	r++D11 	"IIIIII''e'''(((#HO(<(<VT[\\\LBYr3++(++ 	!qLLGGIIIHQXXZZ   	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	
8X&&&&   	Ih 	 	 	D	 BJsO  	HXt|dl:;;;;; 	 	 	DD	 sy   C44C8;C8I% (AI8I% II% II% %
J0JJ
JJJJ ,K. .
K<;K<c                 H    |pt           } |d|             |dd           dS )zBPersist an Anthropic OAuth/setup token and clear the API-key slot.r   r   r7   Nr  r  save_fnwriters      rD   save_anthropic_oauth_tokenrv    s8    &F
Fe$$$
F#####rF   c                 H    | pt           } |dd            |dd           dS )zHUse Claude Code's own credential files instead of persisting env tokens.r   r7   r   Nrr  )rt  ru  s     rD   %use_anthropic_claude_code_credentialsrx    s8    &F
Fb!!!
F#####rF   c                 H    |pt           } |d|             |dd           dS )zBPersist an Anthropic API key and clear the OAuth/setup-token slot.r   r   r7   Nrr  rs  s      rD   save_anthropic_api_keyrz    s8    &F
F&&&
Fb!!!!!rF   c                 .    t          | |           d| ddS )NTF)success	stored_as	validatedrr  )r  r  s     rD   save_env_value_securer  %  s*    3  rF   c                     | t           j        v rt           j        |          S t                      }|                    |           S )z/Get a value from ~/.hermes/.env or environment.)r8   r  r6  r>   )r  r3  s     rD   r  r  /  s:     bjz# zzH<<rF   c                     | st          dt          j                  S t          |           dk     rdS | dd         dz   | dd         z   S )zRedact an API key for display.	(not set)   z***Nr0  ...)r)   r(   DIMr  )r  s    rD   
redact_keyr  >  sO     .[&*---
3xx"}}urr7U?SX%%rF   c            	         t                      } t                       t          t          dt          j                             t          t          dt          j                             t          t          dt          j                             t                       t          t          dt          j        t          j                             t          dt                                  t          dt                                  t          dt                                  t                       t          t          dt          j        t          j                             g d	}|D ]7\  }}t          |          }t          d
|ddt          |                      8t          d          pt          d          }t          d
dddt          |                      t                       t          t          dt          j        t          j                             t          d|                     dd                      t          d|                     di                               dt          d         d                               t                       t          t          dt          j        t          j                             |                     di           }t          d|                    dd                      t          d|                    dd          rdnd             t          d!|                    d"d          rdnd             t                       t          t          d#t          j        t          j                             |                     d$i           }t          d%|                    d&d'                      t          d(|                    d)d*                      t          d+|                    d,d-           d.           |                    d&          d/k    r(t          d0|                    d1d2                      nj|                    d&          d3k    r(t          d4|                    d5d6                      n)|                    d&          d7k    rLt          d8|                    d9d2                      t          d:          }t          d;|rd<nd=            n|                    d&          d>k    rLt          d?|                    d@d2                      t          dA          }	t          dB|	rd<nd=            n_|                    d&          dCk    rFt          dD          }
t          dE          }t          dF|
pd=            t          dG|pd=            t                       t          t          dHt          j        t          j                             |                     dIdJ          }|rt          dK|            n*t          dKt          dLt          j                              t                       t          t          dMt          j        t          j                             |                     dNi           }|                    dOdP          }t          dQ|rdRndS            |rt          dT|                    dUdV          dWz  dXdY           t          dZ|                    d[d\          dWz  dXd]           t          d^|                    d_d`           da           |                    dbdJ          pdc}t          d|            |                    ddde          }|dek    rt          df|            |                     dgi           }|                    dhi           |                    dii           dj}t          dk |                                D                       }|rt                       t          t          dlt          j        t          j                             |                                D ]\  }}|                    dmde          }|                    ddJ          }|dek    s|rIdn| g}|r|                    do|            t          d
|dpd
dq                    |                      t                       t          t          drt          j        t          j                             t          ds          }t          dt          }t          du|rd<nt          dvt          j                              t          dw|rd<nt          dvt          j                              t                       t          t          dxt          j                             t          t          dyt          j                             t          t          dzt          j                             t          t          d{t          j                             t                       d|S )}zDisplay current configuration.u   ┌─────────────────────────────────────────────────────────┐u@   │              ⚕ Hermes Configuration                    │u   └─────────────────────────────────────────────────────────┘u	   ◆ Pathsz  Config:       z  Secrets:      z  Install:      u   ◆ API Keys)	)r:  
OpenRouter)r'  zOpenAI (STT/TTS))rR  Exa)rU  Parallel)r#  	Firecrawl)r-  Tavily)r$  Browserbase)r^  zBrowser Use)r&  FALr  z<14 r   r   	Anthropicu	   ◆ Modelz  Model:        r   znot setz  Max turns:    r   r   u   ◆ Displayr   z  Personality:  r   r   z  Reasoning:    r   Fonr   z  Bell:         r   u   ◆ Terminalr   z  Backend:      r   r   z  Working dir:  r   r   z  Timeout:      r   r  sdockerz  Docker image: r   r   singularityz  Image:        r   r   modalz  Modal image:  r   MODAL_TOKEN_IDz  Modal token:  
configuredr  daytonaz  Daytona image: r   DAYTONA_API_KEYz  API key:      sshTERMINAL_SSH_HOSTTERMINAL_SSH_USERz  SSH host:     z  SSH user:     u   ◆ Timezoner  r7   z  Timezone:     r  u   ◆ Context Compressionr   r   Tz  Enabled:      r-   r  z  Threshold:    r   r   d   z.0f%z  Target ratio: r   r   z% of threshold preservedz  Protect last: r   r   z	 messagesr   z(main model)r   r   z  Provider:     r   r   r   )VisionzWeb extractc              3   v   K   | ]4}|                     d d          dk    p|                     dd          V  5dS )r   r   r   r7   Nr  )r  ts     rD   r  zshow_config.<locals>.<genexpr>  s\         	
j&!!V+AquuWb/A/A     rF   u    ◆ Auxiliary Models (overrides)r   z	provider=zmodel=12s, u   ◆ Messaging Platformsrm  rp  z  Telegram:     znot configuredz  Discord:      u   ────────────────────────────────────────────────────────────z+  hermes config edit     # Edit config filez!  hermes config set <key> <value>z+  hermes setup           # Run setup wizardN)r  rX   r)   r(   CYANBOLDr^   r`   re   r  r  r>   r  r  r  valuesr  r  r'  )r  r:  env_keyr  r  anthropic_valuer   r   modal_tokendaytona_keyssh_hostssh_usertzr   r   _smcomp_providerr   	aux_taskshas_overrideslabeltask_cfgprovmdlr  telegram_tokendiscord_tokens                              rD   show_configr  G  s
   ]]F	GGG	%  D  FL  FQ  R  R  S  S  S	%RTZT_
`
`aaa	%  D  FL  FQ  R  R  S  S  S 
GGG	%V[&+
6
6777	
0_..
0
0111	
-\^^
-
-...	
1-//
1
1222 
GGG	%V[
9
9:::
 
 
D  3 3g&&14111j//112222#$566\-H[:\:\O	
>{
>
>
>O!<!<
>
>??? 
GGG	%V[&+
6
6777	
=VZZ;;
=
=>>>	
mVZZ4488nU\F]^iFjkk
m
mnnn 
GGG	%v{FK
8
8999jjB''G	
CW[[AA
C
CDDD	
VW[[1A5%I%ITTTu
V
VWWW	
XW[[1CU%K%KVTTQV
X
XYYY 
GGG	%V[
9
9:::zz*b))H	
?X\\)W==
?
?@@@	
7X\\%55
7
7888	
;X\\)R88
;
;
;<<<||I(**mn>j!k!kmmnnnn	i	 	 M	1	1{.ACx!y!y{{||||	i	 	 G	+	+lm=i!j!jllmmm#$455O!M+OOPPPP	i	 	 I	-	-o(,,@l"m"mooppp#$566O!M+OOPPPP	i	 	 E	)	) !455 !455:!8[::;;;:!8[::;;; 
GGG	%V[
9
9:::	J	#	#B	 H%%%&&&&F'7!D!DFFGGG 
GGG	%)6;
D
DEEE**]B//Kooi..G	
9g7UU4
9
9::: 6Pd!C!Cc!IPPPPQQQj!F!F!LjjjjkkkQ1A2!F!FQQQRRRooor22Dn&&&'''#(:FCCF""4]44555 

;++I }}Xr22 }}]B77 I   !!##    M  
<e6V[QQRRR(00 	< 	<OE8<<
F33D,,w++Cv~~~+T++, 1LL#000:5:::		%(8(8::;;; 
GGG	%)6;
D
DEEE"#788N!"566M	
f^d\\GWY_YcAdAd
f
fggg	
e]c\\FVX^Xb@c@c
e
efff	GGG	%
FJ
'
'(((	%=vz
J
JKKK	%3VZ
@
@AAA	%=vz
J
JKKK	GGGGGrF   c                  (   t                      rt          d           dS t                      } |                                 s&t	          t
                     t          d|             t          j        d          pt          j        d          }|s"dD ]}ddl	}|
                    |          r|} n |s#t          d           t          d	|             dS t          d
|  d| d           t          j        |t          |           g           dS )z"Open config file in user's editor.zedit configurationNzCreated EDITORVISUAL)nanovimvicodenotepadr   z#No editor found. Config file is at:r  zOpening  in r  )rJ   r[   r^   r@   r  r  rX   r8   r9   shutilwhich
subprocessrunrn   )r  editorcmdr  s       rD   edit_configr    sE   || *+++!##K  (N###&&&''' Yx  7BIh$7$7F ; 	 	CMMM||C     3444 ;  !!!	
1[
1
1f
1
1
1222NFC,,-.....rF   c                     t                      rt          d           dS g d}|                                 |v su|                                                     d          sN|                                                     d          s'|                                                     d          rEt          |                                 |           t          d|  dt                                  dS t                      }i }|	                                rS	 t          |d	
          5 }t          j        |          pi }ddd           n# 1 swxY w Y   n# t          $ r i }Y nw xY w|                     d          }|}|dd         D ];}||vs(t          |                    |          t"                    si ||<   ||         }<|                                dv rd}nu|                                dv rd}n\|                                rt)          |          }n8|                    ddd                                          rt-          |          }|||d         <   t/                       t          |dd	
          5 }t          j        ||dd           ddd           n# 1 swxY w Y   dddddddddddd }	| |	v r#t          |	|          t3          |                     t          d|  d!| d|            dS )"zSet a configuration value.zset configuration valuesN)r:  r   r   r'  rR  rU  r#  rV  rW  rX  rY  rZ  r-  r$  r%  r^  r&  rm  rp  r  r  r   r  r*  r+  ri  rj  re  ra  _API_KEY_TOKENTERMINAL_SSHu   ✓ Set r  rr   rs   r   r  )r+   r-   r  T)r  r  r   Fr7   r   rT  )default_flow_style	sort_keysr   r.  TERMINAL_DOCKER_IMAGETERMINAL_SINGULARITY_IMAGETERMINAL_MODAL_IMAGETERMINAL_DAYTONA_IMAGE&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACETERMINAL_CWDTERMINAL_TIMEOUTTERMINAL_SANDBOX_DIRTERMINAL_PERSISTENT_SHELL)zterminal.backendzterminal.modal_modezterminal.docker_imagezterminal.singularity_imagezterminal.modal_imagezterminal.daytona_imagez&terminal.docker_mount_cwd_to_workspacezterminal.cwdzterminal.timeoutzterminal.sandbox_dirzterminal.persistent_shellr  )rJ   r[   upperrl  r  r  rX   r`   r^   r@   r  r  r  r  r  r  r>   r  r;   isdigitintr+  floatr   dumprn   )
r  r  api_keysr  r  r  r  r  r  _config_to_env_syncs
             rD   set_config_valuer    s   || 0111  H yy{{h#))++"6"6z"B"BciikkFZFZ[cFdFdhkhqhqhshsh~h~  @N  iO  iOsyy{{E***222,..22333
 "##KK 	kG444 6"nQ//526 6 6 6 6 6 6 6 6 6 6 6 6 6 6 	 	 	KKK	 IIcNNEGcrc
    wjT1B1BD&I&IGDM$- {{}}---	0	0	0	 E

	sB	"	"	*	*	,	, eGE"I 	k3	1	1	1 MQ	+qUeLLLLM M M M M M M M M M M M M M M +4!8&B 6":2Z&. 6%@  !!!*3/U<<<	
5S
5
5U
5
5
5
566666sH   E *EE EE EE E('E(J&&J*-J*c           	         t          | dd          }||dk    rt                       dS |dk    rt                       dS |dk    rt          | dd          }t          | dd          }|r|mt          d           t                       t          d	           t          d
           t          d           t          d           t	          j        d           t          ||           dS |dk    rt          t                                 dS |dk    rt          t                                 dS |dk    rt                       t          t          dt          j        t          j                             t                       t          d          }t                      }t                      \  }}|s?|s=||k    r7t          t          dt          j                             t                       dS ||k     rt          d| d|            |r t          dt#          |           d           d |D             }d |D             }	|r=t          dt#          |           d           |D ]}
t          d|
d                     |	rzt          dt#          |	           d            |	D ]W}
|
                    d!g           }|r!d"d#                    |dd$                    d%nd&}t          d|
d          |            Xt                       t)          d'd(          }t                       |d)         s|d*         r't          t          d+t          j                             |d,         rCt                       |d,         D ],}t          t          d-| t          j                             -t                       dS |d.k    rt                       t          t          d/t          j        t          j                             t                       t                      \  }}||k    rt          d| d0           n.t          t          d| d| d1t          j                             t                       t          t          d2t          j                             t,          D ]O}t/          |          rt          d3|            $t          t          d4| d5t          j                             Pt                       t          t          d6t          j                             t2                                          D ]\  }}t/          |          rt          d3|            '|                    d!g           }|r dd#                    |dd$                    nd&}t          t          d7| | t          j                             t                      }|rUt                       t          t          d8t#          |           d9t          j                             t          d:           t                       dS t          d;|            t                       t          d<           t          d=           t          d>           t          d?           t          d@           t          dA           t          dB           t          dC           t	          j        d           dS )DzHandle config subcommands.config_commandNshoweditr  r  r  z&Usage: hermes config set <key> <value>z	Examples:z3  hermes config set model anthropic/claude-sonnet-4z+  hermes config set terminal.backend dockerz0  hermes config set OPENROUTER_API_KEY sk-or-...r   rk   zenv-pathmigrateu*   🔄 Checking configuration for updates...Fr  u    ✓ Configuration is up to date!z  Config version: r  r  z1 new config option(s) will be added with defaultsc                 <    g | ]}|                     d           |S )r  r  r  s     rD   r  z"config_command.<locals>.<listcomp>  s)    KKK!aeeM6J6JKAKKKrF   c                 f    g | ].}|                     d           |                     d          ,|/S )r  r9  r  r  s     rD   r  z"config_command.<locals>.<listcomp>  sN     
 
 
55''
01j0A0A

 
 
rF   u   
  ⚠️  z required API key(s) missing:u	        • r  u   
  ℹ️  z$ optional API key(s) not configured:r=  z (enables: r     )r7   T)r  r  r  r  u   ✓ Configuration updated!r  u
     ⚠️  checku   📋 Configuration Statusu    ✓z (update available)z  Required:u       ✓ u       ✗ z
 (missing)z  Optional:u       ○ r  z new config option(s) availablez+    Run 'hermes config migrate' to add themzUnknown config command: zAvailable commands:z4  hermes config           Show current configurationz/  hermes config edit      Open config in editorz6  hermes config set <key> <value>   Set a config valuez;  hermes config check     Check for missing/outdated configz8  hermes config migrate   Update config with new optionsz/  hermes config path      Show config file pathz-  hermes config env-path  Show .env file path)getattrr  r  rX   rY   exitr  r^   r`   r)   r(   r  r  r  r  r  GREENr  r>   r'  r  YELLOWr  r  REDr  r  r  )argssubcmdr  r  r  r  r  r  required_missingoptional_missingr  r=  	tools_strr  warningr  r  s                    rD   r  r  M  sA   T+T22F~6))	6			5dE4((gt,, 	em:;;;GGG+GHHH?@@@DEEEHQKKKe$$$$$	6		o     	:		lnn	9		e@&+v{[[\\\ +???244"6"8"8Z 	> 	kZ6O6O%:FLIIJJJGGGF ##E{EEEEFFF 	a_^,,___```KK{KKK
 
"
 
 

  	1U%5!6!6UUUVVV' 1 1/#f+//0000 	<\%5!6!6\\\]]]' < <,,EJRA$))E"1"I*>*>AAAAPR	:#f+:y::;;;; !T???; 	E7>#: 	E%4flCCDDD: 	DGGG":. D De222FMBBCCCC	7		e/fkJJKKK"6"8"8Z*$$8{8889999%^[^^z^^^`f`mnnoooeM6;//000) 	J 	JHX&& J+++,,,,e;x;;;VZHHIIIIeM6;//000/5577 	K 	KNHdX&& K+++,,,,"-->CK:DIIeBQBi$8$8:::	e<x<<<fjIIJJJJ244 	AGGG%QS00QQQSYS`aabbb?@@@ 	111222#$$$DEEE?@@@FGGGKLLLHIII?@@@=>>>rF   )rP   )rU   )F)TFr  )X__doc__r8   platformr  rm  r  rY   rY  pathlibr   typingr   r   r   r   r   tools.tool_backend_helpersr	   _managed_nous_tools_enabledsystemr0  compileri  	frozensetr;  r  hermes_cli.colorsr(   r)   hermes_cli.default_soulr*   r<   r=   rn   rE   boolrJ   rM   rO   rT   r[   hermes_constantsr?   r^   r`   re   rl   ro   rw   r   r  r2  r  __annotations__r  r  _hidden_varr  r  r  r  r  r  r  r  r  r  r  r  r%  r&  _COMMENTED_SECTIONSr  r6  r  rJ  r  r  rv  rx  rz  r  r  r  r  r  r  r  rI   rF   rD   <module>r     s"     
			  				      



        3 3 3 3 3 3 3 3 3 3 3 3 3 3 ` ` ` ` ` `ho9,2:9::  )       + + + + + + + + 3 3 3 3 3 3 , 	  HSM    ,D , , , ,HSM    ;C ; ; ; ;
 3 s    8; ;# ; ; ; ; - , , , , ,- - - - -&d & & & &2$ 2 2 2 2    $ 4    	" 	" 	" IRI"I !"I 	I
  !' I  7f 	s 	3	 	2 	D 	b 	R 	C 	E 	  	D!" 	%#$ 	%, 	"-2 	(3< 	D=I` ! # "5
 aIB  CIR 7SIV "  WIh 	 iIB  "
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
g: :CIz  &!!&  {IZ e[Id 
'

 /0
 

 '
 
 3	
 
 eIR 
V
 [
	 	SIh !$  iI Ix  yIF  $!
 
 
GIf  gI~ RIH IIV bWI^ _Id "$	 eIt  uIJ	  K	IV	 W	IZ	 b[	Ib	 Rc	Ih	  
 
 i	IB
  	C
IP
 rQ
I Id
 YXX "67E E E		- - T#tCy.)     x6B x W&+"$78 x& [& 'x6 =  7xF =  GxV 5A Wxf 0 . gxv :; wxF 8#( GxV 2> Wxf 9+* gxv :F wxF D$7 GxT @% Uxb W%> cxp `& qx@ V() Ax xP 7C Qx` U') axp 6B qx@ o&7 AxN K9 Oxb J . cxr N$%. sxB F%'. CxR O= Sxb jM cxr  o. sxB  j+ CxR  O+   Sxb T",;;; cxr n')$o6 sxB \*)$o6 CxR n')$o6 Sx x xb r&:$o6 cxr 9 "# sxB	 7"@MMM C	xR	 I!+"$56 S	xb	 X:5'6 c	xr	 M&' s	x@
 \ 3 A
xR
 G"'"# S
xb
 V@ c
xp
 ;&' q
x~
 l?) 
xL @%< MxZ P> [xh P /+ ixz G /+ {xL L)/ MxZ F( [x x xh SA! !ixv !z0# #wxD (c?* *ExR P)6 Sx` L' axn B1 ox| e= }xJ f0   KxZ  L2 [xj y2 kxz A# {xJ  ]# KxZ k0 [xh J  ixv t" wxH N? IxV R! Wx xf X"  WB  WB" " `.% % i+' 'cx x x t #"$$ 1 1 1 	k40000  d38n9M    , #    4S#X#7    8	eCHo 	 	 	 	u u uD uT#s(^ u u u upd d t    (  (tCH~ $sCx.    <S#X 4S>    "]T#s(^ ] ] ] ]6  ! H( VS#X    :$sCx.    &0t 0 0 0 0 0f*3 * * * *Z; ;C ; ; ; ;|$ $c $ $ $ $$ $ $ $" "# " " " "s 3 4S>    s x}    &C &C & & & &L L L^/ / /@P7# P7c P7 P7 P7 P7nF F F F FrF   