1010
1111from pydantic import Json , TypeAdapter , ValidationError
1212from pydantic_core import SchemaValidator , to_json
13- from typing_extensions import Self , TypedDict , TypeVar , assert_never
13+ from typing_extensions import Self , TypedDict , TypeVar
1414
1515from pydantic_ai ._instrumentation import InstrumentationNames
1616
@@ -215,11 +215,12 @@ async def validate(
215215class BaseOutputSchema (ABC , Generic [OutputDataT ]):
216216 text_processor : BaseOutputProcessor [OutputDataT ] | None = None
217217 toolset : OutputToolset [Any ] | None = None
218+ object_def : OutputObjectDefinition | None = None
218219 allows_deferred_tools : bool = False
219220 allows_image : bool = False
220221
221- @abstractmethod
222- def with_default_mode (self , mode : StructuredOutputMode ) -> OutputSchema [ OutputDataT ] :
222+ @property
223+ def mode (self ) -> OutputMode | None :
223224 raise NotImplementedError ()
224225
225226 @property
@@ -231,6 +232,8 @@ def allows_text(self) -> bool:
231232class OutputSchema (BaseOutputSchema [OutputDataT ], ABC ):
232233 """Model the final output from an agent run."""
233234
235+ # TODO (DouweM): Rename/merge this, BaseOutputSchema, and OutputSchemaWithoutMode
236+
234237 @classmethod
235238 @overload
236239 def build (
@@ -260,7 +263,6 @@ def build( # noqa: C901
260263 cls ,
261264 output_spec : OutputSpec [OutputDataT ],
262265 * ,
263- default_mode : StructuredOutputMode | None = None ,
264266 name : str | None = None ,
265267 description : str | None = None ,
266268 strict : bool | None = None ,
@@ -382,15 +384,12 @@ def build( # noqa: C901
382384 )
383385
384386 if len (other_outputs ) > 0 :
385- schema = OutputSchemaWithoutMode (
387+ return OutputSchemaWithoutMode (
386388 processor = cls ._build_processor (other_outputs , name = name , description = description , strict = strict ),
387389 toolset = toolset ,
388390 allows_deferred_tools = allows_deferred_tools ,
389391 allows_image = allows_image ,
390392 )
391- if default_mode :
392- schema = schema .with_default_mode (default_mode )
393- return schema
394393
395394 if allows_image :
396395 return ImageOutputSchema (allows_deferred_tools = allows_deferred_tools )
@@ -410,19 +409,12 @@ def _build_processor(
410409
411410 return UnionOutputProcessor (outputs = outputs , strict = strict , name = name , description = description )
412411
413- @property
414- @abstractmethod
415- def mode (self ) -> OutputMode :
416- raise NotImplementedError ()
417-
418412 def raise_if_unsupported (self , profile : ModelProfile ) -> None :
419413 """Raise an error if the mode is not supported by this model."""
414+ # TODO (DouweM): Remove method?
420415 if self .allows_image and not profile .supports_image_output :
421416 raise UserError ('Image output is not supported by this model.' )
422417
423- def with_default_mode (self , mode : StructuredOutputMode ) -> OutputSchema [OutputDataT ]:
424- return self
425-
426418
427419@dataclass (init = False )
428420class OutputSchemaWithoutMode (BaseOutputSchema [OutputDataT ]):
@@ -441,30 +433,16 @@ def __init__(
441433 super ().__init__ (
442434 allows_deferred_tools = allows_deferred_tools ,
443435 toolset = toolset ,
436+ object_def = processor .object_def ,
444437 text_processor = processor ,
445438 allows_image = allows_image ,
446439 )
447440 self .processor = processor
448441
449- def with_default_mode (self , mode : StructuredOutputMode ) -> OutputSchema [OutputDataT ]:
450- if mode == 'native' :
451- return NativeOutputSchema (
452- processor = self .processor ,
453- allows_deferred_tools = self .allows_deferred_tools ,
454- allows_image = self .allows_image ,
455- )
456- elif mode == 'prompted' :
457- return PromptedOutputSchema (
458- processor = self .processor ,
459- allows_deferred_tools = self .allows_deferred_tools ,
460- allows_image = self .allows_image ,
461- )
462- elif mode == 'tool' :
463- return ToolOutputSchema (
464- toolset = self .toolset , allows_deferred_tools = self .allows_deferred_tools , allows_image = self .allows_image
465- )
466- else :
467- assert_never (mode )
442+ @property
443+ def mode (self ) -> OutputMode | None :
444+ # TODO (DouweM): Could this be a field?
445+ return None
468446
469447
470448@dataclass (init = False )
@@ -483,7 +461,7 @@ def __init__(
483461 )
484462
485463 @property
486- def mode (self ) -> OutputMode :
464+ def mode (self ) -> OutputMode | None :
487465 return 'text'
488466
489467 def raise_if_unsupported (self , profile : ModelProfile ) -> None :
@@ -496,7 +474,7 @@ def __init__(self, *, allows_deferred_tools: bool):
496474 super ().__init__ (allows_deferred_tools = allows_deferred_tools , allows_image = True )
497475
498476 @property
499- def mode (self ) -> OutputMode :
477+ def mode (self ) -> OutputMode | None :
500478 return 'image'
501479
502480 def raise_if_unsupported (self , profile : ModelProfile ) -> None :
@@ -513,18 +491,17 @@ def __init__(
513491 self , * , processor : BaseObjectOutputProcessor [OutputDataT ], allows_deferred_tools : bool , allows_image : bool
514492 ):
515493 super ().__init__ (
516- text_processor = processor , allows_deferred_tools = allows_deferred_tools , allows_image = allows_image
494+ text_processor = processor ,
495+ object_def = processor .object_def ,
496+ allows_deferred_tools = allows_deferred_tools ,
497+ allows_image = allows_image ,
517498 )
518499 self .processor = processor
519500
520- @property
521- def object_def (self ) -> OutputObjectDefinition :
522- return self .processor .object_def
523-
524501
525502class NativeOutputSchema (StructuredTextOutputSchema [OutputDataT ]):
526503 @property
527- def mode (self ) -> OutputMode :
504+ def mode (self ) -> OutputMode | None :
528505 return 'native'
529506
530507 def raise_if_unsupported (self , profile : ModelProfile ) -> None :
@@ -553,7 +530,7 @@ def __init__(
553530 self .template = template
554531
555532 @property
556- def mode (self ) -> OutputMode :
533+ def mode (self ) -> OutputMode | None :
557534 return 'prompted'
558535
559536 @classmethod
@@ -599,7 +576,7 @@ def __init__(
599576 )
600577
601578 @property
602- def mode (self ) -> OutputMode :
579+ def mode (self ) -> OutputMode | None :
603580 return 'tool'
604581
605582 def raise_if_unsupported (self , profile : ModelProfile ) -> None :
0 commit comments