2525from __future__ import annotations
2626
2727import json
28- from typing import Any , Dict , List , Literal , Optional , Union
28+ from typing import Dict , List , Literal , Mapping , Optional , Union , cast
2929
3030from pydantic import BaseModel , ConfigDict , Field , field_validator
3131from typing_extensions import Annotated
@@ -309,7 +309,7 @@ class LibrarianInterrupt(BaseModel):
309309 description = "The exact applies-when phrase that matched the buffer." ,
310310 )
311311 evidence : List [EvidenceItem ] = Field (
312- default_factory = list ,
312+ default_factory = list [ EvidenceItem ] ,
313313 description = (
314314 "List of EvidenceItem dicts (NOT strings). Each item is "
315315 "{turn_id, role, quote}. Emit at least one verbatim turn quote."
@@ -326,7 +326,7 @@ class LibrarianInterrupt(BaseModel):
326326
327327 @field_validator ("evidence" , mode = "before" )
328328 @classmethod
329- def _coerce_evidence (cls , v ) :
329+ def _coerce_evidence (cls , v : object ) -> object :
330330 """Tolerate LLM-shape drift on evidence.
331331
332332 The schema asks for ``list[EvidenceItem]`` (dicts), but Sonnet /
@@ -343,11 +343,12 @@ def _coerce_evidence(cls, v):
343343 return []
344344 if isinstance (v , str ):
345345 return [{"quote" : v }]
346- if isinstance (v , dict ):
347- return [v ]
346+ if isinstance (v , Mapping ):
347+ return [cast ( Mapping [ object , object ], v ) ]
348348 if isinstance (v , list ):
349- out = []
350- for item in v :
349+ raw = cast (list [object ], v )
350+ out : list [object ] = []
351+ for item in raw :
351352 if isinstance (item , str ):
352353 out .append ({"quote" : item })
353354 else :
@@ -367,7 +368,7 @@ class LibrarianProposal(BaseModel):
367368 model_config = ConfigDict (extra = "ignore" )
368369
369370 proposals : List [ProposedAction ] = Field (
370- default_factory = list ,
371+ default_factory = list [ ProposedAction ] ,
371372 description = (
372373 "Ordered list of curator actions the Librarian wants the "
373374 "Scholar to execute. Each item is a typed action object "
@@ -377,7 +378,7 @@ class LibrarianProposal(BaseModel):
377378 ),
378379 )
379380 interrupts : List [LibrarianInterrupt ] = Field (
380- default_factory = list ,
381+ default_factory = list [ LibrarianInterrupt ] ,
381382 description = (
382383 "Optional list of interrupt-nudge candidates: turns in the "
383384 "buffer that match an existing entry's applies-when phrases. "
@@ -479,7 +480,7 @@ class ScholarReview(BaseModel):
479480 model_config = ConfigDict (extra = "ignore" )
480481
481482 decisions : List [ScholarDecision ] = Field (
482- default_factory = list ,
483+ default_factory = list [ ScholarDecision ] ,
483484 description = (
484485 "One ScholarDecision per Librarian proposal, matched by "
485486 "`action_index`. Order need not mirror the proposals — the "
@@ -488,7 +489,7 @@ class ScholarReview(BaseModel):
488489 ),
489490 )
490491 interrupts_processed : List [ScholarInterruptDecision ] = Field (
491- default_factory = list ,
492+ default_factory = list [ ScholarInterruptDecision ] ,
492493 description = (
493494 "One ScholarInterruptDecision per LibrarianInterrupt the "
494495 "Scholar reviewed. Approved decisions are written to "
@@ -513,10 +514,10 @@ class LibrarianResponse(BaseModel):
513514
514515 model_config = ConfigDict (extra = "ignore" )
515516
516- candidates : List [Dict [str , Any ]] = Field (default_factory = list )
517- interrupt_candidates : List [Dict [str , Any ]] = Field (default_factory = list )
518- proposals : List [Dict [str , Any ]] = Field (default_factory = list )
519- interrupts : List [Dict [str , Any ]] = Field (default_factory = list )
517+ candidates : List [Dict [str , object ]] = Field (default_factory = list [ Dict [ str , object ]] )
518+ interrupt_candidates : List [Dict [str , object ]] = Field (default_factory = list [ Dict [ str , object ]] )
519+ proposals : List [Dict [str , object ]] = Field (default_factory = list [ Dict [ str , object ]] )
520+ interrupts : List [Dict [str , object ]] = Field (default_factory = list [ Dict [ str , object ]] )
520521
521522
522523class ScholarResponse (BaseModel ):
@@ -527,8 +528,8 @@ class ScholarResponse(BaseModel):
527528
528529 model_config = ConfigDict (extra = "ignore" )
529530
530- candidates_processed : List [Dict [str , Any ]] = Field (default_factory = list )
531- interrupts_processed : List [Dict [str , Any ]] = Field (default_factory = list )
531+ candidates_processed : List [Dict [str , object ]] = Field (default_factory = list [ Dict [ str , object ]] )
532+ interrupts_processed : List [Dict [str , object ]] = Field (default_factory = list [ Dict [ str , object ]] )
532533
533534
534535# ── Prompt-shape generators ──────────────────────────────────────────
0 commit comments