
    iA'                     @   d Z ddlZddlmZmZmZmZ h dZ G d d          Z	 	 	 d&deeee	ef                           d	e
d
ee         de	fdZde
fdZdddddddddddddg ddddg dddd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 )'a4  
Todo Tool Module - Planning & Task Management

Provides an in-memory task list the agent uses to decompose complex tasks,
track progress, and maintain focus across long conversations. The state
lives on the AIAgent instance (one per session) and is re-injected into
the conversation after context compression events.

Design:
- Single `todo` tool: provide `todos` param to write, omit to read
- Every call returns the full current list
- No system prompt mutation, no tool response modification
- Behavioral guidance lives entirely in the tool schema description
    N)DictAnyListOptional>   pending	cancelled	completedin_progressc            
       J   e Zd ZdZd Zddeeeef                  de	deeeef                  fdZ
deeeef                  fdZde	fd	Zdee         fd
Zedeeef         deeef         fd            Zedeeeef                  deeeef                  fd            ZdS )	TodoStorea"  
    In-memory todo list. One instance per AIAgent (one per session).

    Items are ordered -- list position is priority. Each item has:
      - id: unique string identifier (agent-chosen)
      - content: task description
      - status: pending | in_progress | completed | cancelled
    c                     g | _         d S )N_itemsselfs    4/home/ubuntu/.hermes/hermes-agent/tools/todo_tool.py__init__zTodoStore.__init__#   s    ,.    Ftodosmergereturnc                     |s( fd                      |          D              _        nd  j        D             }                      |          D ]}t          |                    dd                                                    }|s;||v rd|v r8|d         r0t          |d                                                   ||         d<   d|v rU|d         rMt          |d                                                                                   }|t          v r|||         d<   Չ                     |          }|||d         <    j                            |           t                      }g }	 j        D ]X}
|                    |
d         |
          }|d         |vr0|	                    |           |
                    |d                    Y|	 _                                         S )a  
        Write todos. Returns the full current list after writing.

        Args:
            todos: list of {id, content, status} dicts
            merge: if False, replace the entire list. If True, update
                   existing items by id and append new ones.
        c                 :    g | ]}                     |          S  )	_validate).0tr   s     r   
<listcomp>z#TodoStore.write.<locals>.<listcomp>1   s%    PPP4>>!,,PPPr   c                      i | ]}|d          |S )idr   r   items     r   
<dictcomp>z#TodoStore.write.<locals>.<dictcomp>4   s    AAATT
DAAAr   r     contentstatus)_dedupe_by_idr   strgetstriplowerVALID_STATUSESr   appendsetaddread)r   r   r   existingr   item_idr&   	validatedseenrebuiltr"   currents   `           r   writezTodoStore.write&   s      	"PPPPd6H6H6O6OPPPDKK BAT[AAAH''.. 2 2aeeD"oo..4466 h&& A~~!I,~7:1Y<7H7H7N7N7P7P))41}}8}!$Qx[!1!1!7!7!9!9!?!?!A!A!^33:@HW-h7 !%q 1 1I09HYt_-K&&y111155DG , ,",,tDz4884=,,NN7+++HHWT]+++!DKyy{{r   c                 $    d | j         D             S )z"Return a copy of the current list.c                 6    g | ]}|                                 S r   )copyr!   s     r   r   z"TodoStore.read.<locals>.<listcomp>T   s     444		444r   r   r   s    r   r0   zTodoStore.readR   s    444444r   c                 *    t          | j                  S )z)Check if there are any items in the list.)boolr   r   s    r   	has_itemszTodoStore.has_itemsV   s    DK   r   c                 &   | j         sdS ddddd}d | j         D             }|sdS dg}|D ]R}|                    |d	         d
          }|                    d| d|d          d|d          d|d	          d	           Sd                    |          S )z
        Render the todo list for post-compression injection.

        Returns a human-readable string to append to the compressed
        message history, or None if the list is empty.
        Nz[x]z[>]z[ ]z[~])r	   r
   r   r   c                 &    g | ]}|d          dv |S )r&   )r   r
   r   r!   s     r   r   z2TodoStore.format_for_injection.<locals>.<listcomp>n   s2     
 
 
H~!;;; ;;;r   z@[Your active task list was preserved across context compression]r&   z[?]z-  r    z. r%   z ()
)r   r)   r-   join)r   markersactive_itemslinesr"   markers         r   format_for_injectionzTodoStore.format_for_injectionZ   s     { 	4  	
 

 
![
 
 
  	4ST  	[ 	[D[[h77FLLYfYYtDzYYT)_YYXYYYZZZZyyr   r"   c                    t          |                     dd                                                    }|sd}t          |                     dd                                                    }|sd}t          |                     dd                                                                                    }|t          vrd}|||dS )	z
        Validate and normalize a todo item.

        Ensures required fields exist and status is valid.
        Returns a clean dict with only {id, content, status}.
        r    r$   ?r%   z(no description)r&   r   r    r%   r&   )r(   r)   r*   r+   r,   )r"   r2   r%   r&   s       r   r   zTodoStore._validate|   s     dhhtR(())//11 	Gdhhy"--..4466 	)(GTXXh	223399;;AACC''F'VDDDr   c                     i }t                     D ]A\  }}t          |                    dd                                                    pd}|||<   B fdt	          |                                          D             S )zDCollapse duplicate ids, keeping the last occurrence in its position.r    r$   rJ   c                      g | ]
}|         S r   r   )r   ir   s     r   r   z+TodoStore._dedupe_by_id.<locals>.<listcomp>   s    >>>Qa>>>r   )	enumerater(   r)   r*   sortedvalues)r   
last_indexrN   r"   r2   s   `    r   r'   zTodoStore._dedupe_by_id   s     &(
 '' 	$ 	$GAt$((4,,--3355<G"#Jw>>>>&):):)<)<"="=>>>>r   N)F)__name__
__module____qualname____doc__r   r   r   r(   r   r<   r7   r0   r=   r   rH   staticmethodr   r'   r   r   r   r   r      sh        / / /* *4S#X/ * *dSVX[S[nI] * * * *X5d4S>* 5 5 5 5!4 ! ! ! !  hsm            D ES#X E4S> E E E \E* ?T$sCx.1 ?d4S>6J ? ? ? \? ? ?r   r   Fr   r   storer   c           	         |t          d          S | |                    | |          }n|                                }t          d |D                       }t          d |D                       }t          d |D                       }t          d |D                       }t	          j        |t          |          ||||ddd	
          S )a  
    Single entry point for the todo tool. Reads or writes depending on params.

    Args:
        todos: if provided, write these items. If None, read current list.
        merge: if True, update by id. If False (default), replace entire list.
        store: the TodoStore instance from the AIAgent.

    Returns:
        JSON string with the full current list and summary metadata.
    NzTodoStore not initializedc              3   2   K   | ]}|d          dk    dV  dS )r&   r      Nr   r   rN   s     r   	<genexpr>ztodo_tool.<locals>.<genexpr>   s0      ??akY&>&>!&>&>&>&>??r   c              3   2   K   | ]}|d          dk    dV  dS )r&   r
   r[   Nr   r\   s     r   r]   ztodo_tool.<locals>.<genexpr>   s0      GGA!H+*F*Fa*F*F*F*FGGr   c              3   2   K   | ]}|d          dk    dV  dS )r&   r	   r[   Nr   r\   s     r   r]   ztodo_tool.<locals>.<genexpr>   0      CC!({(B(BA(B(B(B(BCCr   c              3   2   K   | ]}|d          dk    dV  dS )r&   r   r[   Nr   r\   s     r   r]   ztodo_tool.<locals>.<genexpr>   r`   r   )totalr   r
   r	   r   )r   summaryF)ensure_ascii)
tool_errorr7   r0   sumjsondumpslen)r   r   rX   itemsr   r
   r	   r   s           r   	todo_toolrk      s      }5666E5))

 ??U?????GGGGGGGGKCCuCCCCCICCuCCCCCI:ZZ&""
 
	 	 	 	 	 	r   c                      dS )z;Todo tool has no external requirements -- always available.Tr   r   r   r   check_todo_requirementsrm      s    4r   todoa  Manage your task list for the current session. Use for complex tasks with 3+ steps or when the user provides multiple tasks. Call with no parameters to read the current list.

Writing:
- Provide 'todos' array to create/update items
- merge=false (default): replace the entire list with a fresh plan
- merge=true: update existing items by id, add any new ones

Each item: {id: string, content: string, status: pending|in_progress|completed|cancelled}
List order is priority. Only ONE item in_progress at a time.
Mark items completed immediately when done. If something fails, cancel it and add a revised item.

Always returns the full current list.objectarrayz/Task items to write. Omit to read current list.stringzUnique item identifier)typedescriptionzTask description)r   r
   r	   r   zCurrent status)rr   enumrs   rK   )rr   
propertiesrequired)rr   rs   rj   booleanzZtrue: update existing items by id, add new ones. false (default): replace the entire list.)rr   rs   default)r   r   )namers   
parameters)registryre   c                     t          |                     d          |                     dd          |                    d                    S )Nr   r   FrX   )r   r   rX   )rk   r)   )argskws     r   <lambda>r     sC    yhhwtxx'?'?rvvg X  X  X r   u   📋)ry   toolsetschemahandlercheck_fnemoji)NFN)rV   rg   typingr   r   r   r   r,   r   r(   r<   rk   rm   TODO_SCHEMAtools.registryr{   re   registerr   r   r   <module>r      s     , , , , , , , , , , , , FEE@? @? @? @? @? @? @? @?H -1!%' 'Dc3h()'' I' 		' ' ' 'T     	0   P$ %-+C 
 %-+=$ $
 %-$X$X$X+;# ## # !< ; ;#  0 "@ ! 1 
  
B G$ $#6 6t 0 / / / / / / /  	X X$
     r   