test_context_tracking.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. from __future__ import annotations
  2. import httpx
  3. from production_build_agents.observability.context_tracking import (
  4. activate_context_tracking,
  5. begin_model_call,
  6. context_tracking_active,
  7. deactivate_context_tracking,
  8. finish_model_call,
  9. observe_transport_request,
  10. observe_transport_response,
  11. observed_http_clients,
  12. )
  13. def _snapshot() -> dict:
  14. return {
  15. "physical_call_id": "physical-1",
  16. "logical_call_index": 1,
  17. "logical_call_key": "logical-1",
  18. "identity": {"agent_run_id": "agent-1"},
  19. "previous": None,
  20. }
  21. def test_transport_attempts_and_retries_are_recorded() -> None:
  22. capture_token = activate_context_tracking()
  23. call_token = begin_model_call(_snapshot())
  24. try:
  25. first = httpx.Request(
  26. "POST",
  27. "https://provider.example/v1/chat",
  28. headers={"x-stainless-retry-count": "0"},
  29. )
  30. observe_transport_request(first)
  31. observe_transport_response(httpx.Response(429, request=first))
  32. second = httpx.Request(
  33. "POST",
  34. "https://provider.example/v1/chat",
  35. headers={"x-stainless-retry-count": "1"},
  36. )
  37. observe_transport_request(second)
  38. observe_transport_response(httpx.Response(200, request=second))
  39. terminal = finish_model_call(
  40. call_token,
  41. message=None,
  42. response=None,
  43. status="success",
  44. )
  45. finally:
  46. deactivate_context_tracking(capture_token)
  47. transport = terminal["transport"]
  48. assert transport["observed"] is True
  49. assert transport["attempt_count"] == 2
  50. assert transport["retry_count"] == 1
  51. assert [item["status_code"] for item in transport["attempts"]] == [
  52. 429,
  53. 200,
  54. ]
  55. assert "provider.example" not in str(transport)
  56. def test_unobserved_transport_is_unknown_not_zero() -> None:
  57. call_token = begin_model_call(_snapshot())
  58. terminal = finish_model_call(
  59. call_token,
  60. message=None,
  61. response=None,
  62. status="failure",
  63. error_type="TimeoutError",
  64. )
  65. assert terminal["transport"] == {
  66. "observed": False,
  67. "attempt_count": None,
  68. "retry_count": None,
  69. "attempts": [],
  70. }
  71. assert terminal["error_type"] == "TimeoutError"
  72. def test_transport_exception_marks_attempt_without_response_as_error() -> None:
  73. capture_token = activate_context_tracking()
  74. call_token = begin_model_call(_snapshot())
  75. try:
  76. request = httpx.Request(
  77. "POST",
  78. "https://provider.example/v1/chat",
  79. headers={"x-stainless-retry-count": "0"},
  80. )
  81. observe_transport_request(request)
  82. terminal = finish_model_call(
  83. call_token,
  84. message=None,
  85. response=None,
  86. status="failure",
  87. error_type="ConnectError",
  88. )
  89. finally:
  90. deactivate_context_tracking(capture_token)
  91. assert terminal["transport"]["attempt_count"] == 1
  92. assert terminal["transport"]["retry_count"] == 0
  93. assert terminal["transport"]["attempts"][0]["outcome"] == "error"
  94. assert terminal["transport"]["attempts"][0]["status_code"] is None
  95. def test_http_client_is_only_enabled_inside_full_capture() -> None:
  96. assert context_tracking_active() is False
  97. assert observed_http_clients("openai") == {}
  98. token = activate_context_tracking()
  99. try:
  100. assert context_tracking_active() is True
  101. assert "http_client" in observed_http_clients("openai")
  102. assert observed_http_clients("anthropic") == {}
  103. finally:
  104. deactivate_context_tracking(token)