openai-agents 0.2.8__py3-none-any.whl → 0.6.8__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.
Files changed (96) hide show
  1. agents/__init__.py +105 -4
  2. agents/_debug.py +15 -4
  3. agents/_run_impl.py +1203 -96
  4. agents/agent.py +164 -19
  5. agents/apply_diff.py +329 -0
  6. agents/editor.py +47 -0
  7. agents/exceptions.py +35 -0
  8. agents/extensions/experimental/__init__.py +6 -0
  9. agents/extensions/experimental/codex/__init__.py +92 -0
  10. agents/extensions/experimental/codex/codex.py +89 -0
  11. agents/extensions/experimental/codex/codex_options.py +35 -0
  12. agents/extensions/experimental/codex/codex_tool.py +1142 -0
  13. agents/extensions/experimental/codex/events.py +162 -0
  14. agents/extensions/experimental/codex/exec.py +263 -0
  15. agents/extensions/experimental/codex/items.py +245 -0
  16. agents/extensions/experimental/codex/output_schema_file.py +50 -0
  17. agents/extensions/experimental/codex/payloads.py +31 -0
  18. agents/extensions/experimental/codex/thread.py +214 -0
  19. agents/extensions/experimental/codex/thread_options.py +54 -0
  20. agents/extensions/experimental/codex/turn_options.py +36 -0
  21. agents/extensions/handoff_filters.py +13 -1
  22. agents/extensions/memory/__init__.py +120 -0
  23. agents/extensions/memory/advanced_sqlite_session.py +1285 -0
  24. agents/extensions/memory/async_sqlite_session.py +239 -0
  25. agents/extensions/memory/dapr_session.py +423 -0
  26. agents/extensions/memory/encrypt_session.py +185 -0
  27. agents/extensions/memory/redis_session.py +261 -0
  28. agents/extensions/memory/sqlalchemy_session.py +334 -0
  29. agents/extensions/models/litellm_model.py +449 -36
  30. agents/extensions/models/litellm_provider.py +3 -1
  31. agents/function_schema.py +47 -5
  32. agents/guardrail.py +16 -2
  33. agents/{handoffs.py → handoffs/__init__.py} +89 -47
  34. agents/handoffs/history.py +268 -0
  35. agents/items.py +237 -11
  36. agents/lifecycle.py +75 -14
  37. agents/mcp/server.py +280 -37
  38. agents/mcp/util.py +24 -3
  39. agents/memory/__init__.py +22 -2
  40. agents/memory/openai_conversations_session.py +91 -0
  41. agents/memory/openai_responses_compaction_session.py +249 -0
  42. agents/memory/session.py +19 -261
  43. agents/memory/sqlite_session.py +275 -0
  44. agents/memory/util.py +20 -0
  45. agents/model_settings.py +14 -3
  46. agents/models/__init__.py +13 -0
  47. agents/models/chatcmpl_converter.py +303 -50
  48. agents/models/chatcmpl_helpers.py +63 -0
  49. agents/models/chatcmpl_stream_handler.py +290 -68
  50. agents/models/default_models.py +58 -0
  51. agents/models/interface.py +4 -0
  52. agents/models/openai_chatcompletions.py +103 -49
  53. agents/models/openai_provider.py +10 -4
  54. agents/models/openai_responses.py +162 -46
  55. agents/realtime/__init__.py +4 -0
  56. agents/realtime/_util.py +14 -3
  57. agents/realtime/agent.py +7 -0
  58. agents/realtime/audio_formats.py +53 -0
  59. agents/realtime/config.py +78 -10
  60. agents/realtime/events.py +18 -0
  61. agents/realtime/handoffs.py +2 -2
  62. agents/realtime/items.py +17 -1
  63. agents/realtime/model.py +13 -0
  64. agents/realtime/model_events.py +12 -0
  65. agents/realtime/model_inputs.py +18 -1
  66. agents/realtime/openai_realtime.py +696 -150
  67. agents/realtime/session.py +243 -23
  68. agents/repl.py +7 -3
  69. agents/result.py +197 -38
  70. agents/run.py +949 -168
  71. agents/run_context.py +13 -2
  72. agents/stream_events.py +1 -0
  73. agents/strict_schema.py +14 -0
  74. agents/tool.py +413 -15
  75. agents/tool_context.py +22 -1
  76. agents/tool_guardrails.py +279 -0
  77. agents/tracing/__init__.py +2 -0
  78. agents/tracing/config.py +9 -0
  79. agents/tracing/create.py +4 -0
  80. agents/tracing/processor_interface.py +84 -11
  81. agents/tracing/processors.py +65 -54
  82. agents/tracing/provider.py +64 -7
  83. agents/tracing/spans.py +105 -0
  84. agents/tracing/traces.py +116 -16
  85. agents/usage.py +134 -12
  86. agents/util/_json.py +19 -1
  87. agents/util/_transforms.py +12 -2
  88. agents/voice/input.py +5 -4
  89. agents/voice/models/openai_stt.py +17 -9
  90. agents/voice/pipeline.py +2 -0
  91. agents/voice/pipeline_config.py +4 -0
  92. {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/METADATA +44 -19
  93. openai_agents-0.6.8.dist-info/RECORD +134 -0
  94. {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/WHEEL +1 -1
  95. openai_agents-0.2.8.dist-info/RECORD +0 -103
  96. {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import logging
3
4
  import os
4
5
  import threading
5
6
  import uuid
@@ -8,12 +9,38 @@ from datetime import datetime, timezone
8
9
  from typing import Any
9
10
 
10
11
  from ..logger import logger
12
+ from .config import TracingConfig
11
13
  from .processor_interface import TracingProcessor
12
14
  from .scope import Scope
13
15
  from .spans import NoOpSpan, Span, SpanImpl, TSpanData
14
16
  from .traces import NoOpTrace, Trace, TraceImpl
15
17
 
16
18
 
19
+ def _safe_debug(message: str) -> None:
20
+ """Best-effort debug logging that tolerates closed streams during shutdown."""
21
+
22
+ def _has_closed_stream_handler(log: logging.Logger) -> bool:
23
+ current: logging.Logger | None = log
24
+ while current is not None:
25
+ for handler in current.handlers:
26
+ stream = getattr(handler, "stream", None)
27
+ if stream is not None and getattr(stream, "closed", False):
28
+ return True
29
+ if not current.propagate:
30
+ break
31
+ current = current.parent
32
+ return False
33
+
34
+ try:
35
+ # Avoid emitting debug logs when any handler already owns a closed stream.
36
+ if _has_closed_stream_handler(logger):
37
+ return
38
+ logger.debug(message)
39
+ except Exception:
40
+ # Avoid noisy shutdown errors when the underlying stream is already closed.
41
+ return
42
+
43
+
17
44
  class SynchronousMultiTracingProcessor(TracingProcessor):
18
45
  """
19
46
  Forwards all calls to a list of TracingProcessors, in order of registration.
@@ -83,7 +110,7 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
83
110
  Called when the application stops.
84
111
  """
85
112
  for processor in self._processors:
86
- logger.debug(f"Shutting down trace processor {processor}")
113
+ _safe_debug(f"Shutting down trace processor {processor}")
87
114
  try:
88
115
  processor.shutdown()
89
116
  except Exception as e:
@@ -147,6 +174,7 @@ class TraceProvider(ABC):
147
174
  group_id: str | None = None,
148
175
  metadata: dict[str, Any] | None = None,
149
176
  disabled: bool = False,
177
+ tracing: TracingConfig | None = None,
150
178
  ) -> Trace:
151
179
  """Create a new trace."""
152
180
 
@@ -168,10 +196,10 @@ class TraceProvider(ABC):
168
196
  class DefaultTraceProvider(TraceProvider):
169
197
  def __init__(self) -> None:
170
198
  self._multi_processor = SynchronousMultiTracingProcessor()
171
- self._disabled = os.environ.get("OPENAI_AGENTS_DISABLE_TRACING", "false").lower() in (
172
- "true",
173
- "1",
174
- )
199
+ # Lazily read env flag on first use to honor env set after import but before first trace.
200
+ self._env_disabled: bool | None = None
201
+ self._manual_disabled: bool | None = None
202
+ self._disabled = False
175
203
 
176
204
  def register_processor(self, processor: TracingProcessor):
177
205
  """
@@ -201,7 +229,27 @@ class DefaultTraceProvider(TraceProvider):
201
229
  """
202
230
  Set whether tracing is disabled.
203
231
  """
204
- self._disabled = disabled
232
+ self._manual_disabled = disabled
233
+ self._refresh_disabled_flag()
234
+
235
+ def _refresh_disabled_flag(self) -> None:
236
+ """Refresh disabled flag from cached env value and manual override.
237
+
238
+ The env flag is read once on first use to avoid surprises mid-run; further env
239
+ changes are ignored after the manual flag is set via set_disabled, which always
240
+ takes precedence over the env value.
241
+ """
242
+ if self._env_disabled is None:
243
+ self._env_disabled = os.environ.get(
244
+ "OPENAI_AGENTS_DISABLE_TRACING", "false"
245
+ ).lower() in (
246
+ "true",
247
+ "1",
248
+ )
249
+ if self._manual_disabled is None:
250
+ self._disabled = bool(self._env_disabled)
251
+ else:
252
+ self._disabled = self._manual_disabled
205
253
 
206
254
  def time_iso(self) -> str:
207
255
  """Return the current time in ISO 8601 format."""
@@ -226,10 +274,12 @@ class DefaultTraceProvider(TraceProvider):
226
274
  group_id: str | None = None,
227
275
  metadata: dict[str, Any] | None = None,
228
276
  disabled: bool = False,
277
+ tracing: TracingConfig | None = None,
229
278
  ) -> Trace:
230
279
  """
231
280
  Create a new trace.
232
281
  """
282
+ self._refresh_disabled_flag()
233
283
  if self._disabled or disabled:
234
284
  logger.debug(f"Tracing is disabled. Not creating trace {name}")
235
285
  return NoOpTrace()
@@ -244,6 +294,7 @@ class DefaultTraceProvider(TraceProvider):
244
294
  group_id=group_id,
245
295
  metadata=metadata,
246
296
  processor=self._multi_processor,
297
+ tracing_api_key=tracing.get("api_key") if tracing else None,
247
298
  )
248
299
 
249
300
  def create_span(
@@ -256,6 +307,8 @@ class DefaultTraceProvider(TraceProvider):
256
307
  """
257
308
  Create a new span.
258
309
  """
310
+ self._refresh_disabled_flag()
311
+ tracing_api_key: str | None = None
259
312
  if self._disabled or disabled:
260
313
  logger.debug(f"Tracing is disabled. Not creating span {span_data}")
261
314
  return NoOpSpan(span_data)
@@ -277,6 +330,7 @@ class DefaultTraceProvider(TraceProvider):
277
330
 
278
331
  parent_id = current_span.span_id if current_span else None
279
332
  trace_id = current_trace.trace_id
333
+ tracing_api_key = current_trace.tracing_api_key
280
334
 
281
335
  elif isinstance(parent, Trace):
282
336
  if isinstance(parent, NoOpTrace):
@@ -284,12 +338,14 @@ class DefaultTraceProvider(TraceProvider):
284
338
  return NoOpSpan(span_data)
285
339
  trace_id = parent.trace_id
286
340
  parent_id = None
341
+ tracing_api_key = parent.tracing_api_key
287
342
  elif isinstance(parent, Span):
288
343
  if isinstance(parent, NoOpSpan):
289
344
  logger.debug(f"Parent {parent} is no-op, returning NoOpSpan")
290
345
  return NoOpSpan(span_data)
291
346
  parent_id = parent.span_id
292
347
  trace_id = parent.trace_id
348
+ tracing_api_key = parent.tracing_api_key
293
349
 
294
350
  logger.debug(f"Creating span {span_data} with id {span_id}")
295
351
 
@@ -299,6 +355,7 @@ class DefaultTraceProvider(TraceProvider):
299
355
  parent_id=parent_id,
300
356
  processor=self._multi_processor,
301
357
  span_data=span_data,
358
+ tracing_api_key=tracing_api_key,
302
359
  )
303
360
 
304
361
  def shutdown(self) -> None:
@@ -306,7 +363,7 @@ class DefaultTraceProvider(TraceProvider):
306
363
  return
307
364
 
308
365
  try:
309
- logger.debug("Shutting down trace provider")
366
+ _safe_debug("Shutting down trace provider")
310
367
  self._multi_processor.shutdown()
311
368
  except Exception as e:
312
369
  logger.error(f"Error shutting down trace provider: {e}")
agents/tracing/spans.py CHANGED
@@ -16,24 +16,84 @@ TSpanData = TypeVar("TSpanData", bound=SpanData)
16
16
 
17
17
 
18
18
  class SpanError(TypedDict):
19
+ """Represents an error that occurred during span execution.
20
+
21
+ Attributes:
22
+ message: A human-readable error description
23
+ data: Optional dictionary containing additional error context
24
+ """
25
+
19
26
  message: str
20
27
  data: dict[str, Any] | None
21
28
 
22
29
 
23
30
  class Span(abc.ABC, Generic[TSpanData]):
31
+ """Base class for representing traceable operations with timing and context.
32
+
33
+ A span represents a single operation within a trace (e.g., an LLM call, tool execution,
34
+ or agent run). Spans track timing, relationships between operations, and operation-specific
35
+ data.
36
+
37
+ Type Args:
38
+ TSpanData: The type of span-specific data this span contains.
39
+
40
+ Example:
41
+ ```python
42
+ # Creating a custom span
43
+ with custom_span("database_query", {
44
+ "operation": "SELECT",
45
+ "table": "users"
46
+ }) as span:
47
+ results = await db.query("SELECT * FROM users")
48
+ span.set_output({"count": len(results)})
49
+
50
+ # Handling errors in spans
51
+ with custom_span("risky_operation") as span:
52
+ try:
53
+ result = perform_risky_operation()
54
+ except Exception as e:
55
+ span.set_error({
56
+ "message": str(e),
57
+ "data": {"operation": "risky_operation"}
58
+ })
59
+ raise
60
+ ```
61
+
62
+ Notes:
63
+ - Spans automatically nest under the current trace
64
+ - Use context managers for reliable start/finish
65
+ - Include relevant data but avoid sensitive information
66
+ - Handle errors properly using set_error()
67
+ """
68
+
24
69
  @property
25
70
  @abc.abstractmethod
26
71
  def trace_id(self) -> str:
72
+ """The ID of the trace this span belongs to.
73
+
74
+ Returns:
75
+ str: Unique identifier of the parent trace.
76
+ """
27
77
  pass
28
78
 
29
79
  @property
30
80
  @abc.abstractmethod
31
81
  def span_id(self) -> str:
82
+ """Unique identifier for this span.
83
+
84
+ Returns:
85
+ str: The span's unique ID within its trace.
86
+ """
32
87
  pass
33
88
 
34
89
  @property
35
90
  @abc.abstractmethod
36
91
  def span_data(self) -> TSpanData:
92
+ """Operation-specific data for this span.
93
+
94
+ Returns:
95
+ TSpanData: Data specific to this type of span (e.g., LLM generation data).
96
+ """
37
97
  pass
38
98
 
39
99
  @abc.abstractmethod
@@ -67,6 +127,11 @@ class Span(abc.ABC, Generic[TSpanData]):
67
127
  @property
68
128
  @abc.abstractmethod
69
129
  def parent_id(self) -> str | None:
130
+ """ID of the parent span, if any.
131
+
132
+ Returns:
133
+ str | None: The parent span's ID, or None if this is a root span.
134
+ """
70
135
  pass
71
136
 
72
137
  @abc.abstractmethod
@@ -76,6 +141,11 @@ class Span(abc.ABC, Generic[TSpanData]):
76
141
  @property
77
142
  @abc.abstractmethod
78
143
  def error(self) -> SpanError | None:
144
+ """Any error that occurred during span execution.
145
+
146
+ Returns:
147
+ SpanError | None: Error details if an error occurred, None otherwise.
148
+ """
79
149
  pass
80
150
 
81
151
  @abc.abstractmethod
@@ -85,15 +155,39 @@ class Span(abc.ABC, Generic[TSpanData]):
85
155
  @property
86
156
  @abc.abstractmethod
87
157
  def started_at(self) -> str | None:
158
+ """When the span started execution.
159
+
160
+ Returns:
161
+ str | None: ISO format timestamp of span start, None if not started.
162
+ """
88
163
  pass
89
164
 
90
165
  @property
91
166
  @abc.abstractmethod
92
167
  def ended_at(self) -> str | None:
168
+ """When the span finished execution.
169
+
170
+ Returns:
171
+ str | None: ISO format timestamp of span end, None if not finished.
172
+ """
173
+ pass
174
+
175
+ @property
176
+ @abc.abstractmethod
177
+ def tracing_api_key(self) -> str | None:
178
+ """The API key to use when exporting this span."""
93
179
  pass
94
180
 
95
181
 
96
182
  class NoOpSpan(Span[TSpanData]):
183
+ """A no-op implementation of Span that doesn't record any data.
184
+
185
+ Used when tracing is disabled but span operations still need to work.
186
+
187
+ Args:
188
+ span_data: The operation-specific data for this span.
189
+ """
190
+
97
191
  __slots__ = ("_span_data", "_prev_span_token")
98
192
 
99
193
  def __init__(self, span_data: TSpanData):
@@ -155,6 +249,10 @@ class NoOpSpan(Span[TSpanData]):
155
249
  def ended_at(self) -> str | None:
156
250
  return None
157
251
 
252
+ @property
253
+ def tracing_api_key(self) -> str | None:
254
+ return None
255
+
158
256
 
159
257
  class SpanImpl(Span[TSpanData]):
160
258
  __slots__ = (
@@ -167,6 +265,7 @@ class SpanImpl(Span[TSpanData]):
167
265
  "_prev_span_token",
168
266
  "_processor",
169
267
  "_span_data",
268
+ "_tracing_api_key",
170
269
  )
171
270
 
172
271
  def __init__(
@@ -176,6 +275,7 @@ class SpanImpl(Span[TSpanData]):
176
275
  parent_id: str | None,
177
276
  processor: TracingProcessor,
178
277
  span_data: TSpanData,
278
+ tracing_api_key: str | None,
179
279
  ):
180
280
  self._trace_id = trace_id
181
281
  self._span_id = span_id or util.gen_span_id()
@@ -186,6 +286,7 @@ class SpanImpl(Span[TSpanData]):
186
286
  self._error: SpanError | None = None
187
287
  self._prev_span_token: contextvars.Token[Span[TSpanData] | None] | None = None
188
288
  self._span_data = span_data
289
+ self._tracing_api_key = tracing_api_key
189
290
 
190
291
  @property
191
292
  def trace_id(self) -> str:
@@ -251,6 +352,10 @@ class SpanImpl(Span[TSpanData]):
251
352
  def ended_at(self) -> str | None:
252
353
  return self._ended_at
253
354
 
355
+ @property
356
+ def tracing_api_key(self) -> str | None:
357
+ return self._tracing_api_key
358
+
254
359
  def export(self) -> dict[str, Any] | None:
255
360
  return {
256
361
  "object": "trace.span",
agents/tracing/traces.py CHANGED
@@ -11,8 +11,35 @@ from .scope import Scope
11
11
 
12
12
 
13
13
  class Trace(abc.ABC):
14
- """
15
- A trace is the root level object that tracing creates. It represents a logical "workflow".
14
+ """A complete end-to-end workflow containing related spans and metadata.
15
+
16
+ A trace represents a logical workflow or operation (e.g., "Customer Service Query"
17
+ or "Code Generation") and contains all the spans (individual operations) that occur
18
+ during that workflow.
19
+
20
+ Example:
21
+ ```python
22
+ # Basic trace usage
23
+ with trace("Order Processing") as t:
24
+ validation_result = await Runner.run(validator, order_data)
25
+ if validation_result.approved:
26
+ await Runner.run(processor, order_data)
27
+
28
+ # Trace with metadata and grouping
29
+ with trace(
30
+ "Customer Service",
31
+ group_id="chat_123",
32
+ metadata={"customer": "user_456"}
33
+ ) as t:
34
+ result = await Runner.run(support_agent, query)
35
+ ```
36
+
37
+ Notes:
38
+ - Use descriptive workflow names
39
+ - Group related traces with consistent group_ids
40
+ - Add relevant metadata for filtering/analysis
41
+ - Use context managers for reliable cleanup
42
+ - Consider privacy when adding trace data
16
43
  """
17
44
 
18
45
  @abc.abstractmethod
@@ -25,51 +52,98 @@ class Trace(abc.ABC):
25
52
 
26
53
  @abc.abstractmethod
27
54
  def start(self, mark_as_current: bool = False):
28
- """
29
- Start the trace.
55
+ """Start the trace and optionally mark it as the current trace.
30
56
 
31
57
  Args:
32
- mark_as_current: If true, the trace will be marked as the current trace.
58
+ mark_as_current: If true, marks this trace as the current trace
59
+ in the execution context.
60
+
61
+ Notes:
62
+ - Must be called before any spans can be added
63
+ - Only one trace can be current at a time
64
+ - Thread-safe when using mark_as_current
33
65
  """
34
66
  pass
35
67
 
36
68
  @abc.abstractmethod
37
69
  def finish(self, reset_current: bool = False):
38
- """
39
- Finish the trace.
70
+ """Finish the trace and optionally reset the current trace.
40
71
 
41
72
  Args:
42
- reset_current: If true, the trace will be reset as the current trace.
73
+ reset_current: If true, resets the current trace to the previous
74
+ trace in the execution context.
75
+
76
+ Notes:
77
+ - Must be called to complete the trace
78
+ - Finalizes all open spans
79
+ - Thread-safe when using reset_current
43
80
  """
44
81
  pass
45
82
 
46
83
  @property
47
84
  @abc.abstractmethod
48
85
  def trace_id(self) -> str:
49
- """
50
- The trace ID.
86
+ """Get the unique identifier for this trace.
87
+
88
+ Returns:
89
+ str: The trace's unique ID in the format 'trace_<32_alphanumeric>'
90
+
91
+ Notes:
92
+ - IDs are globally unique
93
+ - Used to link spans to their parent trace
94
+ - Can be used to look up traces in the dashboard
51
95
  """
52
96
  pass
53
97
 
54
98
  @property
55
99
  @abc.abstractmethod
56
100
  def name(self) -> str:
57
- """
58
- The name of the workflow being traced.
101
+ """Get the human-readable name of this workflow trace.
102
+
103
+ Returns:
104
+ str: The workflow name (e.g., "Customer Service", "Data Processing")
105
+
106
+ Notes:
107
+ - Should be descriptive and meaningful
108
+ - Used for grouping and filtering in the dashboard
109
+ - Helps identify the purpose of the trace
59
110
  """
60
111
  pass
61
112
 
62
113
  @abc.abstractmethod
63
114
  def export(self) -> dict[str, Any] | None:
115
+ """Export the trace data as a serializable dictionary.
116
+
117
+ Returns:
118
+ dict | None: Dictionary containing trace data, or None if tracing is disabled.
119
+
120
+ Notes:
121
+ - Includes all spans and their data
122
+ - Used for sending traces to backends
123
+ - May include metadata and group ID
64
124
  """
65
- Export the trace as a dictionary.
66
- """
125
+ pass
126
+
127
+ @property
128
+ @abc.abstractmethod
129
+ def tracing_api_key(self) -> str | None:
130
+ """The API key to use when exporting this trace and its spans."""
67
131
  pass
68
132
 
69
133
 
70
134
  class NoOpTrace(Trace):
71
- """
72
- A no-op trace that will not be recorded.
135
+ """A no-op implementation of Trace that doesn't record any data.
136
+
137
+ Used when tracing is disabled but trace operations still need to work.
138
+ Maintains proper context management but doesn't store or export any data.
139
+
140
+ Example:
141
+ ```python
142
+ # When tracing is disabled, traces become NoOpTrace
143
+ with trace("Disabled Workflow") as t:
144
+ # Operations still work but nothing is recorded
145
+ await Runner.run(agent, "query")
146
+ ```
73
147
  """
74
148
 
75
149
  def __init__(self):
@@ -101,13 +175,32 @@ class NoOpTrace(Trace):
101
175
 
102
176
  @property
103
177
  def trace_id(self) -> str:
178
+ """The trace's unique identifier.
179
+
180
+ Returns:
181
+ str: A unique ID for this trace.
182
+ """
104
183
  return "no-op"
105
184
 
106
185
  @property
107
186
  def name(self) -> str:
187
+ """The workflow name for this trace.
188
+
189
+ Returns:
190
+ str: Human-readable name describing this workflow.
191
+ """
108
192
  return "no-op"
109
193
 
110
194
  def export(self) -> dict[str, Any] | None:
195
+ """Export the trace data as a dictionary.
196
+
197
+ Returns:
198
+ dict | None: Trace data in exportable format, or None if no data.
199
+ """
200
+ return None
201
+
202
+ @property
203
+ def tracing_api_key(self) -> str | None:
111
204
  return None
112
205
 
113
206
 
@@ -122,6 +215,7 @@ class TraceImpl(Trace):
122
215
  __slots__ = (
123
216
  "_name",
124
217
  "_trace_id",
218
+ "_tracing_api_key",
125
219
  "group_id",
126
220
  "metadata",
127
221
  "_prev_context_token",
@@ -136,9 +230,11 @@ class TraceImpl(Trace):
136
230
  group_id: str | None,
137
231
  metadata: dict[str, Any] | None,
138
232
  processor: TracingProcessor,
233
+ tracing_api_key: str | None,
139
234
  ):
140
235
  self._name = name
141
236
  self._trace_id = trace_id or util.gen_trace_id()
237
+ self._tracing_api_key = tracing_api_key
142
238
  self.group_id = group_id
143
239
  self.metadata = metadata
144
240
  self._prev_context_token: contextvars.Token[Trace | None] | None = None
@@ -153,6 +249,10 @@ class TraceImpl(Trace):
153
249
  def name(self) -> str:
154
250
  return self._name
155
251
 
252
+ @property
253
+ def tracing_api_key(self) -> str | None:
254
+ return self._tracing_api_key
255
+
156
256
  def start(self, mark_as_current: bool = False):
157
257
  if self._started:
158
258
  return