ó
    À‘´jÒ  ã                  ól  • S r SSKJr  SSKJr  SSK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  SSKJr  SS	KJr  SS
K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"  Sr#SS jr$S r%Sr& " S S\5      r'\" SS9S S j5       r(S!S jr)S"S#S jjr*S$S jr+ S"       S%S jjr, S"     S&S jjr-g)'ac  The playground's Claude model factory, its answer-context format, and the prose baseline.

`anthropic_model` decides which credential a playground agent runs on. Every
Pydantic AI agent defined in this package builds its model through it: the
answering agents, the selection agent in `selection.py`, and the planner in
`answers/planned.py`. Two agents the playground also runs, the cover-page
attributor at upload and the footnote lookup at ingest, are built in
`quber.agents` and choose their credential there. `answer_model` fixes which Claude model answers, for the
live answering agents in `answers/fixed.py` and `answers/declared.py` and for
the prose agent here. `build_context` is the chunk-to-prompt format the
answering agents share.

The prose agent (`answer`, `GroundedAnswer`) answers in free text, strictly
from the retrieved chunks, and returns the ids it grounded on. A table chunk's
HTML carries an id on every cell (`<td id="t0-8-1">`), so it can cite
individual cells. It is not on the playground's request path.
`benchmark/run_shapes.py` uses `answer` as its baseline, and `answer_stream`
has no caller.
é    )Úannotations)Ú	lru_cache)ÚAnyÚDictÚListÚOptional)Ú	BaseModelÚField)ÚAgent)ÚAnthropicModel)ÚAnthropicProvider)ÚModelSettings)Úmake_oauth_anthropic_model)Úusage_metadata_from)ÚDocumentIdentityÚwith_document)ÚRetrievedChunk)Úrun_metadataÚtracer)Úget_settingszclaude-opus-5c                óä   • [        5       R                  nUR                  (       a  [        XR                  5      $ UR                  (       a  [        U [        UR                  S9S9$ [        S5      e)a™  An Anthropic model over whichever credential the host presents.

The subscription OAuth token wins when it is set, routed through the OAuth
gate in `quber.agents._oauth_gate`. Without one the API key is used through the stock model,
which is how the hosted playground runs: the token never leaves the
developer host, and the task is given only the key. Neither set is a
configuration error, reported as such.
)Úapi_key)Úproviderz\Neither ANTHROPIC_AUTH_TOKEN nor ANTHROPIC_API_KEY is set; the playground needs one of them.)r   ÚllmÚanthropic_auth_tokenr   Úanthropic_api_keyr   r   ÚRuntimeError)Úmodel_idr   s     Ú4/home/mande/repo/quber/src/quber/playground/agent.pyÚanthropic_modelr    +   s]   € ô ‹.×
Ñ
€CØ
××Ü)¨(×4LÑ4LÓMÐMØ
××Ü˜hÔ1BÈ3×K`ÑK`Ñ1aÑbÐbÜ
Øfóð ó    c                 ó    • [        [        5      $ )zÖThe playground's answering model.

One place decides which model answers. The fixed and declared answering
agents and the prose baseline below all build from here rather than each
pinning its own copy of the name.
)r    ÚDEFAULT_MODEL© r!   r   Úanswer_modelr%   >   s   € ô œ=Ó)Ð)r!   u  You are a financial-document analyst answering questions about ONE parsed
document. You are given a set of context chunks retrieved from that document.

Rules:
- Answer ONLY from the provided context chunks. Never use outside knowledge
  and never invent figures. If the context does not contain the answer, say
  so plainly.
- Be precise and quantitative. Report exact values, units, and periods as
  they appear in the source.
- Populate `cited_ids` with the ids that support your answer. Each context
  chunk begins with a header line: `[chunk id=<ID> | page <N> | type <TYPE>]`.
  * By default, cite the `<ID>` from the header of each chunk you used.
  * If a chunk's content exposes finer-grained element ids â€” e.g. table cells
    tagged like `<td id="0-8">` â€” you MAY cite those specific cell ids instead,
    for tighter grounding.
  * Only cite ids that literally appear in the provided context (a header
    `<ID>` or an element id inside a chunk's content). NEVER invent, guess, or
    construct an id that is not present verbatim.
c                  óD   • \ rS rSr% \" SS9rS\S'   \" \SS9rS\S	'   S
r	g)ÚGroundedAnsweré^   z/The answer, drawn only from the context chunks.)ÚdescriptionÚstrÚanswerz8Chunk ids and/or table cell ids that support the answer.)Údefault_factoryr)   z	List[str]Ú	cited_idsr$   N)
Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__r
   r+   Ú__annotations__Úlistr-   Ú__static_attributes__r$   r!   r   r'   r'   ^   s)   ‡ ÙÐ$UÑV€FˆCÓVÙ ØØNñ€Iˆyö r!   r'   é   )Úmaxsizec            	     óH   • [        [        5       [        [        [	        SS9S9$ )Ng        )Útemperature)Úoutput_typeÚsystem_promptÚmodel_settings)r   r%   r'   ÚSYSTEM_PROMPTr   r$   r!   r   Ú_agentr=   f   s"   € äÜ‹Ü"Ü#Ü$°Ñ5ñ	ð r!   c                óÔ   • / nU  HP  nSUR                    SUR                  S-    SUR                   S3nUR                  U SUR                   35        MR     SR                  U5      $ )Nz
[chunk id=z | page r5   z | type Ú]Ú
z

)Úchunk_idÚpageÚ
chunk_typeÚappendÚcontentÚjoin)ÚchunksÚblocksÚcÚheaders       r   Úbuild_contextrK   p   sh   € Ø€FÛˆà˜aŸj™j˜\¨°!·&±&¸1±*°¸XÀaÇlÁlÀ^ÐSTÐUˆØ�‰˜˜  1§9¡9 +Ð.Ö/ñ ð �;‰;�vÓÐr!   Nc                ó@   • [        U5      nSU SU  S3n[        XB5      $ )NzContext chunks:

z

Question: z:

Answer from the context above and cite the ids you used.)rK   r   )ÚquestionrG   ÚdocumentÚcontextÚprompts        r   Ú_promptrQ   y   s;   € Ü˜FÓ#€Gà
˜g˜Yð 'Ø�Jð Cð	Cð ô
 ˜Ó*Ð*r!   c                ób   • S[         S.SU S./U Vs/ s H  o"R                  PM     snS.$ s  snf )NÚsystem©ÚrolerE   Úuser)ÚmessagesÚ	chunk_ids)r<   rA   )rP   rG   rI   s      r   Ú_trace_inputsrY   ƒ   s>   € ð ¬-Ñ8Ø¨Ñ/ð
ñ +1Ó1ª& Q—j”j©&Ñ1ñð ùò
 2s   ’,c              ƒ  ó°  #   • [        XU5      n[        5       R                  S[        X15      [        [        5       S9 IS h  v•N n[        5       R                  U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$  Nr NS N
! , IS h  v•N  (       d  f       W$ = f7f)NÚanswer_grounded©ÚmodelÚextra_metadataÚ	assistantrT   ©rW   Úusage_metadata)rQ   r   Úllm_runrY   r#   r   r=   ÚrunÚoutputÚmodel_dump_jsonr   ÚusageÚoutputs)rM   rG   rN   rP   rc   Úresultrd   s          r   r+   r+   �   s¸   é € ô �X xÓ0€FÜ‹x×ÑØœ=¨Ó8ÄÔ^jÓ^lð  ÷ ñ à	Ü“x—|‘| FÓ+×+ˆØ!'§¡ˆà"-¸&×:PÑ:PÓ:RÑSÐTÜ1°&·,±,Ó?ñ
ˆŒ÷÷ ð €Mññ ,÷÷ ÷ ð €MüsZ   ‚A CÁB5ÁCÁB;Á#B7Á$?B;Â#CÂ.B9Â/CÂ7B;Â9CÂ;CÃCÃCÃCc               óÈ  #   • [        XU5      n[        5       R                  S[        X15      [        [        5       S9 ISh  v•N n[        5       R                  U5       ISh  v•N nSnUR                  SS9  Sh  v•N n[        USS5      =(       d    SnU(       d  M(  X†:w  d  M/  UnSU47v •  M:   Nq NQ N9
 UR                  5       I Sh  v•N  n	S	U	R                  5       S
./[        UR                  5      S.Ul        SSS5      ISh  v•N    O! , ISh  v•N  (       d  f       O= fSW	47v •  SSS5      ISh  v•N    g! , ISh  v•N  (       d  f       g= f7f)zwYield ("delta", <answer so far>) as the model generates, then
("final", GroundedAnswer) once the full output validates.r[   r\   NÚ gš™™™™™©?)Údebounce_byr+   Údeltar_   rT   r`   Úfinal)rQ   r   rb   rY   r#   r   r=   Ú
run_streamÚstream_outputÚgetattrÚ
get_outputre   r   rf   rg   )
rM   rG   rN   rP   rc   rh   ÚlastÚpartialÚtextrm   s
             r   Úanswer_streamru   �   s/  é € ô
 �X xÓ0€FÜ‹x×ÑØœ=¨Ó8ÄÔ^jÓ^lð  ÷ ñ à	Ü“8×&Ñ& v×.Ô.°&ØˆDØ!'×!5Ñ!5À$Ð!5Ñ!G÷ (�gÜ˜w¨°"Ó5×;¸�ß�4˜D�LØ�DØ! 4˜-Õ'ññ /ñ(Ð!Gð
 +1×*;Ñ*;Ó*=×$=Ð$=ˆEà&1¸e×>SÑ>SÓ>UÑVÐWÜ"5°f·l±lÓ"CñˆCŒK÷ /×.×.×.×.Ð.úð �uˆnÓ÷÷ ÷ ÷ ÷ ð üsÆ   ‚A E"ÁB4ÁE"ÁEÁ$B6Á%EÁ(DÁ:B:Á>B8
Á?B:ÂDÂ"DÂ)DÂ4E"Â6EÂ8B:Â:DÃCÃ4DÄEÄDÄEÄD,	ÄDÄD,	Ä(EÄ6E"ÅEÅE"ÅEÅEÅEÅE")r   r*   )ÚreturnzAgent[None, GroundedAnswer])rG   úList[RetrievedChunk]rv   r*   )N)rM   r*   rG   rw   rN   úOptional[DocumentIdentity]rv   r*   )rP   r*   rG   rw   rv   zDict[str, Any])rM   r*   rG   rw   rN   rx   rv   r'   )rM   r*   rG   rw   rN   rx   ).Ú__doc__Ú
__future__r   Ú	functoolsr   Útypingr   r   r   r   Úpydanticr	   r
   Úpydantic_air   Úpydantic_ai.models.anthropicr   Úpydantic_ai.providers.anthropicr   Úpydantic_ai.settingsr   Úquber.agents._oauth_gater   Úquber.agents.langsmith_tracerr   Ú!quber.playground.answers.documentr   r   Úquber.playground.retrievalr   Úquber.playground.tracingr   r   Úquber.settingsr   r#   r    r%   r<   r'   r=   rK   rQ   rY   r+   ru   r$   r!   r   Ú<module>rˆ      sÕ   ðñõ( #å ß ,Ó ,ç %Ý Ý 7Ý =Ý .å ?Ý =ß MÝ 5ß 9Ý 'ð  €ôò&*ð€ô,�Yô ñ �1Ñóó ðôö+ôð Y]ðØðØ/ðØ;Uðàõð" Y]ðØðØ/ðØ;Uör!   