ó
    À‘´jýS  ã                  óÞ  • S r SSKJr  SSKrSSKJr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Jr  SSKJr  SSKJr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 S\5      r! " S S\5      r" " S S\5      r#S\RH                  " \#RK                  5       SS9 S3r&\ " S S\
5      5       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-g))uÍ  FigureCorrector Protocol â€” what a figure the scan has read leaves on the page.

Three things, from one look at the page image: which of the text around the figure
is its furniture, which footnote markers the figure's own labels carry, and the
note lines printed for each figure, as marker and text. The caller records the
markers and notes on the figure's picture.

Once the scan has read a figure, the fragments the parse lifted off the same
image are that figure read worse, and they are removed. Removing them by tree
position only reaches the ones the parse filed under the picture. It files
inconsistently: on one page of a quarterly deck it put twenty-two of a page's
twenty-six texts beneath the two pictures, and on another it left forty-six of
seventy-eight attached to the page body, where nothing looking at the picture's
children can see them. Those forty-six included forty axis tick labels.

Position on the page does not settle it either, and neither does the text. Both
were measured on three decks and both fail, in opposite directions.

Sweeping everything printed inside the figure's box deletes real content. On one
page the scan bounded two charts as a single figure spanning the width of the
page, and inside that box sat a four-line sentence about the portfolio's
sensitivity to rate changes that the scan did not transcribe.

Sweeping only what the scan's own description repeats deletes nothing useful. A
chart's axis runs 0.00 to 5.00 in half steps and the description never mentions
those numbers, because a gridline is a ruler marking rather than a fact. All
forty ticks would stay.

What separates the two is what the text is, which is visible on the page. A tick
label sits at the edge of the plot in an evenly spaced series. An annotation sits
over the plot and reads as language. So the page image goes to an agent with the
description and the candidate fragments, and it names the furniture.

It is told to keep whatever it is unsure of. Leaving a tick label in costs a
chunk that answers nothing; removing a sentence costs a statement the document no
longer makes anywhere. A failed call removes nothing at all.

The smaller model is not sufficient here. Asked the same question on the same
pages it removed the four-line sentence while its own stated reason called it an
annotation, and missed seven of the forty ticks. The stronger model returned all
forty and none of the sentence, identically on three runs.

The markers come from the same call because they are the same act of reading. A
chart's label prints its qualification as a raised digit â€” "Undepreciated Book
Equity Value(1,2)" â€” and the marker alone says only that a qualification exists,
not what it says. Read on its own, that chart states a figure the document
elsewhere excludes a noncontrolling interest from and calls non-GAAP. Which
markers a figure carries is what a table's correction agent reports for a table,
off the table image, for the same reason and against the same distinctions: a
raised digit is a marker, a parenthesized negative value is not, and a reference
naming a section of the document points somewhere a footnote lookup will never
find. A figure had nobody reporting it, and this agent is already looking at the
page the markers are printed on.
é    )ÚannotationsN)ÚAnyÚDictÚListÚLiteralÚOptionalÚProtocolÚSequenceÚruntime_checkable)Úlogger)Ú	BaseModelÚFieldÚfield_validator)Úsupports_sampling_temperature)ÚLangSmithTracerÚusage_metadata_from)ÚCOMPOUND_MARKER_REÚMARKER_GROUP_RE)ÚDEFAULT_LLM_MODELÚget_settingsc                  óF   • \ rS rSr% Sr\" SS9rS\S'   \" SS9rS\S	'   S
r	g)ÚFigureéF   zCOne figure the scan read on this page, numbered so markers name it.ú(Position in the list the agent was shown©ÚdescriptionÚintÚindexz*What the scanner read the figure as sayingÚstrr   © N)
Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r   Ú__annotations__r   Ú__static_attributes__r    ó    Ú</home/mande/repo/quber/src/quber/agents/figure_correction.pyr   r   F   s%   ‡ ÙMáÐ#MÑN€Eˆ3ÓNÙÐ)UÑV€K�ÖVr(   r   c                  óF   • \ rS rSr% Sr\" SS9rS\S'   \" SS9rS\S	'   S
r	g)ÚFragmentéM   zJOne candidate, numbered so the agent answers by index rather than by text.r   r   r   r   zWhat the fragment saysr   Útextr    N)
r!   r"   r#   r$   r%   r   r   r&   r-   r'   r    r(   r)   r+   r+   M   s%   ‡ ÙTáÐ#MÑN€Eˆ3ÓNÙÐ":Ñ;€Dˆ#Ö;r(   r+   c                  óB   • \ rS rSr% \" SS9rS\S'   \" SS9rS\S'   S	rg
)Ú	FurnitureéT   z6The index of a fragment that is the figure's furniturer   r   r   z#Why it is furniture, in a few wordsr   Úreasonr    N)	r!   r"   r#   r$   r   r   r&   r1   r'   r    r(   r)   r/   r/   T   s"   ‡ ÙÐ#[Ñ\€Eˆ3Ó\ÙÐ$IÑJ€FˆCÖJr(   r/   c                  óv   • \ 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SS9r
S\S'   Srg)ÚMarkeréY   z=One footnote reference marker printed on one figure's labels.z8The index of the figure carrying it, from the list shownr   r   Úfigureuí   ONE reference marker exactly as printed: '1', '(1)', a letter 'a', an asterisk '*', a dagger. A label printed with several markers at once â€” '(1,2)', '(b)(c)' â€” carries several: report one entry per marker, never the combined string.r   ÚmarkerÚ zFThe label the marker is printed on, copied as it appears on the figure)Údefaultr   ÚlabelÚfootnoteu½  What the marker points at, judged from the PAGE, not from the marker's wording. 'footnote': it points at a note printed for this figure â€” a note line below it or nearby that defines it, EVEN WHEN that line's own text sends the reader onward ('see Selected Definitions on page 40' is a printed note and the answer is that line). 'section': it is a cross-reference to a named part of the document (a numbered note in the financial statements, a schedule, an appendix) whose content lives elsewhere, not in a note line printed for this figure â€” and the label names that part, so the marker is written WITH its word ('Note 16', 'Schedule II'), never as a bare number. A bare marker is never 'section'.zLiteral['footnote', 'section']Úkindr    N)r!   r"   r#   r$   r%   r   r5   r&   r6   r9   r;   r'   r    r(   r)   r3   r3   Y   sa   ‡ ÙGáÐ$^Ñ_€FˆCÓ_Ùð#ñ€FˆCó ñ ØØ\ñ€Eˆ3ó ñ ,1Øð	Xñ,€DÐ
(ö r(   r3   c                  ó\   • \ rS rSr% Sr\" SS9rS\S'   \" SS9rS\S	'   \" S
S9r	S\S'   Sr
g)ÚNoteéz   zßOne note printed on the page for a figure: its own marker plus its text.

The marker is read off the image, where the note line prints it. The image's
formatting decides what is a marker; an unmarked general note has none.
z/The index of the figure the note is printed forr   r   r5   z The note's OWN marker exactly as printed at the start of its line: '1', '(1)', 'a', '*', a dagger. EMPTY for an unmarked general note that opens with no marker.r   r6   z+The note's text, without the leading markerr-   r    N)r!   r"   r#   r$   r%   r   r5   r&   r6   r-   r'   r    r(   r)   r=   r=   z   sA   ‡ ññ Ð$UÑV€FˆCÓVÙðñ€FˆCó ñ Ð"OÑP€Dˆ#ÖPr(   r=   c                  ó®   • \ rS rSr% \" \SS9rS\S'   \" \SS9rS\S'   \	" SS	S
9\
SS j5       5       r\	" SS	S
9\
SS j5       5       r\" \SS9rS\S'   Srg)ÚFigureCorrectionéŒ   z3Only the furniture; every fragment not listed stays)Údefault_factoryr   úList[Furniture]Ú	furniturezKEvery footnote reference marker printed on a figure's labels; empty if noneúList[Marker]ÚmarkersÚafter)Úmodec                ó¬   • [        5       nU Vs/ s H8  o3R                  U;   a  M  UR                  UR                  5      (       a  M6  UPM:     sn$ s  snf )uX  A fragment named twice is named once.

The agent sometimes returns the same index in two entries with different
reasons. Both name one text item, and the caller deletes what it is given,
so a repeat reaches the document model as the same element queued for
removal twice â€” which it rejects, failing the whole sweep. The first
reason is kept.
)Úsetr   Úadd)ÚclsÚvÚseenÚfs       r)   Úone_verdict_per_fragmentÚ)FigureCorrection.one_verdict_per_fragment•   s<   € ô ›ˆÙÓKš1�a§W¡W°¡_“¸¿¹ÀÇÁ×8I—™1ÑKÐKùÒKs   �A¦AÁAc                ó  ^• / nU Hz  mTR                   R                  5       n[        R                  " U5      (       a1  UR	                  U4S j[
        R                  " U5       5       5        Mi  UR                  T5        M|     U$ )uy  A stacked group reported as one marker becomes one marker per group.

The prompt asks for one entry per marker and compliance is not certain, so
a label printed '(b)(c)(d)' that comes back as a single string is split
here â€” the same normalization a table's markers get, against the same
pattern, which is strict enough that a parenthesized negative value can
never match it.
c              3  óF   >#   • U  H  nTR                  S U0S9v •  M     g7f)r6   )ÚupdateN)Ú
model_copy)Ú.0ÚgÚmarks     €r)   Ú	<genexpr>Ú:FigureCorrection.split_compound_markers.<locals>.<genexpr>²   s"   øé € ÐeÒJdÀQ˜4Ÿ?™?°8¸Q°-˜?Õ@ÒJdùs   ƒ!)r6   Ústripr   Ú	fullmatchÚextendr   ÚfindallÚappend)rL   rM   ÚoutÚsrX   s       @r)   Úsplit_compound_markersÚ'FigureCorrection.split_compound_markers£   sh   ø€ ð ˆÛˆDØ—‘×!Ñ!Ó#ˆAÜ!×+Ò+¨A×.Ñ.Ø—
‘
ÔeÌ/×JaÒJaÐbcÔJdÓeÖeà—
‘
˜4Ö ñ ð ˆ
r(   zDEvery note line printed on the page for a figure, as marker and textz
List[Note]Únotesr    N)rM   rC   ÚreturnrC   )rM   rE   re   rE   )r!   r"   r#   r$   r   ÚlistrD   r&   rF   r   ÚclassmethodrP   rb   rd   r'   r    r(   r)   r@   r@   Œ   s“   ‡ Ù!&ØÐ*_ñ"€Iˆó ñ "ØØañ€Gˆ\ó ñ
 �[ wÑ/Øó
Ló ó 0ð
Lñ �Y WÑ-Øóó ó .ðñ$ ØØZñ€Eˆ:ö r(   r@   u¢  You are shown one page of a financial document, a numbered list of the figures a
scanner read on that page with the description it wrote for each, and a numbered
list of text fragments a parser extracted from inside those figures' regions.

You have two jobs.

JOB 1 â€” NAME THE FURNITURE.

Decide which fragments are the figure's FURNITURE: text that exists only to mark
its scale or label its parts, and carries no fact on its own. Axis tick values,
gridline labels, the numbers running up a y-axis or along an x-axis, legend keys
and unit markers are furniture. They are already accounted for by the
description, which reports what the figure shows.

Everything else STAYS. A sentence, a callout, an annotation, a note, a heading, a
stated figure that is not a position on an axis â€” all of these say something and
must be kept even when they sit inside the figure.

Look at the image. A tick label sits at the edge of the plot in a regular series,
evenly spaced, ascending or descending. An annotation sits over or beside the
plot and reads as language. That difference is visible and it is what you are
judging.

Default to keeping. If you are not sure a fragment is furniture, leave it out of
your answer. Removing a real statement is far worse than leaving a tick label in.

When the fragment list is EMPTY there is nothing to judge: return an empty
furniture list and do job 2 only. Never name an index that was not shown to you.

JOB 2 â€” READ THE FOOTNOTE MARKERS.

Report every FOOTNOTE REFERENCE MARKER printed on a figure's labels â€” its title,
its axis names, its series names, its data labels â€” read off the IMAGE, because a
raised digit is often lost from extracted text. A marker is a superscript or
parenthetical number, letter or symbol pointing at a note: '1', '(1)', a letter
'a', an asterisk '*', a dagger 'â€ ' or 'â€¡', a section sign 'Â§'. Write each as it
appears, and name the figure it belongs to by its index.

These are NOT markers. A parenthesized NEGATIVE VALUE like '(84)'. A unit like
'(%)' or '($m)'. A year, a count, or any number that is the thing being stated
rather than a pointer away from it.

A label naming a NAMED SECTION of the document â€” '(Note 16)', 'Schedule II' â€” is
written as printed WITH its word, never as a bare number.

The kind says what the marker POINTS AT, judged from the page. A marker pointing
at a note printed for this figure is 'footnote' â€” including when that note's own
text sends the reader onward. 'For a description of this non-GAAP financial
measure, see Selected Definitions on page 40' is a printed note, and the answer is
that line, so its marker is 'footnote'.

'section' is for a label that CROSS-REFERENCES a named part of the document whose
content lives elsewhere, not in a note printed here. Such a label names its target
in words, so its marker is written with that word â€” 'Note 16', 'Schedule II'. A
bare number or letter is never 'section'; a marker with no note printed for it is
still 'footnote', and reporting it that way is what says the note is missing.

One entry per marker. A label reading 'Book Value(1,2)' carries two markers and
gets two entries, never one reading '1,2'. Empty list if the page's figures carry
no markers, which is the common case.

JOB 3 â€” READ THE NOTES THEMSELVES.

Report every note line printed on the page for a figure, as a PAIR: the note's
OWN marker exactly as printed at the start of its line, and its text without that
marker. Read them off the IMAGE.

The image's formatting decides what is a marker. A general note that opens with
no marker â€” a basis-of-presentation line, a line beginning 'Note:' â€” gets an
EMPTY marker and keeps its full text. A line whose text sends the reader onward
is still a note: report it as printed.

Notes are printed at the foot of the page, beneath the figure, or beside it. They
often run together on one physical line: 'Note: As of 03/31/2026. 1. For a
description of this measure, see Selected Definitions on page 40.' is a general
note AND note 1 â€” report them separately.

Every marker you reported in job 2 should have a note here unless no line on the
page defines it. Report a note even when no marker points at it.

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)ÚFigureCorrectori  c              ƒ  ó   #   • g 7f©Nr    )ÚselfÚ
page_imageÚfiguresÚ	fragmentss       r)   Úcorrect_figureÚFigureCorrector.correct_figure  s   é € àùs   ‚r    N©ro   Úbytesrp   úSequence[Figure]rq   úSequence[Fragment]re   r@   )r!   r"   r#   r$   rr   r'   r    r(   r)   rk   rk     s'   † ðØðØ*:ðØGYðà	÷r(   rk   c                ó2   • SR                  S U  5       5      $ )z=The page's figures, numbered the way a marker refers to them.z

c              3  óZ   #   • U  H!  nS UR                    SUR                   3v •  M#     g7f)zFIGURE z:
N)r   r   ©rV   rO   s     r)   rY   Úfigure_block.<locals>.<genexpr>  s%   é € ÐNÂgÀ˜ §¡ 	¨¨Q¯]©]¨OÕ<Âgùs   ‚)+©Újoin)rp   s    r)   Úfigure_blockr~     s   € à�;‰;ÑNÁgÓNÓNÐNr(   c                ó2   • SR                  S U  5       5      $ )zIThe candidates, one per line, numbered the way the answer refers to them.Ú
c              3  óV   #   • U  H  oR                    S UR                   3v •  M!     g7f)z: N)r   r-   rz   s     r)   rY   Ú!fragment_block.<locals>.<genexpr>$  s!   é € Ð?²Y°Ÿ™�y  1§6¡6 (Õ+²Yùs   ‚')r|   )rq   s    r)   Úfragment_blockrƒ   "  s   € à�9‰9Ñ?±YÓ?Ó?Ð?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)ÚPydanticAIFigureCorrectori'  zºFigureCorrector 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    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)ÚproviderzyPydanticAIFigureCorrector: 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-correction)Úrun_name)Úpydantic_air‡   Úpydantic_ai.models.anthropicrˆ   Úpydantic_ai.providers.anthropicr‰   Úpydantic_ai.settingsrŠ   r   ÚllmÚfigure_correction_modelÚmodelr   r   Úanthropic_auth_tokenÚanthropic_api_keyÚquber.agents._oauth_gater‹   ÚRuntimeErrorrŽ   r@   ÚFIGURE_CORRECTION_PROMPTÚagentr   Útracer)rn   r™   Ú
auth_tokenrŒ   rŽ   r‡   rˆ   r‰   rŠ   Úllm_settingsÚresolved_authÚresolved_keyr‹   Ú
anth_modelr�   r‘   s                   r)   Ú__init__Ú"PydanticAIFigureCorrector.__init__2  sô   € õ 	&Ý?ÝEÝ6ä#“~×)Ñ)ˆØ×h˜×=Ñ=×hÀ×ASÑAS×hÔWhˆØÑ"Ô+HÈ×+OÑ+OØˆKØ"×G l×&GÑ&GˆØ×@ ,×"@Ñ"@ˆæÝKá3°EÓI‰JÞÙ(°Ñ>ˆHÙ'¨ÑA‰JäðPóð ð
 Œ
Ø&ÔØ!,Ñ!4™¹-ÐT_Ñ:`ˆÙØÜ(Ü2Ø)ñ	
ˆŒ
ô &Ð/HÑIˆ�r(   c                ó^   • SS[         S.SS[        U5      S.S[        U5      S.SSS./S./0$ )	NÚmessagesÚsystem©ÚroleÚcontentÚuserr-   )Útyper-   Úimagez[page image attached])rž   r~   rƒ   )rn   rp   rq   s      r)   Útrace_inputsÚ&PydanticAIFigureCorrector.trace_inputs_  sM   € àØ!Ô.FÑGà"à!'´¸gÓ1FÑGØ!'´À	Ó1JÑKØ!(Ð2IÑJð ñð
ð
ð 	
r(   c              ƒ  óê  #   • SSK Jn  U" USS9nS[        U5       3n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                  XgU/5      I S h  v•N n	U	R                  n
S	U
R                  5       S
./[        U
R                  5      [        U
R                  5      [        U
R                  5      [!        U	R"                  5      S.Ul        S S S 5      IS h  v•N   U Vs1 s H  o»R&                  iM     nnW
R                   Vs/ s H  o»R&                  U;   d  M  UPM     nn[        U5      [        U
R                  5      :w  aY  U(       d  [(        R*                  O[(        R,                  nU" S[        U
R                  5      [        U5      -
  [        U5      5        U Vs1 s H  o»R&                  iM     nnU
R                   Vs/ s H8  nUR.                  U;   d  M  UR0                  R3                  5       (       d  M6  UPM:     nn[        U5      [        U
R                  5      :w  a6  [(        R,                  " S[        U
R                  5      [        U5      -
  5        U
R                   Vs/ s H8  nUR.                  U;   d  M  UR4                  R3                  5       (       d  M6  UPM:     nn[7        UUUS9$  GN� GNn GNê! , IS h  v•N  (       d  f       GN = fs  snf s  snf s  snf s  snf s  snf ! [8         a4  n[(        R:                  " S[        U5      U5        [7        / S9s S nA$ S nAff = f7f)Nr   )ÚBinaryContentz	image/png)ÚdataÚ
media_typez'Figures the scanner read on this page:
z3Fragments extracted from inside the figure region:
Úfigure_correction)r™   Ú	assistantr«   )r©   rD   rF   rd   Úusage_metadatazQfigure_correction: ignoring {} verdict(s) naming a fragment not in the list of {}zHfigure_correction: ignoring {} marker(s) naming a figure not in the list©rD   rF   rd   zbfigure_correction: LLM call failed; all {} fragment(s) are kept and no markers are recorded exc={})rD   )r“   r´   r~   rƒ   r    Úllm_runr±   r™   rŸ   ÚrunÚoutputÚmodel_dump_jsonÚlenrD   rF   rd   r   ÚusageÚoutputsr   r   ÚdebugÚwarningr5   r6   r[   r-   r@   Ú	ExceptionÚerror)rn   ro   rp   rq   r´   r°   Ú	describedÚlistedr¼   Úresultr½   rO   ÚaskedÚkeptÚreportÚshownÚmÚmarksÚnrd   Úexcs                        r)   rr   Ú(PydanticAIFigureCorrector.correct_figuren  s¶  é € õ 	.á :¸+ÑFˆØ>¼|ÈGÓ?TÐ>UÐVˆ	ØGÌÐW`ÓHaÐGbÐcˆð+	2Ø—{‘{×*Ñ*Ø# T×%6Ñ%6°wÓ%JÐRV×R\ÑR\ð +÷ ñ àØ#Ÿz™zŸ~™~¨yÀ%Ð.HÓI×I�ØŸ™�à*5À&×BXÑBXÓBZÑ![Ð \Ü!$ V×%5Ñ%5Ó!6Ü" 6§>¡>Ó2Ü  §¡Ó.Ü&9¸&¿,¹,Ó&Gñ�”÷÷ ñ '0Ó0¢i —W”W¡iˆEÐ0Ø%×/Ò/ÓDÒ/˜!·7±7¸eÑ3C—AÑ/ˆDÐDÜ�4‹yœC × 0Ñ 0Ó1Ó1ö .7œŸš¼F¿N¹N�ÙØgÜ˜×(Ñ(Ó)¬C°«IÑ5Ü˜	“Nôñ
 '.Ó.¢g —W”W¡gˆEÐ.Ø &§¢ÓY¢˜1°!·(±(¸eÑ2C“QÈÏÉÏÉ×HX—Q¡ˆEÐYÜ�5‹zœS §¡Ó0Ó0Ü—’Ø^Ü˜Ÿ™Ó'¬#¨e«*Ñ4ôð !'§¢ÓU¢˜1°·±¸EÑ0A“QÀaÇfÁfÇlÁlÇn—Q¡ˆEÐUÜ#¨d¸EÈÑOÐOòEò J÷÷ ÷ ò üò 1ùÚDùò /ùÚYùò Vøäó 	2Ü�LŠLð&ä�I“Øô	ô $¨bÑ1Õ1ûð	2üsë   ‚*M3­8L2 Á%K5Á&L2 Á)!K>Â
K8ÂA;K>ÄL2 ÄK;ÄL2 ÄLÄ/L2 Ä?LÅLÅBL2 ÇL#Ç2L2 ÈL(ÈL(È;L(ÉA(L2 Ê)L-ËL-Ë"L-Ë(L2 Ë4M3Ë5L2 Ë8K>Ë;L2 Ë>LÌLÌLÌ!L2 Ì2
M0Ì<)M+Í%M0Í&M3Í+M0Í0M3)rŸ   r™   rŽ   r    )
r™   úOptional[str]r¡   rÒ   rŒ   rÒ   rŽ   zOptional[float]re   ÚNone)rp   rv   rq   rw   re   zDict[str, Any]rt   )
r!   r"   r#   r$   r%   ÚDEFAULT_TEMPERATUREr¦   r±   rr   r'   r    r(   r)   r…   r…   '  sƒ   † ñð Ðð  $Ø$(Ø!%Ø':ð+Jàð+Jð "ð+Jð ð	+Jð
 %ð+Jð 
õ+JôZ
ð32Øð32Ø*:ð32ØGYð32à	÷32r(   r…   c                  óT   • \ rS rSrSr   S       SS jjr        S	S jrSrg)
ÚMockFigureCorrectori¤  zONames a fixed set of fragment texts as furniture, and fixed markers. For tests.Nc                ó¶   • [        U=(       d    S5      U l        [        U=(       d    S5      U l        [        U=(       d    S5      U l        / U l        / U l        g )Nr    )rJ   rD   rf   rF   rd   Úcallsrp   )rn   rD   rF   rd   s       r)   r¦   ÚMockFigureCorrector.__init__§  sB   € ô ˜YŸ_¨"Ó-ˆŒÜ˜GŸM rÓ*ˆŒÜ˜%Ÿ+ 2Ó&ˆŒ
Ø+-ˆŒ
Ø+-ˆ�r(   c           
   ƒ  ó>  #   • UnU R                   R                  [        U5      5        U R                  R                  [        U5      5        U Vs1 s H  oUR                  iM     nn[        U Vs/ s H2  oUR                  U R                  ;   d  M  [        UR                  SS9PM4     snU R                   Vs/ s H  owR                  U;   d  M  UPM     snU R                   Vs/ s H  oˆR                  U;   d  M  UPM     snS9$ s  snf s  snf s  snf s  snf 7f)NÚmock)r   r1   rº   )rØ   r_   rf   rp   r   r@   r-   rD   r/   rF   r5   rd   )	rn   ro   rp   rq   Ú_rO   rÌ   rÍ   rÏ   s	            r)   rr   Ú"MockFigureCorrector.correct_figure³  sã   é € ð ˆØ�
‰
×Ñœ$˜y›/Ô*Ø�‰×ÑœD ›MÔ*Ù")Ó*¢'˜Q—”¡'ˆÐ*ÜáAJóÚAJ¸AÏfÉfÐX\×XfÑXfÑNfÓ7”	 §¡°Ô7Áñð !%§¢ÓB¢˜1·±¸EÑ0A—Q¡ÑBØ"ŸjšjÓ>šj˜¯H©H¸Ñ,=—1™jÑ>ñ
ð 	
ùò +ùòùò CùÚ>ùsH   ‚ADÁD	Á&DÁ1DÂDÂ*DÂ:D
ÃD
ÃDÃ'DÃ>DÄD)rØ   rp   rD   rF   rd   )NNN)rD   zOptional[Sequence[str]]rF   zOptional[Sequence[Marker]]rd   zOptional[Sequence[Note]]re   rÓ   rt   )r!   r"   r#   r$   r%   r¦   rr   r'   r    r(   r)   rÖ   rÖ   ¤  s`   † ÙYð .2Ø.2Ø*.ð	
.à*ð
.ð ,ð
.ð (ð	
.ð
 
õ
.ð
Øð
Ø*:ð
ØGYð
à	÷
r(   rÖ   )ÚapirÛ   Ú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)zJThe figure corrector for this run, or None when the sweep is switched off.rÞ   rÛ   rß   Nz)Unknown QUBER_FIGURE_CORRECTION_BACKEND: z. Expected api|mock|off.)r   r—   Úfigure_correction_backendr…   rÖ   Ú
ValueError)ÚbackendÚselecteds     r)   Úget_figure_correctorrå   Æ  s]   € à×Fœ,›.×,Ñ,×FÑF€HØ�5ÓÜ(Ó*Ð*Ø�6ÓÜ"Ó$Ð$Ø�5ÓØÜ
Ð@ÀÁÐLdÐeÓ
fÐfr(   )rp   rv   re   r   )rq   rw   re   r   rm   )rã   z!Optional[FigureCorrectionBackend]re   zOptional[FigureCorrector]).r%   Ú
__future__r   ÚjsonÚtypingr   r   r   r   r   r	   r
   r   Úlogurur   Úpydanticr   r   r   Úquber.agents.factoryr   Úquber.agents.langsmith_tracerr   r   Úquber.agents.llm_clientr   r   Úquber.settingsr   r   r   r+   r/   r3   r=   r@   ÚdumpsÚmodel_json_schemarž   rk   r~   rƒ   r…   rÖ   ÚFigureCorrectionBackendrå   r    r(   r)   Ú<module>rò      s  ðñ5õn #ã ß \× \Ó \å ß 6Ñ 6å >ß Nß Gß :ôWˆYô Wô<ˆyô <ôK�	ô Kô
ˆYô ôBQˆ9ô Qô$.�yô .ðbS ðf ‡‚Ð×.Ñ.Ó0¸Ñ;Ð <ð =ðgVÐ ðr ô�hó ó ðôOô
@÷
z2ñ z2÷z
ñ 
ð> "Ð"6Ñ7Ð ÷	gr(   