openai-agents 0.0.4__py3-none-any.whl → 0.0.5__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 CHANGED
@@ -5,7 +5,7 @@ from typing import Literal
5
5
  from openai import AsyncOpenAI
6
6
 
7
7
  from . import _config
8
- from .agent import Agent
8
+ from .agent import Agent, ToolsToFinalOutputFunction, ToolsToFinalOutputResult
9
9
  from .agent_output import AgentOutputSchema
10
10
  from .computer import AsyncComputer, Button, Computer, Environment
11
11
  from .exceptions import (
@@ -57,6 +57,7 @@ from .tool import (
57
57
  ComputerTool,
58
58
  FileSearchTool,
59
59
  FunctionTool,
60
+ FunctionToolResult,
60
61
  Tool,
61
62
  WebSearchTool,
62
63
  default_tool_error_function,
@@ -73,6 +74,7 @@ from .tracing import (
73
74
  SpanData,
74
75
  SpanError,
75
76
  Trace,
77
+ TracingProcessor,
76
78
  add_trace_processor,
77
79
  agent_span,
78
80
  custom_span,
@@ -129,14 +131,15 @@ def set_default_openai_api(api: Literal["chat_completions", "responses"]) -> Non
129
131
 
130
132
  def enable_verbose_stdout_logging():
131
133
  """Enables verbose logging to stdout. This is useful for debugging."""
132
- for name in ["openai.agents", "openai.agents.tracing"]:
133
- logger = logging.getLogger(name)
134
- logger.setLevel(logging.DEBUG)
135
- logger.addHandler(logging.StreamHandler(sys.stdout))
134
+ logger = logging.getLogger("openai.agents")
135
+ logger.setLevel(logging.DEBUG)
136
+ logger.addHandler(logging.StreamHandler(sys.stdout))
136
137
 
137
138
 
138
139
  __all__ = [
139
140
  "Agent",
141
+ "ToolsToFinalOutputFunction",
142
+ "ToolsToFinalOutputResult",
140
143
  "Runner",
141
144
  "Model",
142
145
  "ModelProvider",
@@ -190,6 +193,7 @@ __all__ = [
190
193
  "AgentUpdatedStreamEvent",
191
194
  "StreamEvent",
192
195
  "FunctionTool",
196
+ "FunctionToolResult",
193
197
  "ComputerTool",
194
198
  "FileSearchTool",
195
199
  "Tool",
@@ -209,6 +213,7 @@ __all__ = [
209
213
  "set_tracing_disabled",
210
214
  "trace",
211
215
  "Trace",
216
+ "TracingProcessor",
212
217
  "SpanError",
213
218
  "Span",
214
219
  "SpanData",
agents/_run_impl.py CHANGED
@@ -1,8 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import inspect
5
+ from collections.abc import Awaitable
4
6
  from dataclasses import dataclass
5
- from typing import TYPE_CHECKING, Any
7
+ from typing import TYPE_CHECKING, Any, cast
6
8
 
7
9
  from openai.types.responses import (
8
10
  ResponseComputerToolCall,
@@ -25,8 +27,7 @@ from openai.types.responses.response_computer_tool_call import (
25
27
  from openai.types.responses.response_input_param import ComputerCallOutput
26
28
  from openai.types.responses.response_reasoning_item import ResponseReasoningItem
27
29
 
28
- from . import _utils
29
- from .agent import Agent
30
+ from .agent import Agent, ToolsToFinalOutputResult
30
31
  from .agent_output import AgentOutputSchema
31
32
  from .computer import AsyncComputer, Computer
32
33
  from .exceptions import AgentsException, ModelBehaviorError, UserError
@@ -49,7 +50,7 @@ from .logger import logger
49
50
  from .models.interface import ModelTracing
50
51
  from .run_context import RunContextWrapper, TContext
51
52
  from .stream_events import RunItemStreamEvent, StreamEvent
52
- from .tool import ComputerTool, FunctionTool
53
+ from .tool import ComputerTool, FunctionTool, FunctionToolResult
53
54
  from .tracing import (
54
55
  SpanError,
55
56
  Trace,
@@ -59,6 +60,7 @@ from .tracing import (
59
60
  handoff_span,
60
61
  trace,
61
62
  )
63
+ from .util import _coro, _error_tracing
62
64
 
63
65
  if TYPE_CHECKING:
64
66
  from .run import RunConfig
@@ -70,6 +72,8 @@ class QueueCompleteSentinel:
70
72
 
71
73
  QUEUE_COMPLETE_SENTINEL = QueueCompleteSentinel()
72
74
 
75
+ _NOT_FINAL_OUTPUT = ToolsToFinalOutputResult(is_final_output=False, final_output=None)
76
+
73
77
 
74
78
  @dataclass
75
79
  class ToolRunHandoff:
@@ -199,7 +203,7 @@ class RunImpl:
199
203
  config=run_config,
200
204
  ),
201
205
  )
202
- new_step_items.extend(function_results)
206
+ new_step_items.extend([result.run_item for result in function_results])
203
207
  new_step_items.extend(computer_results)
204
208
 
205
209
  # Second, check if there are any handoffs
@@ -216,6 +220,36 @@ class RunImpl:
216
220
  run_config=run_config,
217
221
  )
218
222
 
223
+ # Third, we'll check if the tool use should result in a final output
224
+ check_tool_use = await cls._check_for_final_output_from_tools(
225
+ agent=agent,
226
+ tool_results=function_results,
227
+ context_wrapper=context_wrapper,
228
+ config=run_config,
229
+ )
230
+
231
+ if check_tool_use.is_final_output:
232
+ # If the output type is str, then let's just stringify it
233
+ if not agent.output_type or agent.output_type is str:
234
+ check_tool_use.final_output = str(check_tool_use.final_output)
235
+
236
+ if check_tool_use.final_output is None:
237
+ logger.error(
238
+ "Model returned a final output of None. Not raising an error because we assume"
239
+ "you know what you're doing."
240
+ )
241
+
242
+ return await cls.execute_final_output(
243
+ agent=agent,
244
+ original_input=original_input,
245
+ new_response=new_response,
246
+ pre_step_items=pre_step_items,
247
+ new_step_items=new_step_items,
248
+ final_output=check_tool_use.final_output,
249
+ hooks=hooks,
250
+ context_wrapper=context_wrapper,
251
+ )
252
+
219
253
  # Now we can check if the model also produced a final output
220
254
  message_items = [item for item in new_step_items if isinstance(item, MessageOutputItem)]
221
255
 
@@ -293,7 +327,7 @@ class RunImpl:
293
327
  elif isinstance(output, ResponseComputerToolCall):
294
328
  items.append(ToolCallItem(raw_item=output, agent=agent))
295
329
  if not computer_tool:
296
- _utils.attach_error_to_current_span(
330
+ _error_tracing.attach_error_to_current_span(
297
331
  SpanError(
298
332
  message="Computer tool not found",
299
333
  data={},
@@ -324,7 +358,7 @@ class RunImpl:
324
358
  # Regular function tool call
325
359
  else:
326
360
  if output.name not in function_map:
327
- _utils.attach_error_to_current_span(
361
+ _error_tracing.attach_error_to_current_span(
328
362
  SpanError(
329
363
  message="Tool not found",
330
364
  data={"tool_name": output.name},
@@ -355,10 +389,10 @@ class RunImpl:
355
389
  hooks: RunHooks[TContext],
356
390
  context_wrapper: RunContextWrapper[TContext],
357
391
  config: RunConfig,
358
- ) -> list[RunItem]:
392
+ ) -> list[FunctionToolResult]:
359
393
  async def run_single_tool(
360
394
  func_tool: FunctionTool, tool_call: ResponseFunctionToolCall
361
- ) -> str:
395
+ ) -> Any:
362
396
  with function_span(func_tool.name) as span_fn:
363
397
  if config.trace_include_sensitive_data:
364
398
  span_fn.span_data.input = tool_call.arguments
@@ -368,7 +402,7 @@ class RunImpl:
368
402
  (
369
403
  agent.hooks.on_tool_start(context_wrapper, agent, func_tool)
370
404
  if agent.hooks
371
- else _utils.noop_coroutine()
405
+ else _coro.noop_coroutine()
372
406
  ),
373
407
  func_tool.on_invoke_tool(context_wrapper, tool_call.arguments),
374
408
  )
@@ -378,11 +412,11 @@ class RunImpl:
378
412
  (
379
413
  agent.hooks.on_tool_end(context_wrapper, agent, func_tool, result)
380
414
  if agent.hooks
381
- else _utils.noop_coroutine()
415
+ else _coro.noop_coroutine()
382
416
  ),
383
417
  )
384
418
  except Exception as e:
385
- _utils.attach_error_to_current_span(
419
+ _error_tracing.attach_error_to_current_span(
386
420
  SpanError(
387
421
  message="Error running tool",
388
422
  data={"tool_name": func_tool.name, "error": str(e)},
@@ -404,10 +438,14 @@ class RunImpl:
404
438
  results = await asyncio.gather(*tasks)
405
439
 
406
440
  return [
407
- ToolCallOutputItem(
408
- output=str(result),
409
- raw_item=ItemHelpers.tool_call_output_item(tool_run.tool_call, str(result)),
410
- agent=agent,
441
+ FunctionToolResult(
442
+ tool=tool_run.function_tool,
443
+ output=result,
444
+ run_item=ToolCallOutputItem(
445
+ output=result,
446
+ raw_item=ItemHelpers.tool_call_output_item(tool_run.tool_call, str(result)),
447
+ agent=agent,
448
+ ),
411
449
  )
412
450
  for tool_run, result in zip(tool_runs, results)
413
451
  ]
@@ -502,7 +540,7 @@ class RunImpl:
502
540
  source=agent,
503
541
  )
504
542
  if agent.hooks
505
- else _utils.noop_coroutine()
543
+ else _coro.noop_coroutine()
506
544
  ),
507
545
  )
508
546
 
@@ -520,7 +558,7 @@ class RunImpl:
520
558
  new_items=tuple(new_step_items),
521
559
  )
522
560
  if not callable(input_filter):
523
- _utils.attach_error_to_span(
561
+ _error_tracing.attach_error_to_span(
524
562
  span_handoff,
525
563
  SpanError(
526
564
  message="Invalid input filter",
@@ -530,7 +568,7 @@ class RunImpl:
530
568
  raise UserError(f"Invalid input filter: {input_filter}")
531
569
  filtered = input_filter(handoff_input_data)
532
570
  if not isinstance(filtered, HandoffInputData):
533
- _utils.attach_error_to_span(
571
+ _error_tracing.attach_error_to_span(
534
572
  span_handoff,
535
573
  SpanError(
536
574
  message="Invalid input filter result",
@@ -591,7 +629,7 @@ class RunImpl:
591
629
  hooks.on_agent_end(context_wrapper, agent, final_output),
592
630
  agent.hooks.on_end(context_wrapper, agent, final_output)
593
631
  if agent.hooks
594
- else _utils.noop_coroutine(),
632
+ else _coro.noop_coroutine(),
595
633
  )
596
634
 
597
635
  @classmethod
@@ -646,6 +684,47 @@ class RunImpl:
646
684
  if event:
647
685
  queue.put_nowait(event)
648
686
 
687
+ @classmethod
688
+ async def _check_for_final_output_from_tools(
689
+ cls,
690
+ *,
691
+ agent: Agent[TContext],
692
+ tool_results: list[FunctionToolResult],
693
+ context_wrapper: RunContextWrapper[TContext],
694
+ config: RunConfig,
695
+ ) -> ToolsToFinalOutputResult:
696
+ """Returns (i, final_output)."""
697
+ if not tool_results:
698
+ return _NOT_FINAL_OUTPUT
699
+
700
+ if agent.tool_use_behavior == "run_llm_again":
701
+ return _NOT_FINAL_OUTPUT
702
+ elif agent.tool_use_behavior == "stop_on_first_tool":
703
+ return ToolsToFinalOutputResult(
704
+ is_final_output=True, final_output=tool_results[0].output
705
+ )
706
+ elif isinstance(agent.tool_use_behavior, dict):
707
+ names = agent.tool_use_behavior.get("stop_at_tool_names", [])
708
+ for tool_result in tool_results:
709
+ if tool_result.tool.name in names:
710
+ return ToolsToFinalOutputResult(
711
+ is_final_output=True, final_output=tool_result.output
712
+ )
713
+ return ToolsToFinalOutputResult(is_final_output=False, final_output=None)
714
+ elif callable(agent.tool_use_behavior):
715
+ if inspect.iscoroutinefunction(agent.tool_use_behavior):
716
+ return await cast(
717
+ Awaitable[ToolsToFinalOutputResult],
718
+ agent.tool_use_behavior(context_wrapper, tool_results),
719
+ )
720
+ else:
721
+ return cast(
722
+ ToolsToFinalOutputResult, agent.tool_use_behavior(context_wrapper, tool_results)
723
+ )
724
+
725
+ logger.error(f"Invalid tool_use_behavior: {agent.tool_use_behavior}")
726
+ raise UserError(f"Invalid tool_use_behavior: {agent.tool_use_behavior}")
727
+
649
728
 
650
729
  class TraceCtxManager:
651
730
  """Creates a trace only if there is no current trace, and manages the trace lifecycle."""
@@ -706,7 +785,7 @@ class ComputerAction:
706
785
  (
707
786
  agent.hooks.on_tool_start(context_wrapper, agent, action.computer_tool)
708
787
  if agent.hooks
709
- else _utils.noop_coroutine()
788
+ else _coro.noop_coroutine()
710
789
  ),
711
790
  output_func,
712
791
  )
@@ -716,7 +795,7 @@ class ComputerAction:
716
795
  (
717
796
  agent.hooks.on_tool_end(context_wrapper, agent, action.computer_tool, output)
718
797
  if agent.hooks
719
- else _utils.noop_coroutine()
798
+ else _coro.noop_coroutine()
720
799
  ),
721
800
  )
722
801
 
agents/agent.py CHANGED
@@ -4,10 +4,10 @@ import dataclasses
4
4
  import inspect
5
5
  from collections.abc import Awaitable
6
6
  from dataclasses import dataclass, field
7
- from typing import TYPE_CHECKING, Any, Callable, Generic, cast
7
+ from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, cast
8
+
9
+ from typing_extensions import TypeAlias, TypedDict
8
10
 
9
- from . import _utils
10
- from ._utils import MaybeAwaitable
11
11
  from .guardrail import InputGuardrail, OutputGuardrail
12
12
  from .handoffs import Handoff
13
13
  from .items import ItemHelpers
@@ -15,20 +15,49 @@ from .logger import logger
15
15
  from .model_settings import ModelSettings
16
16
  from .models.interface import Model
17
17
  from .run_context import RunContextWrapper, TContext
18
- from .tool import Tool, function_tool
18
+ from .tool import FunctionToolResult, Tool, function_tool
19
+ from .util import _transforms
20
+ from .util._types import MaybeAwaitable
19
21
 
20
22
  if TYPE_CHECKING:
21
23
  from .lifecycle import AgentHooks
22
24
  from .result import RunResult
23
25
 
24
26
 
27
+ @dataclass
28
+ class ToolsToFinalOutputResult:
29
+ is_final_output: bool
30
+ """Whether this is the final output. If False, the LLM will run again and receive the tool call
31
+ output.
32
+ """
33
+
34
+ final_output: Any | None = None
35
+ """The final output. Can be None if `is_final_output` is False, otherwise must match the
36
+ `output_type` of the agent.
37
+ """
38
+
39
+
40
+ ToolsToFinalOutputFunction: TypeAlias = Callable[
41
+ [RunContextWrapper[TContext], list[FunctionToolResult]],
42
+ MaybeAwaitable[ToolsToFinalOutputResult],
43
+ ]
44
+ """A function that takes a run context and a list of tool results, and returns a
45
+ `ToolToFinalOutputResult`.
46
+ """
47
+
48
+
49
+ class StopAtTools(TypedDict):
50
+ stop_at_tool_names: list[str]
51
+ """A list of tool names, any of which will stop the agent from running further."""
52
+
53
+
25
54
  @dataclass
26
55
  class Agent(Generic[TContext]):
27
56
  """An agent is an AI model configured with instructions, tools, guardrails, handoffs and more.
28
57
 
29
58
  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.
59
+ addition, you can pass `handoff_description`, which is a human-readable description of the
60
+ agent, used when the agent is used inside tools/handoffs.
32
61
 
33
62
  Agents are generic on the context type. The context is a (mutable) object you create. It is
34
63
  passed to tool functions, handoffs, guardrails, etc.
@@ -95,6 +124,25 @@ class Agent(Generic[TContext]):
95
124
  """A class that receives callbacks on various lifecycle events for this agent.
96
125
  """
97
126
 
127
+ tool_use_behavior: (
128
+ Literal["run_llm_again", "stop_on_first_tool"] | StopAtTools | ToolsToFinalOutputFunction
129
+ ) = "run_llm_again"
130
+ """This lets you configure how tool use is handled.
131
+ - "run_llm_again": The default behavior. Tools are run, and then the LLM receives the results
132
+ and gets to respond.
133
+ - "stop_on_first_tool": The output of the first tool call is used as the final output. This
134
+ means that the LLM does not process the result of the tool call.
135
+ - A list of tool names: The agent will stop running if any of the tools in the list are called.
136
+ The final output will be the output of the first matching tool call. The LLM does not
137
+ process the result of the tool call.
138
+ - A function: If you pass a function, it will be called with the run context and the list of
139
+ tool results. It must return a `ToolToFinalOutputResult`, which determines whether the tool
140
+ calls result in a final output.
141
+
142
+ NOTE: This configuration is specific to FunctionTools. Hosted tools, such as file search,
143
+ web search, etc are always processed by the LLM.
144
+ """
145
+
98
146
  def clone(self, **kwargs: Any) -> Agent[TContext]:
99
147
  """Make a copy of the agent, with the given arguments changed. For example, you could do:
100
148
  ```
@@ -126,7 +174,7 @@ class Agent(Generic[TContext]):
126
174
  """
127
175
 
128
176
  @function_tool(
129
- name_override=tool_name or _utils.transform_string_function_style(self.name),
177
+ name_override=tool_name or _transforms.transform_string_function_style(self.name),
130
178
  description_override=tool_description or "",
131
179
  )
132
180
  async def run_agent(context: RunContextWrapper, input: str) -> str:
agents/agent_output.py CHANGED
@@ -4,10 +4,10 @@ from typing import Any
4
4
  from pydantic import BaseModel, TypeAdapter
5
5
  from typing_extensions import TypedDict, get_args, get_origin
6
6
 
7
- from . import _utils
8
7
  from .exceptions import ModelBehaviorError, UserError
9
8
  from .strict_schema import ensure_strict_json_schema
10
9
  from .tracing import SpanError
10
+ from .util import _error_tracing, _json
11
11
 
12
12
  _WRAPPER_DICT_KEY = "response"
13
13
 
@@ -87,10 +87,10 @@ class AgentOutputSchema:
87
87
  """Validate a JSON string against the output type. Returns the validated object, or raises
88
88
  a `ModelBehaviorError` if the JSON is invalid.
89
89
  """
90
- validated = _utils.validate_json(json_str, self._type_adapter, partial)
90
+ validated = _json.validate_json(json_str, self._type_adapter, partial)
91
91
  if self._is_wrapped:
92
92
  if not isinstance(validated, dict):
93
- _utils.attach_error_to_current_span(
93
+ _error_tracing.attach_error_to_current_span(
94
94
  SpanError(
95
95
  message="Invalid JSON",
96
96
  data={"details": f"Expected a dict, got {type(validated)}"},
@@ -101,7 +101,7 @@ class AgentOutputSchema:
101
101
  )
102
102
 
103
103
  if _WRAPPER_DICT_KEY not in validated:
104
- _utils.attach_error_to_current_span(
104
+ _error_tracing.attach_error_to_current_span(
105
105
  SpanError(
106
106
  message="Invalid JSON",
107
107
  data={"details": f"Could not find key {_WRAPPER_DICT_KEY} in JSON"},
agents/function_schema.py CHANGED
@@ -33,6 +33,9 @@ class FuncSchema:
33
33
  """The signature of the function."""
34
34
  takes_context: bool = False
35
35
  """Whether the function takes a RunContextWrapper argument (must be the first argument)."""
36
+ strict_json_schema: bool = True
37
+ """Whether the JSON schema is in strict mode. We **strongly** recommend setting this to True,
38
+ as it increases the likelihood of correct JSON input."""
36
39
 
37
40
  def to_call_args(self, data: BaseModel) -> tuple[list[Any], dict[str, Any]]:
38
41
  """
@@ -337,4 +340,5 @@ def function_schema(
337
340
  params_json_schema=json_schema,
338
341
  signature=sig,
339
342
  takes_context=takes_context,
343
+ strict_json_schema=strict_json_schema,
340
344
  )
agents/guardrail.py CHANGED
@@ -7,10 +7,10 @@ from typing import TYPE_CHECKING, Any, Callable, Generic, Union, overload
7
7
 
8
8
  from typing_extensions import TypeVar
9
9
 
10
- from ._utils import MaybeAwaitable
11
10
  from .exceptions import UserError
12
11
  from .items import TResponseInputItem
13
12
  from .run_context import RunContextWrapper, TContext
13
+ from .util._types import MaybeAwaitable
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from .agent import Agent
agents/handoffs.py CHANGED
@@ -8,12 +8,12 @@ from typing import TYPE_CHECKING, Any, Callable, Generic, cast, overload
8
8
  from pydantic import TypeAdapter
9
9
  from typing_extensions import TypeAlias, TypeVar
10
10
 
11
- from . import _utils
12
11
  from .exceptions import ModelBehaviorError, UserError
13
12
  from .items import RunItem, TResponseInputItem
14
13
  from .run_context import RunContextWrapper, TContext
15
14
  from .strict_schema import ensure_strict_json_schema
16
15
  from .tracing.spans import SpanError
16
+ from .util import _error_tracing, _json, _transforms
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from .agent import Agent
@@ -104,7 +104,7 @@ class Handoff(Generic[TContext]):
104
104
 
105
105
  @classmethod
106
106
  def default_tool_name(cls, agent: Agent[Any]) -> str:
107
- return _utils.transform_string_function_style(f"transfer_to_{agent.name}")
107
+ return _transforms.transform_string_function_style(f"transfer_to_{agent.name}")
108
108
 
109
109
  @classmethod
110
110
  def default_tool_description(cls, agent: Agent[Any]) -> str:
@@ -192,7 +192,7 @@ def handoff(
192
192
  ) -> Agent[Any]:
193
193
  if input_type is not None and type_adapter is not None:
194
194
  if input_json is None:
195
- _utils.attach_error_to_current_span(
195
+ _error_tracing.attach_error_to_current_span(
196
196
  SpanError(
197
197
  message="Handoff function expected non-null input, but got None",
198
198
  data={"details": "input_json is None"},
@@ -200,7 +200,7 @@ def handoff(
200
200
  )
201
201
  raise ModelBehaviorError("Handoff function expected non-null input, but got None")
202
202
 
203
- validated_input = _utils.validate_json(
203
+ validated_input = _json.validate_json(
204
204
  json_str=input_json,
205
205
  type_adapter=type_adapter,
206
206
  partial=False,
agents/items.py CHANGED
@@ -129,8 +129,10 @@ class ToolCallOutputItem(RunItemBase[Union[FunctionCallOutput, ComputerCallOutpu
129
129
  raw_item: FunctionCallOutput | ComputerCallOutput
130
130
  """The raw item from the model."""
131
131
 
132
- output: str
133
- """The output of the tool call."""
132
+ output: Any
133
+ """The output of the tool call. This is whatever the tool call returned; the `raw_item`
134
+ contains a string representation of the output.
135
+ """
134
136
 
135
137
  type: Literal["tool_call_output_item"] = "tool_call_output_item"
136
138
 
@@ -54,7 +54,7 @@ from openai.types.responses import (
54
54
  ResponseUsage,
55
55
  )
56
56
  from openai.types.responses.response_input_param import FunctionCallOutput, ItemReference, Message
57
- from openai.types.responses.response_usage import OutputTokensDetails
57
+ from openai.types.responses.response_usage import InputTokensDetails, OutputTokensDetails
58
58
 
59
59
  from .. import _debug
60
60
  from ..agent_output import AgentOutputSchema
@@ -420,6 +420,11 @@ class OpenAIChatCompletionsModel(Model):
420
420
  and usage.completion_tokens_details.reasoning_tokens
421
421
  else 0
422
422
  ),
423
+ input_tokens_details=InputTokensDetails(
424
+ cached_tokens=usage.prompt_tokens_details.cached_tokens
425
+ if usage.prompt_tokens_details and usage.prompt_tokens_details.cached_tokens
426
+ else 0
427
+ ),
423
428
  )
424
429
  if usage
425
430
  else None
agents/result.py CHANGED
@@ -17,6 +17,7 @@ from .items import ItemHelpers, ModelResponse, RunItem, TResponseInputItem
17
17
  from .logger import logger
18
18
  from .stream_events import StreamEvent
19
19
  from .tracing import Trace
20
+ from .util._pretty_print import pretty_print_result, pretty_print_run_result_streaming
20
21
 
21
22
  if TYPE_CHECKING:
22
23
  from ._run_impl import QueueCompleteSentinel
@@ -89,6 +90,9 @@ class RunResult(RunResultBase):
89
90
  """The last agent that was run."""
90
91
  return self._last_agent
91
92
 
93
+ def __str__(self) -> str:
94
+ return pretty_print_result(self)
95
+
92
96
 
93
97
  @dataclass
94
98
  class RunResultStreaming(RunResultBase):
@@ -216,3 +220,6 @@ class RunResultStreaming(RunResultBase):
216
220
 
217
221
  if self._output_guardrails_task and not self._output_guardrails_task.done():
218
222
  self._output_guardrails_task.cancel()
223
+
224
+ def __str__(self) -> str:
225
+ return pretty_print_run_result_streaming(self)
agents/run.py CHANGED
@@ -7,7 +7,6 @@ from typing import Any, cast
7
7
 
8
8
  from openai.types.responses import ResponseCompletedEvent
9
9
 
10
- from . import Model, _utils
11
10
  from ._run_impl import (
12
11
  NextStepFinalOutput,
13
12
  NextStepHandoff,
@@ -33,7 +32,7 @@ from .items import ItemHelpers, ModelResponse, RunItem, TResponseInputItem
33
32
  from .lifecycle import RunHooks
34
33
  from .logger import logger
35
34
  from .model_settings import ModelSettings
36
- from .models.interface import ModelProvider
35
+ from .models.interface import Model, ModelProvider
37
36
  from .models.openai_provider import OpenAIProvider
38
37
  from .result import RunResult, RunResultStreaming
39
38
  from .run_context import RunContextWrapper, TContext
@@ -41,6 +40,7 @@ from .stream_events import AgentUpdatedStreamEvent, RawResponsesStreamEvent
41
40
  from .tracing import Span, SpanError, agent_span, get_current_trace, trace
42
41
  from .tracing.span_data import AgentSpanData
43
42
  from .usage import Usage
43
+ from .util import _coro, _error_tracing
44
44
 
45
45
  DEFAULT_MAX_TURNS = 10
46
46
 
@@ -193,7 +193,7 @@ class Runner:
193
193
 
194
194
  current_turn += 1
195
195
  if current_turn > max_turns:
196
- _utils.attach_error_to_span(
196
+ _error_tracing.attach_error_to_span(
197
197
  current_span,
198
198
  SpanError(
199
199
  message="Max turns exceeded",
@@ -447,7 +447,7 @@ class Runner:
447
447
  for done in asyncio.as_completed(guardrail_tasks):
448
448
  result = await done
449
449
  if result.output.tripwire_triggered:
450
- _utils.attach_error_to_span(
450
+ _error_tracing.attach_error_to_span(
451
451
  parent_span,
452
452
  SpanError(
453
453
  message="Guardrail tripwire triggered",
@@ -511,7 +511,7 @@ class Runner:
511
511
  streamed_result.current_turn = current_turn
512
512
 
513
513
  if current_turn > max_turns:
514
- _utils.attach_error_to_span(
514
+ _error_tracing.attach_error_to_span(
515
515
  current_span,
516
516
  SpanError(
517
517
  message="Max turns exceeded",
@@ -583,7 +583,7 @@ class Runner:
583
583
  pass
584
584
  except Exception as e:
585
585
  if current_span:
586
- _utils.attach_error_to_span(
586
+ _error_tracing.attach_error_to_span(
587
587
  current_span,
588
588
  SpanError(
589
589
  message="Error in agent run",
@@ -615,7 +615,7 @@ class Runner:
615
615
  (
616
616
  agent.hooks.on_start(context_wrapper, agent)
617
617
  if agent.hooks
618
- else _utils.noop_coroutine()
618
+ else _coro.noop_coroutine()
619
619
  ),
620
620
  )
621
621
 
@@ -705,7 +705,7 @@ class Runner:
705
705
  (
706
706
  agent.hooks.on_start(context_wrapper, agent)
707
707
  if agent.hooks
708
- else _utils.noop_coroutine()
708
+ else _coro.noop_coroutine()
709
709
  ),
710
710
  )
711
711
 
@@ -796,7 +796,7 @@ class Runner:
796
796
  # Cancel all guardrail tasks if a tripwire is triggered.
797
797
  for t in guardrail_tasks:
798
798
  t.cancel()
799
- _utils.attach_error_to_current_span(
799
+ _error_tracing.attach_error_to_current_span(
800
800
  SpanError(
801
801
  message="Guardrail tripwire triggered",
802
802
  data={"guardrail": result.guardrail.get_name()},
@@ -834,7 +834,7 @@ class Runner:
834
834
  # Cancel all guardrail tasks if a tripwire is triggered.
835
835
  for t in guardrail_tasks:
836
836
  t.cancel()
837
- _utils.attach_error_to_current_span(
837
+ _error_tracing.attach_error_to_current_span(
838
838
  SpanError(
839
839
  message="Guardrail tripwire triggered",
840
840
  data={"guardrail": result.guardrail.get_name()},
agents/tool.py CHANGED
@@ -11,14 +11,16 @@ from openai.types.responses.web_search_tool_param import UserLocation
11
11
  from pydantic import ValidationError
12
12
  from typing_extensions import Concatenate, ParamSpec
13
13
 
14
- from . import _debug, _utils
15
- from ._utils import MaybeAwaitable
14
+ from . import _debug
16
15
  from .computer import AsyncComputer, Computer
17
16
  from .exceptions import ModelBehaviorError
18
17
  from .function_schema import DocstringStyle, function_schema
18
+ from .items import RunItem
19
19
  from .logger import logger
20
20
  from .run_context import RunContextWrapper
21
21
  from .tracing import SpanError
22
+ from .util import _error_tracing
23
+ from .util._types import MaybeAwaitable
22
24
 
23
25
  ToolParams = ParamSpec("ToolParams")
24
26
 
@@ -28,6 +30,18 @@ ToolFunctionWithContext = Callable[Concatenate[RunContextWrapper[Any], ToolParam
28
30
  ToolFunction = Union[ToolFunctionWithoutContext[ToolParams], ToolFunctionWithContext[ToolParams]]
29
31
 
30
32
 
33
+ @dataclass
34
+ class FunctionToolResult:
35
+ tool: FunctionTool
36
+ """The tool that was run."""
37
+
38
+ output: Any
39
+ """The output of the tool."""
40
+
41
+ run_item: RunItem
42
+ """The run item that was produced as a result of the tool call."""
43
+
44
+
31
45
  @dataclass
32
46
  class FunctionTool:
33
47
  """A tool that wraps a function. In most cases, you should use the `function_tool` helpers to
@@ -43,15 +57,15 @@ class FunctionTool:
43
57
  params_json_schema: dict[str, Any]
44
58
  """The JSON schema for the tool's parameters."""
45
59
 
46
- on_invoke_tool: Callable[[RunContextWrapper[Any], str], Awaitable[str]]
60
+ on_invoke_tool: Callable[[RunContextWrapper[Any], str], Awaitable[Any]]
47
61
  """A function that invokes the tool with the given context and parameters. The params passed
48
62
  are:
49
63
  1. The tool run context.
50
64
  2. The arguments from the LLM, as a JSON string.
51
65
 
52
- You must return a string representation of the tool output. In case of errors, you can either
53
- raise an Exception (which will cause the run to fail) or return a string error message (which
54
- will be sent back to the LLM).
66
+ You must return a string representation of the tool output, or something we can call `str()` on.
67
+ In case of errors, you can either raise an Exception (which will cause the run to fail) or
68
+ return a string error message (which will be sent back to the LLM).
55
69
  """
56
70
 
57
71
  strict_json_schema: bool = True
@@ -137,6 +151,7 @@ def function_tool(
137
151
  docstring_style: DocstringStyle | None = None,
138
152
  use_docstring_info: bool = True,
139
153
  failure_error_function: ToolErrorFunction | None = None,
154
+ strict_mode: bool = True,
140
155
  ) -> FunctionTool:
141
156
  """Overload for usage as @function_tool (no parentheses)."""
142
157
  ...
@@ -150,6 +165,7 @@ def function_tool(
150
165
  docstring_style: DocstringStyle | None = None,
151
166
  use_docstring_info: bool = True,
152
167
  failure_error_function: ToolErrorFunction | None = None,
168
+ strict_mode: bool = True,
153
169
  ) -> Callable[[ToolFunction[...]], FunctionTool]:
154
170
  """Overload for usage as @function_tool(...)."""
155
171
  ...
@@ -163,6 +179,7 @@ def function_tool(
163
179
  docstring_style: DocstringStyle | None = None,
164
180
  use_docstring_info: bool = True,
165
181
  failure_error_function: ToolErrorFunction | None = default_tool_error_function,
182
+ strict_mode: bool = True,
166
183
  ) -> FunctionTool | Callable[[ToolFunction[...]], FunctionTool]:
167
184
  """
168
185
  Decorator to create a FunctionTool from a function. By default, we will:
@@ -186,6 +203,11 @@ def function_tool(
186
203
  failure_error_function: If provided, use this function to generate an error message when
187
204
  the tool call fails. The error message is sent to the LLM. If you pass None, then no
188
205
  error message will be sent and instead an Exception will be raised.
206
+ strict_mode: Whether to enable strict mode for the tool's JSON schema. We *strongly*
207
+ recommend setting this to True, as it increases the likelihood of correct JSON input.
208
+ If False, it allows non-strict JSON schemas. For example, if a parameter has a default
209
+ value, it will be optional, additional properties are allowed, etc. See here for more:
210
+ https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#supported-schemas
189
211
  """
190
212
 
191
213
  def _create_function_tool(the_func: ToolFunction[...]) -> FunctionTool:
@@ -195,9 +217,10 @@ def function_tool(
195
217
  description_override=description_override,
196
218
  docstring_style=docstring_style,
197
219
  use_docstring_info=use_docstring_info,
220
+ strict_json_schema=strict_mode,
198
221
  )
199
222
 
200
- async def _on_invoke_tool_impl(ctx: RunContextWrapper[Any], input: str) -> str:
223
+ async def _on_invoke_tool_impl(ctx: RunContextWrapper[Any], input: str) -> Any:
201
224
  try:
202
225
  json_data: dict[str, Any] = json.loads(input) if input else {}
203
226
  except Exception as e:
@@ -244,9 +267,9 @@ def function_tool(
244
267
  else:
245
268
  logger.debug(f"Tool {schema.name} returned {result}")
246
269
 
247
- return str(result)
270
+ return result
248
271
 
249
- async def _on_invoke_tool(ctx: RunContextWrapper[Any], input: str) -> str:
272
+ async def _on_invoke_tool(ctx: RunContextWrapper[Any], input: str) -> Any:
250
273
  try:
251
274
  return await _on_invoke_tool_impl(ctx, input)
252
275
  except Exception as e:
@@ -257,7 +280,7 @@ def function_tool(
257
280
  if inspect.isawaitable(result):
258
281
  return await result
259
282
 
260
- _utils.attach_error_to_current_span(
283
+ _error_tracing.attach_error_to_current_span(
261
284
  SpanError(
262
285
  message="Error running tool (non-fatal)",
263
286
  data={
@@ -273,6 +296,7 @@ def function_tool(
273
296
  description=schema.description or "",
274
297
  params_json_schema=schema.params_json_schema,
275
298
  on_invoke_tool=_on_invoke_tool,
299
+ strict_json_schema=strict_mode,
276
300
  )
277
301
 
278
302
  # If func is actually a callable, we were used as @function_tool with no parentheses
agents/tracing/create.py CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from collections.abc import Mapping, Sequence
4
4
  from typing import TYPE_CHECKING, Any
5
5
 
6
- from .logger import logger
6
+ from ..logger import logger
7
7
  from .setup import GLOBAL_TRACE_PROVIDER
8
8
  from .span_data import (
9
9
  AgentSpanData,
@@ -9,7 +9,7 @@ from typing import Any
9
9
 
10
10
  import httpx
11
11
 
12
- from .logger import logger
12
+ from ..logger import logger
13
13
  from .processor_interface import TracingExporter, TracingProcessor
14
14
  from .spans import Span
15
15
  from .traces import Trace
@@ -40,7 +40,7 @@ class BackendSpanExporter(TracingExporter):
40
40
  """
41
41
  Args:
42
42
  api_key: The API key for the "Authorization" header. Defaults to
43
- `os.environ["OPENAI_TRACE_API_KEY"]` if not provided.
43
+ `os.environ["OPENAI_API_KEY"]` if not provided.
44
44
  organization: The OpenAI organization to use. Defaults to
45
45
  `os.environ["OPENAI_ORG_ID"]` if not provided.
46
46
  project: The OpenAI project to use. Defaults to
agents/tracing/scope.py CHANGED
@@ -2,7 +2,7 @@
2
2
  import contextvars
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- from .logger import logger
5
+ from ..logger import logger
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from .spans import Span
agents/tracing/setup.py CHANGED
@@ -4,8 +4,8 @@ import os
4
4
  import threading
5
5
  from typing import Any
6
6
 
7
+ from ..logger import logger
7
8
  from . import util
8
- from .logger import logger
9
9
  from .processor_interface import TracingProcessor
10
10
  from .scope import Scope
11
11
  from .spans import NoOpSpan, Span, SpanImpl, TSpanData
@@ -51,7 +51,7 @@ class AgentSpanData(SpanData):
51
51
  class FunctionSpanData(SpanData):
52
52
  __slots__ = ("name", "input", "output")
53
53
 
54
- def __init__(self, name: str, input: str | None, output: str | None):
54
+ def __init__(self, name: str, input: str | None, output: Any | None):
55
55
  self.name = name
56
56
  self.input = input
57
57
  self.output = output
@@ -65,7 +65,7 @@ class FunctionSpanData(SpanData):
65
65
  "type": self.type,
66
66
  "name": self.name,
67
67
  "input": self.input,
68
- "output": self.output,
68
+ "output": str(self.output) if self.output else None,
69
69
  }
70
70
 
71
71
 
agents/tracing/spans.py CHANGED
@@ -6,8 +6,8 @@ from typing import Any, Generic, TypeVar
6
6
 
7
7
  from typing_extensions import TypedDict
8
8
 
9
+ from ..logger import logger
9
10
  from . import util
10
- from .logger import logger
11
11
  from .processor_interface import TracingProcessor
12
12
  from .scope import Scope
13
13
  from .span_data import SpanData
agents/tracing/traces.py CHANGED
@@ -4,8 +4,8 @@ import abc
4
4
  import contextvars
5
5
  from typing import Any
6
6
 
7
+ from ..logger import logger
7
8
  from . import util
8
- from .logger import logger
9
9
  from .processor_interface import TracingProcessor
10
10
  from .scope import Scope
11
11
 
File without changes
agents/util/_coro.py ADDED
@@ -0,0 +1,2 @@
1
+ async def noop_coroutine() -> None:
2
+ pass
@@ -0,0 +1,16 @@
1
+ from typing import Any
2
+
3
+ from ..logger import logger
4
+ from ..tracing import Span, SpanError, get_current_span
5
+
6
+
7
+ def attach_error_to_span(span: Span[Any], error: SpanError) -> None:
8
+ span.set_error(error)
9
+
10
+
11
+ def attach_error_to_current_span(error: SpanError) -> None:
12
+ span = get_current_span()
13
+ if span:
14
+ attach_error_to_span(span, error)
15
+ else:
16
+ logger.warning(f"No span to add error {error} to")
agents/util/_json.py ADDED
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ from pydantic import TypeAdapter, ValidationError
6
+ from typing_extensions import TypeVar
7
+
8
+ from ..exceptions import ModelBehaviorError
9
+ from ..tracing import SpanError
10
+ from ._error_tracing import attach_error_to_current_span
11
+
12
+ T = TypeVar("T")
13
+
14
+
15
+ def validate_json(json_str: str, type_adapter: TypeAdapter[T], partial: bool) -> T:
16
+ partial_setting: bool | Literal["off", "on", "trailing-strings"] = (
17
+ "trailing-strings" if partial else False
18
+ )
19
+ try:
20
+ validated = type_adapter.validate_json(json_str, experimental_allow_partial=partial_setting)
21
+ return validated
22
+ except ValidationError as e:
23
+ attach_error_to_current_span(
24
+ SpanError(
25
+ message="Invalid JSON provided",
26
+ data={},
27
+ )
28
+ )
29
+ raise ModelBehaviorError(
30
+ f"Invalid JSON when parsing {json_str} for {type_adapter}; {e}"
31
+ ) from e
@@ -0,0 +1,56 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from pydantic import BaseModel
4
+
5
+ if TYPE_CHECKING:
6
+ from ..result import RunResult, RunResultBase, RunResultStreaming
7
+
8
+
9
+ def _indent(text: str, indent_level: int) -> str:
10
+ indent_string = " " * indent_level
11
+ return "\n".join(f"{indent_string}{line}" for line in text.splitlines())
12
+
13
+
14
+ def _final_output_str(result: "RunResultBase") -> str:
15
+ if result.final_output is None:
16
+ return "None"
17
+ elif isinstance(result.final_output, str):
18
+ return result.final_output
19
+ elif isinstance(result.final_output, BaseModel):
20
+ return result.final_output.model_dump_json(indent=2)
21
+ else:
22
+ return str(result.final_output)
23
+
24
+
25
+ def pretty_print_result(result: "RunResult") -> str:
26
+ output = "RunResult:"
27
+ output += f'\n- Last agent: Agent(name="{result.last_agent.name}", ...)'
28
+ output += (
29
+ f"\n- Final output ({type(result.final_output).__name__}):\n"
30
+ f"{_indent(_final_output_str(result), 2)}"
31
+ )
32
+ output += f"\n- {len(result.new_items)} new item(s)"
33
+ output += f"\n- {len(result.raw_responses)} raw response(s)"
34
+ output += f"\n- {len(result.input_guardrail_results)} input guardrail result(s)"
35
+ output += f"\n- {len(result.output_guardrail_results)} output guardrail result(s)"
36
+ output += "\n(See `RunResult` for more details)"
37
+
38
+ return output
39
+
40
+
41
+ def pretty_print_run_result_streaming(result: "RunResultStreaming") -> str:
42
+ output = "RunResultStreaming:"
43
+ output += f'\n- Current agent: Agent(name="{result.current_agent.name}", ...)'
44
+ output += f"\n- Current turn: {result.current_turn}"
45
+ output += f"\n- Max turns: {result.max_turns}"
46
+ output += f"\n- Is complete: {result.is_complete}"
47
+ output += (
48
+ f"\n- Final output ({type(result.final_output).__name__}):\n"
49
+ f"{_indent(_final_output_str(result), 2)}"
50
+ )
51
+ output += f"\n- {len(result.new_items)} new item(s)"
52
+ output += f"\n- {len(result.raw_responses)} raw response(s)"
53
+ output += f"\n- {len(result.input_guardrail_results)} input guardrail result(s)"
54
+ output += f"\n- {len(result.output_guardrail_results)} output guardrail result(s)"
55
+ output += "\n(See `RunResultStreaming` for more details)"
56
+ return output
@@ -0,0 +1,11 @@
1
+ import re
2
+
3
+
4
+ def transform_string_function_style(name: str) -> str:
5
+ # Replace spaces with underscores
6
+ name = name.replace(" ", "_")
7
+
8
+ # Replace non-alphanumeric characters with underscores
9
+ name = re.sub(r"[^a-zA-Z0-9]", "_", name)
10
+
11
+ return name.lower()
agents/util/_types.py ADDED
@@ -0,0 +1,7 @@
1
+ from collections.abc import Awaitable
2
+ from typing import Union
3
+
4
+ from typing_extensions import TypeVar
5
+
6
+ T = TypeVar("T")
7
+ MaybeAwaitable = Union[Awaitable[T], T]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openai-agents
3
- Version: 0.0.4
3
+ Version: 0.0.5
4
4
  Summary: OpenAI Agents SDK
5
5
  Project-URL: Homepage, https://github.com/openai/openai-agents-python
6
6
  Project-URL: Repository, https://github.com/openai/openai-agents-python
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Classifier: Typing :: Typed
20
20
  Requires-Python: >=3.9
21
21
  Requires-Dist: griffe<2,>=1.5.6
22
- Requires-Dist: openai>=1.66.2
22
+ Requires-Dist: openai>=1.66.5
23
23
  Requires-Dist: pydantic<3,>=2.10
24
24
  Requires-Dist: requests<3,>=2.0
25
25
  Requires-Dist: types-requests<3,>=2.0
@@ -35,7 +35,7 @@ The OpenAI Agents SDK is a lightweight yet powerful framework for building multi
35
35
  ### Core concepts:
36
36
 
37
37
  1. [**Agents**](https://openai.github.io/openai-agents-python/agents): LLMs configured with instructions, tools, guardrails, and handoffs
38
- 2. [**Handoffs**](https://openai.github.io/openai-agents-python/handoffs/): Allow agents to transfer control to other agents for specific tasks
38
+ 2. [**Handoffs**](https://openai.github.io/openai-agents-python/handoffs/): A specialized tool call used by the Agents SDK for transferring control between agents
39
39
  3. [**Guardrails**](https://openai.github.io/openai-agents-python/guardrails/): Configurable safety checks for input and output validation
40
40
  4. [**Tracing**](https://openai.github.io/openai-agents-python/tracing/): Built-in tracking of agent runs, allowing you to view, debug and optimize your workflows
41
41
 
@@ -170,7 +170,7 @@ The Agents SDK is designed to be highly flexible, allowing you to model a wide r
170
170
 
171
171
  ## Tracing
172
172
 
173
- 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), [Scorecard](https://docs.scorecard.io/docs/documentation/features/tracing#openai-agents-sdk-integration), and [Keywords AI](https://docs.keywordsai.co/integration/development-frameworks/openai-agent). For more details about how to customize or disable tracing, see [Tracing](http://openai.github.io/openai-agents-python/tracing).
173
+ 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), [Scorecard](https://docs.scorecard.io/docs/documentation/features/tracing#openai-agents-sdk-integration), and [Keywords AI](https://docs.keywordsai.co/integration/development-frameworks/openai-agent). For more details about how to customize or disable tracing, see [Tracing](http://openai.github.io/openai-agents-python/tracing), which also includes a larger list of [external tracing processors](http://openai.github.io/openai-agents-python/tracing/#external-tracing-processors-list).
174
174
 
175
175
  ## Development (only needed if you need to edit the SDK/examples)
176
176
 
@@ -0,0 +1,55 @@
1
+ agents/__init__.py,sha256=vdpHPLytdNImdTlOJUnZi_Wx6Egot3q_InhcFixd6zU,6422
2
+ agents/_config.py,sha256=ANrM7GP2VSQehDkMc9qocxkUlPwqU-i5sieMJyEwxpM,796
3
+ agents/_debug.py,sha256=7OKys2lDjeCtGggTkM53m_8vw0WIr3yt-_JPBDAnsw0,608
4
+ agents/_run_impl.py,sha256=B-YeWxms2vi3SHMSsHPEjif0ZbcpxDetRugo-_mkUVw,31991
5
+ agents/agent.py,sha256=ODhpQ74vZfYpk_8vxExJEXBl1dJVsgudXabY9t069qQ,8324
6
+ agents/agent_output.py,sha256=sUlsur0_C2pPokyvspo5gxIkM0PtcNxdbZmeu_6Z4TE,5379
7
+ agents/computer.py,sha256=XD44UgiUWSfniv-xKwwDP6wFKVwBiZkpaL1hO-0-7ZA,2516
8
+ agents/exceptions.py,sha256=F3AltRt27PGdhbFqKBhRJL9eHqoN4SQx7oxBn0GWmhs,1856
9
+ agents/function_schema.py,sha256=8f90espzzVE4i9cCiOYAzX5zHHhYm195gX9Ytvtr1P4,12908
10
+ agents/guardrail.py,sha256=vWWcApo9s_6aHapQ5AMko08MqC8Jrlk-J5iqIRctCDQ,9291
11
+ agents/handoffs.py,sha256=wRg-HBGKBZev88mOg_mfv6CR8T2kewZM8eX3tb71l1g,9043
12
+ agents/items.py,sha256=xCoX-ZcUUs3WHN90_o8PQSnX8jt8oQ2TJPz7k74ooQ4,8182
13
+ agents/lifecycle.py,sha256=wYFG6PLSKQ7bICKVbB8oGtdoJNINGq9obh2RSKlAkDE,2938
14
+ agents/logger.py,sha256=p_ef7vWKpBev5FFybPJjhrCCQizK08Yy1A2EDO1SNNg,60
15
+ agents/model_settings.py,sha256=4JOqsLswjdrEszNqNEJ_dYjxUMCyt68hOIdgxlXELw0,2169
16
+ agents/result.py,sha256=JOscHoh2EIUY4w-ESO500Z3DnNYq67vtkRrWr70fOr4,8421
17
+ agents/run.py,sha256=SI0u7XQ6e3lEP6v1k530rDDcJJbg8K_DcdK2o0leCqI,37129
18
+ agents/run_context.py,sha256=vuSUQM8O4CLensQY27-22fOqECnw7yvwL9U3WO8b_bk,851
19
+ agents/stream_events.py,sha256=ULgBEcL_H4vklZoxhpY2yomeoxVF0UiXvswsFsjFv4s,1547
20
+ agents/strict_schema.py,sha256=FEyEvF3ZjxIHRLmraBGZyjJjuFiPCZGaCFV22LlwaTQ,5783
21
+ agents/tool.py,sha256=XKeR1khfbaPbyO8DiGsn8WMO_Hkbrmm9NQzGeRsKcPs,11641
22
+ agents/usage.py,sha256=-MZOmSDVdWxA2V_yVVnmUcwVcLdvYFccv0HXZ7Ow3_A,733
23
+ agents/version.py,sha256=bkeg2DaYBS8OnV7R7J6OuF5pNA__0mJ4QZsJjC1DTI0,223
24
+ agents/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ agents/extensions/handoff_filters.py,sha256=2cXxu1JROez96CpTiGuT9PIuaIrIE8ksP01fX83krKM,1977
26
+ agents/extensions/handoff_prompt.py,sha256=oGWN0uNh3Z1L7E-Ev2up8W084fFrDNOsLDy7P6bcmic,1006
27
+ agents/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ agents/models/_openai_shared.py,sha256=4Ngwo2Fv2RXY61Pqck1cYPkSln2tDnb8Ai-ao4QG-iE,836
29
+ agents/models/fake_id.py,sha256=lbXjUUSMeAQ8eFx4V5QLUnBClHE6adJlYYav55RlG5w,268
30
+ agents/models/interface.py,sha256=dgIlKyPaCbNRTHXxd6x7OQwJuAelG3F-C19P-aacHWQ,3129
31
+ agents/models/openai_chatcompletions.py,sha256=xs2JdEl0taqz3LIRWL8etr88tzpa_UWggAwAQPTyoxQ,39375
32
+ agents/models/openai_provider.py,sha256=3zKt8stSm0IcDJzX8GqXa3UcECKK79A290Zzem1nlUo,2784
33
+ agents/models/openai_responses.py,sha256=4CowZT0wAMflEzDgi6hEidcMq_0zchIm2uX_vV090TM,13386
34
+ agents/tracing/__init__.py,sha256=pp2_mBCQGL9oN6_czCWHQsV4ZTEOcy1AVxdjQ41PNr0,2424
35
+ agents/tracing/create.py,sha256=xn0n1Zr6Az4SMw0x_OeBNiBHJ1yYxL1FNhA_bLhBodY,12111
36
+ agents/tracing/logger.py,sha256=J4KUDRSGa7x5UVfUwWe-gbKwoaq8AeETRqkPt3QvtGg,68
37
+ agents/tracing/processor_interface.py,sha256=wNyZCwNJko5CrUIWD_lMou5ppQ67CFYwvWRsJRM3up8,1659
38
+ agents/tracing/processors.py,sha256=z3NAwo4ZG8KloEIq7ihIadxMfduL_cECY5XCgOaK1H8,9595
39
+ agents/tracing/scope.py,sha256=84gOESqFfR2E_XCZsT11DLyR-3UTyqxHrfBBjH1Ic44,1373
40
+ agents/tracing/setup.py,sha256=1wRMIVnsMOx5nWWnldqbTXg44a7-ABcC0jZK4q4I-S8,6729
41
+ agents/tracing/span_data.py,sha256=5VOoiHHakviJDeiLcPAQS_jy2hPS__GwKsREAUg8Bd4,4604
42
+ agents/tracing/spans.py,sha256=6vVzocGMsdgIma1ksqkBZmhar91xj4RpgcpUC3iibqg,6606
43
+ agents/tracing/traces.py,sha256=G5LlECSK-DBRFP-bjT8maZjBQulz6SaHILYauUVlfq8,4775
44
+ agents/tracing/util.py,sha256=BsDvn2rjE4SRQvfm55utljT8agdA0Z36KWXd1vdx4hs,392
45
+ agents/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ agents/util/_coro.py,sha256=S38XUYFC7bqTELSgMUBsAX1GoRlIrV7coupcUAWH__4,45
47
+ agents/util/_error_tracing.py,sha256=hdkYNx180b18lP0PSB1toE5atNHsMg_Bm9Osw812vLo,421
48
+ agents/util/_json.py,sha256=eKeQeMlQkBXRFeL3ilNZFmszGyfhtzZdW_GW_As6dcg,972
49
+ agents/util/_pretty_print.py,sha256=rRVp24UmTgzCm-W4ritWBOxxnPRinzFdrZlOhTi1KVQ,2227
50
+ agents/util/_transforms.py,sha256=CZe74NOHkHneyo4fHYfFWksCSTn-kXtEyejL9P0_xlA,270
51
+ agents/util/_types.py,sha256=8KxYfCw0gYSMWcQmacJoc3Q7Lc46LmT-AWvhF10KJ-E,160
52
+ openai_agents-0.0.5.dist-info/METADATA,sha256=fHalk7G3p4YxZCj85yRVbOpYX63vgxcR0mIFdEEpfgU,7757
53
+ openai_agents-0.0.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
54
+ openai_agents-0.0.5.dist-info/licenses/LICENSE,sha256=E994EspT7Krhy0qGiES7WYNzBHrh1YDk3r--8d1baRU,1063
55
+ openai_agents-0.0.5.dist-info/RECORD,,
agents/_utils.py DELETED
@@ -1,61 +0,0 @@
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
@@ -1,49 +0,0 @@
1
- agents/__init__.py,sha256=NGc7r2Su7RM8c1Ym3gl_LWDFMiIiL_bY-YUgFDDugYo,6267
2
- agents/_config.py,sha256=ANrM7GP2VSQehDkMc9qocxkUlPwqU-i5sieMJyEwxpM,796
3
- agents/_debug.py,sha256=7OKys2lDjeCtGggTkM53m_8vw0WIr3yt-_JPBDAnsw0,608
4
- agents/_run_impl.py,sha256=jMlWtHi7blDC8bJTpzQ1-Xi9wcPBiGUSyfItgw-L1io,28550
5
- agents/_utils.py,sha256=L21Hdl20U66Asp-W61yTnahmo8b6X58jsgdUBWb9_Rk,1685
6
- agents/agent.py,sha256=Y0lnIva9qL_WJVUVxDQtSrMa0KuM5IXLWK0q6CzIxas,6297
7
- agents/agent_output.py,sha256=k271F9MgMaoS1nPtsSwsURP8mNxv8VrEOWrv7PJSQT4,5345
8
- agents/computer.py,sha256=XD44UgiUWSfniv-xKwwDP6wFKVwBiZkpaL1hO-0-7ZA,2516
9
- agents/exceptions.py,sha256=F3AltRt27PGdhbFqKBhRJL9eHqoN4SQx7oxBn0GWmhs,1856
10
- agents/function_schema.py,sha256=OgeuiDhLowhYt6T9CU-7Fk05uKIxPaDPgL2hdnMFjpQ,12666
11
- agents/guardrail.py,sha256=3y4oGa-dPp75nsS15zZdJ-GBT34jDu5c8gMeFHC4SME,9286
12
- agents/handoffs.py,sha256=onlvwSCTNJKof2Ftk-qZ5-zxTNT9AimjvyOcxj4Rp38,8999
13
- agents/items.py,sha256=DQPAJQkAVRR9Js-RVDtp4eizxiVaL30bbB0W-8U7GuQ,8069
14
- agents/lifecycle.py,sha256=wYFG6PLSKQ7bICKVbB8oGtdoJNINGq9obh2RSKlAkDE,2938
15
- agents/logger.py,sha256=p_ef7vWKpBev5FFybPJjhrCCQizK08Yy1A2EDO1SNNg,60
16
- agents/model_settings.py,sha256=4JOqsLswjdrEszNqNEJ_dYjxUMCyt68hOIdgxlXELw0,2169
17
- agents/result.py,sha256=k8B5Q9Vf-H6IzGaEHqJyMNoairUcF4yCfnePS8Qanzo,8176
18
- agents/run.py,sha256=GLPPfHH7MswO_5oW27y7RsZVY5rbkvyCBxG4kbN5y-Q,37064
19
- agents/run_context.py,sha256=vuSUQM8O4CLensQY27-22fOqECnw7yvwL9U3WO8b_bk,851
20
- agents/stream_events.py,sha256=ULgBEcL_H4vklZoxhpY2yomeoxVF0UiXvswsFsjFv4s,1547
21
- agents/strict_schema.py,sha256=FEyEvF3ZjxIHRLmraBGZyjJjuFiPCZGaCFV22LlwaTQ,5783
22
- agents/tool.py,sha256=I6MD3H3wB9ka9FUOg6hlx9Swe9fceSnbH2BPMmNYXl0,10629
23
- agents/usage.py,sha256=-MZOmSDVdWxA2V_yVVnmUcwVcLdvYFccv0HXZ7Ow3_A,733
24
- agents/version.py,sha256=bkeg2DaYBS8OnV7R7J6OuF5pNA__0mJ4QZsJjC1DTI0,223
25
- agents/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- agents/extensions/handoff_filters.py,sha256=2cXxu1JROez96CpTiGuT9PIuaIrIE8ksP01fX83krKM,1977
27
- agents/extensions/handoff_prompt.py,sha256=oGWN0uNh3Z1L7E-Ev2up8W084fFrDNOsLDy7P6bcmic,1006
28
- agents/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- agents/models/_openai_shared.py,sha256=4Ngwo2Fv2RXY61Pqck1cYPkSln2tDnb8Ai-ao4QG-iE,836
30
- agents/models/fake_id.py,sha256=lbXjUUSMeAQ8eFx4V5QLUnBClHE6adJlYYav55RlG5w,268
31
- agents/models/interface.py,sha256=dgIlKyPaCbNRTHXxd6x7OQwJuAelG3F-C19P-aacHWQ,3129
32
- agents/models/openai_chatcompletions.py,sha256=e7iA9mxflbVKNCbt11gxCXKHRjMS1JXd0vpzjlOQOI8,39059
33
- agents/models/openai_provider.py,sha256=3zKt8stSm0IcDJzX8GqXa3UcECKK79A290Zzem1nlUo,2784
34
- agents/models/openai_responses.py,sha256=4CowZT0wAMflEzDgi6hEidcMq_0zchIm2uX_vV090TM,13386
35
- agents/tracing/__init__.py,sha256=pp2_mBCQGL9oN6_czCWHQsV4ZTEOcy1AVxdjQ41PNr0,2424
36
- agents/tracing/create.py,sha256=PAhfJKAeJ8jbZvxylTiikU_LqAhezYHphR4jG5EdaAE,12110
37
- agents/tracing/logger.py,sha256=J4KUDRSGa7x5UVfUwWe-gbKwoaq8AeETRqkPt3QvtGg,68
38
- agents/tracing/processor_interface.py,sha256=wNyZCwNJko5CrUIWD_lMou5ppQ67CFYwvWRsJRM3up8,1659
39
- agents/tracing/processors.py,sha256=74BB0w3XQjerlYN6kgRiqtV4VPAvZSMTPByutcX464c,9600
40
- agents/tracing/scope.py,sha256=x1m-aYilS1DeeV4L7Ckv55LVWod7c_nnTKoCGhJCumk,1372
41
- agents/tracing/setup.py,sha256=P5JaIcHej6m62rb27bSutN2Bqv0XSD9Z_Ki7ynCVdbs,6728
42
- agents/tracing/span_data.py,sha256=UQUPpMQ7Z1XOqKFJNHUxAJUVPwa6JMfGa7dm_NovuhQ,4574
43
- agents/tracing/spans.py,sha256=KWCqcRwUlt85NCZPQp98UIF5vAQAVWuVWQh3tgPK0WE,6605
44
- agents/tracing/traces.py,sha256=GL9EoEQKVk7eo0BcfRfQ6C7tdzlmPhkneQn4fdsCdqA,4774
45
- agents/tracing/util.py,sha256=BsDvn2rjE4SRQvfm55utljT8agdA0Z36KWXd1vdx4hs,392
46
- openai_agents-0.0.4.dist-info/METADATA,sha256=8a-UqdtxRJCgwuT6jsfJ1MwDwwYWS-NnbcJB52QpZP4,7582
47
- openai_agents-0.0.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
- openai_agents-0.0.4.dist-info/licenses/LICENSE,sha256=E994EspT7Krhy0qGiES7WYNzBHrh1YDk3r--8d1baRU,1063
49
- openai_agents-0.0.4.dist-info/RECORD,,