ó
    À‘´j´'  ã                  ó�  • S r SSKJr  SSKrSSKJr  SSKJrJrJ	r	J
r
JrJrJr  SSKJr  SSKJrJr  SSKJr  SS	KJrJr  SS
KJrJr   " S S\5      r " S S\5      r " S S\5      rS\R<                  " \R?                  5       SS9 S3r \ " S S\5      5       r!SS jr" " S S5      r# " S S5      r$\
S   r%S S!S jjr&S"S jr'g)#ud  CellReader Protocol â€” read named cells off a table image and say what they print.

A table printed as an image is read twice: once by the parse, once by the page
scan. A cell the scan read is put to this agent with the table's image when the
parse read something different there or read no cell there at all. A cell only
the parse read, blank in the scan, is never asked about. The agent answers what
the page prints, cell by cell.

It is given both prior readings. They bracket the answer. A cell one reader gave
as `$ 3.000.00` and the other as `S 3,000,00` prints `$ 3,000.00`, which is
neither â€” each side has something the other lost. An agent reading the crop with
nothing to check itself against could return `$ 4,010.00` and it would look
exactly like a correct reading.

It is asked about a whole table at once rather than a cell at a time. A number
read out of a bare cell crop has lost its column header and its row label; read
in place it sits among values of the same magnitude, where a separator in the
wrong place is obvious.

Cells are named by the address printed beside them in the grid it is shown, the
same convention the structure correction uses, so the agent reads an address off
a label rather than counting rows and columns.

A failed call changes nothing. Every cell keeps the reading it arrived with,
which is the scan's, and the failure is logged.
é    )ÚannotationsN)ÚPath)ÚAnyÚDictÚListÚLiteralÚOptionalÚProtocolÚruntime_checkable)Úlogger)Ú	BaseModelÚField)Úsupports_sampling_temperature)ÚLangSmithTracerÚusage_metadata_from)ÚDEFAULT_LLM_MODELÚget_settingsc                  ó^   • \ rS rSr% Sr\" SS9rS\S'   \" SS9rS\S'   \" S	S
S9r	S\S'   Sr
g	)ÚCellQuestioné*   z7One cell to read, and what has already been read there.z'The cell's address in the grid, e.g. B3©ÚdescriptionÚstrÚaddressz$What the page scan read in this cellÚ	scan_readNzCWhat the parse read in this cell; absent when it read no cell there)Údefaultr   úOptional[str]Ú
parse_read© )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r   Ú__annotations__r   r   Ú__static_attributes__r   ó    Ú6/home/mande/repo/quber/src/quber/agents/cell_reader.pyr   r   *   s<   ‡ ÙAáÐ%NÑO€GˆSÓOÙÐ'MÑN€IˆsÓNÙ %ØÐ"gñ!€J�ö r'   r   c                  óB   • \ rS rSr% \" SS9rS\S'   \" SS9rS\S'   Srg	)
Ú	CellValueé4   z;The address this value belongs to, copied from the questionr   r   r   z3Exactly what the page prints in that cell, verbatimÚvaluer   N)	r    r!   r"   r#   r   r   r%   r,   r&   r   r'   r(   r*   r*   4   s"   ‡ ÙÐ%bÑc€GˆSÓcÙÐ#XÑY€Eˆ3ÖYr'   r*   c                  ó.   • \ rS rSr% \" \SS9rS\S'   Srg)Ú
CellValuesé9   z!One entry per address asked about)Údefault_factoryr   zList[CellValue]Úcellsr   N)	r    r!   r"   r#   r   Úlistr1   r%   r&   r   r'   r(   r.   r.   9   s   ‡ Ù"°4ÐEhÑi€Eˆ?Öir'   r.   a   You are looking at a cropped image of one table from a financial document, and a
rendering of that table where every cell carries its address in square brackets.

Two tools have read this table. They disagree about some cells, and for other
cells only one of them produced a reading at all. You will be given a list of
those cells by address, with what each tool read.

For each address in the list, report exactly what the page prints in that cell.

Rules:
- Report the printed characters verbatim: currency symbols, thousands
  separators, decimal points, parentheses around negatives, percent signs,
  footnote markers, and minus signs or dashes, exactly as typeset.
- The two prior readings are evidence, not options. Where both are wrong,
  report what the page prints even though it matches neither. Where the cell is
  legible and one of them is right, report that one.
- A common failure in these readings is a thousands separator returned as a
  decimal point, so `19.543.903` where the page prints `19,543,903`. Look
  closely at separators and report what is printed.
- If the page prints nothing in the cell, return an empty string for it.
- Read only the cells you are asked about. Do not report any other cell, do not
  correct the table's structure, and never include an address tag in a value.
- Return one entry per address you were given, using that same address.

Return a JSON object conforming exactly to this schema:

é   )ÚindentuE   

Return only the JSON object â€” no prose, no markdown code fences.
c                  ó.   • \ rS rSr        SS jrSrg)Ú
CellReaderé^   c              ƒ  ó   #   • g 7f©Nr   )ÚselfÚtable_imageÚaddressed_gridÚ	questionss       r(   Ú
read_cellsÚCellReader.read_cells`   s   é € àùs   ‚r   N©r;   Úbytesr<   r   r=   úList[CellQuestion]Úreturnr.   )r    r!   r"   r#   r>   r&   r   r'   r(   r6   r6   ^   s'   † ðØ ðØ25ðØBTðà	÷r'   r6   c                óà   • / nU  HV  nSUR                   < 3nUUR                  b  SUR                  < 3OS-  nUR                  SUR                   SU 35        MX     SR	                  U5      $ )z@The cells to read, one per line, with the readings already made.z
scan read z, parse read z, the parse read no cell herez- z: Ú
)r   r   Úappendr   Újoin)r=   ÚlinesÚqÚseens       r(   Úquestion_blockrK   e   sv   € à€EÛˆØ˜AŸK™K™?Ð+ˆØØ01·±Ñ0Hˆm˜AŸL™LÑ+Ñ,ÐNmñ	
ˆð 	�‰�r˜!Ÿ)™)˜ B t fÐ-Ö.ñ ð �9‰9�UÓÐr'   c                  óh   • \ rS rSrSrSrSSS\4         S	S jjrS
S jr        SS jrSr	g)ÚPydanticAICellReaderéq   zµCellReader backed by pydantic-ai with an Anthropic model.

Auth resolution mirrors the other agents: `ANTHROPIC_AUTH_TOKEN` (OAuth
subscription) preferred over `ANTHROPIC_API_KEY`.
g        Nc                óþ  • SSK Jn  SSKJn  SSKJn  SSKJn  [        5       R                  n	U=(       d    U	R                  =(       d    [        nUb  [        U5      (       d  S nU=(       d    U	R                  n
U=(       d    U	R                  nU
(       a  SSKJn  U" X5      nOU(       a  U" US9nU" XS9nO[#        S	5      eXl
        X@l        Uc  S OU" US
9nU" U[&        [(        US9U l        [-        SS9U l        g )Nr   )ÚAgent)ÚAnthropicModel)ÚAnthropicProvider)ÚModelSettings)Úmake_oauth_anthropic_model)Úapi_key)ÚproviderztPydanticAICellReader: neither ANTHROPIC_AUTH_TOKEN nor ANTHROPIC_API_KEY is set. Provide one via env or constructor.)Útemperature)Úoutput_typeÚsystem_promptÚmodel_settingszquber-cell-reader)Úrun_name)Úpydantic_airP   Úpydantic_ai.models.anthropicrQ   Úpydantic_ai.providers.anthropicrR   Úpydantic_ai.settingsrS   r   ÚllmÚmodelr   r   Úanthropic_auth_tokenÚanthropic_api_keyÚquber.agents._oauth_gaterT   ÚRuntimeErrorrW   r.   ÚCELL_READER_PROMPTÚagentr   Útracer)r:   ra   Ú
auth_tokenrU   rW   rP   rQ   rR   rS   Úllm_settingsÚresolved_authÚresolved_keyrT   Ú
anth_modelrV   rZ   s                   r(   Ú__init__ÚPydanticAICellReader.__init__|   sé   € õ 	&Ý?ÝEÝ6ä#“~×)Ñ)ˆØ×@˜×+Ñ+×@Ô/@ˆØÑ"Ô+HÈ×+OÑ+OØˆKØ"×G l×&GÑ&GˆØ×@ ,×"@Ñ"@ˆæÝKá3°EÓI‰JÞÙ(°Ñ>ˆHÙ'¨ÑA‰JäðPóð ð
 Œ
Ø&ÔØ!,Ñ!4™¹-ÐT_Ñ:`ˆÙØÜ"Ü,Ø)ñ	
ˆŒ
ô &Ð/BÑCˆ�r'   c                óL   • SS[         S.SSUS.S[        U5      S.SSS./S./0$ )	NÚmessagesÚsystem©ÚroleÚcontentÚuserÚtext)Útyperw   Úimagez[table crop attached])rf   rK   )r:   r<   r=   s      r(   Útrace_inputsÚ!PydanticAICellReader.trace_inputs©   sH   € àØ!Ô.@ÑAà"à!'°Ñ@Ø!'´À	Ó1JÑKØ!(Ð2IÑJð ñð
ð
ð 	
r'   c              ƒ  óˆ  #   • SSK Jn  U" USS9n[        U5      nU R                  X#5      n U R                  R                  SXpR                  S9 IS h  v•N nU R                  R                  X&U/5      I S h  v•N n	U	R                  n
SU
R                  5       S./[        U
R                  5      [        U	R                  5      S	.Ul        S S S 5      IS h  v•N   U
$  NŠ Ng N
! , IS h  v•N  (       d  f       W
$ = f! [          a4  n["        R$                  " S
[        U5      U5        ['        / S9s S nA$ S nAff = f7f)Nr   )ÚBinaryContentz	image/png)ÚdataÚ
media_typeÚcell_reader)ra   Ú	assistantrs   )rq   Ú
cells_readÚusage_metadatazPcell_reader: LLM call failed; {} disputed cell(s) keep the scan's reading exc={}©r1   )r\   r}   rK   rz   rh   Úllm_runra   rg   ÚrunÚoutputÚmodel_dump_jsonÚlenr1   r   ÚusageÚoutputsÚ	Exceptionr   Úerrorr.   )r:   r;   r<   r=   r}   ry   ÚaskedÚinputsr†   Úresultr‡   Úexcs               r(   r>   ÚPydanticAICellReader.read_cells¸   s  é € õ 	.á ;¸;ÑGˆÜ˜yÓ)ˆØ×"Ñ" >Ó=ˆð	(Ø—{‘{×*Ñ*¨=¸&Ï
É
Ð*×SÑSÐWZØ#Ÿz™zŸ~™~¨~ÀeÐ.LÓM×M�ØŸ™�à*5À&×BXÑBXÓBZÑ![Ð \Ü"% f§l¡lÓ"3Ü&9¸&¿,¹,Ó&Gñ�”÷ T×Sð ˆMñ TÙM÷ T×S×Sð ˆMûÜó 	(Ü�LŠLØbÜ�I“Øôô
  BÑ'Õ'ûð	(üs›   ‚*E­(D ÁC ÁD Á!C&Á:C"Á;AC&ÃD ÃC$ÃD ÃEÃ D Ã"C&Ã$D Ã&C>Ã,C/Ã-C>Ã9D Ã=EÃ>D Ä
D?Ä)D:Ä4D?Ä5EÄ:D?Ä?E)rg   ra   rW   rh   )
ra   r   ri   r   rU   r   rW   zOptional[float]rC   ÚNone)r<   r   r=   rB   rC   zDict[str, Any]r@   )
r    r!   r"   r#   r$   ÚDEFAULT_TEMPERATURErn   rz   r>   r&   r   r'   r(   rM   rM   q   sƒ   † ñð Ðð  $Ø$(Ø!%Ø':ð+Dàð+Dð "ð+Dð ð	+Dð
 %ð+Dð 
õ+DôZ
ð(Ø ð(Ø25ð(ØBTð(à	÷(r'   rM   c                  ó@   • \ rS rSrSrSSS jjr        S	S jrSrg)
ÚMockCellReaderéÓ   z,Returns canned values by address. For tests.Nc                ó2   • U=(       d    0 U l         / U l        g r9   )ÚvaluesÚcalls)r:   r™   s     r(   rn   ÚMockCellReader.__init__Ö   s   € Ø—l ˆŒØ/1ˆ�
r'   c           
   ƒ  ó   #   • X4nU R                   R                  [        U5      5        [        U Vs/ s HJ  nUR                  U R
                  ;   d  M  [        UR                  U R
                  UR                     S9PML     snS9$ s  snf 7f)N)r   r,   r„   )rš   rF   r2   r.   r   r™   r*   )r:   r;   r<   r=   Ú_rI   s         r(   r>   ÚMockCellReader.read_cellsÚ   s   é € ð Ð'ˆØ�
‰
×Ñœ$˜y›/Ô*Üñ #óâ"�AØ—9‘9 §¡Ñ+ó K”	 !§)¡)°4·;±;¸q¿y¹yÑ3IÔJÙ"ññ
ð 	
ùòùs   ‚1B³B	Á/B	Â
B)rš   r™   r9   )r™   zOptional[Dict[str, str]]rC   r“   r@   )r    r!   r"   r#   r$   rn   r>   r&   r   r'   r(   r–   r–   Ó   s/   † Ù6ö2ð
Ø ð
Ø25ð
ØBTð
à	÷
r'   r–   )ÚapiÚmockÚoffc                ó¾   • U =(       d    [        5       R                  R                  nUS:X  a
  [        5       $ US:X  a
  [	        5       $ US:X  a  g[        SU< S35      e)zEThe cell reader for this run, or None when the check is switched off.rŸ   r    r¡   Nz#Unknown QUBER_CELL_READER_BACKEND: z. Expected api|mock|off.)r   r`   Úcell_reader_backendrM   r–   Ú
ValueError)ÚbackendÚselecteds     r(   Úget_cell_readerr§   ë   s]   € à×@œ,›.×,Ñ,×@Ñ@€HØ�5ÓÜ#Ó%Ð%Ø�6ÓÜÓÐØ�5ÓØÜ
Ð:¸8¹,ÐF^Ð_Ó
`Ð`r'   c                ó4   • [        U 5      R                  5       $ )z@The bytes of a rendered table crop, for a caller holding a file.)r   Ú
read_bytes)Úpaths    r(   Úread_table_imager«   ÷   s   € ä�‹:× Ñ Ó"Ð"r'   )r=   rB   rC   r   r9   )r¥   zOptional[CellReaderBackend]rC   zOptional[CellReader])rª   r   rC   rA   )(r$   Ú
__future__r   ÚjsonÚpathlibr   Útypingr   r   r   r   r	   r
   r   Úlogurur   Úpydanticr   r   Úquber.agents.factoryr   Úquber.agents.langsmith_tracerr   r   Úquber.settingsr   r   r   r*   r.   ÚdumpsÚmodel_json_schemarf   r6   rK   rM   r–   ÚCellReaderBackendr§   r«   r   r'   r(   Ú<module>r¸      sÔ   ðñõ6 #ã Ý ß R× RÑ Rå ß %å >ß Nß :ô�9ô ôZ�	ô Zô
j�ô jðð6 ‡‚ˆJ×(Ñ(Ó*°1Ñ5Ð 6ð 7ð7Ð ðB ô�ó ó ðô	÷_(ñ _(÷D
ñ 
ð* Ð0Ñ1Ð ö	aõ#r'   