ó
    5ûoj}2  ã                  óº  • 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  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JrJrJr  SS
KJrJr   " S S\5      r " S S\5      rS\R@                  " \RC                  5       SS9 S3r"S\R@                  " \RC                  5       SS9 S3r#SS jr$SS jr% " S S5      r& " S S5      r'\
S   r(SS S jjr)SS!S jjr*g)"u	  The two agents behind the figure-value reconciliation pass.

One page produces two independent readings of the values its figures print.
The scan's prose descriptions already state chart titles and labeled values;
a text-only agent lifts them into label/series/value entries. A vision agent
reads the page image alongside the parse's positioned fragments and reports
each printed value with the ids of the fragments whose text contains it, so
the deterministic tie in ``quber.core.figures.values`` can ground agreement
in a box on the page.

Both agents draw the same line: a value is something the figure states â€” a
bar label, a donut segment value or percentage, a donut center total, a
line-point label. Axis scale labels and gridline numbers are the figure's
furniture and are never values. And neither agent invents: the parser
outputs nothing the prose does not state, the reader nothing the image does
not show, and a printed value no fragment contains is reported with empty
fragment ids rather than a fabricated citation.
é    )ÚannotationsN)ÚPath)ÚAnyÚDictÚListÚLiteralÚOptionalÚSequence)Ú	BaseModelÚField)Úsupports_sampling_temperature)ÚLangSmithTracerÚusage_metadata_from)ÚLocalValueReaderÚPageFragmentÚParsedValueÚ	ReadValueÚScanValueParser)ÚDEFAULT_LLM_MODELÚget_settingsc                  ó.   • \ rS rSr% \" \SS9rS\S'   Srg)ÚParsedValuesé"   z3Every labeled value the prose states; empty if none©Údefault_factoryÚdescriptionúList[ParsedValue]Úvalues© N©	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__r   Úlistr   Ú__annotations__Ú__static_attributes__r   ó    Ú8/home/mande/repo/quber/src/quber/agents/figure_values.pyr   r   "   s   ‡ Ù %ØÐ*_ñ!€FÐö r(   r   c                  ó.   • \ rS rSr% \" \SS9rS\S'   Srg)Ú
ReadValuesé(   z>Every value printed inside a figure on the page; empty if noner   úList[ReadValue]r   r   Nr    r   r(   r)   r+   r+   (   s   ‡ Ù#ØÐ*jñ€FˆOö r(   r+   ue  You are given a page scan's prose descriptions of the figures on one page of
a financial document. The descriptions state chart titles and the labeled
values each chart prints.

Extract EVERY labeled numeric value the prose states: bar labels, donut
segment values and their percentages, donut center totals, line-point
labels. Report each as a label/series/value entry. A donut segment stated
with both a value and a percentage is two entries, one per stated form.

The value is copied EXACTLY as the prose states it â€” keep the printed form,
including any '$', '%', commas, and parentheses.

Axis scale labels and gridline numbers are furniture, not values. When the
prose mentions an axis range or the numbers running along an axis, output
nothing for them.

Output nothing that is not stated in the prose.

Return a JSON object conforming exactly to this schema:

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

Return only the JSON object â€” no prose, no markdown code fences.
u´  You are shown one page of a financial document as an image, plus a listing
of the positioned text fragments a parser extracted from that page â€” each
with an id, its text, and its box in the page's normalized frame.

Read EVERY numeric value printed inside a chart or figure on the page image:
bar labels, donut segment values and percentages, donut center totals,
line-point labels. For each, report:

- chart_title: the title of the chart it is printed in
- label: what the value is labeled as on the chart
- series: the series it belongs to, when the chart plots more than one
- value: EXACTLY as printed, including any '$', '%', commas, and parentheses
- fragment_ids: the id(s) of the fragment(s) whose text contains the value,
  plus the fragment carrying its label when the label is printed separately

Cite only fragments whose text actually contains the value or its label.
When a printed value has no fragment containing it, report the value with
EMPTY fragment_ids â€” never cite a fragment that does not print it.

Axis scale labels and gridline numbers are furniture â€” skip them.

Report nothing that is not visible in the image.

Return a JSON object conforming exactly to this schema:

c                óD   • SR                  S [        U 5       5       5      $ )zHThe scan's descriptions, numbered the way one page presents its figures.ú

c              3  ó6   #   • U  H  u  pS U SU 3v •  M     g7f)zFIGURE ú:
Nr   )Ú.0ÚiÚtexts      r)   Ú	<genexpr>Ú$figure_text_block.<locals>.<genexpr>k   s!   é € ÐUÒ=T±'°!˜   3 t fÕ-Ò=Tùs   ‚)ÚjoinÚ	enumerate)Úfigure_textss    r)   Úfigure_text_blockr<   i   s   € à�;‰;ÑU¼YÀ|Ô=TÓUÓUÐUr(   c                óà   • / nU  HV  nUR                   nUR                  UR                   SUR                   SUS   S SUS   S SUS   S SUS   S S	35        MX     S
R	                  U5      $ )zHThe page's fragments, one per line: id, text, box rounded to 3 decimals.z: z box=(Úleftz.3fz, ÚtopÚrightÚbottomÚ)Ú
)ÚboxÚappendÚidr6   r9   )Ú	fragmentsÚlinesÚfragÚbs       r)   Úfragment_listingrK   n   sŠ   € à€EÛˆØ�H‰HˆØ�‰Ø�w‰wˆi�r˜$Ÿ)™)˜ð %Ø�f‘I˜c�? " Q u¡X¨c N°"°Q°w±ZÀÐ4DÀBÀqÈÁ{ÐSVÐFWÐWXðZö	
ñ ð �9‰9�UÓÐr(   c                  óX   • \ 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)ÚPydanticAIScanValueParseréz   zºScanValueParser backed by pydantic-ai with an Anthropic model.

Auth resolution mirrors the other agents: `ANTHROPIC_AUTH_TOKEN` (OAuth
subscription) preferred over `ANTHROPIC_API_KEY`.
ç        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©ÚproviderzyPydanticAIScanValueParser: neither ANTHROPIC_AUTH_TOKEN nor ANTHROPIC_API_KEY is set. Provide one via env or constructor.©Útemperature©Úoutput_typeÚsystem_promptÚmodel_settingszquber-figure-scan-values©Úrun_name)Úpydantic_airR   Úpydantic_ai.models.anthropicrT   Úpydantic_ai.providers.anthropicrV   Úpydantic_ai.settingsrX   r   ÚllmÚmodelr   r   Úanthropic_auth_tokenÚanthropic_api_keyÚquber.agents._oauth_gaterZ   ÚRuntimeErrorr`   r   ÚSCAN_VALUE_PROMPTÚagentr   Útracer©Úselfrl   Ú
auth_tokenr\   r`   rR   rT   rV   rX   Úllm_settingsÚresolved_authÚresolved_keyrZ   Ú
anth_modelr^   rd   s                   r)   Ú__init__Ú"PydanticAIScanValueParser.__init__…   sé   € õ 	&Ý?ÝEÝ6ä#“~×)Ñ)ˆØ×@˜×+Ñ+×@Ô/@ˆØÑ"Ô+HÈ×+OÑ+OØˆKØ"×G l×&GÑ&GˆØ×@ ,×"@Ñ"@ˆæÝKá3°EÓI‰JÞÙ(°Ñ>ˆHÙ'¨ÑA‰JäðPóð ð
 Œ
Ø&ÔØ!,Ñ!4™¹-ÐT_Ñ:`ˆÙØÜ$Ü+Ø)ñ	
ˆŒ
ô &Ð/IÑJˆ�r(   c           	     ó@   • SS[         S.SSU S[        U5       3S./0$ )NÚmessagesÚsystem©ÚroleÚcontentÚuserúpage r1   )rq   r<   )ru   r;   Úpages      r)   Útrace_inputsÚ&PydanticAIScanValueParser.trace_inputs²   s<   € àØ!Ô.?Ñ@à"Ø!& t f¨DÔ1BÀ<Ó1PÐ0QÐRñðð
ð 	
r(   c              ƒ  ó  #   • SU S[        U5       3nU R                  R                  SU R                  X5      U R                  S9 IS h  v•N nU R
                  R                  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   [        WR                  5      $  N› Nz N! , IS h  v•N  (       d  f       N2= f7f)Nz!Figure descriptions read on page z:

Úfigure_scan_values©rl   Ú	assistantr€   ©r~   r   Úusage_metadata)r<   rs   Úllm_runr†   rl   rr   ÚrunÚoutputÚmodel_dump_jsonÚlenr   r   ÚusageÚoutputsr%   )ru   r;   r…   Ú	describedr�   Úresultr�   s          r)   ÚparseÚPydanticAIScanValueParser.parse½   sà   é € Ø7¸°v¸UÔCTÐUaÓCbÐBcÐdˆ	Ø—;‘;×&Ñ&Ø  $×"3Ñ"3°LÓ"GÈtÏzÉzð '÷ 
ñ 
àØŸ:™:Ÿ>™>¨)Ó4×4ˆFØ—]‘]ˆFà&1¸f×>TÑ>TÓ>VÑWÐXÜ˜fŸm™mÓ,Ü"5°f·l±lÓ"CñˆCŒK÷
÷ 
ô �F—M‘MÓ"Ð"ñ
ñ 5÷
÷ 
÷ 
ð 
üs[   ‚A
DÁC(ÁDÁC.Á/C*Á0AC.ÃDÃC,ÃDÃ*C.Ã,DÃ.DÃ4C7Ã5DÄD©rr   rl   r`   rs   ©
rl   úOptional[str]rv   r›   r\   r›   r`   zOptional[float]ÚreturnÚNone)r;   úSequence[str]r…   Úintrœ   úDict[str, Any])r;   rž   r…   rŸ   rœ   r   )
r!   r"   r#   r$   Ú__doc__ÚDEFAULT_TEMPERATUREr{   r†   r—   r'   r   r(   r)   rM   rM   z   sc   † ñð Ðð  $Ø$(Ø!%Ø':ð+Kàð+Kð "ð+Kð ð	+Kð
 %ð+Kð 
õ+KôZ	
÷#r(   rM   c                  óX   • \ 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)ÚPydanticAIFigureValueReaderéÌ   zÂLocalValueReader backed by pydantic-ai with an Anthropic vision model.

Auth resolution mirrors the other agents: `ANTHROPIC_AUTH_TOKEN` (OAuth
subscription) preferred over `ANTHROPIC_API_KEY`.
rO   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    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   rQ   rS   rU   rW   rY   r[   r]   z{PydanticAIFigureValueReader: neither ANTHROPIC_AUTH_TOKEN nor ANTHROPIC_API_KEY is set. Provide one via env or constructor.r_   ra   zquber-figure-value-readerre   )rg   rR   rh   rT   ri   rV   rj   rX   r   rk   Úfigure_values_modelrl   r   r   rm   rn   ro   rZ   rp   r`   r+   ÚFIGURE_VALUE_READER_PROMPTrr   r   rs   rt   s                   r)   r{   Ú$PydanticAIFigureValueReader.__init__×   sô   € õ 	&Ý?ÝEÝ6ä#“~×)Ñ)ˆØ×d˜×9Ñ9×d¸\×=OÑ=O×dÔSdˆØÑ"Ô+HÈ×+OÑ+OØˆKØ"×G l×&GÑ&GˆØ×@ ,×"@Ñ"@ˆæÝKá3°EÓI‰JÞÙ(°Ñ>ˆHÙ'¨ÑA‰JäðPóð ð
 Œ
Ø&ÔØ!,Ñ!4™¹-ÐT_Ñ:`ˆÙØÜ"Ü4Ø)ñ	
ˆŒ
ô &Ð/JÑKˆ�r(   c           
     óP   • SS[         S.SSSU S[        U5       3S.S	S
S./S./0$ )Nr~   r   r€   rƒ   r6   r„   rC   )Útyper6   Úimagez[page image attached])r¨   rK   )ru   rG   r…   s      r)   r†   Ú(PydanticAIFigureValueReader.trace_inputs  sP   € àØ!Ô.HÑIà"à!'°5¸¸¸bÔAQÐR[ÓA\Ð@]Ð1^Ñ_Ø!(Ð2IÑJð ñð	ð
ð 	
r(   c              ƒ  óL  #   • SSK Jn  U" UR                  5       SS9nSU S[        U5       3nU R                  R                  SU R                  X#5      U R                  S9 IS h  v•N nU R                  R                  Xe/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   [#        W	R                  5      $  Nœ Nz N! , IS h  v•N  (       d  f       N2= f7f)Nr   )ÚBinaryContentz	image/png)ÚdataÚ
media_typezFragments extracted from page r3   Úfigure_value_readrŠ   r‹   r€   rŒ   )rg   r¯   Ú
read_bytesrK   rs   rŽ   r†   rl   rr   r�   r�   r‘   r’   r   r   r“   r”   r%   )
ru   Ú
image_pathrG   r…   r¯   r¬   Úlistedr�   r–   r�   s
             r)   ÚreadÚ PydanticAIFigureValueReader.read  sù   é € Ý-á :×#8Ñ#8Ó#:À{ÑSˆØ1°$°°sÔ;KÈIÓ;VÐ:WÐXˆØ—;‘;×&Ñ&Ø ×!2Ñ!2°9Ó!CÈ4Ï:É:ð '÷ 
ñ 
àØŸ:™:Ÿ>™>¨6¨/Ó:×:ˆFØ—]‘]ˆFà&1¸f×>TÑ>TÓ>VÑWÐXÜ˜fŸm™mÓ,Ü"5°f·l±lÓ"CñˆCŒK÷
÷ 
ô �F—M‘MÓ"Ð"ñ
ñ ;÷
÷ 
÷ 
ð 
üs[   ‚A%D$Á'DÁ(D$Á+ D
ÂDÂAD
ÃD$Ã*DÃ+D$ÄD
ÄD$Ä
D!ÄDÄD!ÄD$r™   rš   )rG   úSequence[PageFragment]r…   rŸ   rœ   r    )r´   r   rG   r¸   r…   rŸ   rœ   r-   )
r!   r"   r#   r$   r¡   r¢   r{   r†   r¶   r'   r   r(   r)   r¤   r¤   Ì   sc   † ñð Ðð  $Ø$(Ø!%Ø':ð+Làð+Lð "ð+Lð ð	+Lð
 %ð+Lð 
õ+LôZ
÷#r(   r¤   )ÚapiÚoffc                óž   • U =(       d    [        5       R                  R                  nUS:X  a
  [        5       $ US:X  a  g[	        SU< S35      e)zJThe scan-value parser for this run, or None when the pass is switched off.r¹   rº   Nú%Unknown QUBER_FIGURE_VALUES_BACKEND: ú. Expected api|off.)r   rk   Úfigure_values_backendrM   Ú
ValueError©ÚbackendÚselecteds     r)   Úget_scan_value_parserrÃ   '  sL   € à×Bœ,›.×,Ñ,×BÑB€HØ�5ÓÜ(Ó*Ð*Ø�5ÓØÜ
Ð<¸X¹LÐH[Ð\Ó
]Ð]r(   c                óž   • U =(       d    [        5       R                  R                  nUS:X  a
  [        5       $ US:X  a  g[	        SU< S35      e)zRThe local figure-value reader for this run, or None when the pass is switched off.r¹   rº   Nr¼   r½   )r   rk   r¾   r¤   r¿   rÀ   s     r)   Úget_figure_value_readerrÅ   1  sL   € à×Bœ,›.×,Ñ,×BÑB€HØ�5ÓÜ*Ó,Ð,Ø�5ÓØÜ
Ð<¸X¹LÐH[Ð\Ó
]Ð]r(   )r;   rž   rœ   Ústr)rG   r¸   rœ   rÆ   )N)rÁ   úOptional[FigureValuesBackend]rœ   zOptional[ScanValueParser])rÁ   rÇ   rœ   zOptional[LocalValueReader])+r¡   Ú
__future__r   ÚjsonÚpathlibr   Útypingr   r   r   r   r	   r
   Úpydanticr   r   Úquber.agents.factoryr   Úquber.agents.langsmith_tracerr   r   Úquber.core.figures.valuesr   r   r   r   r   Úquber.settingsr   r   r   r+   ÚdumpsÚmodel_json_schemarq   r¨   r<   rK   rM   r¤   ÚFigureValuesBackendrÃ   rÅ   r   r(   r)   Ú<module>rÔ      sà   ðñõ& #ã Ý ß ?× ?ç %å >ß Nß mÕ mß :ô�9ô ô�ô ðð* ‡‚ˆL×*Ñ*Ó,°QÑ7Ð 8ð 9ð+Ð ð6"ð4 ‡‚ˆJ×(Ñ(Ó*°1Ñ5Ð 6ð 7ð5Ð ô@Vô
	÷O#ñ O#÷dU#ñ U#ðp ˜lÑ+Ð ö^÷^r(   