Skip to content

Commit fe82f3c

Browse files
seanzhougooglecopybara-github
authored andcommitted
fix!: Make credential manager to accept tool_context instead of callback_context
This seems a breaking change, but actually credential manager is used internally only and also it won't work if some one call it using callback context Co-authored-by: Xiang (Sean) Zhou <seanzhougoogle@google.com> PiperOrigin-RevId: 863534476
1 parent 798d005 commit fe82f3c

File tree

2 files changed

+54
-56
lines changed

2 files changed

+54
-56
lines changed

src/google/adk/auth/credential_manager.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
from fastapi.openapi.models import OAuth2
2121

22-
from ..agents.callback_context import CallbackContext
2322
from ..tools.openapi_tool.auth.credential_exchangers.service_account_exchanger import ServiceAccountCredentialExchanger
23+
from ..tools.tool_context import ToolContext
2424
from ..utils.feature_decorator import experimental
2525
from .auth_credential import AuthCredential
2626
from .auth_credential import AuthCredentialTypes
@@ -72,7 +72,7 @@ class CredentialManager:
7272
)
7373
7474
# Load and prepare credential
75-
credential = await manager.load_auth_credential(callback_context)
75+
credential = await manager.load_auth_credential(tool_context)
7676
```
7777
"""
7878

@@ -124,11 +124,11 @@ def register_credential_exchanger(
124124
"""
125125
self._exchanger_registry.register(credential_type, exchanger_instance)
126126

127-
async def request_credential(self, callback_context: CallbackContext) -> None:
128-
callback_context.request_credential(self._auth_config)
127+
async def request_credential(self, tool_context: ToolContext) -> None:
128+
tool_context.request_credential(self._auth_config)
129129

130130
async def get_auth_credential(
131-
self, callback_context: CallbackContext
131+
self, tool_context: ToolContext
132132
) -> Optional[AuthCredential]:
133133
"""Load and prepare authentication credential through a structured workflow."""
134134

@@ -140,14 +140,14 @@ async def get_auth_credential(
140140
return self._auth_config.raw_auth_credential
141141

142142
# Step 3: Try to load existing processed credential
143-
credential = await self._load_existing_credential(callback_context)
143+
credential = await self._load_existing_credential(tool_context)
144144

145145
# Step 4: If no existing credential, load from auth response
146146
# TODO instead of load from auth response, we can store auth response in
147147
# credential service.
148148
was_from_auth_response = False
149149
if not credential:
150-
credential = await self._load_from_auth_response(callback_context)
150+
credential = await self._load_from_auth_response(tool_context)
151151
was_from_auth_response = True
152152

153153
# Step 5: If still no credential available, check if client credentials
@@ -169,38 +169,38 @@ async def get_auth_credential(
169169

170170
# Step 8: Save credential if it was modified
171171
if was_from_auth_response or was_exchanged or was_refreshed:
172-
await self._save_credential(callback_context, credential)
172+
await self._save_credential(tool_context, credential)
173173

174174
return credential
175175

176176
async def _load_existing_credential(
177-
self, callback_context: CallbackContext
177+
self, tool_context: ToolContext
178178
) -> Optional[AuthCredential]:
179179
"""Load existing credential from credential service."""
180180

181181
# Try loading from credential service first
182-
credential = await self._load_from_credential_service(callback_context)
182+
credential = await self._load_from_credential_service(tool_context)
183183
if credential:
184184
return credential
185185

186186
return None
187187

188188
async def _load_from_credential_service(
189-
self, callback_context: CallbackContext
189+
self, tool_context: ToolContext
190190
) -> Optional[AuthCredential]:
191191
"""Load credential from credential service if available."""
192-
credential_service = callback_context._invocation_context.credential_service
192+
credential_service = tool_context._invocation_context.credential_service
193193
if credential_service:
194194
# Note: This should be made async in a future refactor
195195
# For now, assuming synchronous operation
196-
return await callback_context.load_credential(self._auth_config)
196+
return await tool_context.load_credential(self._auth_config)
197197
return None
198198

199199
async def _load_from_auth_response(
200-
self, callback_context: CallbackContext
200+
self, tool_context: ToolContext
201201
) -> Optional[AuthCredential]:
202-
"""Load credential from auth response in callback context."""
203-
return callback_context.get_auth_response(self._auth_config)
202+
"""Load credential from auth response in tool context."""
203+
return tool_context.get_auth_response(self._auth_config)
204204

205205
async def _exchange_credential(
206206
self, credential: AuthCredential
@@ -290,15 +290,15 @@ async def _validate_credential(self) -> None:
290290
# Additional validation can be added here
291291

292292
async def _save_credential(
293-
self, callback_context: CallbackContext, credential: AuthCredential
293+
self, tool_context: ToolContext, credential: AuthCredential
294294
) -> None:
295295
"""Save credential to credential service if available."""
296296
# Update the exchanged credential in config
297297
self._auth_config.exchanged_auth_credential = credential
298298

299-
credential_service = callback_context._invocation_context.credential_service
299+
credential_service = tool_context._invocation_context.credential_service
300300
if credential_service:
301-
await callback_context.save_credential(self._auth_config)
301+
await tool_context.save_credential(self._auth_config)
302302

303303
async def _populate_auth_scheme(self) -> bool:
304304
"""Auto-discover server metadata and populate missing auth scheme info.

tests/unittests/auth/test_credential_manager.py

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ def test_init(self):
4949
async def test_request_credential(self):
5050
"""Test request_credential method."""
5151
auth_config = Mock(spec=AuthConfig)
52-
callback_context = Mock()
53-
callback_context.request_credential = Mock()
52+
tool_context = Mock()
53+
tool_context.request_credential = Mock()
5454

5555
manager = CredentialManager(auth_config)
56-
await manager.request_credential(callback_context)
56+
await manager.request_credential(tool_context)
5757

58-
callback_context.request_credential.assert_called_once_with(auth_config)
58+
tool_context.request_credential.assert_called_once_with(auth_config)
5959

6060
@pytest.mark.asyncio
6161
async def test_load_auth_credentials_success(self):
@@ -69,7 +69,7 @@ async def test_load_auth_credentials_success(self):
6969
mock_credential = Mock(spec=AuthCredential)
7070
mock_credential.auth_type = AuthCredentialTypes.API_KEY
7171

72-
callback_context = Mock()
72+
tool_context = Mock()
7373

7474
manager = CredentialManager(auth_config)
7575

@@ -86,17 +86,17 @@ async def test_load_auth_credentials_success(self):
8686
)
8787
manager._save_credential = AsyncMock()
8888

89-
result = await manager.get_auth_credential(callback_context)
89+
result = await manager.get_auth_credential(tool_context)
9090

9191
# Verify all methods were called
9292
manager._validate_credential.assert_called_once()
9393
manager._is_credential_ready.assert_called_once()
94-
manager._load_existing_credential.assert_called_once_with(callback_context)
95-
manager._load_from_auth_response.assert_called_once_with(callback_context)
94+
manager._load_existing_credential.assert_called_once_with(tool_context)
95+
manager._load_from_auth_response.assert_called_once_with(tool_context)
9696
manager._exchange_credential.assert_called_once_with(mock_credential)
9797
manager._refresh_credential.assert_called_once_with(mock_credential)
9898
manager._save_credential.assert_called_once_with(
99-
callback_context, mock_credential
99+
tool_context, mock_credential
100100
)
101101

102102
assert result == mock_credential
@@ -111,7 +111,7 @@ async def test_load_auth_credentials_no_credential(self):
111111
auth_config.auth_scheme = Mock()
112112
auth_config.auth_scheme.flows = None
113113

114-
callback_context = Mock()
114+
tool_context = Mock()
115115

116116
manager = CredentialManager(auth_config)
117117

@@ -121,13 +121,13 @@ async def test_load_auth_credentials_no_credential(self):
121121
manager._load_existing_credential = AsyncMock(return_value=None)
122122
manager._load_from_auth_response = AsyncMock(return_value=None)
123123

124-
result = await manager.get_auth_credential(callback_context)
124+
result = await manager.get_auth_credential(tool_context)
125125

126126
# Verify methods were called but no credential returned
127127
manager._validate_credential.assert_called_once()
128128
manager._is_credential_ready.assert_called_once()
129-
manager._load_existing_credential.assert_called_once_with(callback_context)
130-
manager._load_from_auth_response.assert_called_once_with(callback_context)
129+
manager._load_existing_credential.assert_called_once_with(tool_context)
130+
manager._load_from_auth_response.assert_called_once_with(tool_context)
131131

132132
assert result is None
133133

@@ -138,12 +138,12 @@ async def test_load_existing_credential_already_exchanged(self):
138138
mock_credential = Mock(spec=AuthCredential)
139139
auth_config.exchanged_auth_credential = mock_credential
140140

141-
callback_context = Mock()
141+
tool_context = Mock()
142142

143143
manager = CredentialManager(auth_config)
144144
manager._load_from_credential_service = AsyncMock(return_value=None)
145145

146-
result = await manager._load_existing_credential(callback_context)
146+
result = await manager._load_existing_credential(tool_context)
147147

148148
assert result is None
149149

@@ -155,23 +155,21 @@ async def test_load_existing_credential_with_credential_service(self):
155155

156156
mock_credential = Mock(spec=AuthCredential)
157157

158-
callback_context = Mock()
158+
tool_context = Mock()
159159

160160
manager = CredentialManager(auth_config)
161161
manager._load_from_credential_service = AsyncMock(
162162
return_value=mock_credential
163163
)
164164

165-
result = await manager._load_existing_credential(callback_context)
165+
result = await manager._load_existing_credential(tool_context)
166166

167-
manager._load_from_credential_service.assert_called_once_with(
168-
callback_context
169-
)
167+
manager._load_from_credential_service.assert_called_once_with(tool_context)
170168
assert result == mock_credential
171169

172170
@pytest.mark.asyncio
173171
async def test_load_from_credential_service_with_service(self):
174-
"""Test _load_from_credential_service from callback context when credential service is available."""
172+
"""Test _load_from_credential_service from tool context when credential service is available."""
175173
auth_config = Mock(spec=AuthConfig)
176174

177175
mock_credential = Mock(spec=AuthCredential)
@@ -183,14 +181,14 @@ async def test_load_from_credential_service_with_service(self):
183181
invocation_context = Mock()
184182
invocation_context.credential_service = credential_service
185183

186-
callback_context = Mock()
187-
callback_context._invocation_context = invocation_context
188-
callback_context.load_credential = AsyncMock(return_value=mock_credential)
184+
tool_context = Mock()
185+
tool_context._invocation_context = invocation_context
186+
tool_context.load_credential = AsyncMock(return_value=mock_credential)
189187

190188
manager = CredentialManager(auth_config)
191-
result = await manager._load_from_credential_service(callback_context)
189+
result = await manager._load_from_credential_service(tool_context)
192190

193-
callback_context.load_credential.assert_called_once_with(auth_config)
191+
tool_context.load_credential.assert_called_once_with(auth_config)
194192
assert result == mock_credential
195193

196194
@pytest.mark.asyncio
@@ -202,11 +200,11 @@ async def test_load_from_credential_service_no_service(self):
202200
invocation_context = Mock()
203201
invocation_context.credential_service = None
204202

205-
callback_context = Mock()
206-
callback_context._invocation_context = invocation_context
203+
tool_context = Mock()
204+
tool_context._invocation_context = invocation_context
207205

208206
manager = CredentialManager(auth_config)
209-
result = await manager._load_from_credential_service(callback_context)
207+
result = await manager._load_from_credential_service(tool_context)
210208

211209
assert result is None
212210

@@ -223,14 +221,14 @@ async def test_save_credential_with_service(self):
223221
invocation_context = Mock()
224222
invocation_context.credential_service = credential_service
225223

226-
callback_context = Mock()
227-
callback_context._invocation_context = invocation_context
228-
callback_context.save_credential = AsyncMock()
224+
tool_context = Mock()
225+
tool_context._invocation_context = invocation_context
226+
tool_context.save_credential = AsyncMock()
229227

230228
manager = CredentialManager(auth_config)
231-
await manager._save_credential(callback_context, mock_credential)
229+
await manager._save_credential(tool_context, mock_credential)
232230

233-
callback_context.save_credential.assert_called_once_with(auth_config)
231+
tool_context.save_credential.assert_called_once_with(auth_config)
234232
assert auth_config.exchanged_auth_credential == mock_credential
235233

236234
@pytest.mark.asyncio
@@ -244,11 +242,11 @@ async def test_save_credential_no_service(self):
244242
invocation_context = Mock()
245243
invocation_context.credential_service = None
246244

247-
callback_context = Mock()
248-
callback_context._invocation_context = invocation_context
245+
tool_context = Mock()
246+
tool_context._invocation_context = invocation_context
249247

250248
manager = CredentialManager(auth_config)
251-
await manager._save_credential(callback_context, mock_credential)
249+
await manager._save_credential(tool_context, mock_credential)
252250

253251
# Should not raise an error, and credential should be set in auth_config
254252
# even when there's no credential service (config is updated regardless)

0 commit comments

Comments
 (0)