Skip to content

Commit 8ace43f

Browse files
seanzhougooglecopybara-github
authored andcommitted
chore: Adapt oauth calendar agent to use authenticated tool
PiperOrigin-RevId: 775433950
1 parent b402b15 commit 8ace43f

File tree

1 file changed

+35
-81
lines changed
  • contributing/samples/oauth_calendar_agent

1 file changed

+35
-81
lines changed

contributing/samples/oauth_calendar_agent/agent.py

Lines changed: 35 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
from datetime import datetime
16-
import json
1716
import os
1817

1918
from dotenv import load_dotenv
@@ -27,8 +26,8 @@
2726
from google.adk.auth import AuthCredentialTypes
2827
from google.adk.auth import OAuth2Auth
2928
from google.adk.tools import ToolContext
29+
from google.adk.tools.authenticated_function_tool import AuthenticatedFunctionTool
3030
from google.adk.tools.google_api_tool import CalendarToolset
31-
from google.auth.transport.requests import Request
3231
from google.oauth2.credentials import Credentials
3332
from googleapiclient.discovery import build
3433

@@ -56,6 +55,7 @@ def list_calendar_events(
5655
end_time: str,
5756
limit: int,
5857
tool_context: ToolContext,
58+
credential: AuthCredential,
5959
) -> list[dict]:
6060
"""Search for calendar events.
6161
@@ -80,84 +80,11 @@ def list_calendar_events(
8080
Returns:
8181
list[dict]: A list of events that match the search criteria.
8282
"""
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+
)
16188

16289
service = build("calendar", "v3", credentials=creds)
16390
events_result = (
@@ -208,6 +135,33 @@ def update_time(callback_context: CallbackContext):
208135
209136
Currnet time: {_time}
210137
""",
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+
],
212166
before_agent_callback=update_time,
213167
)

0 commit comments

Comments
 (0)