openai-agents 0.0.1__py3-none-any.whl → 0.0.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.

Files changed (53) hide show
  1. agents/__init__.py +223 -0
  2. agents/_config.py +23 -0
  3. agents/_debug.py +17 -0
  4. agents/_run_impl.py +792 -0
  5. agents/_utils.py +61 -0
  6. agents/agent.py +159 -0
  7. agents/agent_output.py +144 -0
  8. agents/computer.py +107 -0
  9. agents/exceptions.py +63 -0
  10. agents/extensions/handoff_filters.py +67 -0
  11. agents/extensions/handoff_prompt.py +19 -0
  12. agents/function_schema.py +340 -0
  13. agents/guardrail.py +320 -0
  14. agents/handoffs.py +236 -0
  15. agents/items.py +246 -0
  16. agents/lifecycle.py +105 -0
  17. agents/logger.py +3 -0
  18. agents/model_settings.py +36 -0
  19. agents/models/__init__.py +0 -0
  20. agents/models/_openai_shared.py +34 -0
  21. agents/models/fake_id.py +5 -0
  22. agents/models/interface.py +107 -0
  23. agents/models/openai_chatcompletions.py +952 -0
  24. agents/models/openai_provider.py +65 -0
  25. agents/models/openai_responses.py +384 -0
  26. agents/result.py +220 -0
  27. agents/run.py +904 -0
  28. agents/run_context.py +26 -0
  29. agents/stream_events.py +58 -0
  30. agents/strict_schema.py +167 -0
  31. agents/tool.py +288 -0
  32. agents/tracing/__init__.py +97 -0
  33. agents/tracing/create.py +306 -0
  34. agents/tracing/logger.py +3 -0
  35. agents/tracing/processor_interface.py +69 -0
  36. agents/tracing/processors.py +261 -0
  37. agents/tracing/scope.py +45 -0
  38. agents/tracing/setup.py +211 -0
  39. agents/tracing/span_data.py +188 -0
  40. agents/tracing/spans.py +264 -0
  41. agents/tracing/traces.py +195 -0
  42. agents/tracing/util.py +17 -0
  43. agents/usage.py +22 -0
  44. agents/version.py +7 -0
  45. openai_agents-0.0.3.dist-info/METADATA +204 -0
  46. openai_agents-0.0.3.dist-info/RECORD +49 -0
  47. openai_agents-0.0.3.dist-info/licenses/LICENSE +21 -0
  48. openai-agents/example.py +0 -2
  49. openai_agents-0.0.1.dist-info/METADATA +0 -17
  50. openai_agents-0.0.1.dist-info/RECORD +0 -6
  51. openai_agents-0.0.1.dist-info/licenses/LICENSE +0 -20
  52. {openai-agents → agents/extensions}/__init__.py +0 -0
  53. {openai_agents-0.0.1.dist-info → openai_agents-0.0.3.dist-info}/WHEEL +0 -0
agents/_utils.py ADDED
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from collections.abc import Awaitable
5
+ from typing import Any, Literal, Union
6
+
7
+ from pydantic import TypeAdapter, ValidationError
8
+ from typing_extensions import TypeVar
9
+
10
+ from .exceptions import ModelBehaviorError
11
+ from .logger import logger
12
+ from .tracing import Span, SpanError, get_current_span
13
+
14
+ T = TypeVar("T")
15
+
16
+ MaybeAwaitable = Union[Awaitable[T], T]
17
+
18
+
19
+ def transform_string_function_style(name: str) -> str:
20
+ # Replace spaces with underscores
21
+ name = name.replace(" ", "_")
22
+
23
+ # Replace non-alphanumeric characters with underscores
24
+ name = re.sub(r"[^a-zA-Z0-9]", "_", name)
25
+
26
+ return name.lower()
27
+
28
+
29
+ def validate_json(json_str: str, type_adapter: TypeAdapter[T], partial: bool) -> T:
30
+ partial_setting: bool | Literal["off", "on", "trailing-strings"] = (
31
+ "trailing-strings" if partial else False
32
+ )
33
+ try:
34
+ validated = type_adapter.validate_json(json_str, experimental_allow_partial=partial_setting)
35
+ return validated
36
+ except ValidationError as e:
37
+ attach_error_to_current_span(
38
+ SpanError(
39
+ message="Invalid JSON provided",
40
+ data={},
41
+ )
42
+ )
43
+ raise ModelBehaviorError(
44
+ f"Invalid JSON when parsing {json_str} for {type_adapter}; {e}"
45
+ ) from e
46
+
47
+
48
+ def attach_error_to_span(span: Span[Any], error: SpanError) -> None:
49
+ span.set_error(error)
50
+
51
+
52
+ def attach_error_to_current_span(error: SpanError) -> None:
53
+ span = get_current_span()
54
+ if span:
55
+ attach_error_to_span(span, error)
56
+ else:
57
+ logger.warning(f"No span to add error {error} to")
58
+
59
+
60
+ async def noop_coroutine() -> None:
61
+ pass
agents/agent.py ADDED
@@ -0,0 +1,159 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import inspect
5
+ from collections.abc import Awaitable
6
+ from dataclasses import dataclass, field
7
+ from typing import TYPE_CHECKING, Any, Callable, Generic, cast
8
+
9
+ from . import _utils
10
+ from ._utils import MaybeAwaitable
11
+ from .guardrail import InputGuardrail, OutputGuardrail
12
+ from .handoffs import Handoff
13
+ from .items import ItemHelpers
14
+ from .logger import logger
15
+ from .model_settings import ModelSettings
16
+ from .models.interface import Model
17
+ from .run_context import RunContextWrapper, TContext
18
+ from .tool import Tool, function_tool
19
+
20
+ if TYPE_CHECKING:
21
+ from .lifecycle import AgentHooks
22
+ from .result import RunResult
23
+
24
+
25
+ @dataclass
26
+ class Agent(Generic[TContext]):
27
+ """An agent is an AI model configured with instructions, tools, guardrails, handoffs and more.
28
+
29
+ We strongly recommend passing `instructions`, which is the "system prompt" for the agent. In
30
+ addition, you can pass `description`, which is a human-readable description of the agent, used
31
+ when the agent is used inside tools/handoffs.
32
+
33
+ Agents are generic on the context type. The context is a (mutable) object you create. It is
34
+ passed to tool functions, handoffs, guardrails, etc.
35
+ """
36
+
37
+ name: str
38
+ """The name of the agent."""
39
+
40
+ instructions: (
41
+ str
42
+ | Callable[
43
+ [RunContextWrapper[TContext], Agent[TContext]],
44
+ MaybeAwaitable[str],
45
+ ]
46
+ | None
47
+ ) = None
48
+ """The instructions for the agent. Will be used as the "system prompt" when this agent is
49
+ invoked. Describes what the agent should do, and how it responds.
50
+
51
+ Can either be a string, or a function that dynamically generates instructions for the agent. If
52
+ you provide a function, it will be called with the context and the agent instance. It must
53
+ return a string.
54
+ """
55
+
56
+ handoff_description: str | None = None
57
+ """A description of the agent. This is used when the agent is used as a handoff, so that an
58
+ LLM knows what it does and when to invoke it.
59
+ """
60
+
61
+ handoffs: list[Agent[Any] | Handoff[TContext]] = field(default_factory=list)
62
+ """Handoffs are sub-agents that the agent can delegate to. You can provide a list of handoffs,
63
+ and the agent can choose to delegate to them if relevant. Allows for separation of concerns and
64
+ modularity.
65
+ """
66
+
67
+ model: str | Model | None = None
68
+ """The model implementation to use when invoking the LLM.
69
+
70
+ By default, if not set, the agent will use the default model configured in
71
+ `model_settings.DEFAULT_MODEL`.
72
+ """
73
+
74
+ model_settings: ModelSettings = field(default_factory=ModelSettings)
75
+ """Configures model-specific tuning parameters (e.g. temperature, top_p).
76
+ """
77
+
78
+ tools: list[Tool] = field(default_factory=list)
79
+ """A list of tools that the agent can use."""
80
+
81
+ input_guardrails: list[InputGuardrail[TContext]] = field(default_factory=list)
82
+ """A list of checks that run in parallel to the agent's execution, before generating a
83
+ response. Runs only if the agent is the first agent in the chain.
84
+ """
85
+
86
+ output_guardrails: list[OutputGuardrail[TContext]] = field(default_factory=list)
87
+ """A list of checks that run on the final output of the agent, after generating a response.
88
+ Runs only if the agent produces a final output.
89
+ """
90
+
91
+ output_type: type[Any] | None = None
92
+ """The type of the output object. If not provided, the output will be `str`."""
93
+
94
+ hooks: AgentHooks[TContext] | None = None
95
+ """A class that receives callbacks on various lifecycle events for this agent.
96
+ """
97
+
98
+ def clone(self, **kwargs: Any) -> Agent[TContext]:
99
+ """Make a copy of the agent, with the given arguments changed. For example, you could do:
100
+ ```
101
+ new_agent = agent.clone(instructions="New instructions")
102
+ ```
103
+ """
104
+ return dataclasses.replace(self, **kwargs)
105
+
106
+ def as_tool(
107
+ self,
108
+ tool_name: str | None,
109
+ tool_description: str | None,
110
+ custom_output_extractor: Callable[[RunResult], Awaitable[str]] | None = None,
111
+ ) -> Tool:
112
+ """Transform this agent into a tool, callable by other agents.
113
+
114
+ This is different from handoffs in two ways:
115
+ 1. In handoffs, the new agent receives the conversation history. In this tool, the new agent
116
+ receives generated input.
117
+ 2. In handoffs, the new agent takes over the conversation. In this tool, the new agent is
118
+ called as a tool, and the conversation is continued by the original agent.
119
+
120
+ Args:
121
+ tool_name: The name of the tool. If not provided, the agent's name will be used.
122
+ tool_description: The description of the tool, which should indicate what it does and
123
+ when to use it.
124
+ custom_output_extractor: A function that extracts the output from the agent. If not
125
+ provided, the last message from the agent will be used.
126
+ """
127
+
128
+ @function_tool(
129
+ name_override=tool_name or _utils.transform_string_function_style(self.name),
130
+ description_override=tool_description or "",
131
+ )
132
+ async def run_agent(context: RunContextWrapper, input: str) -> str:
133
+ from .run import Runner
134
+
135
+ output = await Runner.run(
136
+ starting_agent=self,
137
+ input=input,
138
+ context=context.context,
139
+ )
140
+ if custom_output_extractor:
141
+ return await custom_output_extractor(output)
142
+
143
+ return ItemHelpers.text_message_outputs(output.new_items)
144
+
145
+ return run_agent
146
+
147
+ async def get_system_prompt(self, run_context: RunContextWrapper[TContext]) -> str | None:
148
+ """Get the system prompt for the agent."""
149
+ if isinstance(self.instructions, str):
150
+ return self.instructions
151
+ elif callable(self.instructions):
152
+ if inspect.iscoroutinefunction(self.instructions):
153
+ return await cast(Awaitable[str], self.instructions(run_context, self))
154
+ else:
155
+ return cast(str, self.instructions(run_context, self))
156
+ elif self.instructions is not None:
157
+ logger.error(f"Instructions must be a string or a function, got {self.instructions}")
158
+
159
+ return None
agents/agent_output.py ADDED
@@ -0,0 +1,144 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+ from pydantic import BaseModel, TypeAdapter
5
+ from typing_extensions import TypedDict, get_args, get_origin
6
+
7
+ from . import _utils
8
+ from .exceptions import ModelBehaviorError, UserError
9
+ from .strict_schema import ensure_strict_json_schema
10
+ from .tracing import SpanError
11
+
12
+ _WRAPPER_DICT_KEY = "response"
13
+
14
+
15
+ @dataclass(init=False)
16
+ class AgentOutputSchema:
17
+ """An object that captures the JSON schema of the output, as well as validating/parsing JSON
18
+ produced by the LLM into the output type.
19
+ """
20
+
21
+ output_type: type[Any]
22
+ """The type of the output."""
23
+
24
+ _type_adapter: TypeAdapter[Any]
25
+ """A type adapter that wraps the output type, so that we can validate JSON."""
26
+
27
+ _is_wrapped: bool
28
+ """Whether the output type is wrapped in a dictionary. This is generally done if the base
29
+ output type cannot be represented as a JSON Schema object.
30
+ """
31
+
32
+ _output_schema: dict[str, Any]
33
+ """The JSON schema of the output."""
34
+
35
+ strict_json_schema: bool
36
+ """Whether the JSON schema is in strict mode. We **strongly** recommend setting this to True,
37
+ as it increases the likelihood of correct JSON input.
38
+ """
39
+
40
+ def __init__(self, output_type: type[Any], strict_json_schema: bool = True):
41
+ """
42
+ Args:
43
+ output_type: The type of the output.
44
+ strict_json_schema: Whether the JSON schema is in strict mode. We **strongly** recommend
45
+ setting this to True, as it increases the likelihood of correct JSON input.
46
+ """
47
+ self.output_type = output_type
48
+ self.strict_json_schema = strict_json_schema
49
+
50
+ if output_type is None or output_type is str:
51
+ self._is_wrapped = False
52
+ self._type_adapter = TypeAdapter(output_type)
53
+ self._output_schema = self._type_adapter.json_schema()
54
+ return
55
+
56
+ # We should wrap for things that are not plain text, and for things that would definitely
57
+ # not be a JSON Schema object.
58
+ self._is_wrapped = not _is_subclass_of_base_model_or_dict(output_type)
59
+
60
+ if self._is_wrapped:
61
+ OutputType = TypedDict(
62
+ "OutputType",
63
+ {
64
+ _WRAPPER_DICT_KEY: output_type, # type: ignore
65
+ },
66
+ )
67
+ self._type_adapter = TypeAdapter(OutputType)
68
+ self._output_schema = self._type_adapter.json_schema()
69
+ else:
70
+ self._type_adapter = TypeAdapter(output_type)
71
+ self._output_schema = self._type_adapter.json_schema()
72
+
73
+ if self.strict_json_schema:
74
+ self._output_schema = ensure_strict_json_schema(self._output_schema)
75
+
76
+ def is_plain_text(self) -> bool:
77
+ """Whether the output type is plain text (versus a JSON object)."""
78
+ return self.output_type is None or self.output_type is str
79
+
80
+ def json_schema(self) -> dict[str, Any]:
81
+ """The JSON schema of the output type."""
82
+ if self.is_plain_text():
83
+ raise UserError("Output type is plain text, so no JSON schema is available")
84
+ return self._output_schema
85
+
86
+ def validate_json(self, json_str: str, partial: bool = False) -> Any:
87
+ """Validate a JSON string against the output type. Returns the validated object, or raises
88
+ a `ModelBehaviorError` if the JSON is invalid.
89
+ """
90
+ validated = _utils.validate_json(json_str, self._type_adapter, partial)
91
+ if self._is_wrapped:
92
+ if not isinstance(validated, dict):
93
+ _utils.attach_error_to_current_span(
94
+ SpanError(
95
+ message="Invalid JSON",
96
+ data={"details": f"Expected a dict, got {type(validated)}"},
97
+ )
98
+ )
99
+ raise ModelBehaviorError(
100
+ f"Expected a dict, got {type(validated)} for JSON: {json_str}"
101
+ )
102
+
103
+ if _WRAPPER_DICT_KEY not in validated:
104
+ _utils.attach_error_to_current_span(
105
+ SpanError(
106
+ message="Invalid JSON",
107
+ data={"details": f"Could not find key {_WRAPPER_DICT_KEY} in JSON"},
108
+ )
109
+ )
110
+ raise ModelBehaviorError(
111
+ f"Could not find key {_WRAPPER_DICT_KEY} in JSON: {json_str}"
112
+ )
113
+ return validated[_WRAPPER_DICT_KEY]
114
+ return validated
115
+
116
+ def output_type_name(self) -> str:
117
+ """The name of the output type."""
118
+ return _type_to_str(self.output_type)
119
+
120
+
121
+ def _is_subclass_of_base_model_or_dict(t: Any) -> bool:
122
+ if not isinstance(t, type):
123
+ return False
124
+
125
+ # If it's a generic alias, 'origin' will be the actual type, e.g. 'list'
126
+ origin = get_origin(t)
127
+
128
+ allowed_types = (BaseModel, dict)
129
+ # If it's a generic alias e.g. list[str], then we should check the origin type i.e. list
130
+ return issubclass(origin or t, allowed_types)
131
+
132
+
133
+ def _type_to_str(t: type[Any]) -> str:
134
+ origin = get_origin(t)
135
+ args = get_args(t)
136
+
137
+ if origin is None:
138
+ # It's a simple type like `str`, `int`, etc.
139
+ return t.__name__
140
+ elif args:
141
+ args_str = ", ".join(_type_to_str(arg) for arg in args)
142
+ return f"{origin.__name__}[{args_str}]"
143
+ else:
144
+ return str(t)
agents/computer.py ADDED
@@ -0,0 +1,107 @@
1
+ import abc
2
+ from typing import Literal
3
+
4
+ Environment = Literal["mac", "windows", "ubuntu", "browser"]
5
+ Button = Literal["left", "right", "wheel", "back", "forward"]
6
+
7
+
8
+ class Computer(abc.ABC):
9
+ """A computer implemented with sync operations. The Computer interface abstracts the
10
+ operations needed to control a computer or browser."""
11
+
12
+ @property
13
+ @abc.abstractmethod
14
+ def environment(self) -> Environment:
15
+ pass
16
+
17
+ @property
18
+ @abc.abstractmethod
19
+ def dimensions(self) -> tuple[int, int]:
20
+ pass
21
+
22
+ @abc.abstractmethod
23
+ def screenshot(self) -> str:
24
+ pass
25
+
26
+ @abc.abstractmethod
27
+ def click(self, x: int, y: int, button: Button) -> None:
28
+ pass
29
+
30
+ @abc.abstractmethod
31
+ def double_click(self, x: int, y: int) -> None:
32
+ pass
33
+
34
+ @abc.abstractmethod
35
+ def scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> None:
36
+ pass
37
+
38
+ @abc.abstractmethod
39
+ def type(self, text: str) -> None:
40
+ pass
41
+
42
+ @abc.abstractmethod
43
+ def wait(self) -> None:
44
+ pass
45
+
46
+ @abc.abstractmethod
47
+ def move(self, x: int, y: int) -> None:
48
+ pass
49
+
50
+ @abc.abstractmethod
51
+ def keypress(self, keys: list[str]) -> None:
52
+ pass
53
+
54
+ @abc.abstractmethod
55
+ def drag(self, path: list[tuple[int, int]]) -> None:
56
+ pass
57
+
58
+
59
+ class AsyncComputer(abc.ABC):
60
+ """A computer implemented with async operations. The Computer interface abstracts the
61
+ operations needed to control a computer or browser."""
62
+
63
+ @property
64
+ @abc.abstractmethod
65
+ def environment(self) -> Environment:
66
+ pass
67
+
68
+ @property
69
+ @abc.abstractmethod
70
+ def dimensions(self) -> tuple[int, int]:
71
+ pass
72
+
73
+ @abc.abstractmethod
74
+ async def screenshot(self) -> str:
75
+ pass
76
+
77
+ @abc.abstractmethod
78
+ async def click(self, x: int, y: int, button: Button) -> None:
79
+ pass
80
+
81
+ @abc.abstractmethod
82
+ async def double_click(self, x: int, y: int) -> None:
83
+ pass
84
+
85
+ @abc.abstractmethod
86
+ async def scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> None:
87
+ pass
88
+
89
+ @abc.abstractmethod
90
+ async def type(self, text: str) -> None:
91
+ pass
92
+
93
+ @abc.abstractmethod
94
+ async def wait(self) -> None:
95
+ pass
96
+
97
+ @abc.abstractmethod
98
+ async def move(self, x: int, y: int) -> None:
99
+ pass
100
+
101
+ @abc.abstractmethod
102
+ async def keypress(self, keys: list[str]) -> None:
103
+ pass
104
+
105
+ @abc.abstractmethod
106
+ async def drag(self, path: list[tuple[int, int]]) -> None:
107
+ pass
agents/exceptions.py ADDED
@@ -0,0 +1,63 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from .guardrail import InputGuardrailResult, OutputGuardrailResult
5
+
6
+
7
+ class AgentsException(Exception):
8
+ """Base class for all exceptions in the Agents SDK."""
9
+
10
+
11
+ class MaxTurnsExceeded(AgentsException):
12
+ """Exception raised when the maximum number of turns is exceeded."""
13
+
14
+ message: str
15
+
16
+ def __init__(self, message: str):
17
+ self.message = message
18
+
19
+
20
+ class ModelBehaviorError(AgentsException):
21
+ """Exception raised when the model does something unexpected, e.g. calling a tool that doesn't
22
+ exist, or providing malformed JSON.
23
+ """
24
+
25
+ message: str
26
+
27
+ def __init__(self, message: str):
28
+ self.message = message
29
+
30
+
31
+ class UserError(AgentsException):
32
+ """Exception raised when the user makes an error using the SDK."""
33
+
34
+ message: str
35
+
36
+ def __init__(self, message: str):
37
+ self.message = message
38
+
39
+
40
+ class InputGuardrailTripwireTriggered(AgentsException):
41
+ """Exception raised when a guardrail tripwire is triggered."""
42
+
43
+ guardrail_result: "InputGuardrailResult"
44
+ """The result data of the guardrail that was triggered."""
45
+
46
+ def __init__(self, guardrail_result: "InputGuardrailResult"):
47
+ self.guardrail_result = guardrail_result
48
+ super().__init__(
49
+ f"Guardrail {guardrail_result.guardrail.__class__.__name__} triggered tripwire"
50
+ )
51
+
52
+
53
+ class OutputGuardrailTripwireTriggered(AgentsException):
54
+ """Exception raised when a guardrail tripwire is triggered."""
55
+
56
+ guardrail_result: "OutputGuardrailResult"
57
+ """The result data of the guardrail that was triggered."""
58
+
59
+ def __init__(self, guardrail_result: "OutputGuardrailResult"):
60
+ self.guardrail_result = guardrail_result
61
+ super().__init__(
62
+ f"Guardrail {guardrail_result.guardrail.__class__.__name__} triggered tripwire"
63
+ )
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ from ..handoffs import HandoffInputData
4
+ from ..items import (
5
+ HandoffCallItem,
6
+ HandoffOutputItem,
7
+ RunItem,
8
+ ToolCallItem,
9
+ ToolCallOutputItem,
10
+ TResponseInputItem,
11
+ )
12
+
13
+ """Contains common handoff input filters, for convenience. """
14
+
15
+
16
+ def remove_all_tools(handoff_input_data: HandoffInputData) -> HandoffInputData:
17
+ """Filters out all tool items: file search, web search and function calls+output."""
18
+
19
+ history = handoff_input_data.input_history
20
+ new_items = handoff_input_data.new_items
21
+
22
+ filtered_history = (
23
+ _remove_tool_types_from_input(history) if isinstance(history, tuple) else history
24
+ )
25
+ filtered_pre_handoff_items = _remove_tools_from_items(handoff_input_data.pre_handoff_items)
26
+ filtered_new_items = _remove_tools_from_items(new_items)
27
+
28
+ return HandoffInputData(
29
+ input_history=filtered_history,
30
+ pre_handoff_items=filtered_pre_handoff_items,
31
+ new_items=filtered_new_items,
32
+ )
33
+
34
+
35
+ def _remove_tools_from_items(items: tuple[RunItem, ...]) -> tuple[RunItem, ...]:
36
+ filtered_items = []
37
+ for item in items:
38
+ if (
39
+ isinstance(item, HandoffCallItem)
40
+ or isinstance(item, HandoffOutputItem)
41
+ or isinstance(item, ToolCallItem)
42
+ or isinstance(item, ToolCallOutputItem)
43
+ ):
44
+ continue
45
+ filtered_items.append(item)
46
+ return tuple(filtered_items)
47
+
48
+
49
+ def _remove_tool_types_from_input(
50
+ items: tuple[TResponseInputItem, ...],
51
+ ) -> tuple[TResponseInputItem, ...]:
52
+ tool_types = [
53
+ "function_call",
54
+ "function_call_output",
55
+ "computer_call",
56
+ "computer_call_output",
57
+ "file_search_call",
58
+ "web_search_call",
59
+ ]
60
+
61
+ filtered_items: list[TResponseInputItem] = []
62
+ for item in items:
63
+ itype = item.get("type")
64
+ if itype in tool_types:
65
+ continue
66
+ filtered_items.append(item)
67
+ return tuple(filtered_items)
@@ -0,0 +1,19 @@
1
+ # A recommended prompt prefix for agents that use handoffs. We recommend including this or
2
+ # similar instructions in any agents that use handoffs.
3
+ RECOMMENDED_PROMPT_PREFIX = (
4
+ "# System context\n"
5
+ "You are part of a multi-agent system called the Agents SDK, designed to make agent "
6
+ "coordination and execution easy. Agents uses two primary abstraction: **Agents** and "
7
+ "**Handoffs**. An agent encompasses instructions and tools and can hand off a "
8
+ "conversation to another agent when appropriate. "
9
+ "Handoffs are achieved by calling a handoff function, generally named "
10
+ "`transfer_to_<agent_name>`. Transfers between agents are handled seamlessly in the background;"
11
+ " do not mention or draw attention to these transfers in your conversation with the user.\n"
12
+ )
13
+
14
+
15
+ def prompt_with_handoff_instructions(prompt: str) -> str:
16
+ """
17
+ Add recommended instructions to the prompt for agents that use handoffs.
18
+ """
19
+ return f"{RECOMMENDED_PROMPT_PREFIX}\n\n{prompt}"