Skip to content
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openai-agents"
version = "0.17.2"
version = "0.17.3"
description = "OpenAI Agents SDK"
readme = "README.md"
requires-python = ">=3.10"
Expand Down
23 changes: 11 additions & 12 deletions src/agents/extensions/models/any_llm_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
response_terminal_failure_error,
)
from ...models._retry_runtime import should_disable_provider_managed_retries
from ...models._trace import model_config_for_trace
from ...models.chatcmpl_converter import Converter
from ...models.chatcmpl_helpers import HEADERS, HEADERS_OVERRIDE, ChatCmplHelpers
from ...models.chatcmpl_stream_handler import ChatCmplStreamHandler
Expand Down Expand Up @@ -467,12 +468,11 @@ async def _get_response_via_chat(
) -> ModelResponse:
with generation_span(
model=str(self.model),
model_config=model_settings.to_json_dict()
| {
"base_url": str(self.base_url or ""),
"provider": self._provider_name,
"model_impl": "any-llm",
},
model_config=model_config_for_trace(
model_settings,
base_url=self.base_url or "",
extra_config={"provider": self._provider_name, "model_impl": "any-llm"},
),
disabled=tracing.is_disabled(),
) as span_generation:
response = await self._fetch_chat_response(
Expand Down Expand Up @@ -570,12 +570,11 @@ async def _stream_response_via_chat(
) -> AsyncIterator[TResponseStreamEvent]:
with generation_span(
model=str(self.model),
model_config=model_settings.to_json_dict()
| {
"base_url": str(self.base_url or ""),
"provider": self._provider_name,
"model_impl": "any-llm",
},
model_config=model_config_for_trace(
model_settings,
base_url=self.base_url or "",
extra_config={"provider": self._provider_name, "model_impl": "any-llm"},
),
disabled=tracing.is_disabled(),
) as span_generation:
response, stream = await self._fetch_chat_response(
Expand Down
15 changes: 11 additions & 4 deletions src/agents/extensions/models/litellm_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from ...model_settings import ModelSettings
from ...models._openai_retry import get_openai_retry_advice
from ...models._retry_runtime import should_disable_provider_managed_retries
from ...models._trace import model_config_for_trace
from ...models.chatcmpl_converter import Converter
from ...models.chatcmpl_helpers import HEADERS, HEADERS_OVERRIDE, ChatCmplHelpers
from ...models.chatcmpl_stream_handler import ChatCmplStreamHandler
Expand Down Expand Up @@ -213,8 +214,11 @@ async def get_response(
) -> ModelResponse:
with generation_span(
model=str(self.model),
model_config=model_settings.to_json_dict()
| {"base_url": str(self.base_url or ""), "model_impl": "litellm"},
model_config=model_config_for_trace(
model_settings,
base_url=self.base_url or "",
extra_config={"model_impl": "litellm"},
),
disabled=tracing.is_disabled(),
) as span_generation:
response = await self._fetch_response(
Expand Down Expand Up @@ -327,8 +331,11 @@ async def stream_response(
) -> AsyncIterator[TResponseStreamEvent]:
with generation_span(
model=str(self.model),
model_config=model_settings.to_json_dict()
| {"base_url": str(self.base_url or ""), "model_impl": "litellm"},
model_config=model_config_for_trace(
model_settings,
base_url=self.base_url or "",
extra_config={"model_impl": "litellm"},
),
disabled=tracing.is_disabled(),
) as span_generation:
response, stream = await self._fetch_response(
Expand Down
7 changes: 4 additions & 3 deletions src/agents/mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _create_default_streamable_http_client(
timeout: httpx.Timeout | None = None,
auth: httpx.Auth | None = None,
) -> httpx.AsyncClient:
kwargs: dict[str, Any] = {"follow_redirects": True}
kwargs: dict[str, Any] = {"follow_redirects": False}
if timeout is not None:
kwargs["timeout"] = timeout
if headers is not None:
Expand Down Expand Up @@ -1441,8 +1441,9 @@ def create_streams(
auth=self.params.get("auth"),
transport_factory=_InitializedNotificationTolerantStreamableHTTPTransport,
)
if httpx_client_factory is not None:
kwargs["httpx_client_factory"] = httpx_client_factory
kwargs["httpx_client_factory"] = (
httpx_client_factory or _create_default_streamable_http_client
)
if "auth" in self.params:
kwargs["auth"] = self.params["auth"]
return streamablehttp_client(**kwargs)
Expand Down
26 changes: 26 additions & 0 deletions src/agents/model_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,27 @@ class MCPToolChoice:
Headers: TypeAlias = Mapping[str, str | Omit]
ToolChoice: TypeAlias = Literal["auto", "required", "none"] | str | MCPToolChoice | None

_TRACEABLE_MODEL_SETTING_FIELDS = (
"temperature",
"top_p",
"frequency_penalty",
"presence_penalty",
"tool_choice",
"parallel_tool_calls",
"truncation",
"max_tokens",
"reasoning",
"verbosity",
"metadata",
"store",
"prompt_cache_retention",
"include_usage",
"response_include",
"top_logprobs",
"retry",
"context_management",
)


@dataclass
class ModelSettings:
Expand Down Expand Up @@ -199,6 +220,11 @@ def resolve(self, override: ModelSettings | None) -> ModelSettings:
def to_json_dict(self) -> dict[str, Any]:
return cast(dict[str, Any], TypeAdapter(ModelSettings).dump_python(self, mode="json"))

def to_traceable_dict(self) -> dict[str, Any]:
"""Serialize settings for tracing without provider-specific request extras."""
payload = self.to_json_dict()
return {key: payload[key] for key in _TRACEABLE_MODEL_SETTING_FIELDS if key in payload}


def _merge_retry_settings(
inherited: ModelRetrySettings | None,
Expand Down
31 changes: 31 additions & 0 deletions src/agents/models/_trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from typing import Any
from urllib.parse import urlsplit, urlunsplit

from ..model_settings import ModelSettings


def sanitize_url_for_trace(url: object) -> str:
"""Return a URL safe for tracing by removing auth material and request parameters."""
try:
parts = urlsplit(str(url))
except ValueError:
return ""

netloc = parts.netloc.rsplit("@", 1)[-1]
return urlunsplit((parts.scheme, netloc, parts.path, "", ""))


def model_config_for_trace(
model_settings: ModelSettings,
*,
base_url: object | None = None,
extra_config: dict[str, Any] | None = None,
) -> dict[str, Any]:
config = model_settings.to_traceable_dict()
if base_url is not None:
config["base_url"] = sanitize_url_for_trace(base_url)
if extra_config:
config.update(extra_config)
return config
5 changes: 3 additions & 2 deletions src/agents/models/openai_chatcompletions.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from ..util._json import _to_dump_compatible
from ._openai_retry import get_openai_retry_advice
from ._retry_runtime import should_disable_provider_managed_retries
from ._trace import model_config_for_trace
from .chatcmpl_converter import Converter
from .chatcmpl_helpers import HEADERS, HEADERS_OVERRIDE, ChatCmplHelpers
from .chatcmpl_stream_handler import ChatCmplStreamHandler
Expand Down Expand Up @@ -147,7 +148,7 @@ async def get_response(

with generation_span(
model=str(self.model),
model_config=model_settings.to_json_dict() | {"base_url": str(self._client.base_url)},
model_config=model_config_for_trace(model_settings, base_url=self._client.base_url),
disabled=tracing.is_disabled(),
) as span_generation:
response = await self._fetch_response(
Expand Down Expand Up @@ -281,7 +282,7 @@ async def stream_response(

with generation_span(
model=str(self.model),
model_config=model_settings.to_json_dict() | {"base_url": str(self._client.base_url)},
model_config=model_config_for_trace(model_settings, base_url=self._client.base_url),
disabled=tracing.is_disabled(),
) as span_generation:
response, stream = await self._fetch_response(
Expand Down
Loading
Loading