Skip to content

Commit d4144ab

Browse files
committed
fix: remove loaded object via main
1 parent 832f0a2 commit d4144ab

7 files changed

Lines changed: 17 additions & 178 deletions

File tree

packages/uipath-openai-agents/src/uipath_openai_agents/runtime/agent.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ def __init__(self, name: str, file_path: str, variable_name: str):
2828
self.file_path = file_path
2929
self.variable_name = variable_name
3030
self._context_manager: Any = None
31-
self._loaded_object: Any = (
32-
None # Store original loaded object for type inference
33-
)
3431

3532
@classmethod
3633
def from_path_string(cls, name: str, file_path: str) -> Self:
@@ -102,9 +99,6 @@ async def load(self) -> Agent:
10299
category=UiPathErrorCategory.USER,
103100
)
104101

105-
# Store the original loaded object for type inference
106-
self._loaded_object = agent_object
107-
108102
agent = await self._resolve_agent(agent_object)
109103
if not isinstance(agent, Agent):
110104
raise UiPathOpenAIAgentsRuntimeError(
@@ -179,17 +173,6 @@ async def _resolve_agent(self, agent_object: Any) -> Agent:
179173

180174
return agent_instance
181175

182-
def get_loaded_object(self) -> Any:
183-
"""
184-
Get the original loaded object before agent resolution.
185-
186-
This is useful for extracting type annotations from wrapper functions.
187-
188-
Returns:
189-
The original loaded object (could be an Agent, function, or callable)
190-
"""
191-
return self._loaded_object
192-
193176
async def cleanup(self) -> None:
194177
"""Clean up resources (e.g., exit async context managers)."""
195178
if self._context_manager:

packages/uipath-openai-agents/src/uipath_openai_agents/runtime/factory.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,17 +303,11 @@ async def _create_runtime_instance(
303303
storage = await self._get_or_create_storage()
304304
storage_path = storage.storage_path if storage else None
305305

306-
# Get the loaded object from the agent loader for schema inference
307-
loaded_object = None
308-
if entrypoint in self._agent_loaders:
309-
loaded_object = self._agent_loaders[entrypoint].get_loaded_object()
310-
311306
return UiPathOpenAIAgentRuntime(
312307
agent=agent,
313308
runtime_id=runtime_id,
314309
entrypoint=entrypoint,
315310
storage_path=storage_path,
316-
loaded_object=loaded_object,
317311
storage=storage,
318312
)
319313

packages/uipath-openai-agents/src/uipath_openai_agents/runtime/runtime.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ def __init__(
4141
runtime_id: str | None = None,
4242
entrypoint: str | None = None,
4343
storage_path: str | None = None,
44-
loaded_object: Any | None = None,
4544
storage: SqliteAgentStorage | None = None,
4645
):
4746
"""
@@ -52,14 +51,12 @@ def __init__(
5251
runtime_id: Unique identifier for this runtime instance
5352
entrypoint: Optional entrypoint name (for schema generation)
5453
storage_path: Path to SQLite database for session persistence
55-
loaded_object: Original loaded object (for schema inference)
5654
storage: Optional storage instance for state persistence
5755
"""
5856
self.agent: Agent = agent
5957
self.runtime_id: str = runtime_id or "default"
6058
self.entrypoint: str | None = entrypoint
6159
self.storage_path: str | None = storage_path
62-
self.loaded_object: Any | None = loaded_object
6360
self.storage: SqliteAgentStorage | None = storage
6461

6562
# Configure OpenAI Agents SDK to use Responses API
@@ -477,7 +474,7 @@ async def get_schema(self) -> UiPathRuntimeSchema:
477474
Returns:
478475
UiPathRuntimeSchema with input/output schemas and graph structure
479476
"""
480-
entrypoints_schema = get_entrypoints_schema(self.agent, self.loaded_object)
477+
entrypoints_schema = get_entrypoints_schema(self.agent)
481478

482479
return UiPathRuntimeSchema(
483480
filePath=self.entrypoint,

packages/uipath-openai-agents/src/uipath_openai_agents/runtime/schema.py

Lines changed: 7 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Schema extraction utilities for OpenAI Agents."""
22

33
import inspect
4-
from typing import Any, get_args, get_origin, get_type_hints
4+
from typing import Any, get_args, get_origin
55

66
from agents import Agent
77
from 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"] = {

packages/uipath-openai-agents/tests/test_agent_as_tools_schema.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from main import ( # type: ignore # noqa: E402
1111
TranslationInput,
1212
TranslationOutput,
13-
main,
1413
orchestrator_agent,
1514
)
1615

@@ -19,7 +18,7 @@
1918

2019
def test_agent_as_tools_input_schema():
2120
"""Test that input schema uses default messages format (OpenAI Agents pattern)."""
22-
schema = get_entrypoints_schema(orchestrator_agent, main)
21+
schema = get_entrypoints_schema(orchestrator_agent)
2322

2423
# Verify input schema structure - should use default messages
2524
assert "input" in schema
@@ -42,7 +41,7 @@ def test_agent_as_tools_input_schema():
4241

4342
def test_agent_as_tools_output_schema():
4443
"""Test that output schema is extracted from agent's output_type."""
45-
schema = get_entrypoints_schema(orchestrator_agent, main)
44+
schema = get_entrypoints_schema(orchestrator_agent)
4645

4746
# Verify output schema structure
4847
assert "output" in schema
@@ -73,7 +72,7 @@ def test_agent_as_tools_output_schema():
7372

7473
def test_agent_as_tools_schema_metadata():
7574
"""Test that schema includes model metadata from agent's output_type."""
76-
schema = get_entrypoints_schema(orchestrator_agent, main)
75+
schema = get_entrypoints_schema(orchestrator_agent)
7776

7877
# Input uses default messages format (no custom title/description)
7978
assert "input" in schema

packages/uipath-openai-agents/tests/test_integration.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from main import ( # type: ignore # noqa: E402
1313
TranslationInput,
1414
TranslationOutput,
15-
main,
1615
orchestrator_agent,
1716
)
1817

@@ -52,7 +51,7 @@ def test_error_handling():
5251

5352
def test_schema_extraction_with_new_serialization():
5453
"""Test that schema extraction works with the serialization improvements."""
55-
schema = get_entrypoints_schema(orchestrator_agent, main)
54+
schema = get_entrypoints_schema(orchestrator_agent)
5655

5756
# Verify input schema (messages format)
5857
assert "input" in schema
@@ -86,13 +85,11 @@ async def test_runtime_initialization_with_storage():
8685
entrypoint="test",
8786
storage_path=storage_path,
8887
storage=storage,
89-
loaded_object=main,
9088
)
9189

9290
# Verify runtime initialized correctly
9391
assert runtime.storage is not None
9492
assert runtime.runtime_id == "test_runtime"
95-
assert runtime.loaded_object == main
9693

9794
# Test schema generation
9895
schema = await runtime.get_schema()

packages/uipath-openai-agents/tests/test_schema_inference.py

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class OutputModel(BaseModel):
2929

3030

3131
def test_schema_inference_from_agent_output_type():
32-
"""Test that output schema is correctly inferred from agent's output_type (PRIMARY)."""
33-
schema = get_entrypoints_schema(agent_with_output_type, None)
32+
"""Test that output schema is correctly inferred from agent's output_type."""
33+
schema = get_entrypoints_schema(agent_with_output_type)
3434

3535
# Check input schema - should be default messages format
3636
assert "input" in schema
@@ -58,7 +58,7 @@ def test_schema_inference_from_agent_output_type():
5858

5959
def test_schema_fallback_without_types():
6060
"""Test that schemas fall back to defaults when no types are provided."""
61-
schema = get_entrypoints_schema(test_agent, None)
61+
schema = get_entrypoints_schema(test_agent)
6262

6363
# Should use default message-based input schema
6464
assert "input" in schema
@@ -70,8 +70,8 @@ def test_schema_fallback_without_types():
7070

7171

7272
def test_schema_with_plain_agent():
73-
"""Test schema extraction with a plain agent (no wrapper function)."""
74-
schema = get_entrypoints_schema(test_agent, test_agent)
73+
"""Test schema extraction with a plain agent."""
74+
schema = get_entrypoints_schema(test_agent)
7575

7676
# Should use default message input
7777
assert "input" in schema
@@ -80,33 +80,3 @@ def test_schema_with_plain_agent():
8080
# Should use default result output
8181
assert "output" in schema
8282
assert "result" in schema["output"]["properties"]
83-
84-
85-
class WrapperOutputModel(BaseModel):
86-
"""Output model for wrapper function test."""
87-
88-
status: str
89-
data: dict[str, str]
90-
91-
92-
async def typed_wrapper_function(message: str) -> WrapperOutputModel:
93-
"""Wrapper function with type annotations (UiPath pattern - SECONDARY)."""
94-
return WrapperOutputModel(status="success", data={})
95-
96-
97-
def test_schema_with_wrapper_function():
98-
"""Test that wrapper function output schema is used as fallback (SECONDARY)."""
99-
# Agent without output_type should fallback to wrapper function
100-
schema = get_entrypoints_schema(test_agent, typed_wrapper_function)
101-
102-
# Input should still be default messages (not extracted from wrapper)
103-
assert "input" in schema
104-
assert "message" in schema["input"]["properties"]
105-
assert "required" in schema["input"]
106-
assert "message" in schema["input"]["required"]
107-
108-
# Output should come from wrapper function (secondary pattern)
109-
assert "output" in schema
110-
assert "properties" in schema["output"]
111-
assert "status" in schema["output"]["properties"]
112-
assert "data" in schema["output"]["properties"]

0 commit comments

Comments
 (0)