Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a utils directory #195

Merged
merged 3 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ mypy:
tests:
uv run pytest

.PHONY: snapshots-fix
snapshots-fix:
uv run pytest --inline-snapshot=fix

.PHONY: snapshots-create
snapshots-create:
uv run pytest --inline-snapshot=create

.PHONY: old_version_tests
old_version_tests:
UV_PROJECT_ENVIRONMENT=.venv_39 uv run --python 3.9 -m pytest
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/hello_world_jupyter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
agent = Agent(name="Assistant", instructions="You are a helpful assistant")

# Intended for Jupyter notebooks where there's an existing event loop
result = await Runner.run(agent, "Write a haiku about recursion in programming.") # type: ignore[top-level-await] # noqa: F704
result = await Runner.run(agent, "Write a haiku about recursion in programming.") # type: ignore[top-level-await] # noqa: F704
print(result.final_output)

# Code within code loops,
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ dev = [
"mkdocstrings[python]>=0.28.0",
"coverage>=7.6.12",
"playwright==1.50.0",
"inline-snapshot>=0.20.7",
]
[tool.uv.workspace]
members = ["agents"]
Expand Down Expand Up @@ -116,4 +117,7 @@ filterwarnings = [
]
markers = [
"allow_call_model_methods: mark test as allowing calls to real model implementations",
]
]

[tool.inline-snapshot]
format-command="ruff format --stdin-filename {filename}"
24 changes: 12 additions & 12 deletions src/agents/_run_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from openai.types.responses.response_input_param import ComputerCallOutput
from openai.types.responses.response_reasoning_item import ResponseReasoningItem

from . import _utils
from .agent import Agent
from .agent_output import AgentOutputSchema
from .computer import AsyncComputer, Computer
Expand Down Expand Up @@ -59,6 +58,7 @@
handoff_span,
trace,
)
from .util import _coro, _error_tracing

if TYPE_CHECKING:
from .run import RunConfig
Expand Down Expand Up @@ -293,7 +293,7 @@ def process_model_response(
elif isinstance(output, ResponseComputerToolCall):
items.append(ToolCallItem(raw_item=output, agent=agent))
if not computer_tool:
_utils.attach_error_to_current_span(
_error_tracing.attach_error_to_current_span(
SpanError(
message="Computer tool not found",
data={},
Expand Down Expand Up @@ -324,7 +324,7 @@ def process_model_response(
# Regular function tool call
else:
if output.name not in function_map:
_utils.attach_error_to_current_span(
_error_tracing.attach_error_to_current_span(
SpanError(
message="Tool not found",
data={"tool_name": output.name},
Expand Down Expand Up @@ -368,7 +368,7 @@ async def run_single_tool(
(
agent.hooks.on_tool_start(context_wrapper, agent, func_tool)
if agent.hooks
else _utils.noop_coroutine()
else _coro.noop_coroutine()
),
func_tool.on_invoke_tool(context_wrapper, tool_call.arguments),
)
Expand All @@ -378,11 +378,11 @@ async def run_single_tool(
(
agent.hooks.on_tool_end(context_wrapper, agent, func_tool, result)
if agent.hooks
else _utils.noop_coroutine()
else _coro.noop_coroutine()
),
)
except Exception as e:
_utils.attach_error_to_current_span(
_error_tracing.attach_error_to_current_span(
SpanError(
message="Error running tool",
data={"tool_name": func_tool.name, "error": str(e)},
Expand Down Expand Up @@ -502,7 +502,7 @@ async def execute_handoffs(
source=agent,
)
if agent.hooks
else _utils.noop_coroutine()
else _coro.noop_coroutine()
),
)

Expand All @@ -520,7 +520,7 @@ async def execute_handoffs(
new_items=tuple(new_step_items),
)
if not callable(input_filter):
_utils.attach_error_to_span(
_error_tracing.attach_error_to_span(
span_handoff,
SpanError(
message="Invalid input filter",
Expand All @@ -530,7 +530,7 @@ async def execute_handoffs(
raise UserError(f"Invalid input filter: {input_filter}")
filtered = input_filter(handoff_input_data)
if not isinstance(filtered, HandoffInputData):
_utils.attach_error_to_span(
_error_tracing.attach_error_to_span(
span_handoff,
SpanError(
message="Invalid input filter result",
Expand Down Expand Up @@ -591,7 +591,7 @@ async def run_final_output_hooks(
hooks.on_agent_end(context_wrapper, agent, final_output),
agent.hooks.on_end(context_wrapper, agent, final_output)
if agent.hooks
else _utils.noop_coroutine(),
else _coro.noop_coroutine(),
)

@classmethod
Expand Down Expand Up @@ -706,7 +706,7 @@ async def execute(
(
agent.hooks.on_tool_start(context_wrapper, agent, action.computer_tool)
if agent.hooks
else _utils.noop_coroutine()
else _coro.noop_coroutine()
),
output_func,
)
Expand All @@ -716,7 +716,7 @@ async def execute(
(
agent.hooks.on_tool_end(context_wrapper, agent, action.computer_tool, output)
if agent.hooks
else _utils.noop_coroutine()
else _coro.noop_coroutine()
),
)

Expand Down
61 changes: 0 additions & 61 deletions src/agents/_utils.py

This file was deleted.

6 changes: 3 additions & 3 deletions src/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, Callable, Generic, cast

from . import _utils
from ._utils import MaybeAwaitable
from .guardrail import InputGuardrail, OutputGuardrail
from .handoffs import Handoff
from .items import ItemHelpers
Expand All @@ -16,6 +14,8 @@
from .models.interface import Model
from .run_context import RunContextWrapper, TContext
from .tool import Tool, function_tool
from .util import _transforms
from .util._types import MaybeAwaitable

if TYPE_CHECKING:
from .lifecycle import AgentHooks
Expand Down Expand Up @@ -126,7 +126,7 @@ def as_tool(
"""

@function_tool(
name_override=tool_name or _utils.transform_string_function_style(self.name),
name_override=tool_name or _transforms.transform_string_function_style(self.name),
description_override=tool_description or "",
)
async def run_agent(context: RunContextWrapper, input: str) -> str:
Expand Down
8 changes: 4 additions & 4 deletions src/agents/agent_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from pydantic import BaseModel, TypeAdapter
from typing_extensions import TypedDict, get_args, get_origin

from . import _utils
from .exceptions import ModelBehaviorError, UserError
from .strict_schema import ensure_strict_json_schema
from .tracing import SpanError
from .util import _error_tracing, _json

_WRAPPER_DICT_KEY = "response"

Expand Down Expand Up @@ -87,10 +87,10 @@ def validate_json(self, json_str: str, partial: bool = False) -> Any:
"""Validate a JSON string against the output type. Returns the validated object, or raises
a `ModelBehaviorError` if the JSON is invalid.
"""
validated = _utils.validate_json(json_str, self._type_adapter, partial)
validated = _json.validate_json(json_str, self._type_adapter, partial)
if self._is_wrapped:
if not isinstance(validated, dict):
_utils.attach_error_to_current_span(
_error_tracing.attach_error_to_current_span(
SpanError(
message="Invalid JSON",
data={"details": f"Expected a dict, got {type(validated)}"},
Expand All @@ -101,7 +101,7 @@ def validate_json(self, json_str: str, partial: bool = False) -> Any:
)

if _WRAPPER_DICT_KEY not in validated:
_utils.attach_error_to_current_span(
_error_tracing.attach_error_to_current_span(
SpanError(
message="Invalid JSON",
data={"details": f"Could not find key {_WRAPPER_DICT_KEY} in JSON"},
Expand Down
2 changes: 1 addition & 1 deletion src/agents/guardrail.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

from typing_extensions import TypeVar

from ._utils import MaybeAwaitable
from .exceptions import UserError
from .items import TResponseInputItem
from .run_context import RunContextWrapper, TContext
from .util._types import MaybeAwaitable

if TYPE_CHECKING:
from .agent import Agent
Expand Down
8 changes: 4 additions & 4 deletions src/agents/handoffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
from pydantic import TypeAdapter
from typing_extensions import TypeAlias, TypeVar

from . import _utils
from .exceptions import ModelBehaviorError, UserError
from .items import RunItem, TResponseInputItem
from .run_context import RunContextWrapper, TContext
from .strict_schema import ensure_strict_json_schema
from .tracing.spans import SpanError
from .util import _error_tracing, _json, _transforms

if TYPE_CHECKING:
from .agent import Agent
Expand Down Expand Up @@ -104,7 +104,7 @@ def get_transfer_message(self, agent: Agent[Any]) -> str:

@classmethod
def default_tool_name(cls, agent: Agent[Any]) -> str:
return _utils.transform_string_function_style(f"transfer_to_{agent.name}")
return _transforms.transform_string_function_style(f"transfer_to_{agent.name}")

@classmethod
def default_tool_description(cls, agent: Agent[Any]) -> str:
Expand Down Expand Up @@ -192,15 +192,15 @@ async def _invoke_handoff(
) -> Agent[Any]:
if input_type is not None and type_adapter is not None:
if input_json is None:
_utils.attach_error_to_current_span(
_error_tracing.attach_error_to_current_span(
SpanError(
message="Handoff function expected non-null input, but got None",
data={"details": "input_json is None"},
)
)
raise ModelBehaviorError("Handoff function expected non-null input, but got None")

validated_input = _utils.validate_json(
validated_input = _json.validate_json(
json_str=input_json,
type_adapter=type_adapter,
partial=False,
Expand Down
7 changes: 7 additions & 0 deletions src/agents/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .logger import logger
from .stream_events import StreamEvent
from .tracing import Trace
from .util._pretty_print import pretty_print_result, pretty_print_run_result_streaming

if TYPE_CHECKING:
from ._run_impl import QueueCompleteSentinel
Expand Down Expand Up @@ -89,6 +90,9 @@ def last_agent(self) -> Agent[Any]:
"""The last agent that was run."""
return self._last_agent

def __str__(self) -> str:
return pretty_print_result(self)


@dataclass
class RunResultStreaming(RunResultBase):
Expand Down Expand Up @@ -216,3 +220,6 @@ def _cleanup_tasks(self):

if self._output_guardrails_task and not self._output_guardrails_task.done():
self._output_guardrails_task.cancel()

def __str__(self) -> str:
return pretty_print_run_result_streaming(self)
Loading