
    |+j2(                        d Z ddlmZ ddlZddlmZ ddlmZmZm	Z	  ej
        e          ZdZdZdZd	Zd!dZd!dZd"dZd"dZd"dZd#d$dZd%dZd"dZd&dZd'dZd(dZg d ZdS ))u  
Contextual first-touch onboarding hints.

Instead of blocking first-run questionnaires, show a one-time hint the *first*
time a user hits a behavior fork — message-while-running, first long-running
tool, etc.  Each hint is shown once per install (tracked in ``config.yaml`` under
``onboarding.seen.<flag>``) and then never again.

Keep this module tiny and dependency-free so both the CLI and gateway can import
it without pulling in heavy modules.
    )annotationsN)Path)AnyMappingOptionalbusy_input_prompttool_progress_promptopenclaw_residue_cleanupprofile_build_offeredmodestrreturnc                ,    | dk    r	 dS | dk    r	 dS 	 dS )u   Hint shown the first time a user messages while the agent is busy.

    ``mode`` is the effective busy_input_mode that was just applied, so the
    message matches reality ("I just interrupted…" vs "I just queued…").
    queueu   💡 First-time tip — I queued your message instead of interrupting. Send `/busy interrupt` to make new messages stop the current task immediately, or `/busy status` to check. This notice won't appear again.steeru   💡 First-time tip — I steered your message into the current run; it will arrive after the next tool call instead of interrupting. Send `/busy interrupt` or `/busy queue` to change this, or `/busy status` to check. This notice won't appear again.u  💡 First-time tip — I just interrupted my current task to answer you. Send `/busy queue` to queue follow-ups for after the current task instead, `/busy steer` to inject them mid-run without interrupting, or `/busy status` to check. This notice won't appear again. r   s    //usr/local/lib/hermes-agent/agent/onboarding.pybusy_input_hint_gatewayr   $   sH     wW	
 	

 wG	
 	
	C     c                ,    | dk    r	 dS | dk    r	 dS 	 dS )z=CLI version of the busy-input hint (plain text, no markdown).r   z(tip) Your message was queued for the next turn. Use /busy interrupt to make Enter stop the current run instead, or /busy steer to inject mid-run. This tip only shows once.r   z(tip) Your message was steered into the current run; it arrives after the next tool call. Use /busy interrupt or /busy queue to change this. This tip only shows once.z(tip) Your message interrupted the current run. Use /busy queue to queue messages for the next turn instead, or /busy steer to inject mid-run. This tip only shows once.r   r   s    r   busy_input_hint_clir   ?   sE    wJ	
 	

 w5	
 	
	F r   c                     	 dS )Nu   💡 First-time tip — that tool took a while and I'm streaming every step. If the progress messages feel noisy, send `/verbose` to cycle modes (all → new → off). This notice won't appear again.r   r   r   r   tool_progress_hint_gatewayr   T   s    	A r   c                     	 dS )Nz(tip) That tool ran for a while. Use /verbose to cycle tool-progress display modes (all -> new -> off -> verbose). This tip only shows once.r   r   r   r   tool_progress_hint_clir   \   s    	R r   c                     	 dS )uw  Banner shown the first time Hermes starts and finds ``~/.openclaw/``.

    Points users at ``hermes claw migrate`` (non-destructive port of config,
    memory, and skills) first. ``hermes claw cleanup`` is mentioned as the
    follow-up step for users who have already migrated and want to archive
    the old directory — with a warning that archiving breaks OpenClaw.
    uW  A legacy OpenClaw directory was detected at ~/.openclaw/.
To port your config, memory, and skills over to Hermes, run `hermes claw migrate`.
If you've already migrated and want to archive the old directory, run `hermes claw cleanup` (renames it to ~/.openclaw.pre-migration — OpenClaw will stop working after this).
This tip only shows once.r   r   r   r   openclaw_residue_hint_clir   c   s    	$ r   homeOptional[Path]boolc                ~    | pt          j                    }	 |dz                                  S # t          $ r Y dS w xY w)u   Return True if an OpenClaw workspace directory is present in ``$HOME``.

    Pure filesystem check — no side effects. ``home`` override exists for tests.
    z	.openclawF)r   r   is_dirOSError)r   bases     r   detect_openclaw_residuer&   v   sR    
 49;;D{"**,,,   uus   . 
<<configMapping[str, Any]c                8   t          | t                    sdS |                     d          }t          |t                    sdS |                    d          }t          |t                    r,|                                                                dk    rdS dS )u  Resolve the onboarding profile-build mode from config.

    Returns one of:
      ``"ask"``  — on first contact, OFFER to build a profile (default).
      ``"off"``  — never offer; the first-message note stays a plain intro.

    Read from ``config.onboarding.profile_build``. Unknown / missing values
    fall back to ``"ask"`` so the default experience offers the flow. Any
    network/account lookups inside the flow are separately consented to in
    conversation — this setting only governs whether the offer is made.
    ask
onboardingprofile_buildoff)
isinstancer   getr   striplower)r'   r+   r   s      r   profile_build_moder2      s     fg&& uL))Jj'** u>>/**D$ !3!3!5!5!>!>u5r   c                     	 dS )u  System-note directive appended to the very first message ever.

    Instructs the agent to run a short, opt-in, consent-gated profile-build
    flow and persist confirmed facts to the user-profile memory store
    (``memory`` tool, ``target="user"``). Phrased so the agent ASKS before any
    lookup and never silently reads connected accounts — directly addressing
    the privacy concern that reading email/accounts unprompted feels invasive.
    u  

[System note: This is the user's very first message ever. After a one-sentence introduction (mention /help shows commands), OFFER — do not assume — to build a short profile of them so you can be more useful, and explain they can decline or do it later. If and ONLY IF they accept:
  1. Ask for whatever they're comfortable sharing (name, what they do, how they like you to work). Volunteered facts come first.
  2. Before ANY external lookup, say what you intend to look up and get explicit consent for that step. Never read their connected accounts (email, calendar, etc.) silently — ask each time.
  3. With consent, you may use web_search to confirm public details (e.g. employer, public profiles) from the data points they gave.
  4. Save each confirmed, durable fact with the memory tool using target="user" — keep entries compact and high-signal.
If they decline at any point, stop immediately and continue normally. Keep the whole exchange light and conversational, not an interrogation.]r   r   r   r   profile_build_directiver4      s    	S r   c                    t          | t                    r|                     d          nd }t          |t                    si S |                    d          }t          |t                    r|ni S )Nr+   seen)r.   r   r/   )r'   r+   r6   s      r   _get_seen_dictr7      sh    -7-H-HRL)))dJj'** 	>>&!!DdG,,444"4r   flagc                `    t          t          |                               |                    S )zEReturn True if the user has already been shown this first-touch hint.)r!   r7   r/   )r'   r8   s     r   is_seenr:      s&    v&&**400111r   config_pathr   c                   	 ddl }ddlm} n3# t          $ r&}t                              d|           Y d}~dS d}~ww xY w	 i }|                                 r@t          | d          5 }|                    |          pi }ddd           n# 1 swxY w Y   t          |
                    d          t                    si |d<   |d         
                    d	          }t          |t                    si }||d         d	<   |
                    |          d
u rd
S d
||<    || |           d
S # t          $ r'}t                              d||           Y d}~dS d}~ww xY w)u   Persist ``onboarding.seen.<flag> = True`` to ``config_path``.

    Uses the atomic YAML writer so a concurrent process can't observe a
    partially-written file.  Returns True on success, False on any error
    (including the config file being absent — onboarding is best-effort).
    r   N)atomic_yaml_writez+onboarding: failed to import yaml/utils: %sFzutf-8)encodingr+   r6   Tz&onboarding: failed to mark flag %s: %s)yamlutilsr=   	Exceptionloggerdebugexistsopen	safe_loadr.   r/   dict)r;   r8   r?   r=   ecfgfr6   s           r   	mark_seenrK      s   +++++++   BAFFFuuuuu 	.kG444 .nnQ''-2. . . . . . . . . . . . . . .#'',//66 	# "C< $$V,,$%% 	-D(,Cf%88D>>T!!4T
+s+++t   =tQGGGuuuuusS   
 
=8='D- (B D- BD- BBD- D- -
E7EE)BUSY_INPUT_FLAGTOOL_PROGRESS_FLAGOPENCLAW_RESIDUE_FLAGPROFILE_BUILD_FLAGr   r   r   r   r   r&   r2   r4   r:   rK   )r   r   r   r   )r   r   )N)r   r    r   r!   )r'   r(   r   r   )r'   r(   r   r(   )r'   r(   r8   r   r   r!   )r;   r   r8   r   r   r!   )__doc__
__future__r   loggingpathlibr   typingr   r   r   	getLogger__name__rB   rL   rM   rN   rO   r   r   r   r   r   r&   r2   r4   r7   r:   rK   __all__r   r   r   <module>rX      s  
 
 # " " " " "        ) ) ) ) ) ) ) ) ) )		8	$	$ &+ 2 ,    6   *         &	 	 	 	 	    .   B5 5 5 52 2 2 2
       F  r   