
    g5j              	           d Z ddlZddlmZmZmZ dZdefdZ	 	 ddedeee                  d	ee         defd
Z	de
fdZdddddddddieddddgddZddlmZmZ  ej        dded ed           dS )a  
Clarify Tool Module - Interactive Clarifying Questions

Allows the agent to present structured multiple-choice questions or open-ended
prompts to the user. In CLI mode, choices are navigable with arrow keys. On
messaging platforms, choices are rendered as a numbered list.

The actual user-interaction logic lives in the platform layer (cli.py for CLI,
gateway/run.py for messaging). This module defines the schema, validation, and
a thin dispatcher that delegates to a platform-provided callback.
    N)ListOptionalCallable   returnc                    | dS t          | t                    r|                                 S t          | t                    r[dD ]V}|                     |          }t          |t                    r*|                                r|                                c S WdS t          | t
          t          f          r1d                    d | D                                                       S t          |                                           S )u  Coerce a single choice into its user-facing display string.

    The schema declares choices as bare strings, but LLMs sometimes emit
    dict-shaped choices like ``[{"description": "..."}]``. A naive ``str(c)``
    turns the whole dict into its Python repr — ``{'description': '...'}`` —
    which then leaks onto every surface that renders the choice (CLI panel,
    Discord buttons, Telegram numbered list) AND is returned verbatim as the
    user's answer. Normalising here, at the one platform-agnostic entry point,
    fixes the whole class in one place instead of per-adapter.

    Dict unwrap order is the canonical LLM tool-call user-facing keys:
    ``label`` → ``description`` → ``text`` → ``title``. ``name`` and ``value``
    are deliberately excluded — they're component-shaped fields that could
    carry raw enum values or short identifiers, not human-readable labels. A
    dict with none of the canonical keys is dropped (returns ""), since a
    garbage label is worse than no choice at all.
    N )labeldescriptiontexttitle c              3   4   K   | ]}t          |          V  d S N_flatten_choice).0xs     8/home/rurouni/.hermes/hermes-agent/tools/clarify_tool.py	<genexpr>z"_flatten_choice.<locals>.<genexpr>4   s*      66q**666666    )
isinstancestrstripdictgetlisttuplejoin)ckeyvs      r   r   r      s    $ 	yr!S wwyy!T < 	! 	!Cc

A!S!! !aggii !wwyy   r!dE]## ?xx66A66666<<>>>q66<<>>r   questionchoicescallbackc                 h   | r|                                  st          d          S |                                  } |et          |t                    st          d          S d d |D             D             }t	          |          t
          k    r|dt
                   }|sd}|t          j        ddid	          S 	  || |          }n2# t          $ r%}t          j        dd
| id	          cY d}~S d}~ww xY wt          j        | |t          |                                           dd	          S )a  
    Ask the user a question, optionally with multiple-choice options.

    Args:
        question: The question text to present.
        choices:  Up to 4 predefined answer choices. When omitted the
                  question is purely open-ended.
        callback: Platform-provided function that handles the actual UI
                  interaction. Signature: callback(question, choices) -> str.
                  Injected by the agent runner (cli.py / gateway).

    Returns:
        JSON string with the user's response.
    zQuestion text is required.Nz"choices must be a list of strings.c                     g | ]}||S  r(   )r   ss     r   
<listcomp>z clarify_tool.<locals>.<listcomp>Y   s    IIIqI1IIIr   c              3   4   K   | ]}t          |          V  d S r   r   )r   r    s     r   r   zclarify_tool.<locals>.<genexpr>Y   s*      CCaq11CCCCCCr   errorz8Clarify tool is not available in this execution context.F)ensure_asciizFailed to get user input: )r#   choices_offereduser_response)
r   
tool_errorr   r   lenMAX_CHOICESjsondumps	Exceptionr   )r#   r$   r%   r/   excs        r   clarify_toolr7   8   s   &  88>>++ 86777~~H '4(( 	DBCCC JICC7CCCIIIw<<+%%l{l+G 	GzPQ
 
 
 	


 733 
 
 
z83889
 
 
 	
 	
 	
 	
 	
 	

 :"]++1133  	   s   <C	 	
C8C3-C83C8c                      dS )z>Clarify tool has no external requirements -- always available.Tr(   r(   r   r   check_clarify_requirementsr9   t   s    4r   clarifyu  Ask the user a question when you need clarification, feedback, or a decision before proceeding. Supports two modes:

1. **Multiple choice** — provide up to 4 choices. The user picks one or types their own answer via a 5th 'Other' option.
2. **Open-ended** — omit choices entirely. The user types a free-form response.

CRITICAL: when you are offering options, put each option ONLY in the `choices` array — NEVER enumerate the options inside the `question` text. The UI renders `choices` as selectable rows; options written into the question string render as dead prose the user can't pick. Right: question='Which deployment target?', choices=['staging', 'prod']. Wrong: question='Which target? 1) staging 2) prod', choices=[].

Use this tool when:
- The task is ambiguous and you need the user to choose an approach
- You want post-task feedback ('How did that work out?')
- You want to offer to save a skill or update memory
- A decision has meaningful trade-offs the user should weigh in on

Do NOT use this tool for simple yes/no confirmation of dangerous commands (the terminal tool handles that). Prefer making a reasonable default choice yourself when the decision is low-stakes.objectstringu   The question itself, and ONLY the question (e.g. 'Which deployment target?'). Do NOT embed the answer options here — pass them as separate elements in `choices`.)typer   arrayr=   a  REQUIRED whenever you are presenting selectable options: each distinct option is its own array element (up to 4). The UI renders these as pickable rows and auto-appends an 'Other (type your answer)' option. Omit this parameter entirely ONLY for a genuinely open-ended free-text question.)r=   itemsmaxItemsr   )r#   r$   )r=   
propertiesrequired)namer   
parameters)registryr0   c                     t          |                     dd          |                     d          |                    d                    S )Nr#   r	   r$   r%   )r#   r$   r%   )r7   r   )argskws     r   <lambda>rI      sD    |*b))##
## %  %  % r   u   ❓)rC   toolsetschemahandlercheck_fnemoji)NN)__doc__r3   typingr   r   r   r2   r   r   r7   boolr9   CLARIFY_SCHEMAtools.registryrE   r0   registerr(   r   r   <module>rU      s  
 
  + + + + + + + + + +
 #    F $(#'9 99d3i 9 x 9 		9 9 9 9xD     	C,  !G    (+'S 
 
,  L1 12 2l 0 / / / / / / /  	% % (

 
 
 
 
 
r   