ó
    5ûojñ  ã                  óð   • S 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r\
 " S S\5      5       r " S S5      r " S S5      rSSS jjrg)uM  
CaptureAdvisor â€” recommends a Camelot retry adjustment for a flagged capture drop.

Camelot occasionally drops printed values during cell assignment even though
they sit inside the table region and its text extraction captured them. The
measured example: a totals row typeset on a raised baseline splits into two
row bands at the default grouping tolerance, and the numbers' vertical center
lands exactly on the band boundary, failing the strict containment test on
both sides â€” the row's label and dollar signs survive, its numbers vanish.

The drop is detected deterministically (numeric tokens in the region's text
layer that appear in no grid cell) and the retry is accepted deterministically
(it must recover the missing tokens and lose none). This agent sits between
those two checks: given the cropped table image, the extracted grid, and the
dropped tokens with their printed lines, it diagnoses the failure and
recommends ONE bounded retry adjustment. The agent only proposes; the
acceptance gate holds authority, so a wrong recommendation costs one extra
Camelot pass and nothing else.
é    )Úannotations)ÚAnyÚDictÚLiteralÚOptionalÚProtocolÚSequenceÚ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S	S
9rS\S'   \" SSSSS9r	S\S'   \" SSS9r
S\S'   Srg)ÚRetryAdviceé!   zCOne bounded Camelot retry adjustment, with the diagnosis behind it.z}One or two sentences: WHY were these tokens dropped from the grid, grounded in what the image and the provided evidence show.)ÚdescriptionÚstrÚ	diagnosisé   é   zÑVertical grouping tolerance in points for the retry. The failed pass used 2. Raise it when one printed row was split into two bands (e.g. raised or offset baselines); keep 2 if row grouping is not the problem.)ÚgeÚler   ÚintÚrow_tolr   iöÿÿÿzxColumn grouping tolerance for the retry. The failed pass used 0. Change only if the drop is a column-assignment problem.)Údefaultr   r   r   Ú
column_tolÚstreamz]Parser for the retry. Use lattice only if the table has ruled cell borders drawn on the page.)r   r   zLiteral['stream', 'lattice']Úflavor© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r   Ú__annotations__r   r    r"   Ú__static_attributes__r#   ó    Ú:/home/mande/repo/quber/src/quber/agents/capture_advisor.pyr   r   !   sw   ‡ ÙMáðIñ€Iˆsó ñ ØØðVñ	€GˆSó ñ ØØØðFñ€J�ó ñ ,1Øàkñ,€FÐ(ö r+   r   uÉ  You diagnose a table-extraction capture failure and recommend ONE retry
adjustment.

A region-constrained Camelot pass extracted the grid below, but the listed
numeric tokens â€” visible on the page and present in the PDF text layer inside
the table region â€” did NOT land in any grid cell. You get:
1. The cropped table image (what the page really shows).
2. The extracted grid (markdown).
3. The dropped tokens, each with the full printed line it sits on.
4. The knobs the failed pass used: flavor=stream, row_tol=2, column_tol=0.

Recommend the single adjustment most likely to capture the dropped tokens
without corrupting the rest of the grid. Ground your diagnosis in the
evidence; do not guess beyond it.
c                  ó2   • \ rS rSr          SS jrSrg)ÚCaptureAdvisoréV   c              ƒ  ó   #   • g 7f©Nr#   )ÚselfÚcrop_pngÚgrid_markdownÚdropped_linesÚpages        r,   Ú	recommendÚCaptureAdvisor.recommendX   s   é € à #ùs   ‚r#   N©
r3   Úbytesr4   r   r5   zSequence[str]r6   r   ÚreturnúOptional[RetryAdvice])r$   r%   r&   r'   r7   r*   r#   r+   r,   r.   r.   V   s/   † ð$Øð$Ø.1ð$ØBOð$ØWZð$à	÷$r+   r.   c                  óf   • \ rS rSrSrSr   S	       S
S jjrSS jr          SS jrSr	g)ÚPydanticAICaptureAdvisoré]   u–  CaptureAdvisor backed by pydantic-ai with an Anthropic vision model.

Mirrors `PydanticAIGridLocator`: same auth resolution (`ANTHROPIC_AUTH_TOKEN`
preferred over `ANTHROPIC_API_KEY`), greedy decoding so the same failure
yields the same recommendation run to run. A failed call returns None â€”
the caller keeps the original grid with its warned gap; a capture repair
must never take a table down with it.
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=(       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
        U" U["        [$        ['        U5      (       a  U" U R(                  S
9OS S9U l        [-        SS9U l        g )Nr   )ÚAgent)ÚAnthropicModel)ÚAnthropicProvider)ÚModelSettings)Úmake_oauth_anthropic_model)Úapi_key)ÚproviderzxPydanticAICaptureAdvisor: neither ANTHROPIC_AUTH_TOKEN nor ANTHROPIC_API_KEY is set. Provide one via env or constructor.)Útemperature)Úoutput_typeÚsystem_promptÚmodel_settingszquber-capture-advisor)Úrun_name)Úpydantic_airA   Úpydantic_ai.models.anthropicrB   Úpydantic_ai.providers.anthropicrC   Úpydantic_ai.settingsrD   r   ÚllmÚmodelr   Úanthropic_auth_tokenÚanthropic_api_keyÚquber.agents._oauth_gaterE   ÚRuntimeErrorr   ÚADVISE_PROMPTr   ÚDEFAULT_TEMPERATUREÚagentr   Útracer)r2   rR   Ú
auth_tokenrF   rA   rB   rC   rD   Úllm_settingsÚresolved_authÚresolved_keyrE   Ú
anth_modelrG   s                 r,   Ú__init__Ú!PydanticAICaptureAdvisor.__init__i   sÖ   € õ 	&Ý?ÝEÝ6ä#“~×)Ñ)ˆØ×@˜×+Ñ+×@Ô/@ˆØ"×G l×&GÑ&GˆØ×@ ,×"@Ñ"@ˆæÝKá3°EÓI‰JÞÙ(°Ñ>ˆHÙ'¨ÑA‰JäðPóð ð
 Œ
ÙØÜ#Ü'ä,¨U×3Ñ3ñ )°T×5MÑ5MÒNàñ
ˆŒ
ô &Ð/FÑGˆ�r+   c                ó*   • SS[         S.SSUS./S./0$ )NÚmessagesÚsystem©ÚroleÚcontentÚuserÚtext)Útyperi   )rW   )r2   Ú	user_texts     r,   Útrace_inputsÚ%PydanticAICaptureAdvisor.trace_inputs‘   s,   € àØ!¬mÑ<Ø°fÀiÑ-PÐ,QÑRðð
ð 	
r+   c           	   ƒ  óT  #   • SSK Jn  SU S3SR                  U5      -   S-   nU R                  U5      n U R                  R                  SXpR                  S9 IS h  v•N nU R                  R                  Xe" US	S
9/5      I S h  v•N n	U	R                  n
SU
R                  5       S./[        U	R                  5      S.Ul        S S S 5      IS h  v•N   U
$  Nz NS N
! , IS h  v•N  (       d  f       W
$ = f! [         a!  n[        R                   " SXK5         S nAg S nAff = f7f)Nr   )ÚBinaryContentz=== Extracted grid ===
z

=== Dropped tokens ===
Ú
z4

knobs used: flavor=stream, row_tol=2, column_tol=0Úcapture_advise)rR   z	image/png)ÚdataÚ
media_typeÚ	assistantre   )rc   Úusage_metadataz?page {}: capture advisor call failed; keeping original grid: {})rM   ro   Újoinrl   rZ   Úllm_runrR   rY   ÚrunÚoutputÚmodel_dump_jsonr   ÚusageÚoutputsÚ	Exceptionr   Úwarning)r2   r3   r4   r5   r6   ro   rk   Úinputsrx   ÚresultÚadviceÚexcs               r,   r7   Ú"PydanticAICaptureAdvisor.recommend™   s$  é € õ 	.ð ' } oð 6'ð 'Ø)-¯©°=Ó)AñBðEAñAð 	ð
 ×"Ñ" 9Ó-ˆð	Ø—{‘{×*Ñ*Ð+;¸VÏ:É:Ð*×VÑVÐZ]Ø#Ÿz™zŸ~™~Ø °8ÈÑ TÐUó ÷ �ð '-§m¡m�à*5À&×BXÑBXÓBZÑ![Ð \Ü&9¸&¿,¹,Ó&Gñ�”÷ W×Vð ˆMñ Wñ÷ W×V×Vð ˆMûÜó 	Ü�NŠNÐ\Ð^bÔhÜûð	üs”   ‚3D(¶(C: ÁCÁC: Á"%CÂCÂ?CÃC: ÃCÃC: ÃD(ÃC: ÃCÃC: ÃC7Ã%C(Ã&C7Ã2C: Ã6D(Ã7C: Ã:
D%ÄD ÄD(Ä D%Ä%D()rY   rR   rZ   )NNN)rR   úOptional[str]r[   r„   rF   r„   r;   ÚNone)rk   r   r;   zDict[str, Any]r9   )
r$   r%   r&   r'   r(   rX   r`   rl   r7   r*   r#   r+   r,   r>   r>   ]   s}   † ñð Ðð  $Ø$(Ø!%ð	&Hàð&Hð "ð&Hð ð	&Hð
 
õ&HôP
ðØðØ.1ðØBOðØWZðà	÷r+   r>   c                  óD   • \ rS rSrSrSSS jjr          S	S jrSrg)
ÚMockCaptureAdvisoré´   z(Returns a canned RetryAdvice. For tests.Nc                ó   • Xl         / U l        g r1   ©r�   Úcalls)r2   r�   s     r,   r`   ÚMockCaptureAdvisor.__init__·   s   € ØŒØ79ˆ�
r+   c              ƒ  ót   #   • UnU R                   R                  U[        U5      U45        U R                  $ 7fr1   )r‹   ÚappendÚlistr�   )r2   r3   r4   r5   r6   Ú_s         r,   r7   ÚMockCaptureAdvisor.recommend»   s4   é € ð ˆØ�
‰
×Ñ˜=¬$¨}Ó*=¸tÐDÔEØ�{‰{Ðùs   ‚68rŠ   r1   )r�   r<   r;   r…   r9   )r$   r%   r&   r'   r(   r`   r7   r*   r#   r+   r,   r‡   r‡   ´   s7   † Ù2ö:ðØðØ.1ðØBOðØWZðà	÷r+   r‡   Nc                ó¾   • 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)z;Resolve the capture advisor, or None when disabled (`off`).ÚapiÚmockÚoffNz'Unknown QUBER_CAPTURE_ADVISOR_BACKEND: z. Expected api|mock|off.)r   rQ   Úcapture_advisor_backendr>   r‡   Ú
ValueError)ÚbackendÚselecteds     r,   Úget_capture_advisorrš   Ã   s]   € à×Dœ,›.×,Ñ,×DÑD€HØ�5ÓÜ'Ó)Ð)Ø�6ÓÜ!Ó#Ð#Ø�5ÓØÜ
Ð>¸x¹lÐJbÐcÓ
dÐdr+   r1   )r˜   r„   r;   zOptional[CaptureAdvisor])r(   Ú
__future__r   Útypingr   r   r   r   r   r	   r
   Úlogurur   Úpydanticr   r   Úquber.agents.factoryr   Úquber.agents.langsmith_tracerr   r   Úquber.settingsr   r   r   rW   r.   r>   r‡   rš   r#   r+   r,   Ú<module>r¢      ss   ðñõ( #ç V× VÑ Vå ß %å >ß Nß :ô �)ô  ðF€ð$ ô$�Xó $ó ð$÷Tñ T÷nñ ÷	er+   