11"""Schema extraction utilities for OpenAI Agents."""
22
33import inspect
4- from typing import Any , get_args , get_origin , get_type_hints
4+ from typing import Any , get_args , get_origin
55
66from agents import Agent
77from pydantic import BaseModel , TypeAdapter
@@ -41,106 +41,14 @@ def _is_pydantic_model(type_hint: Any) -> bool:
4141 return False
4242
4343
44- def _extract_schema_from_callable (callable_obj : Any ) -> dict [str , Any ] | None :
45- """
46- Extract input/output schemas from a callable's type annotations.
47-
48- Args:
49- callable_obj: A callable object (function, async function, etc.)
50-
51- Returns:
52- Dictionary with input and output schemas if type hints are found,
53- None otherwise
54- """
55- if not callable (callable_obj ):
56- return None
57-
58- try :
59- # Get type hints from the callable
60- type_hints = get_type_hints (callable_obj )
61-
62- if not type_hints :
63- return None
64-
65- # Get function signature to identify parameters
66- sig = inspect .signature (callable_obj )
67- params = list (sig .parameters .values ())
68-
69- # Find the first parameter (usually the input)
70- input_type = None
71-
72- for param in params :
73- if param .name in ("self" , "cls" ):
74- continue
75- if param .name in type_hints :
76- input_type = type_hints [param .name ]
77- break
78-
79- # Get return type
80- return_type = type_hints .get ("return" )
81-
82- schema : dict [str , Any ] = {
83- "input" : {"type" : "object" , "properties" : {}, "required" : []},
84- "output" : {"type" : "object" , "properties" : {}, "required" : []},
85- }
86-
87- # Extract input schema from Pydantic model
88- if input_type and _is_pydantic_model (input_type ):
89- adapter = TypeAdapter (input_type )
90- input_schema = adapter .json_schema ()
91- unpacked_input = _resolve_refs (input_schema )
92-
93- schema ["input" ]["properties" ] = _process_nullable_types (
94- unpacked_input .get ("properties" , {})
95- )
96- schema ["input" ]["required" ] = unpacked_input .get ("required" , [])
97-
98- # Add title and description if available
99- if "title" in unpacked_input :
100- schema ["input" ]["title" ] = unpacked_input ["title" ]
101- if "description" in unpacked_input :
102- schema ["input" ]["description" ] = unpacked_input ["description" ]
103-
104- # Extract output schema from Pydantic model
105- if return_type and _is_pydantic_model (return_type ):
106- adapter = TypeAdapter (return_type )
107- output_schema = adapter .json_schema ()
108- unpacked_output = _resolve_refs (output_schema )
109-
110- schema ["output" ]["properties" ] = _process_nullable_types (
111- unpacked_output .get ("properties" , {})
112- )
113- schema ["output" ]["required" ] = unpacked_output .get ("required" , [])
114-
115- # Add title and description if available
116- if "title" in unpacked_output :
117- schema ["output" ]["title" ] = unpacked_output ["title" ]
118- if "description" in unpacked_output :
119- schema ["output" ]["description" ] = unpacked_output ["description" ]
120-
121- # Only return schema if we found at least one Pydantic model
122- if schema ["input" ]["properties" ] or schema ["output" ]["properties" ]:
123- return schema
124-
125- except Exception :
126- # If schema extraction fails, return None to fall back to default
127- pass
128-
129- return None
130-
131-
132- def get_entrypoints_schema (
133- agent : Agent , loaded_object : Any | None = None
134- ) -> dict [str , Any ]:
44+ def get_entrypoints_schema (agent : Agent ) -> dict [str , Any ]:
13545 """
13646 Extract input/output schema from an OpenAI Agent.
13747
138- Prioritizes the agent's native output_type attribute (OpenAI Agents pattern),
139- with optional fallback to wrapper function type hints (UiPath pattern).
48+ Uses the agent's native output_type attribute for schema extraction.
14049
14150 Args:
14251 agent: An OpenAI Agent instance
143- loaded_object: Optional original loaded object (function/callable) with type annotations
14452
14553 Returns:
14654 Dictionary with input and output schemas
@@ -170,19 +78,19 @@ def get_entrypoints_schema(
17078 "required" : ["message" ],
17179 }
17280
173- # Extract output schema - PRIORITY 1: Agent's output_type (native OpenAI Agents pattern)
81+ # Extract output schema - Agent's output_type (native OpenAI Agents pattern)
17482 output_type = getattr (agent , "output_type" , None )
17583 output_extracted = False
17684
17785 # Unwrap AgentOutputSchema if present (OpenAI Agents SDK wrapper)
178- # Check for AgentOutputSchema by looking for 'schema ' attribute on non-type instances
86+ # AgentOutputSchema wraps the actual Pydantic model in an 'output_type ' attribute
17987 if (
18088 output_type is not None
181- and hasattr (output_type , "schema " )
89+ and hasattr (output_type , "output_type " )
18290 and not isinstance (output_type , type )
18391 ):
18492 # This is an AgentOutputSchema wrapper instance, extract the actual model
185- output_type = output_type .schema
93+ output_type = output_type .output_type
18694
18795 if output_type is not None and _is_pydantic_model (output_type ):
18896 try :
@@ -207,15 +115,6 @@ def get_entrypoints_schema(
207115 # Continue to fallback if extraction fails
208116 pass
209117
210- # Extract output schema - PRIORITY 2: Wrapper function type hints (UiPath pattern)
211- # This allows UiPath-specific patterns where agents are wrapped in typed functions
212- if not output_extracted and loaded_object is not None :
213- wrapper_schema = _extract_schema_from_callable (loaded_object )
214- if wrapper_schema is not None :
215- # Use the wrapper's output schema, but keep the default input (messages)
216- schema ["output" ] = wrapper_schema ["output" ]
217- output_extracted = True
218-
219118 # Fallback: Default output schema for agents without explicit output_type
220119 if not output_extracted :
221120 schema ["output" ] = {
0 commit comments