Merge branch 'main' into patch-1

This commit is contained in:
Vincent Koc 2025-03-13 07:53:07 +11:00 committed by GitHub
commit 03869a75ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 80 additions and 8 deletions

View file

@ -140,7 +140,14 @@ The Agents SDK is designed to be highly flexible, allowing you to model a wide r
## Tracing
The Agents SDK automatically traces your agent runs, making it easy to track and debug the behavior of your agents. Tracing is extensible by design, supporting custom spans and a wide variety of external destinations, including [Logfire](https://logfire.pydantic.dev/docs/integrations/llms/openai/#openai-agents), [AgentOps](https://docs.agentops.ai/v1/integrations/agentssdk), [Braintrust](https://braintrust.dev/docs/guides/traces/integrations#openai-agents-sdk) and [Opik](https://www.comet.com/docs/opik/tracing/integrations/openai_agents). For more details about how to customize or disable tracing, see [Tracing](http://openai.github.io/openai-agents-python/tracing).
The Agents SDK automatically traces your agent runs, making it easy to track and debug the behavior of your agents. Tracing is extensible by design, supporting custom spans and a wide variety of external destinations, including:
- [AgentOps](https://docs.agentops.ai/v1/integrations/agentssdk)
- [Braintrust](https://braintrust.dev/docs/guides/traces/integrations#openai-agents-sdk)
- [Comet Opik](https://www.comet.com/docs/opik/tracing/integrations/openai_agents)
- [Keywords AI](https://docs.keywordsai.co/integration/development-frameworks/openai-agent)
- [Logfire](https://logfire.pydantic.dev/docs/integrations/llms/openai/#openai-agents)
For more details about how to customize or disable tracing, see [Tracing](http://openai.github.io/openai-agents-python/tracing).
## Development (only needed if you need to edit the SDK/examples)

View file

@ -13,6 +13,7 @@ The most common properties of an agent you'll configure are:
```python
from agents import Agent, ModelSettings, function_tool
@function_tool
def get_weather(city: str) -> str:
return f"The weather in {city} is sunny"
@ -20,7 +21,7 @@ agent = Agent(
name="Haiku agent",
instructions="Always respond in haiku form",
model="o3-mini",
tools=[function_tool(get_weather)],
tools=[get_weather],
)
```

View file

@ -36,6 +36,7 @@ class UserInfo: # (1)!
name: str
uid: int
@function_tool
async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) -> str: # (2)!
return f"User {wrapper.context.name} is 47 years old"
@ -44,7 +45,7 @@ async def main():
agent = Agent[UserInfo]( # (4)!
name="Assistant",
tools=[function_tool(fetch_user_age)],
tools=[fetch_user_age],
)
result = await Runner.run(

View file

@ -78,7 +78,7 @@ async def main():
# San Francisco
# Second turn
new_input = output.to_input_list() + [{"role": "user", "content": "What state is it in?"}]
new_input = result.to_input_list() + [{"role": "user", "content": "What state is it in?"}]
result = await Runner.run(agent, new_input)
print(result.final_output)
# California

View file

@ -94,3 +94,4 @@ External trace processors include:
- [Braintrust](https://braintrust.dev/docs/guides/traces/integrations#openai-agents-sdk)
- [Pydantic Logfire](https://logfire.pydantic.dev/docs/integrations/llms/openai/#openai-agents)
- [AgentOps](https://docs.agentops.ai/v1/integrations/agentssdk)
- [Keywords AI](https://docs.keywordsai.co/integration/development-frameworks/openai-agent)

View file

@ -53,7 +53,7 @@ async def math_guardrail(
return GuardrailFunctionOutput(
output_info=final_output,
tripwire_triggered=not final_output.is_math_homework,
tripwire_triggered=final_output.is_math_homework,
)

View file

@ -86,7 +86,7 @@ class InputGuardrail(Generic[TContext]):
[RunContextWrapper[TContext], Agent[Any], str | list[TResponseInputItem]],
MaybeAwaitable[GuardrailFunctionOutput],
]
"""A function that receives the the agent input and the context, and returns a
"""A function that receives the agent input and the context, and returns a
`GuardrailResult`. The result marks whether the tripwire was triggered, and can optionally
include information about the guardrail's output.
"""

View file

@ -10,15 +10,34 @@ class ModelSettings:
This class holds optional model configuration parameters (e.g. temperature,
top_p, penalties, truncation, etc.).
Not all models/providers support all of these parameters, so please check the API documentation
for the specific model and provider you are using.
"""
temperature: float | None = None
"""The temperature to use when calling the model."""
top_p: float | None = None
"""The top_p to use when calling the model."""
frequency_penalty: float | None = None
"""The frequency penalty to use when calling the model."""
presence_penalty: float | None = None
"""The presence penalty to use when calling the model."""
tool_choice: Literal["auto", "required", "none"] | str | None = None
"""The tool choice to use when calling the model."""
parallel_tool_calls: bool | None = False
"""Whether to use parallel tool calls when calling the model."""
truncation: Literal["auto", "disabled"] | None = None
"""The truncation strategy to use when calling the model."""
max_tokens: int | None = None
"""The maximum number of output tokens to generate."""
def resolve(self, override: ModelSettings | None) -> ModelSettings:
"""Produce a new ModelSettings by overlaying any non-None values from the
@ -33,4 +52,5 @@ class ModelSettings:
tool_choice=override.tool_choice or self.tool_choice,
parallel_tool_calls=override.parallel_tool_calls or self.parallel_tool_calls,
truncation=override.truncation or self.truncation,
max_tokens=override.max_tokens or self.max_tokens,
)

View file

@ -503,6 +503,7 @@ class OpenAIChatCompletionsModel(Model):
top_p=self._non_null_or_not_given(model_settings.top_p),
frequency_penalty=self._non_null_or_not_given(model_settings.frequency_penalty),
presence_penalty=self._non_null_or_not_given(model_settings.presence_penalty),
max_tokens=self._non_null_or_not_given(model_settings.max_tokens),
tool_choice=tool_choice,
response_format=response_format,
parallel_tool_calls=parallel_tool_calls,
@ -808,6 +809,13 @@ class _Converter:
"content": cls.extract_text_content(content),
}
result.append(msg_developer)
elif role == "assistant":
flush_assistant_message()
msg_assistant: ChatCompletionAssistantMessageParam = {
"role": "assistant",
"content": cls.extract_text_content(content),
}
result.append(msg_assistant)
else:
raise UserError(f"Unexpected role in easy_input_message: {role}")

View file

@ -235,6 +235,7 @@ class OpenAIResponsesModel(Model):
temperature=self._non_null_or_not_given(model_settings.temperature),
top_p=self._non_null_or_not_given(model_settings.top_p),
truncation=self._non_null_or_not_given(model_settings.truncation),
max_output_tokens=self._non_null_or_not_given(model_settings.max_tokens),
tool_choice=tool_choice,
parallel_tool_calls=parallel_tool_calls,
stream=stream,

View file

@ -216,5 +216,3 @@ class RunResultStreaming(RunResultBase):
if self._output_guardrails_task and not self._output_guardrails_task.done():
self._output_guardrails_task.cancel()
self._output_guardrails_task.cancel()
self._output_guardrails_task.cancel()

View file

@ -393,3 +393,38 @@ def test_unknown_object_errors():
with pytest.raises(UserError, match="Unhandled item type or structure"):
# Purposely ignore the type error
_Converter.items_to_messages([TestObject()]) # type: ignore
def test_assistant_messages_in_history():
"""
Test that assistant messages are added to the history.
"""
messages = _Converter.items_to_messages(
[
{
"role": "user",
"content": "Hello",
},
{
"role": "assistant",
"content": "Hello?",
},
{
"role": "user",
"content": "What was my Name?",
},
]
)
assert messages == [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hello?"},
{"role": "user", "content": "What was my Name?"},
]
assert len(messages) == 3
assert messages[0]["role"] == "user"
assert messages[0]["content"] == "Hello"
assert messages[1]["role"] == "assistant"
assert messages[1]["content"] == "Hello?"
assert messages[2]["role"] == "user"
assert messages[2]["content"] == "What was my Name?"