Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions ts-langchain/src/lib/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { InMemoryStore, MemorySaver } from '@langchain/langgraph';
import { Calculator } from '@langchain/community/tools/calculator';
import { SerpAPI } from '@langchain/community/tools/serpapi';
import { GmailCreateDraft, GmailSearch } from '@langchain/community/tools/gmail';
import { GoogleCalendarCreateTool, GoogleCalendarViewTool } from '@langchain/community/tools/google_calendar';

import { getAccessToken, withCalendar, withGmailRead, withGmailWrite, withAsyncAuthorization } from './auth0-ai';
import { withCalendar, withGmailRead, withGmailWrite, withAsyncAuthorization } from './auth0-ai';
import { getUserInfoTool } from './tools/user-info';
import { shopOnlineTool } from './tools/shop-online';
import { getContextDocumentsTool } from './tools/context-docs';
import { getCalendarEventsTool } from './tools/google-calender';
import { getCalendarEventsTool, createCalendarEventsTool } from './tools/google-calender';

const date = new Date().toISOString();

Expand All @@ -24,23 +23,21 @@ const llm = new ChatOpenAI({
// Provide the access token to the Gmail tools
const gmailParams = {
credentials: {
accessToken: getAccessToken,
accessToken: async () => {
const { getAccessToken } = await import('./auth0-ai');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks weird as we dont do this for any other imports, any reason for this?

return getAccessToken();
},
},
};

const googleCalendarParams = {
credentials: { accessToken: getAccessToken, calendarId: 'primary' },
model: llm,
};
const tools = [
new Calculator(),
// Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/
new SerpAPI(),
withGmailRead(new GmailSearch(gmailParams)),
withGmailWrite(new GmailCreateDraft(gmailParams)),
withCalendar(new GoogleCalendarCreateTool(googleCalendarParams)),
withCalendar(new GoogleCalendarViewTool(googleCalendarParams)),
withCalendar(getCalendarEventsTool),
withCalendar(createCalendarEventsTool),
getUserInfoTool,
withAsyncAuthorization(shopOnlineTool),
getContextDocumentsTool,
Expand Down
71 changes: 71 additions & 0 deletions ts-langchain/src/lib/tools/google-calender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,74 @@ export const getCalendarEventsTool = tool(
}),
},
);

export const createCalendarEventsTool = tool(
async ({ summary, description, startDateTime, endDateTime, location, attendees }) => {
// Get the access token from Auth0 AI
const accessToken = await getAccessToken();

// Google SDK
try {
const calendar = google.calendar('v3');
const auth = new google.auth.OAuth2();

auth.setCredentials({
access_token: accessToken,
});

// Create the event
const response = await calendar.events.insert({
auth,
calendarId: 'primary',
requestBody: {
summary,
description,
location,
start: {
dateTime: startDateTime,
timeZone: 'UTC',
},
end: {
dateTime: endDateTime,
timeZone: 'UTC',
},
attendees: attendees?.map((email) => ({ email })),
},
});

const event = response.data;

return {
success: true,
eventId: event.id,
summary: event.summary,
description: event.description,
startTime: event.start?.dateTime || event.start?.date,
endTime: event.end?.dateTime || event.end?.date,
location: event.location,
htmlLink: event.htmlLink,
message: `Successfully created calendar event: ${event.summary}`,
};
} catch (error) {
if (error instanceof GaxiosError) {
if (error.status === 401) {
throw new TokenVaultError(`Authorization required to access the Token Vault connection.`);
}
}

throw error;
}
},
{
name: 'create_calendar_event',
description: `Create a new event in the user's Google Calendar. Use this tool to schedule meetings, appointments, or reminders.`,
schema: z.object({
summary: z.string().describe('The title/summary of the event'),
description: z.string().optional().describe('Detailed description of the event'),
startDateTime: z.string().describe('Start date and time in ISO 8601 format (e.g., 2025-11-12T14:00:00Z)'),
endDateTime: z.string().describe('End date and time in ISO 8601 format (e.g., 2025-11-12T15:00:00Z)'),
location: z.string().optional().describe('Location of the event'),
attendees: z.array(z.string()).optional().describe('Array of email addresses of attendees to invite'),
}),
},
);