@anuma/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/expo/chunk-LJYAMK62.mjs +25 -0
- package/dist/expo/chunk-MJJIYFAX.mjs +25 -0
- package/dist/expo/chunk-PJCZO4BQ.mjs +25 -0
- package/dist/expo/clientConfig-2MI4KULF.mjs +10 -0
- package/dist/expo/clientConfig-QDAXFL3W.mjs +10 -0
- package/dist/expo/clientConfig-R4IOW7I2.mjs +10 -0
- package/dist/expo/index.cjs +7858 -0
- package/dist/expo/index.d.mts +2590 -0
- package/dist/expo/index.d.ts +2590 -0
- package/dist/expo/index.mjs +7770 -0
- package/dist/index.cjs +1200 -0
- package/dist/index.d.mts +2796 -0
- package/dist/index.d.ts +2796 -0
- package/dist/index.mjs +1138 -0
- package/dist/next/index.cjs +64 -0
- package/dist/next/index.d.mts +23 -0
- package/dist/next/index.d.ts +23 -0
- package/dist/next/index.mjs +39 -0
- package/dist/polyfills/index.cjs +61 -0
- package/dist/polyfills/index.d.mts +9 -0
- package/dist/polyfills/index.d.ts +9 -0
- package/dist/polyfills/index.mjs +34 -0
- package/dist/react/chunk-LJYAMK62.mjs +25 -0
- package/dist/react/chunk-MJJIYFAX.mjs +25 -0
- package/dist/react/chunk-PJCZO4BQ.mjs +25 -0
- package/dist/react/clientConfig-2MI4KULF.mjs +10 -0
- package/dist/react/clientConfig-QDAXFL3W.mjs +10 -0
- package/dist/react/clientConfig-R4IOW7I2.mjs +10 -0
- package/dist/react/index.cjs +15178 -0
- package/dist/react/index.d.mts +6014 -0
- package/dist/react/index.d.ts +6014 -0
- package/dist/react/index.mjs +14945 -0
- package/dist/tools/chunk-KDFGY4SK.mjs +13 -0
- package/dist/tools/clientConfig-RMDOT5YM.mjs +10 -0
- package/dist/tools/index.cjs +775 -0
- package/dist/tools/index.d.mts +121 -0
- package/dist/tools/index.d.ts +121 -0
- package/dist/tools/index.mjs +741 -0
- package/dist/vercel/index.cjs +86 -0
- package/dist/vercel/index.d.mts +149 -0
- package/dist/vercel/index.d.ts +149 -0
- package/dist/vercel/index.mjs +57 -0
- package/package.json +149 -0
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/tools/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createChatTools: () => createChatTools,
|
|
24
|
+
createDriveTools: () => createDriveTools,
|
|
25
|
+
createGoogleCalendarCreateEventTool: () => createGoogleCalendarCreateEventTool,
|
|
26
|
+
createGoogleCalendarTool: () => createGoogleCalendarTool,
|
|
27
|
+
createGoogleCalendarUpdateEventTool: () => createGoogleCalendarUpdateEventTool,
|
|
28
|
+
createGoogleDriveGetContentTool: () => createGoogleDriveGetContentTool,
|
|
29
|
+
createGoogleDriveListRecentTool: () => createGoogleDriveListRecentTool,
|
|
30
|
+
createGoogleDriveSearchTool: () => createGoogleDriveSearchTool
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
|
|
34
|
+
// src/tools/googleCalendar.ts
|
|
35
|
+
function ensureTimezone(timestamp) {
|
|
36
|
+
if (/[Zz]$/.test(timestamp) || /[+-]\d{2}:\d{2}$/.test(timestamp)) {
|
|
37
|
+
return timestamp;
|
|
38
|
+
}
|
|
39
|
+
return `${timestamp}Z`;
|
|
40
|
+
}
|
|
41
|
+
async function fetchCalendarEvents(accessToken, args) {
|
|
42
|
+
const { timeMin, timeMax, maxResults = 10 } = args;
|
|
43
|
+
const params = new URLSearchParams({
|
|
44
|
+
maxResults: String(maxResults),
|
|
45
|
+
singleEvents: "true",
|
|
46
|
+
orderBy: "startTime"
|
|
47
|
+
});
|
|
48
|
+
const now = /* @__PURE__ */ new Date();
|
|
49
|
+
const defaultTimeMin = now.toISOString();
|
|
50
|
+
const defaultTimeMax = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1e3).toISOString();
|
|
51
|
+
params.set("timeMin", ensureTimezone(timeMin || defaultTimeMin));
|
|
52
|
+
params.set("timeMax", ensureTimezone(timeMax || defaultTimeMax));
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(
|
|
55
|
+
`https://www.googleapis.com/calendar/v3/calendars/primary/events?${params.toString()}`,
|
|
56
|
+
{
|
|
57
|
+
headers: {
|
|
58
|
+
Authorization: `Bearer ${accessToken}`,
|
|
59
|
+
"Content-Type": "application/json"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
if (response.status === 401) {
|
|
65
|
+
return "Error: Calendar access not authorized. Please grant calendar permissions.";
|
|
66
|
+
}
|
|
67
|
+
const errorText = await response.text();
|
|
68
|
+
return `Error: Failed to fetch calendar events (${response.status}): ${errorText}`;
|
|
69
|
+
}
|
|
70
|
+
const data = await response.json();
|
|
71
|
+
const events = (data.items || []).map(
|
|
72
|
+
(item) => ({
|
|
73
|
+
id: item.id,
|
|
74
|
+
summary: item.summary || "No title",
|
|
75
|
+
start: item.start?.dateTime || item.start?.date || "Unknown",
|
|
76
|
+
end: item.end?.dateTime || item.end?.date || "Unknown",
|
|
77
|
+
description: item.description,
|
|
78
|
+
location: item.location
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
return events;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function buildEventBody(args) {
|
|
87
|
+
const { summary, start, end, description, location, attendees } = args;
|
|
88
|
+
const isAllDay = !start.includes("T");
|
|
89
|
+
const eventBody = {
|
|
90
|
+
summary,
|
|
91
|
+
description,
|
|
92
|
+
location,
|
|
93
|
+
start: isAllDay ? { date: start } : { dateTime: start },
|
|
94
|
+
end: isAllDay ? { date: end } : { dateTime: end }
|
|
95
|
+
};
|
|
96
|
+
if (attendees && attendees.length > 0) {
|
|
97
|
+
eventBody.attendees = attendees.map((email) => ({ email }));
|
|
98
|
+
}
|
|
99
|
+
return eventBody;
|
|
100
|
+
}
|
|
101
|
+
function parseEventResponse(data) {
|
|
102
|
+
return {
|
|
103
|
+
id: data.id,
|
|
104
|
+
summary: data.summary || "No title",
|
|
105
|
+
start: data.start?.dateTime || data.start?.date || "Unknown",
|
|
106
|
+
end: data.end?.dateTime || data.end?.date || "Unknown",
|
|
107
|
+
description: data.description,
|
|
108
|
+
location: data.location
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function createCalendarEvent(accessToken, args) {
|
|
112
|
+
const eventBody = buildEventBody(args);
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch(
|
|
115
|
+
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
116
|
+
{
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: {
|
|
119
|
+
Authorization: `Bearer ${accessToken}`,
|
|
120
|
+
"Content-Type": "application/json"
|
|
121
|
+
},
|
|
122
|
+
body: JSON.stringify(eventBody)
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
if (response.status === 401) {
|
|
127
|
+
return "Error: Calendar access not authorized. Please grant calendar permissions.";
|
|
128
|
+
}
|
|
129
|
+
const errorText = await response.text();
|
|
130
|
+
return `Error: Failed to create calendar event (${response.status}): ${errorText}`;
|
|
131
|
+
}
|
|
132
|
+
const data = await response.json();
|
|
133
|
+
return parseEventResponse(data);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function buildUpdateEventBody(args) {
|
|
139
|
+
const { summary, start, end, description, location, attendees } = args;
|
|
140
|
+
const eventBody = {};
|
|
141
|
+
if (summary !== void 0) eventBody.summary = summary;
|
|
142
|
+
if (description !== void 0) eventBody.description = description;
|
|
143
|
+
if (location !== void 0) eventBody.location = location;
|
|
144
|
+
if (start !== void 0) {
|
|
145
|
+
const isAllDay = !start.includes("T");
|
|
146
|
+
eventBody.start = isAllDay ? { date: start } : { dateTime: start };
|
|
147
|
+
}
|
|
148
|
+
if (end !== void 0) {
|
|
149
|
+
const isAllDay = !end.includes("T");
|
|
150
|
+
eventBody.end = isAllDay ? { date: end } : { dateTime: end };
|
|
151
|
+
}
|
|
152
|
+
if (attendees !== void 0) {
|
|
153
|
+
eventBody.attendees = attendees.map((email) => ({ email }));
|
|
154
|
+
}
|
|
155
|
+
return eventBody;
|
|
156
|
+
}
|
|
157
|
+
async function updateCalendarEvent(accessToken, args) {
|
|
158
|
+
const { eventId } = args;
|
|
159
|
+
const eventBody = buildUpdateEventBody(args);
|
|
160
|
+
try {
|
|
161
|
+
const response = await fetch(
|
|
162
|
+
`https://www.googleapis.com/calendar/v3/calendars/primary/events/${eventId}`,
|
|
163
|
+
{
|
|
164
|
+
method: "PATCH",
|
|
165
|
+
headers: {
|
|
166
|
+
Authorization: `Bearer ${accessToken}`,
|
|
167
|
+
"Content-Type": "application/json"
|
|
168
|
+
},
|
|
169
|
+
body: JSON.stringify(eventBody)
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
if (response.status === 401) {
|
|
174
|
+
return "Error: Calendar access not authorized. Please grant calendar permissions.";
|
|
175
|
+
}
|
|
176
|
+
if (response.status === 404) {
|
|
177
|
+
return `Error: Event not found with ID: ${eventId}`;
|
|
178
|
+
}
|
|
179
|
+
const errorText = await response.text();
|
|
180
|
+
return `Error: Failed to update calendar event (${response.status}): ${errorText}`;
|
|
181
|
+
}
|
|
182
|
+
const data = await response.json();
|
|
183
|
+
return parseEventResponse(data);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
return `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function createGoogleCalendarTool(getAccessToken, requestCalendarAccess) {
|
|
189
|
+
return {
|
|
190
|
+
type: "function",
|
|
191
|
+
function: {
|
|
192
|
+
name: "google_calendar_list_events",
|
|
193
|
+
description: "Lists upcoming events from the user's Google Calendar. Returns events within a specified time range. If no time range is specified, returns events for the next 7 days.",
|
|
194
|
+
arguments: {
|
|
195
|
+
type: "object",
|
|
196
|
+
properties: {
|
|
197
|
+
timeMin: {
|
|
198
|
+
type: "string",
|
|
199
|
+
description: 'Start of the time range (ISO 8601 format, e.g., "2024-01-15T00:00:00Z"). Defaults to now.'
|
|
200
|
+
},
|
|
201
|
+
timeMax: {
|
|
202
|
+
type: "string",
|
|
203
|
+
description: 'End of the time range (ISO 8601 format, e.g., "2024-01-22T23:59:59Z"). Defaults to 7 days from now.'
|
|
204
|
+
},
|
|
205
|
+
maxResults: {
|
|
206
|
+
type: "number",
|
|
207
|
+
description: "Maximum number of events to return. Defaults to 10."
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
required: []
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
executor: async (args) => {
|
|
214
|
+
let token = getAccessToken();
|
|
215
|
+
if (!token) {
|
|
216
|
+
try {
|
|
217
|
+
token = await requestCalendarAccess();
|
|
218
|
+
} catch {
|
|
219
|
+
return "Error: Failed to get calendar access. Please grant permissions when prompted.";
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!token) {
|
|
223
|
+
return "Error: No Google Calendar access token available. Please connect your Google account.";
|
|
224
|
+
}
|
|
225
|
+
const typedArgs = {
|
|
226
|
+
timeMin: args.timeMin,
|
|
227
|
+
timeMax: args.timeMax,
|
|
228
|
+
maxResults: args.maxResults
|
|
229
|
+
};
|
|
230
|
+
return fetchCalendarEvents(token, typedArgs);
|
|
231
|
+
},
|
|
232
|
+
autoExecute: true
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function createGoogleCalendarCreateEventTool(getAccessToken, requestCalendarAccess) {
|
|
236
|
+
return {
|
|
237
|
+
type: "function",
|
|
238
|
+
function: {
|
|
239
|
+
name: "google_calendar_create_event",
|
|
240
|
+
description: "Creates a new event in the user's Google Calendar. Supports both timed events (with specific times) and all-day events (date only).",
|
|
241
|
+
arguments: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: {
|
|
244
|
+
summary: {
|
|
245
|
+
type: "string",
|
|
246
|
+
description: "The title/name of the event."
|
|
247
|
+
},
|
|
248
|
+
start: {
|
|
249
|
+
type: "string",
|
|
250
|
+
description: 'Start time in ISO 8601 format. For timed events use datetime format (e.g., "2024-01-15T09:00:00-05:00"). For all-day events use date format (e.g., "2024-01-15").'
|
|
251
|
+
},
|
|
252
|
+
end: {
|
|
253
|
+
type: "string",
|
|
254
|
+
description: 'End time in ISO 8601 format. For timed events use datetime format (e.g., "2024-01-15T10:00:00-05:00"). For all-day events use date format (e.g., "2024-01-16", note: end date is exclusive).'
|
|
255
|
+
},
|
|
256
|
+
description: {
|
|
257
|
+
type: "string",
|
|
258
|
+
description: "Optional description or notes for the event."
|
|
259
|
+
},
|
|
260
|
+
location: {
|
|
261
|
+
type: "string",
|
|
262
|
+
description: "Optional location for the event."
|
|
263
|
+
},
|
|
264
|
+
attendees: {
|
|
265
|
+
type: "array",
|
|
266
|
+
items: { type: "string" },
|
|
267
|
+
description: "Optional list of email addresses to invite as attendees."
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
required: ["summary", "start", "end"]
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
executor: async (args) => {
|
|
274
|
+
let token = getAccessToken();
|
|
275
|
+
if (!token) {
|
|
276
|
+
try {
|
|
277
|
+
token = await requestCalendarAccess();
|
|
278
|
+
} catch {
|
|
279
|
+
return "Error: Failed to get calendar access. Please grant permissions when prompted.";
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!token) {
|
|
283
|
+
return "Error: No Google Calendar access token available. Please connect your Google account.";
|
|
284
|
+
}
|
|
285
|
+
const typedArgs = {
|
|
286
|
+
summary: args.summary,
|
|
287
|
+
start: args.start,
|
|
288
|
+
end: args.end,
|
|
289
|
+
description: args.description,
|
|
290
|
+
location: args.location,
|
|
291
|
+
attendees: args.attendees
|
|
292
|
+
};
|
|
293
|
+
return createCalendarEvent(token, typedArgs);
|
|
294
|
+
},
|
|
295
|
+
autoExecute: true
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function createGoogleCalendarUpdateEventTool(getAccessToken, requestCalendarAccess) {
|
|
299
|
+
return {
|
|
300
|
+
type: "function",
|
|
301
|
+
function: {
|
|
302
|
+
name: "google_calendar_update_event",
|
|
303
|
+
description: "Updates an existing event in the user's Google Calendar. Only the fields provided will be updated; other fields remain unchanged. Use google_calendar_list_events first to get the event ID.",
|
|
304
|
+
arguments: {
|
|
305
|
+
type: "object",
|
|
306
|
+
properties: {
|
|
307
|
+
eventId: {
|
|
308
|
+
type: "string",
|
|
309
|
+
description: "The ID of the event to update (obtained from google_calendar_list_events)."
|
|
310
|
+
},
|
|
311
|
+
summary: {
|
|
312
|
+
type: "string",
|
|
313
|
+
description: "The new title/name of the event."
|
|
314
|
+
},
|
|
315
|
+
start: {
|
|
316
|
+
type: "string",
|
|
317
|
+
description: 'New start time in ISO 8601 format. For timed events use datetime format (e.g., "2024-01-15T09:00:00-05:00"). For all-day events use date format (e.g., "2024-01-15").'
|
|
318
|
+
},
|
|
319
|
+
end: {
|
|
320
|
+
type: "string",
|
|
321
|
+
description: 'New end time in ISO 8601 format. For timed events use datetime format (e.g., "2024-01-15T10:00:00-05:00"). For all-day events use date format (e.g., "2024-01-16").'
|
|
322
|
+
},
|
|
323
|
+
description: {
|
|
324
|
+
type: "string",
|
|
325
|
+
description: "New description or notes for the event."
|
|
326
|
+
},
|
|
327
|
+
location: {
|
|
328
|
+
type: "string",
|
|
329
|
+
description: "New location for the event."
|
|
330
|
+
},
|
|
331
|
+
attendees: {
|
|
332
|
+
type: "array",
|
|
333
|
+
items: { type: "string" },
|
|
334
|
+
description: "New list of email addresses to invite as attendees (replaces existing attendees)."
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
required: ["eventId"]
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
executor: async (args) => {
|
|
341
|
+
let token = getAccessToken();
|
|
342
|
+
if (!token) {
|
|
343
|
+
try {
|
|
344
|
+
token = await requestCalendarAccess();
|
|
345
|
+
} catch {
|
|
346
|
+
return "Error: Failed to get calendar access. Please grant permissions when prompted.";
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (!token) {
|
|
350
|
+
return "Error: No Google Calendar access token available. Please connect your Google account.";
|
|
351
|
+
}
|
|
352
|
+
const typedArgs = {
|
|
353
|
+
eventId: args.eventId,
|
|
354
|
+
summary: args.summary,
|
|
355
|
+
start: args.start,
|
|
356
|
+
end: args.end,
|
|
357
|
+
description: args.description,
|
|
358
|
+
location: args.location,
|
|
359
|
+
attendees: args.attendees
|
|
360
|
+
};
|
|
361
|
+
return updateCalendarEvent(token, typedArgs);
|
|
362
|
+
},
|
|
363
|
+
autoExecute: true
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function createChatTools(getAccessToken, requestCalendarAccess) {
|
|
367
|
+
return [
|
|
368
|
+
createGoogleCalendarTool(getAccessToken, requestCalendarAccess),
|
|
369
|
+
createGoogleCalendarCreateEventTool(getAccessToken, requestCalendarAccess),
|
|
370
|
+
createGoogleCalendarUpdateEventTool(getAccessToken, requestCalendarAccess)
|
|
371
|
+
];
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/tools/googleDrive.ts
|
|
375
|
+
async function searchDriveFiles(accessToken, args) {
|
|
376
|
+
const { query, maxResults = 10, mimeType } = args;
|
|
377
|
+
let driveQuery = `fullText contains '${query.replace(/'/g, "\\'")}'`;
|
|
378
|
+
if (mimeType) {
|
|
379
|
+
driveQuery += ` and mimeType = '${mimeType}'`;
|
|
380
|
+
}
|
|
381
|
+
driveQuery += " and trashed = false";
|
|
382
|
+
const params = new URLSearchParams({
|
|
383
|
+
q: driveQuery,
|
|
384
|
+
pageSize: String(maxResults),
|
|
385
|
+
fields: "files(id,name,mimeType,webViewLink,modifiedTime,size,owners)",
|
|
386
|
+
orderBy: "modifiedTime desc"
|
|
387
|
+
});
|
|
388
|
+
try {
|
|
389
|
+
const response = await fetch(`https://www.googleapis.com/drive/v3/files?${params.toString()}`, {
|
|
390
|
+
headers: {
|
|
391
|
+
Authorization: `Bearer ${accessToken}`,
|
|
392
|
+
"Content-Type": "application/json"
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
if (response.status === 401) {
|
|
397
|
+
return "Error: Google Drive access not authorized. Please grant Drive permissions.";
|
|
398
|
+
}
|
|
399
|
+
if (response.status === 403) {
|
|
400
|
+
return "Error: Insufficient permissions to access Google Drive. Please grant read access to your Drive.";
|
|
401
|
+
}
|
|
402
|
+
const errorText = await response.text();
|
|
403
|
+
return `Error: Failed to search Google Drive (${response.status}): ${errorText}`;
|
|
404
|
+
}
|
|
405
|
+
const data = await response.json();
|
|
406
|
+
const files = (data.files || []).map((file) => ({
|
|
407
|
+
id: file.id,
|
|
408
|
+
name: file.name,
|
|
409
|
+
mimeType: file.mimeType,
|
|
410
|
+
webViewLink: file.webViewLink,
|
|
411
|
+
modifiedTime: file.modifiedTime,
|
|
412
|
+
size: file.size,
|
|
413
|
+
owners: file.owners
|
|
414
|
+
}));
|
|
415
|
+
if (files.length === 0) {
|
|
416
|
+
return `No files found matching "${query}"`;
|
|
417
|
+
}
|
|
418
|
+
return files;
|
|
419
|
+
} catch (error) {
|
|
420
|
+
return `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function createGoogleDriveSearchTool(getAccessToken, requestDriveAccess) {
|
|
424
|
+
return {
|
|
425
|
+
type: "function",
|
|
426
|
+
function: {
|
|
427
|
+
name: "google_drive_search",
|
|
428
|
+
description: "Searches for files in the user's Google Drive. Returns matching files with their names, types, and links. Use this to help users find documents, spreadsheets, presentations, PDFs, and other files stored in their Drive.",
|
|
429
|
+
arguments: {
|
|
430
|
+
type: "object",
|
|
431
|
+
properties: {
|
|
432
|
+
query: {
|
|
433
|
+
type: "string",
|
|
434
|
+
description: 'The search query to find files. Searches in file names and content. Examples: "quarterly report", "budget 2024", "meeting notes".'
|
|
435
|
+
},
|
|
436
|
+
maxResults: {
|
|
437
|
+
type: "number",
|
|
438
|
+
description: "Maximum number of files to return. Defaults to 10. Maximum is 100."
|
|
439
|
+
},
|
|
440
|
+
mimeType: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: 'Optional MIME type filter. Common types: "application/vnd.google-apps.document" (Google Docs), "application/vnd.google-apps.spreadsheet" (Sheets), "application/vnd.google-apps.presentation" (Slides), "application/pdf" (PDF files).'
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
required: ["query"]
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
executor: async (args) => {
|
|
449
|
+
let token = getAccessToken();
|
|
450
|
+
if (!token) {
|
|
451
|
+
try {
|
|
452
|
+
token = await requestDriveAccess();
|
|
453
|
+
} catch {
|
|
454
|
+
return "Error: Failed to get Google Drive access. Please grant permissions when prompted.";
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (!token) {
|
|
458
|
+
return "Error: No Google Drive access token available. Please connect your Google account.";
|
|
459
|
+
}
|
|
460
|
+
const typedArgs = {
|
|
461
|
+
query: args.query,
|
|
462
|
+
maxResults: args.maxResults,
|
|
463
|
+
mimeType: args.mimeType
|
|
464
|
+
};
|
|
465
|
+
return searchDriveFiles(token, typedArgs);
|
|
466
|
+
},
|
|
467
|
+
autoExecute: true
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
async function listRecentDriveFiles(accessToken, args) {
|
|
471
|
+
const { maxResults = 10, mimeType } = args;
|
|
472
|
+
let driveQuery = "trashed = false";
|
|
473
|
+
if (mimeType) {
|
|
474
|
+
driveQuery += ` and mimeType = '${mimeType}'`;
|
|
475
|
+
}
|
|
476
|
+
const params = new URLSearchParams({
|
|
477
|
+
q: driveQuery,
|
|
478
|
+
pageSize: String(maxResults),
|
|
479
|
+
fields: "files(id,name,mimeType,webViewLink,modifiedTime,size,owners)",
|
|
480
|
+
orderBy: "modifiedTime desc"
|
|
481
|
+
});
|
|
482
|
+
try {
|
|
483
|
+
const response = await fetch(`https://www.googleapis.com/drive/v3/files?${params.toString()}`, {
|
|
484
|
+
headers: {
|
|
485
|
+
Authorization: `Bearer ${accessToken}`,
|
|
486
|
+
"Content-Type": "application/json"
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
if (!response.ok) {
|
|
490
|
+
if (response.status === 401) {
|
|
491
|
+
return "Error: Google Drive access not authorized. Please grant Drive permissions.";
|
|
492
|
+
}
|
|
493
|
+
if (response.status === 403) {
|
|
494
|
+
return "Error: Insufficient permissions to access Google Drive. Please grant read access to your Drive.";
|
|
495
|
+
}
|
|
496
|
+
const errorText = await response.text();
|
|
497
|
+
return `Error: Failed to list Google Drive files (${response.status}): ${errorText}`;
|
|
498
|
+
}
|
|
499
|
+
const data = await response.json();
|
|
500
|
+
const files = (data.files || []).map((file) => ({
|
|
501
|
+
id: file.id,
|
|
502
|
+
name: file.name,
|
|
503
|
+
mimeType: file.mimeType,
|
|
504
|
+
webViewLink: file.webViewLink,
|
|
505
|
+
modifiedTime: file.modifiedTime,
|
|
506
|
+
size: file.size,
|
|
507
|
+
owners: file.owners
|
|
508
|
+
}));
|
|
509
|
+
if (files.length === 0) {
|
|
510
|
+
return "No recent files found in your Google Drive.";
|
|
511
|
+
}
|
|
512
|
+
return files;
|
|
513
|
+
} catch (error) {
|
|
514
|
+
return `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function createGoogleDriveListRecentTool(getAccessToken, requestDriveAccess) {
|
|
518
|
+
return {
|
|
519
|
+
type: "function",
|
|
520
|
+
function: {
|
|
521
|
+
name: "google_drive_list_recent",
|
|
522
|
+
description: "Lists recent files from the user's Google Drive, ordered by last modified date. Use this when the user wants to see their recent files without a specific search query.",
|
|
523
|
+
arguments: {
|
|
524
|
+
type: "object",
|
|
525
|
+
properties: {
|
|
526
|
+
maxResults: {
|
|
527
|
+
type: "number",
|
|
528
|
+
description: "Maximum number of files to return. Defaults to 10. Maximum is 100."
|
|
529
|
+
},
|
|
530
|
+
mimeType: {
|
|
531
|
+
type: "string",
|
|
532
|
+
description: 'Optional MIME type filter. Common types: "application/vnd.google-apps.document" (Google Docs), "application/vnd.google-apps.spreadsheet" (Sheets), "application/vnd.google-apps.presentation" (Slides), "application/pdf" (PDF files).'
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
required: []
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
executor: async (args) => {
|
|
539
|
+
let token = getAccessToken();
|
|
540
|
+
if (!token) {
|
|
541
|
+
try {
|
|
542
|
+
token = await requestDriveAccess();
|
|
543
|
+
} catch {
|
|
544
|
+
return "Error: Failed to get Google Drive access. Please grant permissions when prompted.";
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (!token) {
|
|
548
|
+
return "Error: No Google Drive access token available. Please connect your Google account.";
|
|
549
|
+
}
|
|
550
|
+
const typedArgs = {
|
|
551
|
+
maxResults: args.maxResults,
|
|
552
|
+
mimeType: args.mimeType
|
|
553
|
+
};
|
|
554
|
+
return listRecentDriveFiles(token, typedArgs);
|
|
555
|
+
},
|
|
556
|
+
autoExecute: true
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
async function findFileByName(accessToken, fileName) {
|
|
560
|
+
const driveQuery = `name contains '${fileName.replace(/'/g, "\\'")}' and trashed = false`;
|
|
561
|
+
const params = new URLSearchParams({
|
|
562
|
+
q: driveQuery,
|
|
563
|
+
pageSize: "1",
|
|
564
|
+
fields: "files(id,name)",
|
|
565
|
+
orderBy: "modifiedTime desc"
|
|
566
|
+
});
|
|
567
|
+
const response = await fetch(`https://www.googleapis.com/drive/v3/files?${params.toString()}`, {
|
|
568
|
+
headers: {
|
|
569
|
+
Authorization: `Bearer ${accessToken}`,
|
|
570
|
+
"Content-Type": "application/json"
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
if (!response.ok) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
const data = await response.json();
|
|
577
|
+
return data.files?.[0]?.id || null;
|
|
578
|
+
}
|
|
579
|
+
var GOOGLE_DOCS_EXPORT_TYPES = {
|
|
580
|
+
"application/vnd.google-apps.document": "text/plain",
|
|
581
|
+
"application/vnd.google-apps.spreadsheet": "text/csv",
|
|
582
|
+
"application/vnd.google-apps.presentation": "text/plain"
|
|
583
|
+
};
|
|
584
|
+
var MAX_CONTENT_LENGTH = 5e4;
|
|
585
|
+
async function resolveFileId(accessToken, fileId, fileName) {
|
|
586
|
+
if (fileId) {
|
|
587
|
+
return { fileId };
|
|
588
|
+
}
|
|
589
|
+
if (fileName) {
|
|
590
|
+
console.log("[google_drive_get_content] Searching for file by name:", fileName);
|
|
591
|
+
const foundId = await findFileByName(accessToken, fileName);
|
|
592
|
+
if (!foundId) {
|
|
593
|
+
return {
|
|
594
|
+
error: `Error: Could not find a file matching "${fileName}". Please check the file name and try again.`
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
console.log("[google_drive_get_content] Found file ID:", foundId);
|
|
598
|
+
return { fileId: foundId };
|
|
599
|
+
}
|
|
600
|
+
return { error: "Error: Please provide either a fileId or fileName to get file content." };
|
|
601
|
+
}
|
|
602
|
+
async function fetchFileMetadata(accessToken, fileId) {
|
|
603
|
+
const response = await fetch(
|
|
604
|
+
`https://www.googleapis.com/drive/v3/files/${fileId}?fields=id,name,mimeType,webViewLink`,
|
|
605
|
+
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
|
606
|
+
);
|
|
607
|
+
if (!response.ok) {
|
|
608
|
+
if (response.status === 404) {
|
|
609
|
+
return { error: "Error: File not found. Please check the file ID." };
|
|
610
|
+
}
|
|
611
|
+
return { error: `Error: Failed to get file metadata (${response.status})` };
|
|
612
|
+
}
|
|
613
|
+
const data = await response.json();
|
|
614
|
+
return {
|
|
615
|
+
metadata: { name: data.name, mimeType: data.mimeType, webViewLink: data.webViewLink }
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function getContentUrl(fileId, mimeType) {
|
|
619
|
+
if (GOOGLE_DOCS_EXPORT_TYPES[mimeType]) {
|
|
620
|
+
const exportMimeType = GOOGLE_DOCS_EXPORT_TYPES[mimeType];
|
|
621
|
+
return {
|
|
622
|
+
url: `https://www.googleapis.com/drive/v3/files/${fileId}/export?mimeType=${encodeURIComponent(exportMimeType)}`,
|
|
623
|
+
isExport: true
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (mimeType.startsWith("text/") || mimeType === "application/json" || mimeType === "application/xml") {
|
|
627
|
+
return {
|
|
628
|
+
url: `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`,
|
|
629
|
+
isExport: false
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
function formatNonTextFileResponse(fileId, metadata) {
|
|
635
|
+
const { name, mimeType, webViewLink } = metadata;
|
|
636
|
+
const linkInfo = webViewLink ? `
|
|
637
|
+
View in Google Drive: ${webViewLink}` : "";
|
|
638
|
+
if (mimeType === "application/pdf") {
|
|
639
|
+
return `File: ${name}
|
|
640
|
+
Type: PDF${linkInfo}
|
|
641
|
+
|
|
642
|
+
Note: PDF content cannot be extracted directly in the browser. The user can click the link above to view the PDF in Google Drive.`;
|
|
643
|
+
}
|
|
644
|
+
if (mimeType.startsWith("image/")) {
|
|
645
|
+
const directUrl = `https://drive.google.com/uc?export=view&id=${fileId}`;
|
|
646
|
+
return `File: ${name}
|
|
647
|
+
Type: ${mimeType}${linkInfo}
|
|
648
|
+
Direct image URL: ${directUrl}
|
|
649
|
+
|
|
650
|
+
To view this image, click the Google Drive link above or use the direct URL.`;
|
|
651
|
+
}
|
|
652
|
+
return `File: ${name}
|
|
653
|
+
Type: ${mimeType}${linkInfo}
|
|
654
|
+
|
|
655
|
+
Note: This file type cannot be displayed as text.`;
|
|
656
|
+
}
|
|
657
|
+
async function fetchAndFormatContent(accessToken, contentUrl, metadata, isExport) {
|
|
658
|
+
const response = await fetch(contentUrl, {
|
|
659
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
660
|
+
});
|
|
661
|
+
if (!response.ok) {
|
|
662
|
+
if (response.status === 403) {
|
|
663
|
+
return `Error: Permission denied. You may not have access to view this file's content.`;
|
|
664
|
+
}
|
|
665
|
+
return `Error: Failed to get file content (${response.status})`;
|
|
666
|
+
}
|
|
667
|
+
const content = await response.text();
|
|
668
|
+
const truncated = content.length > MAX_CONTENT_LENGTH;
|
|
669
|
+
const displayContent = truncated ? content.slice(0, MAX_CONTENT_LENGTH) : content;
|
|
670
|
+
const header = `=== File: ${metadata.name} ===
|
|
671
|
+
Type: ${metadata.mimeType}${isExport ? " (exported as text)" : ""}
|
|
672
|
+
|
|
673
|
+
`;
|
|
674
|
+
const footer = truncated ? `
|
|
675
|
+
|
|
676
|
+
... (content truncated, showing first ${MAX_CONTENT_LENGTH} characters of ${content.length})` : "";
|
|
677
|
+
return header + displayContent + footer;
|
|
678
|
+
}
|
|
679
|
+
async function getDriveFileContent(accessToken, args) {
|
|
680
|
+
console.log("[google_drive_get_content] Starting with:", args);
|
|
681
|
+
const fileIdResult = await resolveFileId(accessToken, args.fileId, args.fileName);
|
|
682
|
+
if ("error" in fileIdResult) {
|
|
683
|
+
return fileIdResult.error;
|
|
684
|
+
}
|
|
685
|
+
const { fileId } = fileIdResult;
|
|
686
|
+
try {
|
|
687
|
+
const metadataResult = await fetchFileMetadata(accessToken, fileId);
|
|
688
|
+
if ("error" in metadataResult) {
|
|
689
|
+
return metadataResult.error;
|
|
690
|
+
}
|
|
691
|
+
const { metadata } = metadataResult;
|
|
692
|
+
console.log("[google_drive_get_content] File metadata:", metadata);
|
|
693
|
+
const contentUrlResult = getContentUrl(fileId, metadata.mimeType);
|
|
694
|
+
if (!contentUrlResult) {
|
|
695
|
+
return formatNonTextFileResponse(fileId, metadata);
|
|
696
|
+
}
|
|
697
|
+
return fetchAndFormatContent(
|
|
698
|
+
accessToken,
|
|
699
|
+
contentUrlResult.url,
|
|
700
|
+
metadata,
|
|
701
|
+
contentUrlResult.isExport
|
|
702
|
+
);
|
|
703
|
+
} catch (error) {
|
|
704
|
+
return `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function createGoogleDriveGetContentTool(getAccessToken, requestDriveAccess) {
|
|
708
|
+
return {
|
|
709
|
+
type: "function",
|
|
710
|
+
function: {
|
|
711
|
+
name: "google_drive_get_content",
|
|
712
|
+
description: "Gets the text content of a file from the user's Google Drive. Works with Google Docs, Sheets, Slides (exported as text/CSV), and text-based files. You can provide either a fileId (from a previous search) or a fileName to search for.",
|
|
713
|
+
arguments: {
|
|
714
|
+
type: "object",
|
|
715
|
+
properties: {
|
|
716
|
+
fileId: {
|
|
717
|
+
type: "string",
|
|
718
|
+
description: "The unique file ID from Google Drive. Use this if you have the ID from a previous search result."
|
|
719
|
+
},
|
|
720
|
+
fileName: {
|
|
721
|
+
type: "string",
|
|
722
|
+
description: "The name (or partial name) of the file to find and read. Use this when you know the file name but not the ID."
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
required: []
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
executor: async (args) => {
|
|
729
|
+
console.log("[google_drive_get_content] Executor called with args:", args);
|
|
730
|
+
let token = getAccessToken();
|
|
731
|
+
if (!token) {
|
|
732
|
+
console.log("[google_drive_get_content] No token, requesting access...");
|
|
733
|
+
try {
|
|
734
|
+
token = await requestDriveAccess();
|
|
735
|
+
} catch {
|
|
736
|
+
return "Error: Failed to get Google Drive access. Please grant permissions when prompted.";
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
if (!token) {
|
|
740
|
+
return "Error: No Google Drive access token available. Please connect your Google account.";
|
|
741
|
+
}
|
|
742
|
+
const typedArgs = {
|
|
743
|
+
fileId: args.fileId,
|
|
744
|
+
fileName: args.fileName
|
|
745
|
+
};
|
|
746
|
+
const result = await getDriveFileContent(token, typedArgs);
|
|
747
|
+
console.log(
|
|
748
|
+
"[google_drive_get_content] Result length:",
|
|
749
|
+
result.length,
|
|
750
|
+
"First 200 chars:",
|
|
751
|
+
result.slice(0, 200)
|
|
752
|
+
);
|
|
753
|
+
return result;
|
|
754
|
+
},
|
|
755
|
+
autoExecute: true
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function createDriveTools(getAccessToken, requestDriveAccess) {
|
|
759
|
+
return [
|
|
760
|
+
createGoogleDriveSearchTool(getAccessToken, requestDriveAccess),
|
|
761
|
+
createGoogleDriveListRecentTool(getAccessToken, requestDriveAccess),
|
|
762
|
+
createGoogleDriveGetContentTool(getAccessToken, requestDriveAccess)
|
|
763
|
+
];
|
|
764
|
+
}
|
|
765
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
766
|
+
0 && (module.exports = {
|
|
767
|
+
createChatTools,
|
|
768
|
+
createDriveTools,
|
|
769
|
+
createGoogleCalendarCreateEventTool,
|
|
770
|
+
createGoogleCalendarTool,
|
|
771
|
+
createGoogleCalendarUpdateEventTool,
|
|
772
|
+
createGoogleDriveGetContentTool,
|
|
773
|
+
createGoogleDriveListRecentTool,
|
|
774
|
+
createGoogleDriveSearchTool
|
|
775
|
+
});
|