Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/agents/tracing/traces.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import abc
import contextvars
import copy
import hashlib
import threading
from collections import OrderedDict
Expand Down Expand Up @@ -178,7 +179,7 @@ def to_json(self, *, include_tracing_api_key: bool = False) -> dict[str, Any] |
exported = self.export()
if exported is None:
return None
payload = dict(exported)
payload = copy.deepcopy(exported)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid deep-copying arbitrary trace metadata

When trace metadata contains an object that cannot be deep-copied, such as a lock or a JSON-compatible container with a custom failing __deepcopy__, this now raises synchronously during every normal run: Runner calls RunState.set_trace() at startup, which reaches TraceState.from_trace() and this line. Previously such metadata only traveled through the non-fatal tracing/export path, so an observability detail can now prevent the application run from starting; detach the supported container structure without requiring every arbitrary metadata value to support deepcopy, or handle copy failures without failing the run.

AGENTS.md reference: AGENTS.md:L162-L162

Useful? React with 👍 / 👎.

if include_tracing_api_key and self.tracing_api_key:
payload["tracing_api_key"] = self.tracing_api_key
return payload
Expand Down
20 changes: 20 additions & 0 deletions tests/test_trace_json_isolation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from __future__ import annotations

from agents.tracing.provider import SynchronousMultiTracingProcessor
from agents.tracing.traces import TraceImpl


def test_trace_to_json_detaches_nested_metadata() -> None:
trace = TraceImpl(
name="workflow",
trace_id="trace_test",
group_id=None,
metadata={"nested": {"value": "original"}},
processor=SynchronousMultiTracingProcessor(),
)

payload = trace.to_json()
assert payload is not None
payload["metadata"]["nested"]["value"] = "changed"

assert trace.metadata == {"nested": {"value": "original"}}