chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from agents import Agent, RunConfig, Runner, ToolExecutionConfig, ToolNotFoundBehavior
|
||||
from agents.model_settings import ModelSettings
|
||||
from agents.models.interface import Model, ModelProvider
|
||||
|
||||
from .fake_model import FakeModel
|
||||
from .test_responses import get_text_message
|
||||
|
||||
|
||||
class DummyProvider(ModelProvider):
|
||||
"""A simple model provider that always returns the same model, and
|
||||
records the model name it was asked to provide."""
|
||||
|
||||
def __init__(self, model_to_return: Model | None = None) -> None:
|
||||
self.last_requested: str | None = None
|
||||
self.model_to_return: Model = model_to_return or FakeModel()
|
||||
|
||||
def get_model(self, model_name: str | None) -> Model:
|
||||
# record the requested model name and return our test model
|
||||
self.last_requested = model_name
|
||||
return self.model_to_return
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_provider_on_run_config_is_used_for_agent_model_name() -> None:
|
||||
"""
|
||||
When the agent's ``model`` attribute is a string and no explicit model override is
|
||||
provided in the ``RunConfig``, the ``Runner`` should resolve the model using the
|
||||
``model_provider`` on the ``RunConfig``.
|
||||
"""
|
||||
fake_model = FakeModel(initial_output=[get_text_message("from-provider")])
|
||||
provider = DummyProvider(model_to_return=fake_model)
|
||||
agent = Agent(name="test", model="test-model")
|
||||
run_config = RunConfig(model_provider=provider)
|
||||
result = await Runner.run(agent, input="any", run_config=run_config)
|
||||
# We picked up the model from our dummy provider
|
||||
assert provider.last_requested == "test-model"
|
||||
assert result.final_output == "from-provider"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_config_model_name_override_takes_precedence() -> None:
|
||||
"""
|
||||
When a model name string is set on the RunConfig, then that name should be looked up
|
||||
using the RunConfig's model_provider, and should override any model on the agent.
|
||||
"""
|
||||
fake_model = FakeModel(initial_output=[get_text_message("override-name")])
|
||||
provider = DummyProvider(model_to_return=fake_model)
|
||||
agent = Agent(name="test", model="agent-model")
|
||||
run_config = RunConfig(model="override-name", model_provider=provider)
|
||||
result = await Runner.run(agent, input="any", run_config=run_config)
|
||||
# We should have requested the override name, not the agent.model
|
||||
assert provider.last_requested == "override-name"
|
||||
assert result.final_output == "override-name"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
("model_name", "reasoning_effort"),
|
||||
[("gpt-5", "low"), ("gpt-5.6", "none")],
|
||||
)
|
||||
async def test_run_config_model_name_override_uses_model_specific_default_settings(
|
||||
monkeypatch,
|
||||
model_name,
|
||||
reasoning_effort,
|
||||
) -> None:
|
||||
"""
|
||||
When RunConfig sets a model name, implicit settings should match that model name rather
|
||||
than the default fallback model.
|
||||
"""
|
||||
monkeypatch.setenv("OPENAI_DEFAULT_MODEL", "gpt-5.4-mini")
|
||||
fake_model = FakeModel(initial_output=[get_text_message("override-name")])
|
||||
provider = DummyProvider(model_to_return=fake_model)
|
||||
agent = Agent(name="test")
|
||||
run_config = RunConfig(model=model_name, model_provider=provider)
|
||||
result = await Runner.run(agent, input="any", run_config=run_config)
|
||||
assert result.final_output == "override-name"
|
||||
assert fake_model.first_turn_args is not None
|
||||
model_settings = fake_model.first_turn_args["model_settings"]
|
||||
assert model_settings.reasoning.effort == reasoning_effort
|
||||
assert model_settings.verbosity == "low"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_config_model_settings_override_implicit_model_specific_defaults(
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
"""
|
||||
RunConfig model settings should overlay the implicit defaults for the resolved model name.
|
||||
"""
|
||||
monkeypatch.setenv("OPENAI_DEFAULT_MODEL", "gpt-5.4-mini")
|
||||
fake_model = FakeModel(initial_output=[get_text_message("override-name")])
|
||||
provider = DummyProvider(model_to_return=fake_model)
|
||||
agent = Agent(name="test")
|
||||
run_config = RunConfig(
|
||||
model="gpt-5",
|
||||
model_provider=provider,
|
||||
model_settings=ModelSettings(temperature=0.3),
|
||||
)
|
||||
result = await Runner.run(agent, input="any", run_config=run_config)
|
||||
assert result.final_output == "override-name"
|
||||
assert fake_model.first_turn_args is not None
|
||||
model_settings = fake_model.first_turn_args["model_settings"]
|
||||
assert model_settings.reasoning.effort == "low"
|
||||
assert model_settings.verbosity == "low"
|
||||
assert model_settings.temperature == 0.3
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_config_model_override_object_takes_precedence() -> None:
|
||||
"""
|
||||
When a concrete Model instance is set on the RunConfig, then that instance should be
|
||||
returned by AgentRunner._get_model regardless of the agent's model.
|
||||
"""
|
||||
fake_model = FakeModel(initial_output=[get_text_message("override-object")])
|
||||
agent = Agent(name="test", model="agent-model")
|
||||
run_config = RunConfig(model=fake_model)
|
||||
result = await Runner.run(agent, input="any", run_config=run_config)
|
||||
# Our FakeModel on the RunConfig should have been used.
|
||||
assert result.final_output == "override-object"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_agent_model_object_is_used_when_present() -> None:
|
||||
"""
|
||||
If the agent has a concrete Model object set as its model, and the RunConfig does
|
||||
not specify a model override, then that object should be used directly without
|
||||
consulting the RunConfig's model_provider.
|
||||
"""
|
||||
fake_model = FakeModel(initial_output=[get_text_message("from-agent-object")])
|
||||
provider = DummyProvider()
|
||||
agent = Agent(name="test", model=fake_model)
|
||||
run_config = RunConfig(model_provider=provider)
|
||||
result = await Runner.run(agent, input="any", run_config=run_config)
|
||||
# The dummy provider should never have been called, and the output should come from
|
||||
# the FakeModel on the agent.
|
||||
assert provider.last_requested is None
|
||||
assert result.final_output == "from-agent-object"
|
||||
|
||||
|
||||
def test_trace_include_sensitive_data_defaults_to_true_when_env_not_set(monkeypatch):
|
||||
"""By default, trace_include_sensitive_data should be True when the env is not set."""
|
||||
monkeypatch.delenv("OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA", raising=False)
|
||||
config = RunConfig()
|
||||
assert config.trace_include_sensitive_data is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"env_value,expected",
|
||||
[
|
||||
("true", True),
|
||||
("True", True),
|
||||
("1", True),
|
||||
("yes", True),
|
||||
("on", True),
|
||||
("false", False),
|
||||
("False", False),
|
||||
("0", False),
|
||||
("no", False),
|
||||
("off", False),
|
||||
],
|
||||
ids=[
|
||||
"lowercase-true",
|
||||
"capital-True",
|
||||
"numeric-1",
|
||||
"text-yes",
|
||||
"text-on",
|
||||
"lowercase-false",
|
||||
"capital-False",
|
||||
"numeric-0",
|
||||
"text-no",
|
||||
"text-off",
|
||||
],
|
||||
)
|
||||
def test_trace_include_sensitive_data_follows_env_value(env_value, expected, monkeypatch):
|
||||
"""trace_include_sensitive_data should follow the environment variable if not explicitly set."""
|
||||
monkeypatch.setenv("OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA", env_value)
|
||||
config = RunConfig()
|
||||
assert config.trace_include_sensitive_data is expected
|
||||
|
||||
|
||||
def test_trace_include_sensitive_data_explicit_override_takes_precedence(monkeypatch):
|
||||
"""Explicit value passed to RunConfig should take precedence over the environment variable."""
|
||||
monkeypatch.setenv("OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA", "false")
|
||||
config = RunConfig(trace_include_sensitive_data=True)
|
||||
assert config.trace_include_sensitive_data is True
|
||||
|
||||
monkeypatch.setenv("OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA", "true")
|
||||
config = RunConfig(trace_include_sensitive_data=False)
|
||||
assert config.trace_include_sensitive_data is False
|
||||
|
||||
|
||||
def test_tool_execution_config_rejects_invalid_function_tool_concurrency() -> None:
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="tool_execution.max_function_tool_concurrency must be at least 1",
|
||||
):
|
||||
ToolExecutionConfig(max_function_tool_concurrency=0)
|
||||
|
||||
|
||||
def test_tool_execution_config_is_public_from_agents_package() -> None:
|
||||
config = RunConfig(tool_execution=ToolExecutionConfig(max_function_tool_concurrency=2))
|
||||
|
||||
assert config.tool_execution is not None
|
||||
assert config.tool_execution.max_function_tool_concurrency == 2
|
||||
|
||||
|
||||
def test_tool_not_found_behavior_defaults_to_raise_error() -> None:
|
||||
config = RunConfig()
|
||||
|
||||
assert config.tool_not_found_behavior == "raise_error"
|
||||
|
||||
|
||||
def test_tool_not_found_behavior_is_public_from_agents_package() -> None:
|
||||
behavior: ToolNotFoundBehavior = "return_error_to_model"
|
||||
config = RunConfig(tool_not_found_behavior=behavior)
|
||||
|
||||
assert config.tool_not_found_behavior == "return_error_to_model"
|
||||
Reference in New Issue
Block a user