openai-agents 0.3.1__py3-none-any.whl → 0.3.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of openai-agents might be problematic. Click here for more details.
- agents/__init__.py +25 -1
- agents/_run_impl.py +236 -20
- agents/exceptions.py +35 -0
- agents/extensions/memory/__init__.py +23 -0
- agents/extensions/memory/advanced_sqlite_session.py +1285 -0
- agents/extensions/memory/redis_session.py +267 -0
- agents/extensions/models/litellm_model.py +122 -6
- agents/models/chatcmpl_converter.py +31 -16
- agents/models/chatcmpl_helpers.py +2 -2
- agents/models/openai_chatcompletions.py +6 -6
- agents/models/openai_responses.py +8 -8
- agents/realtime/session.py +2 -0
- agents/result.py +7 -0
- agents/run.py +31 -7
- agents/tool.py +8 -0
- agents/tool_context.py +14 -1
- agents/tool_guardrails.py +279 -0
- {openai_agents-0.3.1.dist-info → openai_agents-0.3.3.dist-info}/METADATA +13 -2
- {openai_agents-0.3.1.dist-info → openai_agents-0.3.3.dist-info}/RECORD +21 -18
- {openai_agents-0.3.1.dist-info → openai_agents-0.3.3.dist-info}/WHEEL +0 -0
- {openai_agents-0.3.1.dist-info → openai_agents-0.3.3.dist-info}/licenses/LICENSE +0 -0
agents/run.py
CHANGED
|
@@ -53,7 +53,7 @@ from .items import (
|
|
|
53
53
|
ToolCallItemTypes,
|
|
54
54
|
TResponseInputItem,
|
|
55
55
|
)
|
|
56
|
-
from .lifecycle import RunHooks
|
|
56
|
+
from .lifecycle import AgentHooksBase, RunHooks, RunHooksBase
|
|
57
57
|
from .logger import logger
|
|
58
58
|
from .memory import Session, SessionInputCallback
|
|
59
59
|
from .model_settings import ModelSettings
|
|
@@ -68,6 +68,7 @@ from .stream_events import (
|
|
|
68
68
|
StreamEvent,
|
|
69
69
|
)
|
|
70
70
|
from .tool import Tool
|
|
71
|
+
from .tool_guardrails import ToolInputGuardrailResult, ToolOutputGuardrailResult
|
|
71
72
|
from .tracing import Span, SpanError, agent_span, get_current_trace, trace
|
|
72
73
|
from .tracing.span_data import AgentSpanData
|
|
73
74
|
from .usage import Usage
|
|
@@ -461,13 +462,11 @@ class AgentRunner:
|
|
|
461
462
|
) -> RunResult:
|
|
462
463
|
context = kwargs.get("context")
|
|
463
464
|
max_turns = kwargs.get("max_turns", DEFAULT_MAX_TURNS)
|
|
464
|
-
hooks = kwargs.get("hooks")
|
|
465
|
+
hooks = cast(RunHooks[TContext], self._validate_run_hooks(kwargs.get("hooks")))
|
|
465
466
|
run_config = kwargs.get("run_config")
|
|
466
467
|
previous_response_id = kwargs.get("previous_response_id")
|
|
467
468
|
conversation_id = kwargs.get("conversation_id")
|
|
468
469
|
session = kwargs.get("session")
|
|
469
|
-
if hooks is None:
|
|
470
|
-
hooks = RunHooks[Any]()
|
|
471
470
|
if run_config is None:
|
|
472
471
|
run_config = RunConfig()
|
|
473
472
|
|
|
@@ -496,6 +495,8 @@ class AgentRunner:
|
|
|
496
495
|
)
|
|
497
496
|
|
|
498
497
|
input_guardrail_results: list[InputGuardrailResult] = []
|
|
498
|
+
tool_input_guardrail_results: list[ToolInputGuardrailResult] = []
|
|
499
|
+
tool_output_guardrail_results: list[ToolOutputGuardrailResult] = []
|
|
499
500
|
|
|
500
501
|
current_span: Span[AgentSpanData] | None = None
|
|
501
502
|
current_agent = starting_agent
|
|
@@ -586,6 +587,10 @@ class AgentRunner:
|
|
|
586
587
|
original_input = turn_result.original_input
|
|
587
588
|
generated_items = turn_result.generated_items
|
|
588
589
|
|
|
590
|
+
# Collect tool guardrail results from this turn
|
|
591
|
+
tool_input_guardrail_results.extend(turn_result.tool_input_guardrail_results)
|
|
592
|
+
tool_output_guardrail_results.extend(turn_result.tool_output_guardrail_results)
|
|
593
|
+
|
|
589
594
|
if isinstance(turn_result.next_step, NextStepFinalOutput):
|
|
590
595
|
output_guardrail_results = await self._run_output_guardrails(
|
|
591
596
|
current_agent.output_guardrails + (run_config.output_guardrails or []),
|
|
@@ -601,6 +606,8 @@ class AgentRunner:
|
|
|
601
606
|
_last_agent=current_agent,
|
|
602
607
|
input_guardrail_results=input_guardrail_results,
|
|
603
608
|
output_guardrail_results=output_guardrail_results,
|
|
609
|
+
tool_input_guardrail_results=tool_input_guardrail_results,
|
|
610
|
+
tool_output_guardrail_results=tool_output_guardrail_results,
|
|
604
611
|
context_wrapper=context_wrapper,
|
|
605
612
|
)
|
|
606
613
|
await self._save_result_to_session(session, [], turn_result.new_step_items)
|
|
@@ -668,14 +675,12 @@ class AgentRunner:
|
|
|
668
675
|
) -> RunResultStreaming:
|
|
669
676
|
context = kwargs.get("context")
|
|
670
677
|
max_turns = kwargs.get("max_turns", DEFAULT_MAX_TURNS)
|
|
671
|
-
hooks = kwargs.get("hooks")
|
|
678
|
+
hooks = cast(RunHooks[TContext], self._validate_run_hooks(kwargs.get("hooks")))
|
|
672
679
|
run_config = kwargs.get("run_config")
|
|
673
680
|
previous_response_id = kwargs.get("previous_response_id")
|
|
674
681
|
conversation_id = kwargs.get("conversation_id")
|
|
675
682
|
session = kwargs.get("session")
|
|
676
683
|
|
|
677
|
-
if hooks is None:
|
|
678
|
-
hooks = RunHooks[Any]()
|
|
679
684
|
if run_config is None:
|
|
680
685
|
run_config = RunConfig()
|
|
681
686
|
|
|
@@ -710,6 +715,8 @@ class AgentRunner:
|
|
|
710
715
|
max_turns=max_turns,
|
|
711
716
|
input_guardrail_results=[],
|
|
712
717
|
output_guardrail_results=[],
|
|
718
|
+
tool_input_guardrail_results=[],
|
|
719
|
+
tool_output_guardrail_results=[],
|
|
713
720
|
_current_agent_output_schema=output_schema,
|
|
714
721
|
trace=new_trace,
|
|
715
722
|
context_wrapper=context_wrapper,
|
|
@@ -732,6 +739,23 @@ class AgentRunner:
|
|
|
732
739
|
)
|
|
733
740
|
return streamed_result
|
|
734
741
|
|
|
742
|
+
@staticmethod
|
|
743
|
+
def _validate_run_hooks(
|
|
744
|
+
hooks: RunHooksBase[Any, Agent[Any]] | AgentHooksBase[Any, Agent[Any]] | Any | None,
|
|
745
|
+
) -> RunHooks[Any]:
|
|
746
|
+
if hooks is None:
|
|
747
|
+
return RunHooks[Any]()
|
|
748
|
+
input_hook_type = type(hooks).__name__
|
|
749
|
+
if isinstance(hooks, AgentHooksBase):
|
|
750
|
+
raise TypeError(
|
|
751
|
+
"Run hooks must be instances of RunHooks. "
|
|
752
|
+
f"Received agent-scoped hooks ({input_hook_type}). "
|
|
753
|
+
"Attach AgentHooks to an Agent via Agent(..., hooks=...)."
|
|
754
|
+
)
|
|
755
|
+
if not isinstance(hooks, RunHooksBase):
|
|
756
|
+
raise TypeError(f"Run hooks must be instances of RunHooks. Received {input_hook_type}.")
|
|
757
|
+
return hooks
|
|
758
|
+
|
|
735
759
|
@classmethod
|
|
736
760
|
async def _maybe_filter_model_input(
|
|
737
761
|
cls,
|
agents/tool.py
CHANGED
|
@@ -27,6 +27,7 @@ from .logger import logger
|
|
|
27
27
|
from .run_context import RunContextWrapper
|
|
28
28
|
from .strict_schema import ensure_strict_json_schema
|
|
29
29
|
from .tool_context import ToolContext
|
|
30
|
+
from .tool_guardrails import ToolInputGuardrail, ToolOutputGuardrail
|
|
30
31
|
from .tracing import SpanError
|
|
31
32
|
from .util import _error_tracing
|
|
32
33
|
from .util._types import MaybeAwaitable
|
|
@@ -94,6 +95,13 @@ class FunctionTool:
|
|
|
94
95
|
and returns whether the tool is enabled. You can use this to dynamically enable/disable a tool
|
|
95
96
|
based on your context/state."""
|
|
96
97
|
|
|
98
|
+
# Tool-specific guardrails
|
|
99
|
+
tool_input_guardrails: list[ToolInputGuardrail[Any]] | None = None
|
|
100
|
+
"""Optional list of input guardrails to run before invoking this tool."""
|
|
101
|
+
|
|
102
|
+
tool_output_guardrails: list[ToolOutputGuardrail[Any]] | None = None
|
|
103
|
+
"""Optional list of output guardrails to run after invoking this tool."""
|
|
104
|
+
|
|
97
105
|
def __post_init__(self):
|
|
98
106
|
if self.strict_json_schema:
|
|
99
107
|
self.params_json_schema = ensure_strict_json_schema(self.params_json_schema)
|
agents/tool_context.py
CHANGED
|
@@ -14,6 +14,10 @@ def _assert_must_pass_tool_name() -> str:
|
|
|
14
14
|
raise ValueError("tool_name must be passed to ToolContext")
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
def _assert_must_pass_tool_arguments() -> str:
|
|
18
|
+
raise ValueError("tool_arguments must be passed to ToolContext")
|
|
19
|
+
|
|
20
|
+
|
|
17
21
|
@dataclass
|
|
18
22
|
class ToolContext(RunContextWrapper[TContext]):
|
|
19
23
|
"""The context of a tool call."""
|
|
@@ -24,6 +28,9 @@ class ToolContext(RunContextWrapper[TContext]):
|
|
|
24
28
|
tool_call_id: str = field(default_factory=_assert_must_pass_tool_call_id)
|
|
25
29
|
"""The ID of the tool call."""
|
|
26
30
|
|
|
31
|
+
tool_arguments: str = field(default_factory=_assert_must_pass_tool_arguments)
|
|
32
|
+
"""The raw arguments string of the tool call."""
|
|
33
|
+
|
|
27
34
|
@classmethod
|
|
28
35
|
def from_agent_context(
|
|
29
36
|
cls,
|
|
@@ -39,4 +46,10 @@ class ToolContext(RunContextWrapper[TContext]):
|
|
|
39
46
|
f.name: getattr(context, f.name) for f in fields(RunContextWrapper) if f.init
|
|
40
47
|
}
|
|
41
48
|
tool_name = tool_call.name if tool_call is not None else _assert_must_pass_tool_name()
|
|
42
|
-
|
|
49
|
+
tool_args = (
|
|
50
|
+
tool_call.arguments if tool_call is not None else _assert_must_pass_tool_arguments()
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return cls(
|
|
54
|
+
tool_name=tool_name, tool_call_id=tool_call_id, tool_arguments=tool_args, **base_values
|
|
55
|
+
)
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
from collections.abc import Awaitable
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, overload
|
|
7
|
+
|
|
8
|
+
from typing_extensions import TypedDict, TypeVar
|
|
9
|
+
|
|
10
|
+
from .exceptions import UserError
|
|
11
|
+
from .tool_context import ToolContext
|
|
12
|
+
from .util._types import MaybeAwaitable
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .agent import Agent
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ToolInputGuardrailResult:
|
|
20
|
+
"""The result of a tool input guardrail run."""
|
|
21
|
+
|
|
22
|
+
guardrail: ToolInputGuardrail[Any]
|
|
23
|
+
"""The guardrail that was run."""
|
|
24
|
+
|
|
25
|
+
output: ToolGuardrailFunctionOutput
|
|
26
|
+
"""The output of the guardrail function."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class ToolOutputGuardrailResult:
|
|
31
|
+
"""The result of a tool output guardrail run."""
|
|
32
|
+
|
|
33
|
+
guardrail: ToolOutputGuardrail[Any]
|
|
34
|
+
"""The guardrail that was run."""
|
|
35
|
+
|
|
36
|
+
output: ToolGuardrailFunctionOutput
|
|
37
|
+
"""The output of the guardrail function."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RejectContentBehavior(TypedDict):
|
|
41
|
+
"""Rejects the tool call/output but continues execution with a message to the model."""
|
|
42
|
+
|
|
43
|
+
type: Literal["reject_content"]
|
|
44
|
+
message: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class RaiseExceptionBehavior(TypedDict):
|
|
48
|
+
"""Raises an exception to halt execution."""
|
|
49
|
+
|
|
50
|
+
type: Literal["raise_exception"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AllowBehavior(TypedDict):
|
|
54
|
+
"""Allows normal tool execution to continue."""
|
|
55
|
+
|
|
56
|
+
type: Literal["allow"]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class ToolGuardrailFunctionOutput:
|
|
61
|
+
"""The output of a tool guardrail function."""
|
|
62
|
+
|
|
63
|
+
output_info: Any
|
|
64
|
+
"""
|
|
65
|
+
Optional data about checks performed. For example, the guardrail could include
|
|
66
|
+
information about the checks it performed and granular results.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
behavior: RejectContentBehavior | RaiseExceptionBehavior | AllowBehavior = field(
|
|
70
|
+
default_factory=lambda: AllowBehavior(type="allow")
|
|
71
|
+
)
|
|
72
|
+
"""
|
|
73
|
+
Defines how the system should respond when this guardrail result is processed.
|
|
74
|
+
- allow: Allow normal tool execution to continue without interference (default)
|
|
75
|
+
- reject_content: Reject the tool call/output but continue execution with a message to the model
|
|
76
|
+
- raise_exception: Halt execution by raising a ToolGuardrailTripwireTriggered exception
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def allow(cls, output_info: Any = None) -> ToolGuardrailFunctionOutput:
|
|
81
|
+
"""Create a guardrail output that allows the tool execution to continue normally.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
output_info: Optional data about checks performed.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
ToolGuardrailFunctionOutput configured to allow normal execution.
|
|
88
|
+
"""
|
|
89
|
+
return cls(output_info=output_info, behavior=AllowBehavior(type="allow"))
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def reject_content(cls, message: str, output_info: Any = None) -> ToolGuardrailFunctionOutput:
|
|
93
|
+
"""Create a guardrail output that rejects the tool call/output but continues execution.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
message: Message to send to the model instead of the tool result.
|
|
97
|
+
output_info: Optional data about checks performed.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
ToolGuardrailFunctionOutput configured to reject the content.
|
|
101
|
+
"""
|
|
102
|
+
return cls(
|
|
103
|
+
output_info=output_info,
|
|
104
|
+
behavior=RejectContentBehavior(type="reject_content", message=message),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def raise_exception(cls, output_info: Any = None) -> ToolGuardrailFunctionOutput:
|
|
109
|
+
"""Create a guardrail output that raises an exception to halt execution.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
output_info: Optional data about checks performed.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
ToolGuardrailFunctionOutput configured to raise an exception.
|
|
116
|
+
"""
|
|
117
|
+
return cls(output_info=output_info, behavior=RaiseExceptionBehavior(type="raise_exception"))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class ToolInputGuardrailData:
|
|
122
|
+
"""Input data passed to a tool input guardrail function."""
|
|
123
|
+
|
|
124
|
+
context: ToolContext[Any]
|
|
125
|
+
"""
|
|
126
|
+
The tool context containing information about the current tool execution.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
agent: Agent[Any]
|
|
130
|
+
"""
|
|
131
|
+
The agent that is executing the tool.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class ToolOutputGuardrailData(ToolInputGuardrailData):
|
|
137
|
+
"""Input data passed to a tool output guardrail function.
|
|
138
|
+
|
|
139
|
+
Extends input data with the tool's output.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
output: Any
|
|
143
|
+
"""
|
|
144
|
+
The output produced by the tool function.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
TContext_co = TypeVar("TContext_co", bound=Any, covariant=True)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass
|
|
152
|
+
class ToolInputGuardrail(Generic[TContext_co]):
|
|
153
|
+
"""A guardrail that runs before a function tool is invoked."""
|
|
154
|
+
|
|
155
|
+
guardrail_function: Callable[
|
|
156
|
+
[ToolInputGuardrailData], MaybeAwaitable[ToolGuardrailFunctionOutput]
|
|
157
|
+
]
|
|
158
|
+
"""
|
|
159
|
+
The function that implements the guardrail logic.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
name: str | None = None
|
|
163
|
+
"""
|
|
164
|
+
Optional name for the guardrail. If not provided, uses the function name.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
def get_name(self) -> str:
|
|
168
|
+
return self.name or self.guardrail_function.__name__
|
|
169
|
+
|
|
170
|
+
async def run(self, data: ToolInputGuardrailData) -> ToolGuardrailFunctionOutput:
|
|
171
|
+
if not callable(self.guardrail_function):
|
|
172
|
+
raise UserError(f"Guardrail function must be callable, got {self.guardrail_function}")
|
|
173
|
+
|
|
174
|
+
result = self.guardrail_function(data)
|
|
175
|
+
if inspect.isawaitable(result):
|
|
176
|
+
return await result
|
|
177
|
+
return result
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@dataclass
|
|
181
|
+
class ToolOutputGuardrail(Generic[TContext_co]):
|
|
182
|
+
"""A guardrail that runs after a function tool is invoked."""
|
|
183
|
+
|
|
184
|
+
guardrail_function: Callable[
|
|
185
|
+
[ToolOutputGuardrailData], MaybeAwaitable[ToolGuardrailFunctionOutput]
|
|
186
|
+
]
|
|
187
|
+
"""
|
|
188
|
+
The function that implements the guardrail logic.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
name: str | None = None
|
|
192
|
+
"""
|
|
193
|
+
Optional name for the guardrail. If not provided, uses the function name.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def get_name(self) -> str:
|
|
197
|
+
return self.name or self.guardrail_function.__name__
|
|
198
|
+
|
|
199
|
+
async def run(self, data: ToolOutputGuardrailData) -> ToolGuardrailFunctionOutput:
|
|
200
|
+
if not callable(self.guardrail_function):
|
|
201
|
+
raise UserError(f"Guardrail function must be callable, got {self.guardrail_function}")
|
|
202
|
+
|
|
203
|
+
result = self.guardrail_function(data)
|
|
204
|
+
if inspect.isawaitable(result):
|
|
205
|
+
return await result
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# Decorators
|
|
210
|
+
_ToolInputFuncSync = Callable[[ToolInputGuardrailData], ToolGuardrailFunctionOutput]
|
|
211
|
+
_ToolInputFuncAsync = Callable[[ToolInputGuardrailData], Awaitable[ToolGuardrailFunctionOutput]]
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@overload
|
|
215
|
+
def tool_input_guardrail(func: _ToolInputFuncSync): ...
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@overload
|
|
219
|
+
def tool_input_guardrail(func: _ToolInputFuncAsync): ...
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@overload
|
|
223
|
+
def tool_input_guardrail(
|
|
224
|
+
*, name: str | None = None
|
|
225
|
+
) -> Callable[[_ToolInputFuncSync | _ToolInputFuncAsync], ToolInputGuardrail[Any]]: ...
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def tool_input_guardrail(
|
|
229
|
+
func: _ToolInputFuncSync | _ToolInputFuncAsync | None = None,
|
|
230
|
+
*,
|
|
231
|
+
name: str | None = None,
|
|
232
|
+
) -> (
|
|
233
|
+
ToolInputGuardrail[Any]
|
|
234
|
+
| Callable[[_ToolInputFuncSync | _ToolInputFuncAsync], ToolInputGuardrail[Any]]
|
|
235
|
+
):
|
|
236
|
+
"""Decorator to create a ToolInputGuardrail from a function."""
|
|
237
|
+
|
|
238
|
+
def decorator(f: _ToolInputFuncSync | _ToolInputFuncAsync) -> ToolInputGuardrail[Any]:
|
|
239
|
+
return ToolInputGuardrail(guardrail_function=f, name=name or f.__name__)
|
|
240
|
+
|
|
241
|
+
if func is not None:
|
|
242
|
+
return decorator(func)
|
|
243
|
+
return decorator
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
_ToolOutputFuncSync = Callable[[ToolOutputGuardrailData], ToolGuardrailFunctionOutput]
|
|
247
|
+
_ToolOutputFuncAsync = Callable[[ToolOutputGuardrailData], Awaitable[ToolGuardrailFunctionOutput]]
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@overload
|
|
251
|
+
def tool_output_guardrail(func: _ToolOutputFuncSync): ...
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@overload
|
|
255
|
+
def tool_output_guardrail(func: _ToolOutputFuncAsync): ...
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@overload
|
|
259
|
+
def tool_output_guardrail(
|
|
260
|
+
*, name: str | None = None
|
|
261
|
+
) -> Callable[[_ToolOutputFuncSync | _ToolOutputFuncAsync], ToolOutputGuardrail[Any]]: ...
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def tool_output_guardrail(
|
|
265
|
+
func: _ToolOutputFuncSync | _ToolOutputFuncAsync | None = None,
|
|
266
|
+
*,
|
|
267
|
+
name: str | None = None,
|
|
268
|
+
) -> (
|
|
269
|
+
ToolOutputGuardrail[Any]
|
|
270
|
+
| Callable[[_ToolOutputFuncSync | _ToolOutputFuncAsync], ToolOutputGuardrail[Any]]
|
|
271
|
+
):
|
|
272
|
+
"""Decorator to create a ToolOutputGuardrail from a function."""
|
|
273
|
+
|
|
274
|
+
def decorator(f: _ToolOutputFuncSync | _ToolOutputFuncAsync) -> ToolOutputGuardrail[Any]:
|
|
275
|
+
return ToolOutputGuardrail(guardrail_function=f, name=name or f.__name__)
|
|
276
|
+
|
|
277
|
+
if func is not None:
|
|
278
|
+
return decorator(func)
|
|
279
|
+
return decorator
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openai-agents
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: OpenAI Agents SDK
|
|
5
5
|
Project-URL: Homepage, https://openai.github.io/openai-agents-python/
|
|
6
6
|
Project-URL: Repository, https://github.com/openai/openai-agents-python
|
|
@@ -32,6 +32,8 @@ Provides-Extra: litellm
|
|
|
32
32
|
Requires-Dist: litellm<2,>=1.67.4.post1; extra == 'litellm'
|
|
33
33
|
Provides-Extra: realtime
|
|
34
34
|
Requires-Dist: websockets<16,>=15.0; extra == 'realtime'
|
|
35
|
+
Provides-Extra: redis
|
|
36
|
+
Requires-Dist: redis>=6.4.0; extra == 'redis'
|
|
35
37
|
Provides-Extra: sqlalchemy
|
|
36
38
|
Requires-Dist: asyncpg>=0.29.0; extra == 'sqlalchemy'
|
|
37
39
|
Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
|
|
@@ -75,6 +77,8 @@ pip install openai-agents
|
|
|
75
77
|
|
|
76
78
|
For voice support, install with the optional `voice` group: `pip install 'openai-agents[voice]'`.
|
|
77
79
|
|
|
80
|
+
For Redis session support, install with the optional `redis` group: `pip install 'openai-agents[redis]'`.
|
|
81
|
+
|
|
78
82
|
### uv
|
|
79
83
|
|
|
80
84
|
If you're familiar with [uv](https://docs.astral.sh/uv/), using the tool would be even similar:
|
|
@@ -86,6 +90,8 @@ uv add openai-agents
|
|
|
86
90
|
|
|
87
91
|
For voice support, install with the optional `voice` group: `uv add 'openai-agents[voice]'`.
|
|
88
92
|
|
|
93
|
+
For Redis session support, install with the optional `redis` group: `uv add 'openai-agents[redis]'`.
|
|
94
|
+
|
|
89
95
|
## Hello world example
|
|
90
96
|
|
|
91
97
|
```python
|
|
@@ -255,8 +261,13 @@ print(result.final_output) # "Approximately 39 million"
|
|
|
255
261
|
```python
|
|
256
262
|
from agents import Agent, Runner, SQLiteSession
|
|
257
263
|
|
|
258
|
-
#
|
|
264
|
+
# SQLite - file-based or in-memory database
|
|
259
265
|
session = SQLiteSession("user_123", "conversations.db")
|
|
266
|
+
|
|
267
|
+
# Redis - for scalable, distributed deployments
|
|
268
|
+
# from agents.extensions.memory import RedisSession
|
|
269
|
+
# session = RedisSession.from_url("user_123", url="redis://localhost:6379/0")
|
|
270
|
+
|
|
260
271
|
agent = Agent(name="Assistant")
|
|
261
272
|
|
|
262
273
|
# Different session IDs maintain separate conversation histories
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
agents/__init__.py,sha256=
|
|
1
|
+
agents/__init__.py,sha256=ckLaHgy95UvhXWWfqYUW0uBO1PKMNcf3GUqnRBDifIs,8728
|
|
2
2
|
agents/_config.py,sha256=ANrM7GP2VSQehDkMc9qocxkUlPwqU-i5sieMJyEwxpM,796
|
|
3
3
|
agents/_debug.py,sha256=dRe2dUlA9bCLp6f8bAdiX7JfGyJuHyS_DRdW0kZshl0,856
|
|
4
|
-
agents/_run_impl.py,sha256=
|
|
4
|
+
agents/_run_impl.py,sha256=hGkagVDsrh4XU-eOtoopHDXDZRisGPHE3ddmKiwswF0,54690
|
|
5
5
|
agents/agent.py,sha256=P5AzwKz3FiQJjzfautF0R9JzxkTXEeItcEkJgn8z5mM,19832
|
|
6
6
|
agents/agent_output.py,sha256=teTFK8unUN3esXhmEBO0bQGYQm1Axd5rYleDt9TFDgw,7153
|
|
7
7
|
agents/computer.py,sha256=XD44UgiUWSfniv-xKwwDP6wFKVwBiZkpaL1hO-0-7ZA,2516
|
|
8
|
-
agents/exceptions.py,sha256=
|
|
8
|
+
agents/exceptions.py,sha256=roJsYttB5i7FQlzRQNg8QSVdALZFz5u7kUeVvJdaitE,4156
|
|
9
9
|
agents/function_schema.py,sha256=njtbLt44DOkIU0a0U8TeDNEx-iQZU8oohwy3k7-k4A8,14855
|
|
10
10
|
agents/guardrail.py,sha256=7P-kd9rKPhgB8rtI31MCV5ho4ZrEaNCQxHvE8IK3EOk,9582
|
|
11
11
|
agents/handoffs.py,sha256=kDTM3nj3E_0khiJPMJAIN00gektMTRNbaYSbc5ZCnBM,11411
|
|
@@ -16,24 +16,27 @@ agents/model_settings.py,sha256=7Ul-Xg-aNVXIbK6V4Rm2t5EEfNR0tsy_A9ac_wFqLLk,6828
|
|
|
16
16
|
agents/prompts.py,sha256=Ss5y_7s2HFcRAOAKu4WTxQszs5ybI8TfbxgEYdnj9sg,2231
|
|
17
17
|
agents/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
18
18
|
agents/repl.py,sha256=NX0BE5YDnmGQ2rdQsmLm3CKkQZ5m4GC95xXmUsAXJVs,2539
|
|
19
|
-
agents/result.py,sha256=
|
|
20
|
-
agents/run.py,sha256=
|
|
19
|
+
agents/result.py,sha256=i3AtgXMRDiqPOnaflZrusVT9pS98kC8atlrRFKEgk20,12428
|
|
20
|
+
agents/run.py,sha256=Pu1OBFz-h8MKt03cytKsgsXoHX4pfT7nZnIwxxaf178,66030
|
|
21
21
|
agents/run_context.py,sha256=vuSUQM8O4CLensQY27-22fOqECnw7yvwL9U3WO8b_bk,851
|
|
22
22
|
agents/stream_events.py,sha256=VFyTu-DT3ZMnHLtMbg-X_lxec0doQxNfx-hVxLB0BpI,1700
|
|
23
23
|
agents/strict_schema.py,sha256=_KuEJkglmq-Fj3HSeYP4WqTvqrxbSKu6gezfz5Brhh0,5775
|
|
24
|
-
agents/tool.py,sha256=
|
|
25
|
-
agents/tool_context.py,sha256=
|
|
24
|
+
agents/tool.py,sha256=RqEMkX47-LyHDBINyL3iHP7cOsf4DwlNT70S-X4mE9I,17425
|
|
25
|
+
agents/tool_context.py,sha256=g53mgaeX7kCwPaIReiwuUejD8qC7QejMS-F3Wnkuhhg,1866
|
|
26
|
+
agents/tool_guardrails.py,sha256=2uXEr_R5AWy9NHtBjd7G7upc3uZSuoP86Hfsc-qTadM,8344
|
|
26
27
|
agents/usage.py,sha256=Tb5udGd3DPgD0JBdRD8fDctTE4M-zKML5uRn8ZG1yBc,1675
|
|
27
28
|
agents/version.py,sha256=_1knUwzSK-HUeZTpRUkk6Z-CIcurqXuEplbV5TLJ08E,230
|
|
28
29
|
agents/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
30
|
agents/extensions/handoff_filters.py,sha256=CS-k7TGCtT8TW3GeXb04OoFBXKdjg8-85QXswWAYBmI,2095
|
|
30
31
|
agents/extensions/handoff_prompt.py,sha256=oGWN0uNh3Z1L7E-Ev2up8W084fFrDNOsLDy7P6bcmic,1006
|
|
31
32
|
agents/extensions/visualization.py,sha256=sf9D_C-HMwkbWdZccTZvvMPRy_NSiwbm48tRJlESQBI,5144
|
|
32
|
-
agents/extensions/memory/__init__.py,sha256=
|
|
33
|
+
agents/extensions/memory/__init__.py,sha256=CJqBzkU6knvDKHhM7H4VrFw9DygLuZikgKJqcLKji2Y,2233
|
|
34
|
+
agents/extensions/memory/advanced_sqlite_session.py,sha256=rCrXM878foAuBN-rN2fibP2GHs-1hTtRx-TQcDKIfGI,52883
|
|
33
35
|
agents/extensions/memory/encrypt_session.py,sha256=PVnZIEj50bjUq16OLnMKrbZiinLkrVpamPPEw8RnUCA,6485
|
|
36
|
+
agents/extensions/memory/redis_session.py,sha256=JwXY6zUTMgq9bRezlyFZ4Tze7DO7T0hioTc23qjSHjU,9838
|
|
34
37
|
agents/extensions/memory/sqlalchemy_session.py,sha256=H0aykdB4lUikmzKgwWQqI1PSYZBvHA4TDnaj9rP4HDI,11583
|
|
35
38
|
agents/extensions/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
-
agents/extensions/models/litellm_model.py,sha256=
|
|
39
|
+
agents/extensions/models/litellm_model.py,sha256=FM4wIouSWIqXHoksZodoWsMLYTF4CT3j0IeFSWf-8oo,23642
|
|
37
40
|
agents/extensions/models/litellm_provider.py,sha256=ZHgh1nMoEvA7NpawkzLh3JDuDFtwXUV94Rs7UrwWqAk,1083
|
|
38
41
|
agents/mcp/__init__.py,sha256=yHmmYlrmEHzUas1inRLKL2iPqbb_-107G3gKe_tyg4I,750
|
|
39
42
|
agents/mcp/server.py,sha256=4T58xiWCLiCm6JoUy_3jYWz5A8ZNsHiV1hIxjahoedU,26624
|
|
@@ -45,16 +48,16 @@ agents/memory/sqlite_session.py,sha256=6HGzSL70mQgutITIPZUC2x2Qtj6U4hXiZTceu3Da7
|
|
|
45
48
|
agents/memory/util.py,sha256=ZAHOrNVA36xICFzuNgHgEA1_s_oEMO6Wsu6-EecY8JU,586
|
|
46
49
|
agents/models/__init__.py,sha256=E0XVqWayVAsFqxucDLBW30siaqfNQsVrAnfidG_C3ok,287
|
|
47
50
|
agents/models/_openai_shared.py,sha256=4Ngwo2Fv2RXY61Pqck1cYPkSln2tDnb8Ai-ao4QG-iE,836
|
|
48
|
-
agents/models/chatcmpl_converter.py,sha256=
|
|
49
|
-
agents/models/chatcmpl_helpers.py,sha256=
|
|
51
|
+
agents/models/chatcmpl_converter.py,sha256=yPf8AbCm43hpkB37zd3gdPtD-wHdcCDQS9vSeAmBPk4,24748
|
|
52
|
+
agents/models/chatcmpl_helpers.py,sha256=YC2krp_-uBgRCrCEImLjNvONTWRWfwLlPKHI4kBmNXE,1483
|
|
50
53
|
agents/models/chatcmpl_stream_handler.py,sha256=r8nc-4hJg1plw87y24MD48O23xnfC_2gHKowtOYgO3M,28896
|
|
51
54
|
agents/models/default_models.py,sha256=mlvBePn8H4UkHo7lN-wh7A3k2ciLgBUFKpROQxzdTfs,2098
|
|
52
55
|
agents/models/fake_id.py,sha256=lbXjUUSMeAQ8eFx4V5QLUnBClHE6adJlYYav55RlG5w,268
|
|
53
56
|
agents/models/interface.py,sha256=-AFUHC8iRuGZmtQwguDw4s-M4OPL2y2mct4TAmWvVrU,4057
|
|
54
57
|
agents/models/multi_provider.py,sha256=aiDbls5G4YomPfN6qH1pGlj41WS5jlDp2T82zm6qcnM,5578
|
|
55
|
-
agents/models/openai_chatcompletions.py,sha256=
|
|
58
|
+
agents/models/openai_chatcompletions.py,sha256=RUNrNWWjLADAyWTgQvixvSNShrwc8v_NMeXDF0fBSZo,13916
|
|
56
59
|
agents/models/openai_provider.py,sha256=vBu3mlgDBrI_cZVVmfnWBHoPlJlsmld3lfdX8sNQQAM,3624
|
|
57
|
-
agents/models/openai_responses.py,sha256=
|
|
60
|
+
agents/models/openai_responses.py,sha256=bcWdFkRwBm5_MiBwLsPXk2t061ZMSnz_A_45BJQAPmc,18999
|
|
58
61
|
agents/realtime/README.md,sha256=5YCYXH5ULmlWoWo1PE9TlbHjeYgjnp-xY8ZssSFY2Vk,126
|
|
59
62
|
agents/realtime/__init__.py,sha256=v8SKjD85pqQD1ZPzEQAtmbZb2CRApe0XwrxkRxzCm7c,5013
|
|
60
63
|
agents/realtime/_default_tracker.py,sha256=4OMxBvD1MnZmMn6JZYKL42uWhVzvK6NdDLDfPP54d78,1765
|
|
@@ -70,7 +73,7 @@ agents/realtime/model_events.py,sha256=2NKofzLszKHwtlcsogsNnH6hdeFfO7S96yWDB4Alx
|
|
|
70
73
|
agents/realtime/model_inputs.py,sha256=gRas0-ohirmGbCMWc8tHTo-e3ZPcPn7TK9BauCK9ynA,2657
|
|
71
74
|
agents/realtime/openai_realtime.py,sha256=x3dLSax3DF-hbQDSPXUtvHalN3nlwwcXYBIa36_ZqNo,44307
|
|
72
75
|
agents/realtime/runner.py,sha256=KfU7utmc9QFH2htIKN2IN9H-5EnB0qN9ezmvlRTnOm4,2511
|
|
73
|
-
agents/realtime/session.py,sha256=
|
|
76
|
+
agents/realtime/session.py,sha256=e4fJ3E5lS_y5IfczPAnX81vHr5rvEzJbT1LsmVdW7lc,35199
|
|
74
77
|
agents/tracing/__init__.py,sha256=5HO_6na5S6EwICgwl50OMtxiIIosUrqalhvldlYvSVc,2991
|
|
75
78
|
agents/tracing/create.py,sha256=xpJ4ZRnGyUDPKoVVkA_8hmdhtwOKGhSkwRco2AQIhAo,18003
|
|
76
79
|
agents/tracing/logger.py,sha256=J4KUDRSGa7x5UVfUwWe-gbKwoaq8AeETRqkPt3QvtGg,68
|
|
@@ -105,7 +108,7 @@ agents/voice/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
105
108
|
agents/voice/models/openai_model_provider.py,sha256=Khn0uT-VhsEbe7_OhBMGFQzXNwL80gcWZyTHl3CaBII,3587
|
|
106
109
|
agents/voice/models/openai_stt.py,sha256=eZ0dmX_uDywpR1H3Q2N5jrV7NK3bR9l2a1InWM3yegk,17151
|
|
107
110
|
agents/voice/models/openai_tts.py,sha256=4KoLQuFDHKu5a1VTJlu9Nj3MHwMlrn9wfT_liJDJ2dw,1477
|
|
108
|
-
openai_agents-0.3.
|
|
109
|
-
openai_agents-0.3.
|
|
110
|
-
openai_agents-0.3.
|
|
111
|
-
openai_agents-0.3.
|
|
111
|
+
openai_agents-0.3.3.dist-info/METADATA,sha256=hFUaemXENkZOPW-c06PatiRUDp19Mx0yj8LQ74eyHOk,12933
|
|
112
|
+
openai_agents-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
113
|
+
openai_agents-0.3.3.dist-info/licenses/LICENSE,sha256=E994EspT7Krhy0qGiES7WYNzBHrh1YDk3r--8d1baRU,1063
|
|
114
|
+
openai_agents-0.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|