
    epja|                    *   d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
 ddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ ddlmZ ddlmZ ddl m!Z!  ej"        e#          Z$d	 Z%d!dZ&dZ'd"dZ(d#d$dZ)d#d%dZ*d&dZ+	 d#ddd'dZ,d(dZ-g d Z.dS ))u  System-prompt assembly for :class:`AIAgent`.

The agent's system prompt is built once per session and reused across all
turns — only context compression triggers a rebuild.  This keeps the
upstream prefix cache warm.  See ``hermes-agent-dev``'s
``references/system-prompt-invariant.md`` for the invariants and
``references/self-improvement-loop.md`` for how the background-review
fork inherits the cached prompt verbatim.

Three tiers are joined with ``\n\n``:

* ``stable``   — identity (SOUL.md or DEFAULT_AGENT_IDENTITY), tool
  guidance, computer-use guidance, nous subscription block, tool-use
  enforcement guidance + per-model operational guidance,
  alibaba model-name workaround, environment hints, coding guidance,
  platform hints.
* ``context``  — caller-supplied ``system_message`` plus context files
  (AGENTS.md / .cursorrules / etc.) discovered under ``TERMINAL_CWD``,
  plus the session's coding-workspace snapshot.
* ``volatile`` — skills index, memory snapshot, USER.md profile, external
  memory provider block, timestamp/session/model/provider line.

Pure helpers that read the agent's state.  AIAgent keeps thin forwarders.
    )annotationsN)AnyDictListOptional)DEFAULT_AGENT_IDENTITY!GOOGLE_MODEL_OPERATIONAL_GUIDANCEHERMES_AGENT_HELP_GUIDANCEKANBAN_GUIDANCEMEMORY_GUIDANCEOPENAI_MODEL_EXECUTION_GUIDANCEPARALLEL_TOOL_CALL_GUIDANCEPLATFORM_HINTSSESSION_SEARCH_GUIDANCESKILLS_GUIDANCESTEER_CHANNEL_NOTETASK_COMPLETION_GUIDANCETELEGRAM_RICH_MESSAGES_HINTTOOL_USE_ENFORCEMENT_GUIDANCETOOL_USE_ENFORCEMENT_MODELSdrain_truncation_warnings)resolve_context_cwd)get_hermes_home)is_truthy_valuec                     ddl } | S )a  Lazy reference to the ``run_agent`` module.

    Helpers like ``load_soul_md``, ``build_environment_hints``,
    ``build_context_files_prompt``, ``build_nous_subscription_prompt``,
    ``build_skills_system_prompt`` and ``get_toolset_for_tool`` are
    imported into ``run_agent``'s namespace.  Many tests
    ``patch("run_agent.load_soul_md", ...)``; if we imported them
    directly here those patches would not reach us.  Looking them up
    through ``run_agent`` on every call preserves the patch contract.
    r   N	run_agentr   s    9/home/thesage/.hermes/hermes-agent/agent/system_prompt.py_rar   :   s         agentr   platform_keystrdefault_hintreturnc                   |s|S t          | dd          }t          |t                    r|s|S |                    |          }||S t          |t                    r1|                                }|r| d|                                 n|S t          |t                    s|S |                    d          }t          |t                    r)|                                r|                                }n|}|                    d          }t          |t                    r?|                                r+| d|                                                                 S |S )u  Apply a per-platform prompt-hint override to the default hint.

    Reads ``agent._platform_hint_overrides`` (populated from
    ``config.yaml`` ``platform_hints`` by ``agent_init``) and resolves the
    effective hint for *platform_key*:

      * ``replace`` — substitute the default hint entirely.
      * ``append``  — keep the default and append the extra text.
      * a bare string value — treated as ``append`` (convenience shorthand).

    Precedence: ``replace`` wins over ``append`` if both are present.
    Override text is added on top of (not instead of) the SOUL/context/
    memory tiers — it only affects the platform-hint segment, so other
    platforms are unaffected and general system instructions still apply.

    Defensive: any malformed entry falls back to the unmodified default so
    a bad config value can never break prompt assembly or leak across
    platforms.
    _platform_hint_overridesN

replaceappend)getattr
isinstancedictgetr#   strip)	r!   r"   r$   	overridesspecextrareplace_textbaseappend_texts	            r   _resolve_platform_hintr6   I   sx   (  94@@Ii&& i ==&&D| $ O

7<N,++E++11333,NdD!! 88I&&L,$$ ););)=)= !!##((8$$K+s## :(9(9(;(; :11K--//1177999Kr    u    You're in its embedded terminal pane, beside the GUI chat — the user can select your output (Option-drag on macOS, Shift-drag elsewhere) and press Cmd/Ctrl+L to send it to the chat composer.hintc                z    | s| S t           | v r| S t          t          j        d                    s| S | t           z   S )u  Append the desktop-embedded-terminal-pane clarifier to a tui hint.

    Triggered by ``HERMES_DESKTOP_TERMINAL=1`` (set by ``main.cjs`` only on the
    shell env of the desktop's embedded TUI PTY — never on the chat backend).
    This is a runtime-surface qualifier, not a config override, so it lives at
    the resolution site rather than inside ``_resolve_platform_hint`` (which
    is purely the config-platform_hints override applier). Byte-stable for the
    cache: called once per session build, deterministically from env state.

    Idempotent and empty-safe: re-applying on an already-augmented hint is a
    no-op, and an empty input returns empty (we never synthesize the
    clarifier without its tui framing).
    HERMES_DESKTOP_TERMINAL)_TUI_EMBEDDED_PANE_CLARIFIERr   osgetenv)r7   s    r   _tui_embedded_pane_clarifierr=      sM      #t++29%>??@@ ...r    system_messageOptional[str]Dict[str, str]c                :   01 t                      0d}t           dd          }|.t          |dd          }t          |t                    r|dk    r|}g }d} j        s j        s.0                    |          }|r|                    |           d}|s|                    t                     |                    t                     t           dd          r! j
        r|                    t                     t           dd          r! j
        r|                    t                     g }d	 j
        v r|                    t                     d
 j
        v r|                    t                     d j
        v r|                    t                     t           dd          }	|	r|                    |	           n%|	#d j
        v r|                    t                      |r(|                    d                    |                      j
        r|                    t$                     d j
        v r#ddlm}
 |                     |
                       0                     j
                  }|r|                    |            j
        rs j        }d}|du s+t          |t.                    r|                                dv rd}n|du s+t          |t.                    r|                                dv rd}nt          |t2                    r7 j        pd                                1t7          1fd|D                       }n; j        pd                                1t7          1fdt8          D                       }|r}|                    t:                      j        pd                                }d|v sd|v r|                    t<                     d|v sd|v sd|v r|                    t>                     t7           fddD                       }|rd 0fd j
        D             D             }tA                      }	 ddl!m"}  | j#        tI                                 }n# tJ          $ r tA                      }Y nw xY w0&                     j
        ||pd!          }nd} j'        d"k    rQd# j        v r  j        (                    d#          d$         n j        }|                    d%| d& j         d'           0)                                }|r|                    |           g }g } j
        rU	 dd(l!m*}  | j#        tI                       j        )          \  }}}|+                    |           n# tJ          $ r Y nw xY w|rg }n|+                    |           |}t           d*d          r9	 dd+l,m-}  |            }|r|                    |           n# tJ          $ r Y nw xY w	 dd,l.m/}  |            }n# tJ          $ r d-}Y nw xY w|d-k    r5|                    d.t/          ta                                z   d/z              ng|                    d0| d1ta                       d2| d3ta                       d4ta                       d5ta                       d6ta                       d7            j#        pd                                1                                }d} |td          v rtd          |         } n?|r=	 dd8l3m4}! |!5                    |          }"|"r|"j6        r|"j6        } n# tJ          $ r Y nw xY w|d9k    r| r	 dd:l7m8}#  |#            }$|$5                    d;          pi 5                    d9          pi 5                    d<          pi }%|%5                    d=          r| 9                                dz   tt          z   } n# tJ          $ r Y nw xY wtw           ||           }&|d>k    r|&rty          |&          }&|&r|                    |&           g }'|r?|'+                    |           |'+                    |           |'+                    |           ||'                    |            j        sC0=                    tI                      || j#        d?v @          }(|(r|'                    |(           g })|r|)                    |            j>        rp j?        r1 j>        @                    d	          }*|*r|)                    |*            jA        r1 j>        @                    dA          }+|+r|)                    |+            jB        rB	  jB        C                                },|,r|)                    |,           n# tJ          $ r Y nw xY wddBlDmE}-  |-            }.dC|.F                    dD           }/ jG        r jH        r|/dE jH         z  }/ j        r|/dF j         z  }/ j'        r|/dG j'         z  }/ j#        r|/dH j#         z  }/|)                    |/           dI                    dJ |D                       dI                    dK |'D                       dI                    dL |)D                       dMS )Nu2  Assemble the system prompt as three ordered cache tiers.

    Returns a dict with three keys:
      * ``stable``   — the cross-session-stable prefix, through the coding
        operating brief when a workspace snapshot follows.
      * ``context``  — the workspace snapshot followed by the remaining
        session-stable guidance, context files, and caller-supplied
        system_message.
      * ``volatile`` — skills index, memory snapshot, user profile,
        external memory provider block, timestamp line.

    Joined into a single string by :func:`build_system_prompt` and
    cached on ``agent._cached_system_prompt`` for the lifetime of the
    AIAgent.  Hermes never re-renders parts of this string mid-
    session — that's the only way to keep upstream prompt caches
    warm across turns.
    Ncontext_compressorcontext_lengthr   FT_task_completion_guidance_parallel_tool_call_guidancememorysession_searchskill_manage_kanban_worker_guidancekanban_show computer_use)computer_use_guidance>   onyestruealways>   noofffalsenever c              3  n   K   | ]/}t          |t                    |                                v V  0d S N)r,   r#   lower.0pmodel_lowers     r   	<genexpr>z,build_system_prompt_parts.<locals>.<genexpr>  sA      [[q
STVYHZHZ[!'')){2[[[[[[r    c              3      K   | ]}|v V  	d S rX    rZ   s     r   r^   z,build_system_prompt_parts.<locals>.<genexpr>  s(      PPq!{*PPPPPPr    geminigemmagptcodexgrokc              3  *   K   | ]}|j         v V  d S rX   )valid_tool_names)r[   namer!   s     r   r^   z,build_system_prompt_parts.<locals>.<genexpr>+  s+      ttd45#99ttttttr    )skills_list
skill_viewrH   c                    h | ]}||S r`   r`   )r[   toolsets     r   	<setcomp>z,build_system_prompt_parts.<locals>.<setcomp>-  s0     
 
 
 

 
 
r    c              3  B   K   | ]}                     |          V  d S rX   )get_toolset_for_tool)r[   	tool_name_rs     r   r^   z,build_system_prompt_parts.<locals>.<genexpr>/  sB        7@''	22     r    )coding_compact_skill_categories)platformcwd)available_toolsavailable_toolsetscompact_categoriesalibaba/z#You are powered by the model named z. The exact model ID is zt. When asked what model you are, always answer based on this information, not on any model name returned by the API.)coding_system_prompt_parts)rs   rt   model_environment_probe)get_environment_probe_line)_resolve_active_profile_namedefaultzCActive Hermes profile: default. Other profiles (if any) live under z/profiles/<name>/. Each profile has its own skills/, plugins/, cron/, and memories/ that affect a different session than this one. Do not modify another profile's skills/plugins/cron/memories unless the user explicitly directs you to.zActive Hermes profile: z . This session reads and writes z
/profiles/z'/. The default profile's data lives at z
/skills/, z/plugins/, z/cron/, u/  /memories/ — those belong to a different session run from a different shell. Do NOT modify another profile's skills/plugins/cron/memories unless the user explicitly directs you to. The cross-profile write guard will refuse such writes by default; pass cross_profile=True only after explicit direction.)platform_registrytelegram)load_config_readonly	platformsr2   rich_messagestui)clir   )rt   	skip_soulrC   allow_install_tree_fallbackuser)nowzConversation started: z%A, %B %d, %Yz
Session ID: z
Model: z
Provider: z
Platform: r(   c              3  j   K   | ].}||                                 |                                 V  /d S rX   r/   r[   r\   s     r   r^   z,build_system_prompt_parts.<locals>.<genexpr>+  <      UUaQU17799U		UUUUUUr    c              3  j   K   | ].}||                                 |                                 V  /d S rX   r   r   s     r   r^   z,build_system_prompt_parts.<locals>.<genexpr>,  r   r    c              3  j   K   | ].}||                                 |                                 V  /d S rX   r   r   s     r   r^   z,build_system_prompt_parts.<locals>.<genexpr>-  r   r    )stablecontextvolatile)Ir   r+   r,   intload_soul_identityskip_context_filesload_soul_mdr*   r   r
   rg   r   r   r   r   r   r   joinr   agent.prompt_builderrM   build_nous_subscription_prompt_tool_use_enforcementr#   rY   listr|   anyr   r   r	   r   	frozensetagent.coding_contextrr   rs   r   	Exceptionbuild_skills_system_promptprovidersplitbuild_environment_hintsr{   extendtools.env_prober~   agent.file_safetyr   r   r/   r   gateway.platform_registryr   r.   platform_hinthermes_cli.configr   rstripr   r6   r=   build_context_files_prompt_memory_store_memory_enabledformat_for_system_prompt_user_profile_enabled_memory_managerbuild_system_prompthermes_timer   strftimepass_session_id
session_id)2r!   r>   _ctx_len_cc_cc_lenstable_parts_soul_loaded_soul_contenttool_guidance_kanban_guidancerM   nous_subscription_prompt_enforce_inject_model_lowerhas_skills_toolsavail_toolsets_compact_catsrr   skills_prompt_model_short
_env_hintscoding_workspace_partscoding_trailing_partsr{   coding_prefix_partspost_workspace_partsr~   _probe_liner   active_profiler"   _default_hintr   _entryr   _cfg	_tg_extra_effective_hintcontext_partscontext_files_promptvolatile_parts	mem_block
user_block_ext_mem_block_hermes_nowr   timestamp_linerq   r]   s2   `                                               @@r   build_system_prompt_partsr      s   * 
B #H
%-t
4
4C
#/66gs## 	!H !L
 L  u'?  11 	 ...L 42333 2333 u1488 6U=S 64555 u4d;; 9@V 97888 M5)))_---51114555///_---
 u&?FF .-....		!mu7M&M&M_--- 5CHH]33444  0./// ///>>>>>>1133444!@@AWXX 64555  E.t
8S 9 9hnn>N>NRq>q>qGG:h#<#<AQAQUtAtAtGG$'' 	Q ;,"3355K[[[[H[[[[[GG !;,"3355KPPPP4OPPPPPG 	E =>>>!K-24466L <''7l+B+B##$EFFF $$<(?(?6\CYCY##$CDDDttttFsttttt 
 
   DIDZ  
 
 
 "	(LLLLLL;;-@-B-B  MM  	( 	( 	(%KKMMM	(55!2-,4 6 
 
  ~""58EK5G5Gu{((--b11U[:, : :%*[: : :	
 	
 	
 ++--J (J''' )+') 	GGGGGGQkQk'))kR R RN!79N
  34444 	 	 	D	  ,*,1222+ u*D11 	BBBBBB4466K 9$++K888 	 	 	D	#BBBBBB5577 # # #"#""##?,,--.1	
 	
 	
 	
 	##)n ) ))++) )7E) )'6'8'8) )DSDUDU) )   ) ) +:*;*;) ) )
	
 
	
 
	
 N(b//117799L M~%%&|4	 	CCCCCC&**<88F 5&. 5 & 4 	 	 	D	 z!!m!	>>>>>>''))D((;//52:::FFL"QQRYZZ`^`I}}_-- [ - 4 4 6 6 <?Z Z 	 	 	D	 -UL-PPOu6GG 5##O444  "M 3344423331222 !^,,,# 7  "<<#%%#(-.(H  =  J  J   	7  !5666 !#N  -m,,, 	2  	1+DDXNNI 1%%i000& 	2,EEfMMJ 2%%j111  	"2FFHHN 6%%n555 	 	 	D	 /.....
+--C Ncll?.K.KMMN >!1 >=5+;==={ 43ek333~ :9999~ :9999.))) KKUU<UUUUUKKUU=UUUUUKKUU>UUUUU  s   $Q9 9RRAV 
VV'W6 6
XXX X'&X'+] 
]]B_   
_-,_-+0f 
f)(f)c                    t          | |          }d                    d |d         |d         |d         fD                       }|d         | _        t                      D ]}|                     |           |S )a<  Assemble the full system prompt from all layers.

    Called once per session (cached on ``agent._cached_system_prompt``) and
    only rebuilt after context compression events. This ensures the system
    prompt is stable across all turns in a session, maximizing prefix cache
    hits.

    Layers are ordered cache-friendly: stable identity/guidance first,
    then session-stable context files, then per-call volatile content
    (skills index, memory, USER profile, timestamp). For explicit
    cache_control backends the whole string is one cached block. For
    implicit longest-prefix backends the order is what matters: the
    content most likely to change is rendered last, so when the prompt is
    rebuilt (on compaction/restore) the unchanged stable scaffold ahead of
    the change stays in the reused prefix.
    r>   r(   c              3     K   | ]}||V  	d S rX   r`   r   s     r   r^   z&build_system_prompt.<locals>.<genexpr>C  s(      ``q^_```````r    r   r   r   )r   r   _cached_system_prompt_staticr   _emit_status)r!   r>   partsjoinedwarnings        r   r   r   1  s    " &eNKKKE[[``U8_eI6FjHY$Z`````F).xE& -.. $ $7####Mr    Nonec                f    d| _         d| _        | j        r| j                                         dS dS )zInvalidate the cached system prompt, forcing a rebuild on the next turn.

    Called after context compression events. Also reloads memory from disk
    so the rebuilt prompt captures any writes from this session.
    N)_cached_system_promptr   r   load_from_disk)r!   s    r   invalidate_system_promptr   N  sD     #'E)-E& -**,,,,,- -r    restore)	log_labelr   c               "   t          | dd          sdS t          | dd          }t          |t                    r|sdS t          | dd          }t          |t                    r|r|                    |          rdS t          | dd          |k    rdS 	 t	          | |          d         }|r%|                    |          r|| _        d| _        dS n-# t          $ r  t          	                    d	|d
           Y nw xY wd| _        || _        dS )u  Reconstruct ``_cached_system_prompt_static`` for a stored prompt.

    The static prefix is not persisted (only the full prompt is), so any
    path that adopts a stored/kept ``_cached_system_prompt`` — session
    restore, the compression keep-prompt path, or a failover to a cache-on
    provider mid-turn (#72626) — must rebuild the stable tier to regain the
    two-block ``[static, volatile]`` system layout.

    Safety: the rebuilt stable tier is used ONLY when the stored prompt
    literally starts with it (checked here AND re-checked by
    ``_apply_system_cache_markers``'s ``startswith`` gate). If any
    stable-tier input changed since the prompt was persisted (identity
    changed, SOUL.md edited), the prefix mismatches, the static stays
    None, and requests fall back to the legacy layout with the stored
    prompt bytes untouched — never a rewritten prompt.

    A failed reconstruction is memoized per stored prompt
    (``_static_rebuild_failed_for``): ``build_system_prompt_parts`` does
    real file I/O (SOUL.md, context files, memory), and callers on the
    retry-loop hot path must not re-run it every attempt when the inputs
    haven't changed. A legitimately changed stored prompt retries once.
    _use_prompt_cachingFNr   r   _static_rebuild_failed_forr   r   z0static system-prefix reconstruction failed on %sT)exc_info)
r+   r,   r#   
startswithr   r   r   r   loggerdebug)r!   r>   r   storedexistingstatics         r   reconstruct_static_prefixr   Z  sa   8 5/77 U3T::Ffc"" & u<dCCH(C   X &2C2CH2M2M u2D99VCC
*5PPPQYZ 	f''// 	17E./3E,F 
 
 
> 	 	
 	
 	
 	
 	

 *.E&'-E$$$s   <C 'C>=C>c                    | j         sdS g }| j         D ]T}|d         }|d         |                    dd          |                    di           dd}|                    |           Ut          j        |d	
          S )zFormat tool definitions for the system message in the trajectory format.

    Returns:
        str: JSON string representation of tool definitions
    z[]functionrh   descriptionrV   
parametersN)rh   r   r   requiredF)ensure_ascii)toolsr.   r*   jsondumps)r!   formatted_toolstoolfuncformatted_tools        r   format_tools_for_system_messager    s     ; t O / /JL88M266((<44	
 
 	~....:oE::::r    )r   r   r   r  )r!   r   r"   r#   r$   r#   r%   r#   )r7   r#   r%   r#   rX   )r!   r   r>   r?   r%   r@   )r!   r   r>   r?   r%   r#   )r!   r   r%   r   )r!   r   r>   r?   r   r#   r%   r   )r!   r   r%   r#   )/__doc__
__future__r   r   loggingr;   typingr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   agent.runtime_cwdr   hermes_constantsr   utilsr   	getLogger__name__r   r   r6   r:   r=   r   r   r   r   r  __all__r`   r    r   <module>r     sE   2 # " " " " "   				 , , , , , , , , , , , ,                                   $ 2 1 1 1 1 1 , , , , , , ! ! ! ! ! !		8	$	$  . . . .d2 / / / /.V V V V Vr    :	- 	- 	- 	- %)3. 	3. 3. 3. 3. 3. 3.l; ; ; ;0  r    