Skip to content

Commit c0500a8

Browse files
authored
Merge pull request #10 from mmontan/perf/chat-monkey-patching-2416438301259140265
⚡ Prevent uncontrolled monkey patching in chat client
2 parents 46aaf55 + 1b7818d commit c0500a8

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

src/agent_engine_cli/chat.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ def _install_api_logging_hooks(debug: bool) -> None:
5757
"""Install monkey patches for API request/response logging."""
5858
from google.genai import _api_client
5959

60+
# Prevent repeated monkey patching
61+
if getattr(
62+
_api_client.BaseApiClient.async_request, "_is_logged_async_request", False
63+
):
64+
return
65+
6066
# Monkey patch async_request for non-streaming requests (like create_session)
6167
_original_async_request = _api_client.BaseApiClient.async_request
6268

@@ -82,6 +88,7 @@ async def _logged_async_request(
8288

8389
return result
8490

91+
_logged_async_request._is_logged_async_request = True
8592
_api_client.BaseApiClient.async_request = _logged_async_request
8693

8794
# Monkey patch async_request_streamed for streaming requests

tests/test_chat_monkey_patch.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import sys
2+
from unittest.mock import MagicMock, patch
3+
4+
# We need to import the function to test
5+
from agent_engine_cli.chat import _install_api_logging_hooks
6+
7+
def test_install_api_logging_hooks_idempotency():
8+
"""Test that _install_api_logging_hooks does not double-patch."""
9+
10+
# We need to mock google.genai._api_client because it might not be installed in all environments
11+
# or we want to isolate the test.
12+
# However, since the code imports it directly, we need to mock it in sys.modules
13+
# OR we can rely on the fact that we are in an environment where it is installed.
14+
# Given the previous exploration, it is installed.
15+
16+
from google.genai import _api_client
17+
18+
# Save original state to restore later
19+
original_async_request = _api_client.BaseApiClient.async_request
20+
original_async_request_streamed = _api_client.BaseApiClient.async_request_streamed
21+
22+
# Remove any existing patch markers if present (unlikely in fresh process but good for safety)
23+
if hasattr(original_async_request, "_is_logged_async_request"):
24+
delattr(original_async_request, "_is_logged_async_request")
25+
26+
try:
27+
# First patch
28+
_install_api_logging_hooks(debug=True)
29+
patched_once = _api_client.BaseApiClient.async_request
30+
31+
assert patched_once != original_async_request
32+
assert getattr(patched_once, "_is_logged_async_request", False)
33+
34+
# Second patch
35+
_install_api_logging_hooks(debug=True)
36+
patched_twice = _api_client.BaseApiClient.async_request
37+
38+
# Should be the same object
39+
assert patched_twice == patched_once
40+
41+
finally:
42+
# Restore original state
43+
_api_client.BaseApiClient.async_request = original_async_request
44+
_api_client.BaseApiClient.async_request_streamed = original_async_request_streamed

0 commit comments

Comments
 (0)