
    i6                      d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlmZ ddlmZ ddlmZ ddlmZmZmZmZ d	d
lmZ  ej0                  e      ZdZdZdZ ej<                  dej>                        Z  ej<                  d      Z! ej<                  d      Z" ej<                  d      Z#dFdZ$dGdZ%dHdZ&dIdZ'dJdKdZ(dLdZ)dMdZ*dNdZ+dOdZ,dPdZ-dPdZ.dQdZ/ G d d      Z0dRd Z1dSd!Z2	 dJ	 	 	 	 	 	 	 dTd"Z3	 dJ	 	 	 	 	 dUd#Z4	 	 	 	 dVd$Z5	 dW	 	 	 	 	 	 	 dXd%Z6	 	 	 	 	 	 	 	 	 	 dYd&Z7dZd'Z8	 	 	 	 d[	 	 	 	 	 	 	 	 	 d\d(Z9	 dJ	 	 	 	 	 d]d)Z: e;h d*      Z<e=e>ef   Z?d^d+Z@d_d,ZAd`d-ZB	 	 	 	 dad.ZCdbd/ZDdcd0ZE	 	 	 dd	 	 	 	 	 	 	 	 	 ded1ZF	 	 	 	 	 	 	 	 dfd2ZGdgd3ZHdgd4ZIdhd5ZJdad6ZK	 dJ	 	 	 	 	 did7ZL	 	 	 dd	 	 	 	 	 	 	 	 	 	 	 djd8ZM	 	 	 	 	 	 	 	 dfd9ZNdJdkd:ZOdld;ZPdmd<ZQdnd=ZRdod>ZS	 	 	 	 	 	 	 	 dpd?ZT	 	 	 	 	 	 	 	 	 	 dqd@ZU	 	 	 dd	 	 	 	 	 	 	 	 	 drdAZV	 dJ	 	 	 	 	 	 	 dsdBZW	 	 	 dd	 	 	 	 	 	 	 	 	 	 	 dtdCZX	 dJ	 	 	 	 	 	 	 dudDZY	 	 	 dd	 	 	 	 	 	 	 	 	 	 	 	 	 dvdEZZy)wzSession listing implementation.

Scans ~/.claude/projects/<sanitized-cwd>/ for .jsonl session files and
extracts metadata from stat + head/tail reads without full JSONL parsing.
    )annotationsN)datetime)Path)Any   )SDKSessionInfo
SessionKeySessionMessageSessionStore   )_store_implementsi         z>^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$z^(?:<local-command-stdout>|<session-start-hook>|<tick>|<goal>|\[Request interrupted by user[^\]]*\]|\s*<ide_opened_file>[\s\S]*</ide_opened_file>\s*$|\s*<ide_selection>[\s\S]*</ide_selection>\s*$)z"<command-name>(.*?)</command-name>z[^a-zA-Z0-9]c                2    t         j                  |       r| S y)z4Returns the string if it is a valid UUID, else None.N)_UUID_REmatch)
maybe_uuids    j/volume1/homes/robertsu/coba/app/.venv/lib/python3.12/site-packages/claude_agent_sdk/_internal/sessions.py_validate_uuidr   D   s    ~~j!    c                   d}| D ](  }t        |      }|dz  |z
  |z   }|dz  }|dk\  s$|dz  }* t        |      }|dk(  ryd}g }|}|dkD  r"|j                  ||dz            |dz  }|dkD  r"d	j                  t	        |            S )
zC32-bit integer hash to base36, matching the CLI's directory naming.r      l    l        l        0$0123456789abcdefghijklmnopqrstuvwxyz$    )ordabsappendjoinreversed)shchchardigitsoutns          r   _simple_hashr)   P   s    	A2w!VqL4
N
?A  	AAAv3F
C	A
a%

6!b&>"	b a% 778C=!!r   c                    t         j                  d|       }t        |      t        k  r|S t	        |       }|dt          d| S )zMakes a string safe for use as a directory name.

    Replaces all non-alphanumeric characters with hyphens. For paths
    exceeding MAX_SANITIZED_LENGTH, truncates and appends a hash suffix.
    -N)_SANITIZE_REsublenMAX_SANITIZED_LENGTHr)   )name	sanitizedr#   s      r   _sanitize_pathr2   g   sN       d+I
9~--TA--./q44r   c            	         t         j                  j                  d      } | rt        t	        j
                  d|             S t        t	        j
                  dt        t        j                         dz                    S )zAReturns the Claude config directory (respects CLAUDE_CONFIG_DIR).CLAUDE_CONFIG_DIRNFCz.claude)osenvirongetr   unicodedata	normalizestrhome)
config_dirs    r   _get_claude_config_home_dirr>   y   sX     34JK))%<==%%eSy1H-IJKKr   c                    | r5| j                  d      }|r"t        t        j                  d|            dz  S t	               dz  S )zReturns the projects directory.

    ``env_override`` is consulted before ``os.environ`` so callers that pass
    ``CLAUDE_CONFIG_DIR`` to the subprocess via ``options.env`` resolve the
    same directory the subprocess will write to.
    r4   r5   projects)r8   r   r9   r:   r>   )env_overrideoverrides     r   _get_projects_dirrC      sF     ##$78--eX>?*LL&(:55r   c                .    t               t        |       z  S N)rC   r2   )project_paths    r   _get_project_dirrG      s    !===r   c                    	 t         j                  j                  |       }t        j                  d|      S # t
        $ r t        j                  d|       cY S w xY w)zEResolves a directory path to its canonical form using realpath + NFC.r5   )r6   pathrealpathr9   r:   OSError)dresolveds     r   _canonicalize_pathrN      sP    /77##A&$$UH55 /$$UA../s   47 AAc                R   t        |       }|j                         r|S t        |       }t        |      t        k  ry|dt         }t               }	 |j                         D ]5  }|j                         s|j                  j                  |dz         s3|c S  	 y# t        $ r Y yw xY w)ur  Finds the project directory for a given path.

    Tolerates hash mismatches for long paths (>200 chars). The CLI uses
    Bun.hash while the SDK under Node.js uses simpleHash — for paths that
    exceed MAX_SANITIZED_LENGTH, these produce different directory suffixes.
    This function falls back to prefix-based scanning when the exact match
    doesn't exist.
    Nr+   )
rG   is_dirr2   r.   r/   rC   iterdirr0   
startswithrK   )rF   exactr1   prefixprojects_direntrys         r   _find_project_dirrW      s     \*E||~ |,I
9~--,,-F$&L!))+E||~%**"7"7"E ,
   s$   #B 4B B B 	B&%B&c                    d| vr| S 	 t        j                  d|  d      }t        |t              r|S | S # t         j                  t
        f$ r | cY S w xY w)z3Unescape a JSON string value extracted as raw text.\")jsonloads
isinstancer;   JSONDecodeError
ValueError)rawresults     r   _unescape_json_stringrb      s\    3
auAJ'fc"M
  *- 
s   *5 5 AAc                
   d| dd| dg}|D ]r  }| j                  |      }|dk  r|t        |      z   }|}|t        |       k  s9| |   dk(  r|dz  }| |   dk(  rt        | ||       c S |dz  }|t        |       k  r:t y)	zExtracts a simple JSON string field value without full parsing.

    Looks for "key":"value" or "key": "value" patterns. Returns the first
    match, or None if not found.
    rZ   ":"": "r   rY   r   r   Nfindr.   rb   )textkeypatternspatternidxvalue_startis          r   _extract_json_string_fieldro      s     C5#dm,Hii 7CL(#d)mAw$QAw#~,T+a-@AAFA #d)m  r   c                   d| dd| dg}d}|D ]y  }d}	 | j                  ||      }|dk  r|t        |      z   }|}|t        |       k  r9| |   dk(  r|dz  }| |   dk(  rt        | ||       }n|dz  }|t        |       k  r9|dz   }u |S )	z>Like _extract_json_string_field but finds the LAST occurrence.rZ   rd   re   Nr   rY   r   r   rf   )	rh   ri   rj   
last_valuerk   search_fromrl   rm   rn   s	            r   _extract_last_json_string_fieldrs      s    C5#dm,H!J))G[1CQwG,KAc$i-7d?FA7c>!6tK7J!KJQ c$i- a%K  $ r   c                @   d}d}t        |       }||k  r| j                  d|      }|dk\  r| || }|dz   }n| |d }|}d|vrd|vr8d|v r=d	|v sd
|v rFd|v sd|v rO	 t        j                  |      }t        |t              r|j                  d      dk7  r|j                  d      }t        |t              s|j                  d      }g }	t        |t              r|	j                  |       nqt        |t              ra|D ]\  }
t        |
t              s|
j                  d      dk(  s)t        |
j                  d      t              sI|	j                  |
d          ^ |	D ]  }|j                  dd      j                         }|s&t        j                  |      }|r|s|j!                  d      }Qt"        j%                  |      rgt        |      dkD  r|dd j'                         dz   }|c S  ||k  r|r|S y# t        j                  t
        f$ r Y w xY w)zExtracts the first meaningful user prompt from a JSONL head chunk.

    Skips tool_result messages, isMeta, isCompactSummary, command-name
    messages, and auto-generated patterns. Truncates to 200 chars.
    r   r   
r   Nz"type":"user"z"type": "user"z"tool_result"z"isMeta":truez"isMeta": truez"isCompactSummary":truez"isCompactSummary": truetypeusermessagecontentrh    r   u   …)r.   rg   r[   r\   r^   r_   r]   dictr8   r;   r   listreplacestrip_COMMAND_NAME_REsearchgroup_SKIP_FIRST_PROMPT_PATTERNr   rstrip)headstartcommand_fallbackhead_lennewline_idxlinerV   rx   ry   textsblockr`   ra   	cmd_matchs                 r   _extract_first_prompt_from_headr     s3    E4yH
(
iie,!k*D!OE<DE$&+;4+Gd"d"&6$&>$,0Jd0R	JJt$E %&%))F*;v*E))I&'4(++i(gs#LL!& ud+		&)V3"599V#4c:LLv/ ! C[[s+113F )//7I''0q'9$)//76{S ,,.9M# W (
| Y $$j1 		s    H   HHc                      e Zd ZdZdZddZy)_LiteSessionFilez>Result of reading a session file's head, tail, mtime and size.mtimesizer   tailc                <    || _         || _        || _        || _        y rE   r   )selfr   r   r   r   s        r   __init__z_LiteSessionFile.__init__Y  s    
			r   N)
r   intr   r   r   r;   r   r;   returnNone)__name__
__module____qualname____doc__	__slots__r    r   r   r   r   T  s    H1Ir   r   c                ,   	 | j                  d      5 }t        j                  |j                               }|j                  }t        |j                  dz        }|j                  t              }|s
	 ddd       y|j                  dd      }t        d|t        z
        }|dk(  r|}n9|j                  |       |j                  t              }	|	j                  dd      }t        ||||      cddd       S # 1 sw Y   yxY w# t        $ r Y yw xY w)	zoOpens a session file, stats it, and reads head + tail.

    Returns None on any error or if file is empty.
    rb  Nutf-8r}   errorsr   r   )openr6   fstatfilenost_sizer   st_mtimereadLITE_READ_BUF_SIZEdecodemaxseekr   rK   )
	file_pathfstatr   r   
head_bytesr   tail_offsetr   
tail_bytess
             r   _read_session_liter   `  s    
^^D!Q88AHHJ'D<<D,-E 23J "! $$WY$?Da(:!:;Ka{#VV$67
!(((C#%dDQ' "!!(  s<   D A C;3D <A5C;1	D ;D D D 	DDc                   	 t        j                  g d| dddd      }|j                  dk7  s|j
                  sg S g }|j
                  j                  d      D ]G  }|j                  d      st        j                  d	|t        d      d
       }|j                  |       I |S # t        t         j                  f$ r g cY S w xY w)zReturns absolute worktree paths for the git repo containing cwd.

    Returns empty list if git is unavailable or cwd is not in a repo.
    )gitworktreer|   z--porcelainTr   F)cwdcapture_outputrh   timeoutcheckr   ru   z	worktree r5   N)
subprocessrunrK   SubprocessError
returncodestdoutsplitrR   r9   r:   r.   r   )r   ra   pathsr   rI   s        r   _get_worktree_pathsr     s    

6
 AV]]	E##D)??;'((S5E5G0HIDLL * L Z//0 	s   B% %CCc                   |j                   |j                  |j                  |j                  f\  }}}}|j	                  d      }|dk\  r|d| n|}d|v sd|v ryt        |d      xs, t        |d      xs t        |d      xs t        |d      xs d}	t        |      xs d}
|	xs t        |d      xs t        |d	      xs |
}|syt        |d
      xs t        |d
      xs d}t        |d      xs |xs d}t        d t        |j                  d            D        d      }|rt        |d      xs dnd}d}t        |d      }|rU	 |j                  d      r|j                  dd      n|}t        t        j                  |      j!                         dz        }t%        | ||||	|
||||
      S # t"        $ r Y  w xY w)zParses SDKSessionInfo fields from a lite session read (head/tail/stat).

    Returns None for sidechain sessions or metadata-only sessions with no
    extractable summary.

    Shared by list_sessions and get_session_info.
    ru   r   Nz"isSidechain":truez"isSidechain": truecustomTitleaiTitle
lastPromptsummary	gitBranchr   c              3  D   K   | ]  }|j                  d       s|  yw)z{"type":"tag"N)rR   ).0lns     r   	<genexpr>z0_parse_session_info_from_lite.<locals>.<genexpr>  s     S0BMM/4R0s     tag	timestampZ+00:00r   )

session_idr   last_modified	file_sizecustom_titlefirst_prompt
git_branchr   r   
created_at)r   r   r   r   rg   rs   r   ro   nextr!   r   endswithr}   r   r   fromisoformatr   r_   r   )r   literF   r   r   r   r   first_newline
first_liner   r   r   r   session_cwdtag_liner   r   first_timestamptss                      r   _parse_session_info_from_liter     s%    #iiDJJ		ID$t IIdOM)6!);n}%Jz)-Bj-P
 	(m< 	*4?	*4;	 +4;	   348@DL 	 	*4>	*4;	 	   	(k: 	%dK8	 
 -T59Q\QTK Shtzz$/0SH
 GO	(5	9	ATTX  "J0{CO		 #++C0  ''X6$ 
 X33B7AACdJKJ !!   		s   
AF3 3	F?>F?c                *   	 t        | j                               }g }|D ]`  }|j                  }|j	                  d      s!t        |dd       }|s2t        |      }|@t        |||      }|P|j                  |       b |S # t        $ r g cY S w xY w)zReads session files from a single project directory.

    Each file gets a stat + head/tail read. Filters out sidechain sessions
    and metadata-only sessions (no title/summary/prompt).
    .jsonlNi)	r|   rQ   rK   r0   r   r   r   r   r   )	project_dirrF   entriesresultsrV   r0   r   r   infos	            r   _read_sessions_from_dirr     s    {**,- %'Gzz}}X&#D"I.
!%(<,Z|LNN4    N+  	s   B BBc                    i }| D ]H  }|j                  |j                        }||j                  |j                  kD  s:|||j                  <   J t        |j	                               S )z=Deduplicates by session_id, keeping the newest last_modified.)r8   r   r   r|   values)sessionsby_idr"   existings       r   _deduplicate_by_session_idr   (  s]     (*E99Q\\*q1G1GG"#E!,,  r   c                Z    | j                  d d       |dkD  r| |d } |
|dkD  r| d| } | S )zFSorts sessions by last_modified descending and applies offset + limit.c                    | j                   S rE   )r   )r"   s    r   <lambda>z*_apply_sort_limit_offset.<locals>.<lambda>:  s    r   Tri   reverser   N)sort)r   limitoffsets      r   _apply_sort_limit_offsetr   4  sE     MM/M>zFG$UQYFU#Or   c                   t        |       }|r	 t        |      }ng }t        |      dk  r(t	        |      }|g S t        ||      }t        |||      S t               }t        j                  dk(  }	g }
|D ]4  }t        |      }|	r|j                         n|}|
j                  ||f       6 |
j                  d d       	 |j                         D cg c]  }|j                         s| }}g }t#               }t	        |      }|L|j$                  }|j'                  |	r|j                         n|       t        ||      }|j)                  |       |D ]  }|	r|j$                  j                         n|j$                  }||v r0|
D ]f  \  }}||k(  xs( t        |      t*        k\  xr |j-                  |dz         }|s8|j'                  |       t        ||      }|j)                  |          t/        |      }t        |||      S # t        $ r g }Y w xY wc c}w # t         $ r8 t	        |      }|t        g ||      cY S t        ||      }t        |||      cY S w xY w)zDLists sessions for a specific project directory (and its worktrees).r   win32c                    t        | d         S )Nr   )r.   )xs    r   r   z,_list_sessions_for_project.<locals>.<lambda>g  s    s1Q4yr   Tr   r+   )rN   r   	Exceptionr.   rW   r   r   rC   sysplatformr2   lowerr   r   rQ   rP   rK   setr0   addextendr/   rR   r   )	directoryr   r   include_worktreescanonical_dirworktree_pathsr   r   rU   case_insensitiveindexedwtr1   rT   eall_direntsall_sessions	seen_dirscanonical_project_dirdir_baserV   dir_namewt_pathis_matchdedupeds                            r   _list_sessions_for_projectr  B  s~    'y1M	 0?N  >a'6I*;F'%@@ %&L||w. G"2&	&6"IF|$  LL($L7A"."6"6"8G"8QAHHJq"8G *,L%I .m<((--*:hnn&I*+@-PH%)95::##%uzzy &OGV  6) F33 6''5  h'25'B##H-  ' & )6G#GUF;;K  	 N	 8 H A'6+Bv>>*;F'%@@AsA   H
  H! H(H,H! 
HHH! !#I"I"!I"c                   t               }	 |j                         D cg c]  }|j                         s| }}g }|D ]  }|j	                  t        |              t        |      }t        || |      S c c}w # t        $ r g cY S w xY w)z.Lists sessions across all project directories.)rC   rQ   rP   rK   r  r   r   r   )r   r   rU   r  project_dirsr  r   r  s           r   _list_all_sessionsr    s    $&L#/#7#7#9H#9aQXXZ#9H *,L#3K@A $ )6G#GUF;; I 	s&   A: A5A5A: 5A: :BBc                :    | rt        | |||      S t        ||      S )a  Lists sessions with metadata extracted from stat + head/tail reads.

    When ``directory`` is provided, returns sessions for that project
    directory and its git worktrees. When omitted, returns sessions
    across all projects.

    Use ``limit`` and ``offset`` for pagination.

    Args:
        directory: Directory to list sessions for. When provided, returns
            sessions for this project directory (and optionally its git
            worktrees). When omitted, returns sessions across all projects.
        limit: Maximum number of sessions to return.
        offset: Number of sessions to skip from the start of the sorted
            result set. Use with ``limit`` for pagination. Defaults to 0.
        include_worktrees: When ``directory`` is provided and the directory
            is inside a git repository, include sessions from all git
            worktree paths. Defaults to ``True``.

    Returns:
        List of ``SDKSessionInfo`` sorted by ``last_modified`` descending.

    See Also:
        :func:`list_sessions_from_store` for the :class:`SessionStore`-backed
        async variant.

    Example:
        List sessions for a specific project::

            sessions = list_sessions(directory="/path/to/project")

        Paginate::

            page1 = list_sessions(limit=50)
            page2 = list_sessions(limit=50, offset=50)

        List sessions without scanning git worktrees::

            sessions = list_sessions(
                directory="/path/to/project",
                include_worktrees=False,
            )
    )r  r  )r  r   r   r  s       r   list_sessionsr    s'    b ))UFDUVVeV,,r   c                ,   t        |       }|sy| d}|r|t        |      }t        |      }|t        ||z        }|t	        |||      S 	 t        |      }|D ]5  }||k(  r	t        |      }	|	t        |	|z        }|(t	        |||      c S  yt               }
	 |
j                         D cg c]  }|j                         s| }}|D ]   }t        ||z        }|t	        ||      c S  y# t        $ r g }Y w xY wc c}w # t        $ r Y yw xY w)u  Reads metadata for a single session by ID.

    Wraps ``_read_session_lite`` for one file — no O(n) directory scan.
    Directory resolution matches ``get_session_messages``: ``directory`` is
    the project path; when omitted, all project directories are searched for
    the session file.

    Args:
        session_id: UUID of the session to look up.
        directory: Project directory path (same semantics as
            ``list_sessions(directory=...)``). When omitted, all project
            directories are searched for the session file.

    Returns:
        ``SDKSessionInfo`` for the session, or ``None`` if the session file
        is not found, is a sidechain session, or has no extractable summary.

    See Also:
        :func:`get_session_info_from_store` for the
        :class:`SessionStore`-backed async variant.

    Example:
        Look up a session in a specific project::

            info = get_session_info(
                "550e8400-e29b-41d4-a716-446655440000",
                directory="/path/to/project",
            )
            if info:
                print(info.summary)

        Search all projects for a session::

            info = get_session_info("550e8400-e29b-41d4-a716-446655440000")
    Nr   )r   rN   rW   r   r   r   r   rC   rQ   rP   rK   )r   r  uuid	file_name	canonicalr   r   r
  r  wt_project_dirrU   r  direntsrV   s                 r   get_session_infor$    sU   N *%D&I&y1	'	2"%kI&=>D4T4KK	 0;N !BY.r2N)).9*DE#8tRHH !  %&L*224C4
14C !%)"340t<<  /  	 N	   D s<   C1 D /DD	D 1C?>C?D 	DD>   rw   systemprogress	assistant
attachmentc                L    	 | |z  j                  d      S # t        $ r Y yw xY w)z<Tries to read a session JSONL file from a project directory.r   encodingN)	read_textrK   )r   r   s     r   _try_read_session_filer-  C  s2    i'22G2DD s    	##c                   |  d}|rbt        |      }t        |      }|t        ||      }|r|S 	 t        |      }|D ](  }||k(  r	t        |      }|t        ||      }|s&|c S  yt               }		 t        |	j                               }
|
D ]  }t        ||      }|s|c S  y# t        $ r g }Y yw xY w# t        $ r Y yw xY w)a.  Finds and reads the session JSONL file.

    If directory is provided, looks in that project directory and its git
    worktrees (with prefix-fallback for Bun/Node hash mismatches on long
    paths). Otherwise, searches all project directories.

    Returns the file content, or None if not found.
    r   N)	rN   rW   r-  r   r   rC   r|   rQ   rK   )r   r  r   r	  r   ry   r
  r  r"  rU   r#  rV   s               r   _read_session_filer/  K  s    ,f%I*95 (6",[)DG	 0?N !B]".r2N)0K"N !  %&L|++-. (	:N 
 5  	 N	 $  s#   B( 5B9 (B65B69	CCc                   g }d}t        |       }||k  r| j                  d|      }|dk(  r|}| || j                         }|dz   }|s9	 t        j                  |      }t        |t              s`|j                  d      }|t        v r0t        |j                  d      t              r|j                  |       ||k  r|S # t        j
                  t        f$ r Y w xY w)zParses JSONL content into transcript entries.

    Only keeps entries that have a uuid and are transcript message types
    (user/assistant/progress/system/attachment). Skips corrupt lines.
    r   ru   r   rv   r  )r.   rg   r~   r[   r\   r^   r_   r]   r{   r8   _TRANSCRIPT_ENTRY_TYPESr;   r   )ry   r   r   lengthendr   rV   
entry_types           r   _parse_transcript_entriesr6    s     ')GE\F
&.ll4'"9CuS!'')a	JJt$E %&YYv&
00Z		&@QSV5WNN5!' &.* N $$j1 		s   
C CCc                   | sg S i }| D ]
  }|||d   <    i t        |       D ]  \  }}||d   <    t               }| D ]'  }|j                  d      }|s|j                  |       ) | D cg c]  }|d   |vs| }}g }|D ]z  }	|	}
t               }|
|
d   }||v r|j                  |       |
j                  d      dv r|j	                  |
       R|
j                  d      }|r|j                  |      nd}
|
i| |sg S |D cg c]7  }|j                  d      s$|j                  d      s|j                  d      s|9 }}d
fd	}|r ||      n ||      }g }t               }|}|U|d   }||v rnK|j                  |       |j	                  |       |j                  d      }|r|j                  |      nd}|U|j                          |S c c}w c c}w )u  Builds the conversation chain by finding the leaf and walking parentUuid.

    Returns messages in chronological order (root -> leaf).

    Note: logicalParentUuid (set on compact_boundary entries) is intentionally
    NOT followed. This matches VS Code IDE behavior — post-compaction, the
    isCompactSummary message replaces earlier messages, so following logical
    parents would duplicate content.
    r  
parentUuidNrv   rw   r'  isSidechainteamNameisMetac                    | d   }j                  |d   d      }| dd  D ]!  }j                  |d   d      }||kD  s|}|}# |S )Nr   r  r1  r   r8   )
candidatesbestbest_idxcurcur_idxentry_indexs        r   
_pick_bestz-_build_conversation_chain.<locals>._pick_best  s]    !}??4<4ab>C!ooc&k26G!"	 "
 r   )r?  list[_TranscriptEntry]r   _TranscriptEntry)	enumerater  r8   r  r   r   )r   by_uuidrV   rn   parent_uuidsparentr  	terminalsleavesterminalwalk_cur	walk_seenuidleafmain_leavesrE  chain
chain_seen	chain_currD  s                      @r   _build_conversation_chainrW    s(    	 ,.G!&f  #%Kg&5%&E&M" ' !UL<(V$ 
 $EGqqy'DGIE &(F,4!e	"6"CiMM#||F#'<<h'\\,/F.4w{{6*$H "  	 Dxx&$"	 	   '2:k"z&7ID %'E5J)-I

*sY|,+1GKK't	 
 
MMOLs F.s   .G;G
<Gc                    | j                  d      }|dk7  r|dk7  ry| j                  d      ry| j                  d      ry| j                  d       S )zFReturns True if the entry should be included in the returned messages.rv   rw   r'  Fr<  r:  r;  r>  )rV   r5  s     r   _is_visible_messagerY    sT    6"JV
k 9yyyy
 yy$$$r   c                    | j                  d      }|dk(  rdnd}t        || j                  dd      | j                  dd      | j                  d      d	      S )
z7Converts a transcript entry dict into a SessionMessage.rv   rw   r'  r  r   	sessionIdrx   N)rv   r  r   rx   parent_tool_use_id)r8   r
   )rV   r5  msg_types      r   _to_session_messager^    s[    6"J )F2FHYYvr"99["-		)$ r   c                l    t        |       sg S t        | |      }|sg S t        |      }t        |||      S )a5  Reads a session's conversation messages from its JSONL transcript file.

    Parses the full JSONL, builds the conversation chain via ``parentUuid``
    links, and returns user/assistant messages in chronological order.

    Args:
        session_id: UUID of the session to read.
        directory: Project directory to find the session in. If omitted,
            searches all project directories under ``~/.claude/projects/``.
        limit: Maximum number of messages to return.
        offset: Number of messages to skip from the start.

    Returns:
        List of ``SessionMessage`` objects in chronological order. Returns
        an empty list if the session is not found, the session_id is not a
        valid UUID, or the transcript contains no visible messages.

    See Also:
        :func:`get_session_messages_from_store` for the
        :class:`SessionStore`-backed async variant.

    Example:
        Read all messages from a session::

            messages = get_session_messages(
                "550e8400-e29b-41d4-a716-446655440000",
                directory="/path/to/project",
            )
            for msg in messages:
                print(msg.type, msg.message)

        Read with pagination::

            page = get_session_messages(
                session_id, limit=10, offset=20
            )
    )r   r/  r6  _entries_to_session_messages)r   r  r   r   ry   r   s         r   get_session_messagesra    s?    V *%	 Y7G	'0G'??r   c                    t        |       }|D cg c]  }t        |      s| }}|D cg c]  }t        |       }}||dkD  r||||z    S |dkD  r||d S |S c c}w c c}w )zBuilds the conversation chain from parsed entries and applies paging.

    Shared by the filesystem and SessionStore-backed paths.
    Nr   )rW  rY  r^  )r   r   r   rT  r  visiblemessagess          r   r`  r`  S  s     &g.E:%Q#6q#9q%G:0781#A&H8 UQY%00z  O ;8s   AAAc                   |  ddfd}|rZt        |      }t        |      }| ||      }||S 	 t        |      }|D ]$  }||k(  r	t        |      }| ||      }|"|c S  yt	               }		 t        |	j                               }
|
D ]!  }|j                         s ||      }||c S  y# t        $ r g }Y w xY w# t        $ r Y yw xY w)aI  Resolves the on-disk path of a session JSONL file.

    Directory resolution mirrors ``_read_session_file``: when ``directory``
    is provided, looks in that project directory and its git worktrees;
    otherwise searches all project directories. Returns the path of the
    first non-empty match, or ``None`` if not found.
    r   c                p    | z  }	 |j                         j                  dkD  r|S 	 y # t        $ r Y y w xY w)Nr   )r   r   rK   )r   	candidater   s     r   _stat_candidatez3_resolve_session_file_path.<locals>._stat_candidatew  sN    )+		~~''!+   ,   		s   ) 	55N)r   r   r   Path | None)	rN   rW   r   r   rC   r|   rQ   rK   rP   )r   r  rh  r	  r   foundr
  r  r"  rU   r#  rV   r   s               @r   _resolve_session_file_pathrk  m  s    ,f%I *95'6"#K0E 	 0?N !B]".r2N)'7$ L ! $&L|++-. ||~&L  7  	 N	 "  s#   B4 4C 4CC	CCc                L    t        | |      }|y|j                  d      }|dz  S )zResolves the subagents directory for a given session.

    The session file lives at ``<projectDir>/<sessionId>.jsonl`` and the
    subagents directory at ``<projectDir>/<sessionId>/subagents/``.

    Returns ``None`` if the session cannot be found.
    Nr   	subagents)rk  with_suffix)r   r  rM   session_dirs       r   _resolve_subagents_dirrp    s4     **i@H&&r*K$$r   c                ,    g dfd |        S )a	  Recursively collects ``agent-*.jsonl`` files from a directory tree.

    Subagent transcripts may live directly in ``subagents/`` or in nested
    subdirectories such as ``subagents/workflows/<runId>/``.

    Returns a list of ``(agent_id, file_path)`` tuples.
    c                r   	 t        | j                         d       }|D ]  }|j                  }|j	                         rN|j                  d      r=|j                  d      r,|t        d      t        d        }j                  ||f       m|j                         s~ |        y # t        $ r Y y w xY w)Nc                    | j                   S rE   )r0   )ps    r   r   z5_collect_agent_files.<locals>._walk.<locals>.<lambda>  s    !&&r   )ri   agent-r   )
sortedrQ   rK   r0   is_filerR   r   r.   r   rP   )current_dirr#  rV   r0   agent_id_walkr   s        r   rz  z#_collect_agent_files.<locals>._walk  s    	[0028HIG E::DOOH-MM(+HX?%01e   		s   B* *	B65B6)rx  r   r   r   r   )base_dirrz  r   s    @@r   _collect_agent_filesr|    s     ')G" 
(ONr   c                t   | sg S i }| D ]
  }|||d   <    d}t        |       D ]  }|j                  d      dv s|} n |g S g }t               }|}|U|d   }||v rnK|j                  |       |j	                  |       |j                  d      }|r|j                  |      nd}|U|j                          |S )u
  Builds the conversation chain for a subagent transcript.

    Subagent transcripts are simpler than main sessions — no compaction,
    no sidechains, no preserved segments. Find the last user/assistant
    entry and walk ``parentUuid`` links back to the root.
    r  Nrv   r9  r8  )r!   r8   r  r  r   r   )	r   rI  rV   rR  rT  seencurrentrQ  rK  s	            r   _build_subagent_chainr    s     	+-G!&f 
 %)D'"99V 55D # |	$&EUD'+G

fo$;W\*)/'++f%T 
 
MMOLr   c                    t        |       sg S t        | |      }|g S t        |      D cg c]  \  }}|	 c}}S c c}}w )a  Lists subagent IDs for a given session by scanning the subagents directory.

    Subagent transcripts are stored at
    ``~/.claude/projects/<project>/<sessionId>/subagents/agent-<agentId>.jsonl``
    (and may be nested in subdirectories such as ``workflows/<runId>/``).

    Args:
        session_id: UUID of the parent session.
        directory: Project directory to find the session in. If omitted,
            searches all project directories under ``~/.claude/projects/``.

    Returns:
        List of subagent ID strings. Returns an empty list if the session
        is not found, the session_id is not a valid UUID, or the session
        has no subagents.

    See Also:
        :func:`list_subagents_from_store` for the :class:`SessionStore`-backed
        async variant.

    Example:
        List subagent IDs for a session::

            agent_ids = list_subagents(
                "550e8400-e29b-41d4-a716-446655440000",
                directory="/path/to/project",
            )
    )r   rp  r|  )r   r  subagents_dirry  _s        r   list_subagentsr     sL    @ *%	*:yAM	(<](KL(K1H(KLLLs   <c                   t        |       sg S |sg S t        | |      }|g S d}t        |      D ]  \  }}||k(  s|} n |g S 	 |j                  d      }	|	sg S t        |	      }
t        |
||      S # t        $ r g cY S w xY w)a  Reads a subagent's conversation messages from its JSONL transcript file.

    Parses the subagent transcript, builds the conversation chain via
    ``parentUuid`` links, and returns user/assistant messages in
    chronological order.

    Args:
        session_id: UUID of the parent session.
        agent_id: ID of the subagent (as returned by ``list_subagents``).
        directory: Project directory to find the session in. If omitted,
            searches all project directories under ``~/.claude/projects/``.
        limit: Maximum number of messages to return.
        offset: Number of messages to skip from the start.

    Returns:
        List of ``SessionMessage`` objects in chronological order. Returns
        an empty list if the session or subagent is not found, the
        session_id is not a valid UUID, or the transcript contains no
        user/assistant messages.

    See Also:
        :func:`get_subagent_messages_from_store` for the
        :class:`SessionStore`-backed async variant.

    Example:
        Read all messages from a subagent::

            messages = get_subagent_messages(
                "550e8400-e29b-41d4-a716-446655440000",
                "abc123",
                directory="/path/to/project",
            )
    Nr   r*  )r   rp  r|  r,  rK   r6  _entries_to_subagent_messages)r   ry  r  r   r   r  r   found_idr   ry   r   s              r   get_subagent_messagesr  *  s    P *%		*:yAM	 E3MB)xE  C }	//7/3 	'0G(%@@  	s   A3 3B Bc                    t        |       }|D cg c]!  }|j                  d      dv st        |      # }}||dkD  r||||z    S |dkD  r||d S |S c c}w )zBuilds the subagent chain from parsed entries and applies paging.

    Shared by the filesystem and SessionStore-backed paths.
    rv   r9  Nr   )r  r8   r^  )r   r   r   rT  r  rd  s         r   r  r  p  s}     "'*E(-(-1vBW1WA   UQY%00z  Os
   AAc                H    t        | t        |       nd      }t        |      S )a{  Derive the :class:`SessionStore` ``project_key`` for a directory.

    Defaults to the current working directory. Uses the same realpath + NFC
    normalization + djb2-hashed sanitization the CLI uses for project
    directory names, so keys match between local-disk transcripts and
    store-mirrored transcripts even on filesystems that decompose Unicode
    (macOS HFS+).
    .)rN   r;   r2   )r  abs_paths     r   project_key_for_directoryr    s$     "I4I#i.sSH(##r   c                F    dddj                  fd| D              dz   S )aq  Serialize store entries to a JSONL string (one ``json.dumps`` per line).

    The ``SessionStore.load`` contract permits adapters to reorder object keys
    (e.g. Postgres JSONB), but ``_parse_session_info_from_lite`` scans for
    ``{"type":"tag"`` as a line prefix. Hoist ``type`` to the front so the
    store path matches the byte shape the disk path produces.
    c                @    t        | t              rd| v r	d| d   i| S | S )Nrv   )r]   r{   )r  s    r   _type_firstz&_entries_to_jsonl.<locals>._type_first  s+    a6Q;AfI+++r   ru   c              3  X   K   | ]!  }t        j                   |      d        # yw)),:)
separatorsN)r[   dumps)r   r  r  s     r   r   z$_entries_to_jsonl.<locals>.<genexpr>  s$     UW$**[^
CCWs   '*)r  r   r   r   )r    )r   r  s    @r   _entries_to_jsonlr    s)     			UWUU
	r   c                    | j                  d      }t        |      }|dt         j                  dd      }|t        kD  r'|t	        d|t        z
        d j                  dd      n|}t        ||||      S )a  Build the head/tail/size lite shape from an in-memory JSONL string.

    Matches ``_read_session_lite``'s byte semantics so the store path exposes
    the same slice to ``_parse_session_info_from_lite`` as the disk path
    would for the same transcript.
    r   Nr}   r   r   r   )encoder.   r   r   r   r   )jsonlr   bufr   r   r   s         r   _jsonl_to_liter    s     ,,w
Cs8D""#**79*ED $$ 	C4,,-/077	7R 	
 %dDIIr   c                (   | j                         }||j                  d      dz   d }	 t        j                  |      }t        |t              rv|j                  d      }t        |t              rU	 |j                  d      r|j                  dd      n|}t        t        j                  |      j                         dz        S t        t!        j                          dz        S # t        j                  t
        f$ r d}Y w xY w# t
        $ r Y Lw xY w)zBest-effort mtime: parse the last entry's ``timestamp`` field.

    Falls back to the current wall-clock time when absent or unparseable.
    ru   r   Nr   r   r   r   )r   rfindr[   r\   r^   r_   r]   r{   r8   r;   r   r}   r   r   r   r   time)r  trimmed	last_lineobjr   norms         r   _mtime_from_jsonl_tailr    s    
 llnGd+a/12Ijj# #tWW[!b#46KK4Drzz#x0"811$7AACdJKK tyy{T!""   *-   s$   C$ 0AD $DD	DDc                    g }| D ]\  }t        |t              s|j                  d      t        v s,t        |j                  d      t              sL|j                  |       ^ |S )a  Filter store-loaded entries to transcript message types with a ``uuid``.

    Mirrors ``_parse_transcript_entries`` for the already-parsed object path
    so chain-building never sees metadata-only entries (custom-title, tag,
    agent_metadata, etc.).
    rv   r  )r]   r{   r8   r2  r;   r   )r   ra   r  s      r   _filter_transcript_entriesr    sS     &(Fq$f!88155=#.MM!  Mr   c                |   K   t        |      }||d}| j                  |       d{   }|syt        |      S 7 w)z{Load entries from a SessionStore and serialize to a JSONL string.

    Returns ``None`` if the session has no entries.
    project_keyr   N)r  loadr  )storer   r  r  ri   r   s         r   _load_store_entries_as_jsonlr    sB      ,I6K&1LCJJsO#GW%% $s   %<:<c                   K   t        j                  t              d fdt        j                  fd|D        ddi d{   }g }t	        ||d      D ]r  \  }}|d   }|d   }	t        |t              r|j                  t        |d	|	
             >|At        |t        ||	      |      }
|
[|	|
_        |j                  |
       t |S 7 w)a  Derive ``SDKSessionInfo`` for each ``listing`` entry via per-session
    ``store.load()`` + lite-parse.

    Loads run concurrently with a fixed bound so large listings don't exhaust
    adapter connection pools or hit backend rate limits; adapter errors degrade
    that row to an empty summary instead of failing the whole list. Sidechain
    and no-summary sessions are dropped.
    c                   K   4 d {    t        |        d {   cd d d       d {    S 7 *7 7 	# 1 d {  7  sw Y   y xY wwrE   )r  )sidr  semsession_stores    r   _bounded_loadz-_derive_infos_via_load.<locals>._bounded_load  s5     35mS)TT 33T 333sH   A5A;7;A9A;AAAA	Ac              3  4   K   | ]  } |d            yw)r   Nr   )r   r  r  s     r   r   z)_derive_infos_via_load.<locals>.<genexpr>	  s     	:'Q-,
('s   return_exceptionsTN)strictr   r   r   )r   r   r   )r  r;   r   
str | None)asyncio	Semaphore_STORE_LIST_LOAD_CONCURRENCYgatherzipr]   BaseExceptionr   r   r   r  r   )r  listingr  rF   settledr   rV   outcomer  r   parsedr  r  s   ` `        @@r   _derive_infos_via_loadr    s      

8
9CU NN	:'	: G %'Ggwt<wL!gg}-NN#rO ?./
 > $v% =& N1s   AC	C
BCc                  K   t        |t        |      nd      }t        |      }t        | d      }t        | d      rddlm} 	 | j                  |       d{   }|r9t        | j                  |       d{         }	|	D 
ci c]  }
|
d   |
d    }}
ng }	i }t        j                  d	       g }t               |D ]k  }|d   }|r|j                  |      }||d   |k  r' |||      }|j                  |       D|j                  |d   |d
       j                  |       m |r|j                  fd|	D               |j!                  d d       |dkD  r||d n|}|
|dkD  r|d| }|D cg c]
  }|d   	| }}|rNt#        | |||       d{   }|D ci c]  }|j$                  | }}|D ]  }|j                  |d         |d<    |D cg c]  }|d   	|d    c}S |st)        d      t        | j                  |       d{         }	t#        | |	||       d{   }t+        |||      S 7 7 c c}
w c c}w 7 c c}w c c}w # t&        $ r Y yw xY w7 V7 >w)u  List sessions from a :class:`SessionStore`.

    Async, store-backed counterpart to :func:`list_sessions`. Loads each
    session's entries to derive a real summary via the same lite-parse used
    by the filesystem path, so disk and store paths produce identical
    results for the same transcript content.

    Args:
        session_store: The store to read from. Must implement
            :meth:`SessionStore.list_session_summaries` or
            :meth:`SessionStore.list_sessions` (or both).
        directory: Project directory used to compute the ``project_key``.
            Defaults to the current working directory.
        limit: Maximum number of sessions to return.
        offset: Number of sessions to skip from the start of the sorted
            result set.

    Returns:
        List of ``SDKSessionInfo`` sorted by ``last_modified`` descending.

    Raises:
        ValueError: If ``session_store`` implements neither
            :meth:`SessionStore.list_session_summaries` nor
            :meth:`SessionStore.list_sessions`.

    Note:
        ``include_worktrees`` is a filesystem concept and is not honored on
        the store path — the store operates on a single ``project_key``.

    .. note::
        If the store implements ``list_session_summaries``, this is one batch
        summary call plus one cheap ``list_sessions()`` enumeration to
        gap-fill sessions missing a sidecar or whose sidecar is stale
        (``summary.mtime < list_sessions.mtime``) — zero per-session
        ``load()`` calls when sidecars are complete and fresh. Otherwise
        falls back to one ``store.load()`` per session (bounded at 16
        concurrent), which on remote backends with many or large sessions
        can be expensive (e.g., S3 egress, Postgres large-row reads).

        Gap-fill requires ``list_sessions``: if the store implements
        ``list_session_summaries`` but not ``list_sessions``, sessions
        without a sidecar cannot be discovered and will be absent from the
        result.
    Nr  r  list_session_summariesr   )summary_entry_to_sdk_infor   r   zjlist_session_summaries without list_sessions: gap-fill skipped; sessions lacking a sidecar will be omitted)r   r   c              3  D   K   | ]  }|d    vr|d   |d    dd  yw)r   r   N)r   r   r   r   )r   r  fresh_summary_idss     r   r   z+list_sessions_from_store.<locals>.<genexpr>  s6      $.??  j,QUV$s    c                    | d   S )Nr   r   )sls    r   r   z*list_sessions_from_store.<locals>.<lambda>  s    bkr   Tr   r   r   zsession_store implements neither list_session_summaries() nor list_sessions() -- cannot list sessions. Provide a store with at least one of those methods.)rN   r;   r2   r   session_summaryr  r  r|   r  loggerdebugr  r8   r  r   r  r   r  r   NotImplementedErrorr_   r   )r  r  r   r   rF   r  has_list_sessionsr  	summariesr  r  known_mtimesslotsr"   r  knownr   pager  to_fillfilledr   by_sidr   r  s                           @r   list_sessions_from_storer  #  s    d &	8Mc)nSVWL .K)-I (@A>N	I+BB;OOI !]%@%@%MMNELMW,7 ;WM!J
 +-E*-%o$(,,S1E} !zE) 0LA<%))#.qz4@A!%%c*! " ! $  JJ14J@ &,aZ5>UD UQYFU|$(?DbBvJ,>rDG?5!7I|   4::6a!,,/6:!B!'B|,<!=BvJ " *.H2F1GBvJHH*
 	
 44[AABG
 +w	< G $GUF;;} P  NM\ @ ; IY # 		j B
s   AI7I$ II$  I7;I<I7IC$I7<
III7 I!I7)I=$I7!
I,I3)I7I3I76I57I7I$ I7I7
I7$	I0-I7/I00I75I7c                   K   t        |      syt        | ||       d{   }|yt        |t        |            }t	        |t        |      nd      }t        |||      S 7 Aw)aW  Read metadata for a single session from a :class:`SessionStore`.

    Async, store-backed counterpart to :func:`get_session_info`.

    Args:
        session_store: The store to read from.
        session_id: UUID of the session to look up.
        directory: Project directory used to compute the ``project_key``.
            Defaults to the current working directory.

    Returns:
        ``SDKSessionInfo`` for the session, or ``None`` if the session is
        not found, the ``session_id`` is not a valid UUID, the session is
        a sidechain session, or it has no extractable summary.
    Nr  )r   r  r  r  rN   r;   r   )r  r   r  r  r   rF   s         r   get_session_info_from_storer    si     ( *%.}j)TTE}%!7!>?D%	8Mc)nSVWL(T<HH Us   A#A!AA#c                   K   t        |      sg S t        |      }||d}| j                  |       d{   }|sg S t        t	        |      ||      S 7 w)u  Read a session's conversation messages from a :class:`SessionStore`.

    Async, store-backed counterpart to :func:`get_session_messages`. Feeds
    ``session_store.load()`` results directly into the chain builder — no
    JSONL round-trip.

    Args:
        session_store: The store to read from.
        session_id: UUID of the session to read.
        directory: Project directory used to compute the ``project_key``.
            Defaults to the current working directory.
        limit: Maximum number of messages to return.
        offset: Number of messages to skip from the start.

    Returns:
        List of ``SessionMessage`` objects in chronological order. Empty
        list if the session is not found or ``session_id`` is invalid.
    r  N)r   r  r  r`  r  )r  r   r  r   r   r  ri   r   s           r   get_session_messages_from_storer    sb     2 *%	+I6K&1LC!&&s++G	'"7+UF  ,s   2AAAc                  K   t        |      sg S t        | d      st        d      t        |      }| j	                  ||d       d{   }t               }g }|D ]p  }|j                  d      s|j                  dd      d   }|j                  d	      s<|t        d	      d }	|	|vsO|j                  |	       |j                  |	       r |S 7 w)
a  List subagent IDs for a session from a :class:`SessionStore`.

    Async, store-backed counterpart to :func:`list_subagents`.

    Args:
        session_store: The store to read from. Must implement
            :meth:`SessionStore.list_subkeys`.
        session_id: UUID of the parent session.
        directory: Project directory used to compute the ``project_key``.
            Defaults to the current working directory.

    Returns:
        List of subagent ID strings. Empty list if ``session_id`` is
        invalid or the session has no subagents.

    Raises:
        ValueError: If ``session_store`` does not implement
            :meth:`SessionStore.list_subkeys`.
    list_subkeyszwsession_store does not implement list_subkeys() -- cannot list subagents. Provide a store with a list_subkeys() method.r  N
subagents//r   r1  ru  )r   r   r_   r  r  r  rR   rsplitr.   r  r   )
r  r   r  r  subkeysr~  idssubpathlastry  s
             r   list_subagents_from_storer    s     0 *%	]N;G
 	
 ,I6K!..#:> G UDC!!,/~~c1%b)??8$CMO,Ht#"

8$  Js   AC	C
ACC+'Cc                  K   t        |      sg S |sg S t        |      }d| }t        | d      r<| j                  ||d       d{   }d| t	        fd|D        d      }	|	g S |	}|||d}
| j                  |
       d{   }|sg S |D cg c](  }t        |t              r|j                  d      d	k(  s|* }}|sg S t        t        |      ||      S 7 7 Wc c}w w)
a  Read a subagent's conversation messages from a :class:`SessionStore`.

    Async, store-backed counterpart to :func:`get_subagent_messages`.
    Subagents may live at ``subagents/agent-<id>`` or nested under
    ``subagents/workflows/<runId>/agent-<id>``. Scans subkeys when the
    store implements :meth:`SessionStore.list_subkeys`; otherwise tries
    the direct path.

    Args:
        session_store: The store to read from.
        session_id: UUID of the parent session.
        agent_id: ID of the subagent.
        directory: Project directory used to compute the ``project_key``.
            Defaults to the current working directory.
        limit: Maximum number of messages to return.
        offset: Number of messages to skip from the start.

    Returns:
        List of ``SessionMessage`` objects in chronological order. Empty
        list if the session/subagent is not found.
    zsubagents/agent-r  r  Nru  c              3  t   K   | ]/  }|j                  d       r|j                  dd      d   k(  r| 1 yw)r  r  r   r1  N)rR   r  )r   sktargets     r   r   z3get_subagent_messages_from_store.<locals>.<genexpr>^  s<      !B==.299S!3DR3HF3R !s   58)r  r   r  rv   agent_metadata)r   r  r   r  r   r  r]   r{   r8   r  r  )r  r   ry  r  r   r   r  r  r  r   ri   r   r  
transcriptr  s                 @r    get_subagent_messages_from_storer  4  s5    : *%		+I6K 
+G7%22'zB
 
 ($!
 
 =I # C
 "&&s++G	 A1d#f9I(I 	
  
 	(":.v G
* ,s6   AC&C	>C&CC&-C!C&C&!C&)r   r;   r   r  )r"   r;   r   r;   )r0   r;   r   r;   )r   r   rE   )rA   zdict[str, str] | Noner   r   )rF   r;   r   r   )rL   r;   r   r;   )rF   r;   r   ri  )r`   r;   r   r;   )rh   r;   ri   r;   r   r  )r   r;   r   r;   )r   r   r   z_LiteSessionFile | None)r   r;   r   	list[str])r   r;   r   r   rF   r  r   SDKSessionInfo | None)r   r   rF   r  r   list[SDKSessionInfo])r   r  r   r  )r   )r   r  r   
int | Noner   r   r   r  )
r  r;   r   r  r   r   r  boolr   r  )r   r  r   r   r   r  )NNr   T)
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  )ry   r;   r   rF  )r   rF  r   rF  )rV   rG  r   r  )rV   rG  r   r
   )NNr   )
r   r;   r  r  r   r  r   r   r   list[SessionMessage])r   rF  r   r  r   r   r   r  )r   r;   r  r  r   ri  )r{  r   r   zlist[tuple[str, Path]])r   r;   r  r  r   r  )r   r;   ry  r;   r  r  r   r  r   r   r   r  )r  zstr | Path | Noner   r;   )r   	list[Any]r   r;   )r  r;   r   r   r   r   )r  r;   r   r   )r   r  r   rF  )r  r   r   r;   r  r  r   r  )
r  r   r  r  r  r  rF   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   r  r   r   r   r  )r  r   r   r;   r  r  r   r  )r  r   r   r;   ry  r;   r  r  r   r  r   r   r   r  )[r   
__future__r   r  r[   loggingr6   rer   r  r  r9   r   pathlibr   typingr   typesr   r	   r
   r   session_store_validationr   	getLoggerr   r  r   r  r/   compile
IGNORECASEr   r   r   r,   r   r)   r2   r>   rC   rG   rN   rW   rb   ro   rs   r   r   r   r   r   r   r   r   r  r  r  r$  	frozensetr2  r{   r;   rG  r-  r/  r6  rW  rY  r^  ra  r`  rk  rp  r|  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   <module>r     s   #    	 	  
      L L 7			8	$  
  " 
  2::EMM (RZZ6  2::CD rzz/*".
5$L6>/F
0<Jd	 	FH  $ZZ
Z Z 	ZF 37%/D	 "	 	  "  	Q<Q<Q< Q< 	Q<
 Q<h<$ !"	3-3-3- 3- 	3-
 3-z !OOO On $=  S> 2jDY#YYx% " !	3@3@3@ 3@ 	3@
 3@l#  	49x% >%T !'M'M'M 'MZ !CACACA CA 	CA
 CA CAL#  	4
$(J$#,$&&%(&5?&&,,, , 	,
 ,b !	Z<Z<Z< Z< 	Z<
 Z<@ !III I 	IB !""" " 	"
 " "P !... . 	.j !JJJ J 	J
 J J Jr   