@@ -408,6 +408,51 @@ def test_add_usages_with_none_detail_value():
408408 )
409409
410410
411+ def test_add_request_usages_does_not_mutate_original ():
412+ """Test that __add__ does not mutate the original object's details dict (issue #4605)."""
413+ u1 = RequestUsage (input_tokens = 10 , details = {'reasoning_tokens' : 5 })
414+ u2 = RequestUsage (input_tokens = 20 , details = {'reasoning_tokens' : 3 })
415+
416+ result = u1 + u2
417+
418+ # The result should have the summed details
419+ assert result .details == {'reasoning_tokens' : 8 }
420+ # The original must NOT be mutated
421+ assert u1 .details == {'reasoning_tokens' : 5 }
422+ # They must be independent dict objects
423+ assert u1 .details is not result .details
424+
425+
426+ def test_add_run_usages_does_not_mutate_original ():
427+ """Test that __add__ does not mutate the original object's details dict (issue #4605)."""
428+ r1 = RunUsage (requests = 1 , input_tokens = 10 , details = {'reasoning_tokens' : 50 })
429+ r2 = RunUsage (requests = 1 , input_tokens = 20 , details = {'reasoning_tokens' : 30 })
430+
431+ result = r1 + r2
432+
433+ assert result .details == {'reasoning_tokens' : 80 }
434+ assert r1 .details == {'reasoning_tokens' : 50 }
435+ assert r1 .details is not result .details
436+
437+
438+ def test_add_usage_repeated_calls_stable ():
439+ """Test that repeated __add__ calls return consistent results (issue #4605).
440+
441+ This simulates AgentStream.usage() at result.py:169 being called multiple times:
442+ return self._initial_run_ctx_usage + self._raw_stream_response.usage()
443+ """
444+ initial = RunUsage (requests = 1 , input_tokens = 500 , details = {})
445+ stream = RequestUsage (input_tokens = 500 , output_tokens = 200 , details = {'reasoning_tokens' : 150 })
446+
447+ results = [initial + stream for _ in range (3 )]
448+
449+ # All calls must return the same values
450+ for r in results :
451+ assert r .details == {'reasoning_tokens' : 150 }
452+ # The initial usage must remain unchanged
453+ assert initial .details == {}
454+
455+
411456async def test_tool_call_limit () -> None :
412457 test_agent = Agent (TestModel ())
413458
0 commit comments