
    i                         U d Z ddlZddlZddlmZmZ ddlmZ ddlmZ ddl	m
Z
  ej                  e      Z ed      Z eh d      Zee   ed	<    G d
 d      Zy)uy  
core/workers/genesis_task_worker.py

GenesisTaskWorker — converts AIVA's TASK_DISPATCH intent into a Genesis RWL
task written to the Genesis task board at loop/tasks.json.

Created by Story 5.09 (AIVA RLM Nexus PRD v2).

Responsibilities:
  1. Extract task description from intent.utterance + extracted_entities
  2. Build a task entry with source="AIVA", status="pending", and a UUID
  3. Append the entry to loop/tasks.json (load → append → write, no overwrite)
  4. Return {"task_id": <uuid>, "status": "queued"} — never None

No SQLite. All file I/O is injected at construction so tests never touch the
real task board.
    N)datetimetimezone)Path)uuid4)Anyz%/mnt/e/genesis-system/loop/tasks.json>   you knowaheroksouhumjustlikeokaywellrightactually	basically	literally_FILLER_WORDSc                       e Zd ZdZddedz  ddfdZdedefdZdede	fdZ
d	e	de	fd
Zdee   fdZdee   ddfdZy)GenesisTaskWorkeray  
    Converts an AIVA TASK_DISPATCH IntentSignal into a Genesis RWL task entry
    written to the task board JSON file.

    All file I/O goes through self._path so the worker is fully testable
    without touching the real loop/tasks.json.

    Args:
        task_board_path: Override the default TASK_BOARD_PATH (used in tests
                         via ``tmp_path``).
    Ntask_board_pathreturnc                 "    |xs t         | _        y N)TASK_BOARD_PATH_path)selfr   s     9/mnt/e/genesis-system/core/workers/genesis_task_worker.py__init__zGenesisTaskWorker.__init__=   s    *=o
    intentc                   K   t        t                     }| j                  |      }||dt        j                  t
        j                        j                         dd}	 | j                         }|j                  |       | j                  |       t        j                  d||       |d	d
S # t        $ r/}t        j                  d|       |dt        |      dcY d}~S d}~ww xY ww)u  
        Main entry point. Called by SwarmRouter for every TASK_DISPATCH intent.

        Steps:
          1. Build a human-readable task description from utterance + entities.
          2. Create a task entry dict with a UUID, source="AIVA", created_at
             (ISO 8601 UTC), and status="pending".
          3. Load existing tasks from the task board, append the new entry,
             and write the updated list back atomically.
          4. Return {"task_id": <uuid_str>, "status": "queued"}.

        Args:
            intent: An IntentSignal instance (duck-typed — no direct import
                    keeps this worker decoupled from the classifier layer).

        Returns:
            dict with at minimum ``task_id`` and ``status`` keys. Never None.
        AIVApending)iddescriptionsource
created_atstatusz&AIVA task queued: id=%s description=%rz!Failed to write task to board: %serror)task_idr,   reasonNqueued)r.   r,   )strr   _build_task_descriptionr   nowr   utc	isoformat_load_tasksappend_save_tasksloggerinfo	Exceptionr-   )r    r$   r.   r)   
task_entrytasksexcs          r!   executezGenesisTaskWorker.executeD   s     & 57|77? &",,x||4>>@

	O$$&ELL$U#KK8 #h77	  	OLL<cB&'SXNN	Os7   AC(A	B- (C(-	C%6$C C%C( C%%C(c                     t        |di       xs i }|j                  d      rt        |d         j                         S t        |dd      xs d}| j	                  |      }|r|S y)u  
        Build a human-readable task description from the intent's utterance
        and extracted entities.

        Priority order:
          1. ``extracted_entities["task"]`` — explicit task field from NLP
          2. Cleaned utterance (filler words stripped, whitespace normalised)
          3. Fallback: "AIVA task dispatch"

        Args:
            intent: An IntentSignal (or any duck-typed object).

        Returns:
            Non-empty string describing the task in plain language.
        extracted_entitiestask	utterance zAIVA task dispatch)getattrgetr1   strip_clean_utterance)r    r$   entitiesrC   cleaneds        r!   r2   z)GenesisTaskWorker._build_task_descriptionu   so    " !)=rBHb<<x'(..00 !b9?R	''	2N $r#   rC   c                     |sy|j                         }|D cg c]*  }|j                         j                  d      t        vs)|, }}dj	                  |      j                         S c c}w )z
        Strip common filler words and normalise whitespace from an utterance.

        Args:
            utterance: Raw caller utterance string.

        Returns:
            Cleaned string, or empty string if nothing useful remains.
        rD   z.,!? )splitlowerrstripr   joinrG   )r    rC   wordswfiltereds        r!   rH   z"GenesisTaskWorker._clean_utterance   s_     !$V!	(8(8(@(UAVVxx!'')) Ws   *A(A(c                 6   | j                   j                         sg S 	 | j                   j                  d      j                         }|sg S t	        j
                  |      }t        |t              r|S t        |t              r-dD ](  }t        |j                  |      t              s#||   c S  t        j                  d| j                          g S # t        j                  t        f$ r-}t        j                  d| j                   |       g cY d}~S d}~ww xY w)u  
        Load the existing tasks list from the task board JSON file.

        Returns an empty list if the file does not exist, is empty, or
        contains invalid JSON — safe degradation to allow append.

        Returns:
            list of task dicts (may be empty).
        utf-8encoding)storiesr=   u:   Unrecognised task board structure in %s — starting freshz%Could not load task board from %s: %sN)r   exists	read_textrG   jsonloads
isinstancelistdictrF   r9   warningJSONDecodeErrorOSError)r    contentdatakeyr>   s        r!   r6   zGenesisTaskWorker._load_tasks   s     zz  "I	jj**G*<BBDG	::g&D $%$%/ )C!$((3-6#Cy() NNLdjj I$$g. 	NNBDJJPSTI	s5   -C &C 34C (C /"C D+"DDDr=   c                     | j                   j                  j                  dd       | j                   j                  t	        j
                  |d      d       y)a  
        Write the tasks list back to the task board JSON file.

        Uses ``json.dumps`` with indent=2 for human-readable output.
        Creates parent directories if they don't exist.

        Args:
            tasks: Full list of task dicts to persist.
        T)parentsexist_ok   )indentrU   rV   N)r   parentmkdir
write_textr[   dumps)r    r=   s     r!   r8   zGenesisTaskWorker._save_tasks   sC     	

t<

djjq9GLr#   r   )__name__
__module____qualname____doc__r   r"   r   r_   r?   r1   r2   rH   r^   r6   r8    r#   r!   r   r   0   s    
>t >t >+8C +8D +8b$c $c $<*# *# *""T$Z "HMd M Mr#   r   )rr   r[   loggingr   r   pathlibr   uuidr   typingr   	getLoggerro   r9   r   	frozensetr   r1   __annotations__r   rs   r#   r!   <module>r{      sg   $   '   			8	$ >? !*!y~ cM cMr#   