13
13
# limitations under the License.
14
14
15
15
from datetime import datetime
16
- import json
17
16
import os
18
17
19
18
from dotenv import load_dotenv
27
26
from google .adk .auth import AuthCredentialTypes
28
27
from google .adk .auth import OAuth2Auth
29
28
from google .adk .tools import ToolContext
29
+ from google .adk .tools .authenticated_function_tool import AuthenticatedFunctionTool
30
30
from google .adk .tools .google_api_tool import CalendarToolset
31
- from google .auth .transport .requests import Request
32
31
from google .oauth2 .credentials import Credentials
33
32
from googleapiclient .discovery import build
34
33
@@ -56,6 +55,7 @@ def list_calendar_events(
56
55
end_time : str ,
57
56
limit : int ,
58
57
tool_context : ToolContext ,
58
+ credential : AuthCredential ,
59
59
) -> list [dict ]:
60
60
"""Search for calendar events.
61
61
@@ -80,84 +80,11 @@ def list_calendar_events(
80
80
Returns:
81
81
list[dict]: A list of events that match the search criteria.
82
82
"""
83
- creds = None
84
-
85
- # Check if the tokes were already in the session state, which means the user
86
- # has already gone through the OAuth flow and successfully authenticated and
87
- # authorized the tool to access their calendar.
88
- if "calendar_tool_tokens" in tool_context .state :
89
- creds = Credentials .from_authorized_user_info (
90
- tool_context .state ["calendar_tool_tokens" ], SCOPES
91
- )
92
- if not creds or not creds .valid :
93
- # If the access token is expired, refresh it with the refresh token.
94
- if creds and creds .expired and creds .refresh_token :
95
- creds .refresh (Request ())
96
- else :
97
- auth_scheme = OAuth2 (
98
- flows = OAuthFlows (
99
- authorizationCode = OAuthFlowAuthorizationCode (
100
- authorizationUrl = "https://accounts.google.com/o/oauth2/auth" ,
101
- tokenUrl = "https://oauth2.googleapis.com/token" ,
102
- scopes = {
103
- "https://www.googleapis.com/auth/calendar" : (
104
- "See, edit, share, and permanently delete all the"
105
- " calendars you can access using Google Calendar"
106
- )
107
- },
108
- )
109
- )
110
- )
111
- auth_credential = AuthCredential (
112
- auth_type = AuthCredentialTypes .OAUTH2 ,
113
- oauth2 = OAuth2Auth (
114
- client_id = oauth_client_id , client_secret = oauth_client_secret
115
- ),
116
- )
117
- # If the user has not gone through the OAuth flow before, or the refresh
118
- # token also expired, we need to ask users to go through the OAuth flow.
119
- # First we check whether the user has just gone through the OAuth flow and
120
- # Oauth response is just passed back.
121
- auth_response = tool_context .get_auth_response (
122
- AuthConfig (
123
- auth_scheme = auth_scheme , raw_auth_credential = auth_credential
124
- )
125
- )
126
- if auth_response :
127
- # ADK exchanged the access token already for us
128
- access_token = auth_response .oauth2 .access_token
129
- refresh_token = auth_response .oauth2 .refresh_token
130
-
131
- creds = Credentials (
132
- token = access_token ,
133
- refresh_token = refresh_token ,
134
- token_uri = auth_scheme .flows .authorizationCode .tokenUrl ,
135
- client_id = oauth_client_id ,
136
- client_secret = oauth_client_secret ,
137
- scopes = list (auth_scheme .flows .authorizationCode .scopes .keys ()),
138
- )
139
- else :
140
- # If there are no auth response which means the user has not gone
141
- # through the OAuth flow yet, we need to ask users to go through the
142
- # OAuth flow.
143
- tool_context .request_credential (
144
- AuthConfig (
145
- auth_scheme = auth_scheme ,
146
- raw_auth_credential = auth_credential ,
147
- )
148
- )
149
- # The return value is optional and could be any dict object. It will be
150
- # wrapped in a dict with key as 'result' and value as the return value
151
- # if the object returned is not a dict. This response will be passed
152
- # to LLM to generate a user friendly message. e.g. LLM will tell user:
153
- # "I need your authorization to access your calendar. Please authorize
154
- # me so I can check your meetings for today."
155
- return "Need User Authorization to access their calendar."
156
- # We store the access token and refresh token in the session state for the
157
- # next runs. This is just an example. On production, a tool should store
158
- # those credentials in some secure store or properly encrypt it before store
159
- # it in the session state.
160
- tool_context .state ["calendar_tool_tokens" ] = json .loads (creds .to_json ())
83
+
84
+ creds = Credentials (
85
+ token = credential .oauth2 .access_token ,
86
+ refresh_token = credential .oauth2 .refresh_token ,
87
+ )
161
88
162
89
service = build ("calendar" , "v3" , credentials = creds )
163
90
events_result = (
@@ -208,6 +135,33 @@ def update_time(callback_context: CallbackContext):
208
135
209
136
Currnet time: {_time}
210
137
""" ,
211
- tools = [list_calendar_events , calendar_toolset ],
138
+ tools = [
139
+ AuthenticatedFunctionTool (
140
+ func = list_calendar_events ,
141
+ auth_config = AuthConfig (
142
+ auth_scheme = OAuth2 (
143
+ flows = OAuthFlows (
144
+ authorizationCode = OAuthFlowAuthorizationCode (
145
+ authorizationUrl = (
146
+ "https://accounts.google.com/o/oauth2/auth"
147
+ ),
148
+ tokenUrl = "https://oauth2.googleapis.com/token" ,
149
+ scopes = {
150
+ "https://www.googleapis.com/auth/calendar" : "" ,
151
+ },
152
+ )
153
+ )
154
+ ),
155
+ raw_auth_credential = AuthCredential (
156
+ auth_type = AuthCredentialTypes .OAUTH2 ,
157
+ oauth2 = OAuth2Auth (
158
+ client_id = oauth_client_id ,
159
+ client_secret = oauth_client_secret ,
160
+ ),
161
+ ),
162
+ ),
163
+ ),
164
+ calendar_toolset ,
165
+ ],
212
166
before_agent_callback = update_time ,
213
167
)
0 commit comments