mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 23:01:09 +03:00
Feature/Add teams, gmail, outlook tools (#4577)
* add teams, gmail, outlook tools * update docs link * update credentials for oauth2 * add jira tool * add google drive, google calendar, google sheets tools, powerpoint, excel, word doc loader * update jira logo * Refactor Gmail and Outlook tools to remove maxOutputLength parameter and enhance request handling. Update response formatting to include parameters in the output. Adjust Google Drive tools to simplify success messages by removing unnecessary parameter details.
This commit is contained in:
@@ -0,0 +1,657 @@
|
||||
import { convertMultiOptionsToStringArray, getCredentialData, getCredentialParam, refreshOAuth2Token } from '../../../src/utils'
|
||||
import { createGoogleDriveTools } from './core'
|
||||
import type { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
|
||||
class GoogleDrive_Tools implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
description: string
|
||||
baseClasses: string[]
|
||||
credential: INodeParams
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Google Drive'
|
||||
this.name = 'googleDriveTool'
|
||||
this.version = 1.0
|
||||
this.type = 'GoogleDrive'
|
||||
this.icon = 'google-drive.svg'
|
||||
this.category = 'Tools'
|
||||
this.description = 'Perform Google Drive operations such as managing files, folders, sharing, and searching'
|
||||
this.baseClasses = ['Tool']
|
||||
this.credential = {
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['googleDriveOAuth2']
|
||||
}
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Type',
|
||||
name: 'driveType',
|
||||
type: 'options',
|
||||
description: 'Type of Google Drive operation',
|
||||
options: [
|
||||
{
|
||||
label: 'File',
|
||||
name: 'file'
|
||||
},
|
||||
{
|
||||
label: 'Folder',
|
||||
name: 'folder'
|
||||
},
|
||||
{
|
||||
label: 'Search',
|
||||
name: 'search'
|
||||
},
|
||||
{
|
||||
label: 'Share',
|
||||
name: 'share'
|
||||
}
|
||||
]
|
||||
},
|
||||
// File Actions
|
||||
{
|
||||
label: 'File Actions',
|
||||
name: 'fileActions',
|
||||
type: 'multiOptions',
|
||||
description: 'Actions to perform on files',
|
||||
options: [
|
||||
{
|
||||
label: 'List Files',
|
||||
name: 'listFiles'
|
||||
},
|
||||
{
|
||||
label: 'Get File',
|
||||
name: 'getFile'
|
||||
},
|
||||
{
|
||||
label: 'Create File',
|
||||
name: 'createFile'
|
||||
},
|
||||
{
|
||||
label: 'Update File',
|
||||
name: 'updateFile'
|
||||
},
|
||||
{
|
||||
label: 'Delete File',
|
||||
name: 'deleteFile'
|
||||
},
|
||||
{
|
||||
label: 'Copy File',
|
||||
name: 'copyFile'
|
||||
},
|
||||
{
|
||||
label: 'Download File',
|
||||
name: 'downloadFile'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
driveType: ['file']
|
||||
}
|
||||
},
|
||||
// Folder Actions
|
||||
{
|
||||
label: 'Folder Actions',
|
||||
name: 'folderActions',
|
||||
type: 'multiOptions',
|
||||
description: 'Actions to perform on folders',
|
||||
options: [
|
||||
{
|
||||
label: 'Create Folder',
|
||||
name: 'createFolder'
|
||||
},
|
||||
{
|
||||
label: 'List Folder Contents',
|
||||
name: 'listFolderContents'
|
||||
},
|
||||
{
|
||||
label: 'Delete Folder',
|
||||
name: 'deleteFolder'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
driveType: ['folder']
|
||||
}
|
||||
},
|
||||
// Search Actions
|
||||
{
|
||||
label: 'Search Actions',
|
||||
name: 'searchActions',
|
||||
type: 'multiOptions',
|
||||
description: 'Search operations',
|
||||
options: [
|
||||
{
|
||||
label: 'Search Files',
|
||||
name: 'searchFiles'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
driveType: ['search']
|
||||
}
|
||||
},
|
||||
// Share Actions
|
||||
{
|
||||
label: 'Share Actions',
|
||||
name: 'shareActions',
|
||||
type: 'multiOptions',
|
||||
description: 'Sharing operations',
|
||||
options: [
|
||||
{
|
||||
label: 'Share File',
|
||||
name: 'shareFile'
|
||||
},
|
||||
{
|
||||
label: 'Get Permissions',
|
||||
name: 'getPermissions'
|
||||
},
|
||||
{
|
||||
label: 'Remove Permission',
|
||||
name: 'removePermission'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
driveType: ['share']
|
||||
}
|
||||
},
|
||||
// File Parameters
|
||||
{
|
||||
label: 'File ID',
|
||||
name: 'fileId',
|
||||
type: 'string',
|
||||
description: 'File ID for file operations',
|
||||
show: {
|
||||
fileActions: ['getFile', 'updateFile', 'deleteFile', 'copyFile', 'downloadFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'File ID',
|
||||
name: 'fileId',
|
||||
type: 'string',
|
||||
description: 'File ID for sharing operations',
|
||||
show: {
|
||||
shareActions: ['shareFile', 'getPermissions', 'removePermission']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Folder ID',
|
||||
name: 'folderId',
|
||||
type: 'string',
|
||||
description: 'Folder ID for folder operations',
|
||||
show: {
|
||||
folderActions: ['listFolderContents', 'deleteFolder']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Permission ID',
|
||||
name: 'permissionId',
|
||||
type: 'string',
|
||||
description: 'Permission ID to remove',
|
||||
show: {
|
||||
shareActions: ['removePermission']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'File Name',
|
||||
name: 'fileName',
|
||||
type: 'string',
|
||||
description: 'Name of the file',
|
||||
show: {
|
||||
fileActions: ['createFile', 'copyFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Folder Name',
|
||||
name: 'fileName',
|
||||
type: 'string',
|
||||
description: 'Name of the folder',
|
||||
show: {
|
||||
folderActions: ['createFolder']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'File Content',
|
||||
name: 'fileContent',
|
||||
type: 'string',
|
||||
description: 'Content of the file (for text files)',
|
||||
show: {
|
||||
fileActions: ['createFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'MIME Type',
|
||||
name: 'mimeType',
|
||||
type: 'string',
|
||||
description: 'MIME type of the file (e.g., text/plain, application/pdf)',
|
||||
show: {
|
||||
fileActions: ['createFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Parent Folder ID',
|
||||
name: 'parentFolderId',
|
||||
type: 'string',
|
||||
description: 'ID of the parent folder (comma-separated for multiple parents)',
|
||||
show: {
|
||||
fileActions: ['createFile', 'copyFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Parent Folder ID',
|
||||
name: 'parentFolderId',
|
||||
type: 'string',
|
||||
description: 'ID of the parent folder for the new folder',
|
||||
show: {
|
||||
folderActions: ['createFolder']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'File Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
description: 'File description',
|
||||
show: {
|
||||
fileActions: ['createFile', 'updateFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Folder Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
description: 'Folder description',
|
||||
show: {
|
||||
folderActions: ['createFolder']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
// Search Parameters
|
||||
{
|
||||
label: 'Search Query',
|
||||
name: 'searchQuery',
|
||||
type: 'string',
|
||||
description: 'Search query using Google Drive search syntax',
|
||||
show: {
|
||||
searchActions: ['searchFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Max Results',
|
||||
name: 'maxResults',
|
||||
type: 'number',
|
||||
description: 'Maximum number of results to return (1-1000)',
|
||||
default: 10,
|
||||
show: {
|
||||
fileActions: ['listFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Max Results',
|
||||
name: 'maxResults',
|
||||
type: 'number',
|
||||
description: 'Maximum number of results to return (1-1000)',
|
||||
default: 10,
|
||||
show: {
|
||||
searchActions: ['searchFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Order By',
|
||||
name: 'orderBy',
|
||||
type: 'options',
|
||||
description: 'Sort order for file results',
|
||||
options: [
|
||||
{
|
||||
label: 'Name',
|
||||
name: 'name'
|
||||
},
|
||||
{
|
||||
label: 'Created Time',
|
||||
name: 'createdTime'
|
||||
},
|
||||
{
|
||||
label: 'Modified Time',
|
||||
name: 'modifiedTime'
|
||||
},
|
||||
{
|
||||
label: 'Size',
|
||||
name: 'quotaBytesUsed'
|
||||
},
|
||||
{
|
||||
label: 'Folder',
|
||||
name: 'folder'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
fileActions: ['listFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Order By',
|
||||
name: 'orderBy',
|
||||
type: 'options',
|
||||
description: 'Sort order for search results',
|
||||
options: [
|
||||
{
|
||||
label: 'Name',
|
||||
name: 'name'
|
||||
},
|
||||
{
|
||||
label: 'Created Time',
|
||||
name: 'createdTime'
|
||||
},
|
||||
{
|
||||
label: 'Modified Time',
|
||||
name: 'modifiedTime'
|
||||
},
|
||||
{
|
||||
label: 'Size',
|
||||
name: 'quotaBytesUsed'
|
||||
},
|
||||
{
|
||||
label: 'Folder',
|
||||
name: 'folder'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
searchActions: ['searchFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
// Share Parameters
|
||||
{
|
||||
label: 'Share Role',
|
||||
name: 'shareRole',
|
||||
type: 'options',
|
||||
description: 'Permission role for sharing',
|
||||
options: [
|
||||
{
|
||||
label: 'Reader',
|
||||
name: 'reader'
|
||||
},
|
||||
{
|
||||
label: 'Writer',
|
||||
name: 'writer'
|
||||
},
|
||||
{
|
||||
label: 'Commenter',
|
||||
name: 'commenter'
|
||||
},
|
||||
{
|
||||
label: 'Owner',
|
||||
name: 'owner'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
shareActions: ['shareFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Share Type',
|
||||
name: 'shareType',
|
||||
type: 'options',
|
||||
description: 'Type of permission',
|
||||
options: [
|
||||
{
|
||||
label: 'User',
|
||||
name: 'user'
|
||||
},
|
||||
{
|
||||
label: 'Group',
|
||||
name: 'group'
|
||||
},
|
||||
{
|
||||
label: 'Domain',
|
||||
name: 'domain'
|
||||
},
|
||||
{
|
||||
label: 'Anyone',
|
||||
name: 'anyone'
|
||||
}
|
||||
],
|
||||
show: {
|
||||
shareActions: ['shareFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Email Address',
|
||||
name: 'emailAddress',
|
||||
type: 'string',
|
||||
description: 'Email address for user/group sharing',
|
||||
show: {
|
||||
shareActions: ['shareFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Domain Name',
|
||||
name: 'domainName',
|
||||
type: 'string',
|
||||
description: 'Domain name for domain sharing',
|
||||
show: {
|
||||
shareActions: ['shareFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Send Notification Email',
|
||||
name: 'sendNotificationEmail',
|
||||
type: 'boolean',
|
||||
description: 'Whether to send notification emails when sharing',
|
||||
default: true,
|
||||
show: {
|
||||
shareActions: ['shareFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Email Message',
|
||||
name: 'emailMessage',
|
||||
type: 'string',
|
||||
description: 'Custom message to include in notification email',
|
||||
show: {
|
||||
shareActions: ['shareFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
// Advanced Parameters for File Actions
|
||||
{
|
||||
label: 'Include Items From All Drives',
|
||||
name: 'includeItemsFromAllDrives',
|
||||
type: 'boolean',
|
||||
description: 'Include items from all drives (shared drives)',
|
||||
show: {
|
||||
fileActions: ['listFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Include Items From All Drives',
|
||||
name: 'includeItemsFromAllDrives',
|
||||
type: 'boolean',
|
||||
description: 'Include items from all drives (shared drives)',
|
||||
show: {
|
||||
searchActions: ['searchFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Supports All Drives',
|
||||
name: 'supportsAllDrives',
|
||||
type: 'boolean',
|
||||
description: 'Whether the application supports both My Drives and shared drives',
|
||||
show: {
|
||||
fileActions: ['listFiles', 'getFile', 'createFile', 'updateFile', 'deleteFile', 'copyFile', 'downloadFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Supports All Drives',
|
||||
name: 'supportsAllDrives',
|
||||
type: 'boolean',
|
||||
description: 'Whether the application supports both My Drives and shared drives',
|
||||
show: {
|
||||
folderActions: ['createFolder', 'listFolderContents', 'deleteFolder']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Supports All Drives',
|
||||
name: 'supportsAllDrives',
|
||||
type: 'boolean',
|
||||
description: 'Whether the application supports both My Drives and shared drives',
|
||||
show: {
|
||||
searchActions: ['searchFiles']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Supports All Drives',
|
||||
name: 'supportsAllDrives',
|
||||
type: 'boolean',
|
||||
description: 'Whether the application supports both My Drives and shared drives',
|
||||
show: {
|
||||
shareActions: ['shareFile', 'getPermissions', 'removePermission']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
description: 'Specific fields to include in response (e.g., "files(id,name,mimeType)")',
|
||||
show: {
|
||||
fileActions: ['listFiles', 'getFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Acknowledge Abuse',
|
||||
name: 'acknowledgeAbuse',
|
||||
type: 'boolean',
|
||||
description: 'Acknowledge the risk of downloading known malware or abusive files',
|
||||
show: {
|
||||
fileActions: ['getFile', 'downloadFile']
|
||||
},
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
|
||||
let credentialData = await getCredentialData(nodeData.credential ?? '', options)
|
||||
credentialData = await refreshOAuth2Token(nodeData.credential ?? '', credentialData, options)
|
||||
const accessToken = getCredentialParam('access_token', credentialData, nodeData)
|
||||
|
||||
if (!accessToken) {
|
||||
throw new Error('No access token found in credential')
|
||||
}
|
||||
|
||||
const driveType = nodeData.inputs?.driveType as string
|
||||
const fileActions = convertMultiOptionsToStringArray(nodeData.inputs?.fileActions)
|
||||
const folderActions = convertMultiOptionsToStringArray(nodeData.inputs?.folderActions)
|
||||
const searchActions = convertMultiOptionsToStringArray(nodeData.inputs?.searchActions)
|
||||
const shareActions = convertMultiOptionsToStringArray(nodeData.inputs?.shareActions)
|
||||
|
||||
// Combine all actions based on type
|
||||
let actions: string[] = []
|
||||
if (driveType === 'file') {
|
||||
actions = fileActions
|
||||
} else if (driveType === 'folder') {
|
||||
actions = folderActions
|
||||
} else if (driveType === 'search') {
|
||||
actions = searchActions
|
||||
} else if (driveType === 'share') {
|
||||
actions = shareActions
|
||||
}
|
||||
|
||||
// Collect default parameters from inputs
|
||||
const defaultParams: any = {}
|
||||
|
||||
// Add parameters based on the inputs provided
|
||||
if (nodeData.inputs?.fileId) defaultParams.fileId = nodeData.inputs.fileId
|
||||
if (nodeData.inputs?.folderId) defaultParams.folderId = nodeData.inputs.folderId
|
||||
if (nodeData.inputs?.permissionId) defaultParams.permissionId = nodeData.inputs.permissionId
|
||||
if (nodeData.inputs?.fileName) defaultParams.name = nodeData.inputs.fileName
|
||||
if (nodeData.inputs?.fileContent) defaultParams.content = nodeData.inputs.fileContent
|
||||
if (nodeData.inputs?.mimeType) defaultParams.mimeType = nodeData.inputs.mimeType
|
||||
if (nodeData.inputs?.parentFolderId) defaultParams.parents = nodeData.inputs.parentFolderId
|
||||
if (nodeData.inputs?.description) defaultParams.description = nodeData.inputs.description
|
||||
if (nodeData.inputs?.searchQuery) defaultParams.query = nodeData.inputs.searchQuery
|
||||
if (nodeData.inputs?.maxResults) defaultParams.pageSize = nodeData.inputs.maxResults
|
||||
if (nodeData.inputs?.orderBy) defaultParams.orderBy = nodeData.inputs.orderBy
|
||||
if (nodeData.inputs?.shareRole) defaultParams.role = nodeData.inputs.shareRole
|
||||
if (nodeData.inputs?.shareType) defaultParams.type = nodeData.inputs.shareType
|
||||
if (nodeData.inputs?.emailAddress) defaultParams.emailAddress = nodeData.inputs.emailAddress
|
||||
if (nodeData.inputs?.domainName) defaultParams.domain = nodeData.inputs.domainName
|
||||
if (nodeData.inputs?.sendNotificationEmail !== undefined)
|
||||
defaultParams.sendNotificationEmail = nodeData.inputs.sendNotificationEmail
|
||||
if (nodeData.inputs?.emailMessage) defaultParams.emailMessage = nodeData.inputs.emailMessage
|
||||
if (nodeData.inputs?.includeItemsFromAllDrives !== undefined)
|
||||
defaultParams.includeItemsFromAllDrives = nodeData.inputs.includeItemsFromAllDrives
|
||||
if (nodeData.inputs?.supportsAllDrives !== undefined) defaultParams.supportsAllDrives = nodeData.inputs.supportsAllDrives
|
||||
if (nodeData.inputs?.fields) defaultParams.fields = nodeData.inputs.fields
|
||||
if (nodeData.inputs?.acknowledgeAbuse !== undefined) defaultParams.acknowledgeAbuse = nodeData.inputs.acknowledgeAbuse
|
||||
|
||||
const tools = createGoogleDriveTools({
|
||||
accessToken,
|
||||
actions,
|
||||
defaultParams
|
||||
})
|
||||
|
||||
return tools
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: GoogleDrive_Tools }
|
||||
@@ -0,0 +1,982 @@
|
||||
import { z } from 'zod'
|
||||
import fetch from 'node-fetch'
|
||||
import { DynamicStructuredTool } from '../OpenAPIToolkit/core'
|
||||
import { TOOL_ARGS_PREFIX } from '../../../src/agents'
|
||||
|
||||
export const desc = `Use this when you want to access Google Drive API for managing files and folders`
|
||||
|
||||
export interface Headers {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface Body {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface RequestParameters {
|
||||
headers?: Headers
|
||||
body?: Body
|
||||
url?: string
|
||||
description?: string
|
||||
name?: string
|
||||
actions?: string[]
|
||||
accessToken?: string
|
||||
defaultParams?: any
|
||||
}
|
||||
|
||||
// Define schemas for different Google Drive operations
|
||||
|
||||
// File Schemas
|
||||
const ListFilesSchema = z.object({
|
||||
pageSize: z.number().optional().default(10).describe('Maximum number of files to return (1-1000)'),
|
||||
pageToken: z.string().optional().describe('Token for next page of results'),
|
||||
orderBy: z.string().optional().describe('Sort order (name, folder, createdTime, modifiedTime, etc.)'),
|
||||
query: z.string().optional().describe('Search query (e.g., "name contains \'hello\'")'),
|
||||
spaces: z.string().optional().default('drive').describe('Spaces to search (drive, appDataFolder, photos)'),
|
||||
fields: z.string().optional().describe('Fields to include in response'),
|
||||
includeItemsFromAllDrives: z.boolean().optional().describe('Include items from all drives'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const GetFileSchema = z.object({
|
||||
fileId: z.string().describe('File ID'),
|
||||
fields: z.string().optional().describe('Fields to include in response'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives'),
|
||||
acknowledgeAbuse: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the user is acknowledging the risk of downloading known malware or other abusive files')
|
||||
})
|
||||
|
||||
const CreateFileSchema = z.object({
|
||||
name: z.string().describe('File name'),
|
||||
parents: z.string().optional().describe('Comma-separated list of parent folder IDs'),
|
||||
mimeType: z.string().optional().describe('MIME type of the file'),
|
||||
description: z.string().optional().describe('File description'),
|
||||
content: z.string().optional().describe('File content (for text files)'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const UpdateFileSchema = z.object({
|
||||
fileId: z.string().describe('File ID to update'),
|
||||
name: z.string().optional().describe('New file name'),
|
||||
description: z.string().optional().describe('New file description'),
|
||||
starred: z.boolean().optional().describe('Whether the file is starred'),
|
||||
trashed: z.boolean().optional().describe('Whether the file is trashed'),
|
||||
parents: z.string().optional().describe('Comma-separated list of new parent folder IDs'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const DeleteFileSchema = z.object({
|
||||
fileId: z.string().describe('File ID to delete'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const CopyFileSchema = z.object({
|
||||
fileId: z.string().describe('File ID to copy'),
|
||||
name: z.string().describe('Name for the copied file'),
|
||||
parents: z.string().optional().describe('Comma-separated list of parent folder IDs for the copy'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const DownloadFileSchema = z.object({
|
||||
fileId: z.string().describe('File ID to download'),
|
||||
acknowledgeAbuse: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the user is acknowledging the risk of downloading known malware or other abusive files'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const CreateFolderSchema = z.object({
|
||||
name: z.string().describe('Folder name'),
|
||||
parents: z.string().optional().describe('Comma-separated list of parent folder IDs'),
|
||||
description: z.string().optional().describe('Folder description'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const SearchFilesSchema = z.object({
|
||||
query: z.string().describe('Search query using Google Drive search syntax'),
|
||||
pageSize: z.number().optional().default(10).describe('Maximum number of files to return'),
|
||||
orderBy: z.string().optional().describe('Sort order'),
|
||||
includeItemsFromAllDrives: z.boolean().optional().describe('Include items from all drives'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
const ShareFileSchema = z.object({
|
||||
fileId: z.string().describe('File ID to share'),
|
||||
role: z.enum(['reader', 'writer', 'commenter', 'owner']).describe('Permission role'),
|
||||
type: z.enum(['user', 'group', 'domain', 'anyone']).describe('Permission type'),
|
||||
emailAddress: z.string().optional().describe('Email address (required for user/group types)'),
|
||||
domain: z.string().optional().describe('Domain name (required for domain type)'),
|
||||
allowFileDiscovery: z.boolean().optional().describe('Whether the file can be discovered by search'),
|
||||
sendNotificationEmail: z.boolean().optional().default(true).describe('Whether to send notification emails'),
|
||||
emailMessage: z.string().optional().describe('Custom message to include in notification email'),
|
||||
supportsAllDrives: z.boolean().optional().describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
})
|
||||
|
||||
class BaseGoogleDriveTool extends DynamicStructuredTool {
|
||||
protected accessToken: string = ''
|
||||
|
||||
constructor(args: any) {
|
||||
super(args)
|
||||
this.accessToken = args.accessToken ?? ''
|
||||
}
|
||||
|
||||
async makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method = 'GET',
|
||||
body,
|
||||
params
|
||||
}: {
|
||||
endpoint: string
|
||||
method?: string
|
||||
body?: any
|
||||
params?: any
|
||||
}): Promise<string> {
|
||||
const baseUrl = 'https://www.googleapis.com/drive/v3'
|
||||
const url = `${baseUrl}/${endpoint}`
|
||||
|
||||
const headers: { [key: string]: string } = {
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
Accept: 'application/json',
|
||||
...this.headers
|
||||
}
|
||||
|
||||
if (method !== 'GET' && body) {
|
||||
headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers,
|
||||
body: body ? (typeof body === 'string' ? body : JSON.stringify(body)) : undefined
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Google Drive API Error ${response.status}: ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.text()
|
||||
return data + TOOL_ARGS_PREFIX + JSON.stringify(params)
|
||||
}
|
||||
}
|
||||
|
||||
// File Tools
|
||||
class ListFilesTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'list_files',
|
||||
description: 'List files and folders from Google Drive',
|
||||
schema: ListFilesSchema,
|
||||
baseUrl: '',
|
||||
method: 'GET',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString())
|
||||
if (params.pageToken) queryParams.append('pageToken', params.pageToken)
|
||||
if (params.orderBy) queryParams.append('orderBy', params.orderBy)
|
||||
if (params.query) queryParams.append('q', params.query)
|
||||
if (params.spaces) queryParams.append('spaces', params.spaces)
|
||||
if (params.fields) queryParams.append('fields', params.fields)
|
||||
if (params.includeItemsFromAllDrives) queryParams.append('includeItemsFromAllDrives', params.includeItemsFromAllDrives.toString())
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files?${queryParams.toString()}`
|
||||
|
||||
try {
|
||||
const response = await this.makeGoogleDriveRequest({ endpoint, params })
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error listing files: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'get_file',
|
||||
description: 'Get file metadata from Google Drive',
|
||||
schema: GetFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'GET',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.fields) queryParams.append('fields', params.fields)
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
if (params.acknowledgeAbuse) queryParams.append('acknowledgeAbuse', params.acknowledgeAbuse.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}?${queryParams.toString()}`
|
||||
|
||||
try {
|
||||
const response = await this.makeGoogleDriveRequest({ endpoint, params })
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error getting file: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CreateFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'create_file',
|
||||
description: 'Create a new file in Google Drive',
|
||||
schema: CreateFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'POST',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
// Validate required parameters
|
||||
if (!params.name) {
|
||||
throw new Error('File name is required')
|
||||
}
|
||||
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
// Prepare metadata
|
||||
const fileMetadata: any = {
|
||||
name: params.name
|
||||
}
|
||||
|
||||
if (params.parents) {
|
||||
// Validate parent folder IDs format
|
||||
const parentIds = params.parents
|
||||
.split(',')
|
||||
.map((p: string) => p.trim())
|
||||
.filter((p: string) => p.length > 0)
|
||||
if (parentIds.length > 0) {
|
||||
fileMetadata.parents = parentIds
|
||||
}
|
||||
}
|
||||
if (params.mimeType) fileMetadata.mimeType = params.mimeType
|
||||
if (params.description) fileMetadata.description = params.description
|
||||
|
||||
// Determine upload type based on content and metadata
|
||||
if (!params.content) {
|
||||
// Metadata-only upload (no file content) - standard endpoint
|
||||
const endpoint = `files?${queryParams.toString()}`
|
||||
const response = await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'POST',
|
||||
body: fileMetadata,
|
||||
params
|
||||
})
|
||||
return response
|
||||
} else {
|
||||
// Validate content
|
||||
if (typeof params.content !== 'string') {
|
||||
throw new Error('File content must be a string')
|
||||
}
|
||||
|
||||
// Check if we have metadata beyond just the name
|
||||
const hasAdditionalMetadata = params.parents || params.description || params.mimeType
|
||||
|
||||
if (!hasAdditionalMetadata) {
|
||||
// Simple upload (uploadType=media) - only file content, basic metadata
|
||||
return await this.performSimpleUpload(params, queryParams)
|
||||
} else {
|
||||
// Multipart upload (uploadType=multipart) - file content + metadata
|
||||
return await this.performMultipartUpload(params, fileMetadata, queryParams)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
return `Error creating file: ${error}`
|
||||
}
|
||||
}
|
||||
|
||||
private async performSimpleUpload(params: any, queryParams: URLSearchParams): Promise<string> {
|
||||
// Simple upload: POST https://www.googleapis.com/upload/drive/v3/files?uploadType=media
|
||||
queryParams.append('uploadType', 'media')
|
||||
const url = `https://www.googleapis.com/upload/drive/v3/files?${queryParams.toString()}`
|
||||
|
||||
const headers: { [key: string]: string } = {
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
'Content-Type': params.mimeType || 'application/octet-stream',
|
||||
'Content-Length': Buffer.byteLength(params.content, 'utf8').toString()
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: params.content
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Google Drive API Error ${response.status}: ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.text()
|
||||
return data + TOOL_ARGS_PREFIX + JSON.stringify(params)
|
||||
}
|
||||
|
||||
private async performMultipartUpload(params: any, fileMetadata: any, queryParams: URLSearchParams): Promise<string> {
|
||||
// Multipart upload: POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart
|
||||
queryParams.append('uploadType', 'multipart')
|
||||
const url = `https://www.googleapis.com/upload/drive/v3/files?${queryParams.toString()}`
|
||||
|
||||
// Create multipart/related body according to RFC 2387
|
||||
const boundary = '-------314159265358979323846'
|
||||
|
||||
// Build multipart body - RFC 2387 format
|
||||
let body = `--${boundary}\r\n`
|
||||
|
||||
// Part 1: Metadata (application/json; charset=UTF-8)
|
||||
body += 'Content-Type: application/json; charset=UTF-8\r\n\r\n'
|
||||
body += JSON.stringify(fileMetadata) + '\r\n'
|
||||
|
||||
// Part 2: Media content (any MIME type)
|
||||
body += `--${boundary}\r\n`
|
||||
body += `Content-Type: ${params.mimeType || 'application/octet-stream'}\r\n\r\n`
|
||||
body += params.content + '\r\n'
|
||||
|
||||
// Close boundary
|
||||
body += `--${boundary}--`
|
||||
|
||||
const headers: { [key: string]: string } = {
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
'Content-Type': `multipart/related; boundary="${boundary}"`,
|
||||
'Content-Length': Buffer.byteLength(body, 'utf8').toString()
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: body
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
console.error('Multipart upload failed:', {
|
||||
url,
|
||||
headers: { ...headers, Authorization: '[REDACTED]' },
|
||||
metadata: fileMetadata,
|
||||
contentLength: params.content?.length || 0,
|
||||
error: errorText
|
||||
})
|
||||
throw new Error(`Google Drive API Error ${response.status}: ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.text()
|
||||
return data + TOOL_ARGS_PREFIX + JSON.stringify(params)
|
||||
} catch (error) {
|
||||
throw new Error(`Multipart upload failed: ${error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'update_file',
|
||||
description: 'Update file metadata in Google Drive',
|
||||
schema: UpdateFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'PATCH',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const updateData: any = {}
|
||||
|
||||
if (params.name) updateData.name = params.name
|
||||
if (params.description) updateData.description = params.description
|
||||
if (params.starred !== undefined) updateData.starred = params.starred
|
||||
if (params.trashed !== undefined) updateData.trashed = params.trashed
|
||||
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'PATCH',
|
||||
body: updateData,
|
||||
params
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error updating file: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'delete_file',
|
||||
description: 'Delete a file from Google Drive',
|
||||
schema: DeleteFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'DELETE',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}?${queryParams.toString()}`
|
||||
|
||||
await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'DELETE',
|
||||
params
|
||||
})
|
||||
return `File deleted successfully`
|
||||
} catch (error) {
|
||||
return `Error deleting file: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CopyFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'copy_file',
|
||||
description: 'Copy a file in Google Drive',
|
||||
schema: CopyFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'POST',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const copyData: any = {
|
||||
name: params.name
|
||||
}
|
||||
|
||||
if (params.parents) {
|
||||
copyData.parents = params.parents.split(',').map((p: string) => p.trim())
|
||||
}
|
||||
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}/copy?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'POST',
|
||||
body: copyData,
|
||||
params
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error copying file: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'download_file',
|
||||
description: 'Download a file from Google Drive',
|
||||
schema: DownloadFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'GET',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('alt', 'media')
|
||||
if (params.acknowledgeAbuse) queryParams.append('acknowledgeAbuse', params.acknowledgeAbuse.toString())
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({ endpoint, params })
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error downloading file: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CreateFolderTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'create_folder',
|
||||
description: 'Create a new folder in Google Drive',
|
||||
schema: CreateFolderSchema,
|
||||
baseUrl: '',
|
||||
method: 'POST',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const folderData: any = {
|
||||
name: params.name,
|
||||
mimeType: 'application/vnd.google-apps.folder'
|
||||
}
|
||||
|
||||
if (params.parents) {
|
||||
folderData.parents = params.parents.split(',').map((p: string) => p.trim())
|
||||
}
|
||||
if (params.description) folderData.description = params.description
|
||||
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'POST',
|
||||
body: folderData,
|
||||
params
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error creating folder: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SearchFilesTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'search_files',
|
||||
description: 'Search files in Google Drive',
|
||||
schema: SearchFilesSchema,
|
||||
baseUrl: '',
|
||||
method: 'GET',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('q', params.query)
|
||||
if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString())
|
||||
if (params.orderBy) queryParams.append('orderBy', params.orderBy)
|
||||
if (params.includeItemsFromAllDrives)
|
||||
queryParams.append('includeItemsFromAllDrives', params.includeItemsFromAllDrives.toString())
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({ endpoint, params })
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error searching files: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ShareFileTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'share_file',
|
||||
description: 'Share a file in Google Drive',
|
||||
schema: ShareFileSchema,
|
||||
baseUrl: '',
|
||||
method: 'POST',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const permissionData: any = {
|
||||
role: params.role,
|
||||
type: params.type
|
||||
}
|
||||
|
||||
if (params.emailAddress) permissionData.emailAddress = params.emailAddress
|
||||
if (params.domain) permissionData.domain = params.domain
|
||||
if (params.allowFileDiscovery !== undefined) permissionData.allowFileDiscovery = params.allowFileDiscovery
|
||||
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.sendNotificationEmail !== undefined)
|
||||
queryParams.append('sendNotificationEmail', params.sendNotificationEmail.toString())
|
||||
if (params.emailMessage) queryParams.append('emailMessage', params.emailMessage)
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}/permissions?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'POST',
|
||||
body: permissionData,
|
||||
params
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error sharing file: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ListFolderContentsTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'list_folder_contents',
|
||||
description: 'List contents of a specific folder in Google Drive',
|
||||
schema: z.object({
|
||||
folderId: z.string().describe('Folder ID to list contents from'),
|
||||
pageSize: z.number().optional().default(10).describe('Maximum number of files to return'),
|
||||
orderBy: z.string().optional().describe('Sort order'),
|
||||
includeItemsFromAllDrives: z.boolean().optional().describe('Include items from all drives'),
|
||||
supportsAllDrives: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
}),
|
||||
baseUrl: '',
|
||||
method: 'GET',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('q', `'${params.folderId}' in parents`)
|
||||
if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString())
|
||||
if (params.orderBy) queryParams.append('orderBy', params.orderBy)
|
||||
if (params.includeItemsFromAllDrives)
|
||||
queryParams.append('includeItemsFromAllDrives', params.includeItemsFromAllDrives.toString())
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({ endpoint, params })
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error listing folder contents: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteFolderTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'delete_folder',
|
||||
description: 'Delete a folder from Google Drive',
|
||||
schema: z.object({
|
||||
folderId: z.string().describe('Folder ID to delete'),
|
||||
supportsAllDrives: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
}),
|
||||
baseUrl: '',
|
||||
method: 'DELETE',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.folderId)}?${queryParams.toString()}`
|
||||
|
||||
await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'DELETE',
|
||||
params
|
||||
})
|
||||
return `Folder deleted successfully`
|
||||
} catch (error) {
|
||||
return `Error deleting folder: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetPermissionsTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'get_permissions',
|
||||
description: 'Get permissions for a file in Google Drive',
|
||||
schema: z.object({
|
||||
fileId: z.string().describe('File ID to get permissions for'),
|
||||
supportsAllDrives: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
}),
|
||||
baseUrl: '',
|
||||
method: 'GET',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}/permissions?${queryParams.toString()}`
|
||||
|
||||
const response = await this.makeGoogleDriveRequest({ endpoint, params })
|
||||
return response
|
||||
} catch (error) {
|
||||
return `Error getting permissions: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemovePermissionTool extends BaseGoogleDriveTool {
|
||||
defaultParams: any
|
||||
|
||||
constructor(args: any) {
|
||||
const toolInput = {
|
||||
name: 'remove_permission',
|
||||
description: 'Remove a permission from a file in Google Drive',
|
||||
schema: z.object({
|
||||
fileId: z.string().describe('File ID to remove permission from'),
|
||||
permissionId: z.string().describe('Permission ID to remove'),
|
||||
supportsAllDrives: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the requesting application supports both My Drives and shared drives')
|
||||
}),
|
||||
baseUrl: '',
|
||||
method: 'DELETE',
|
||||
headers: {}
|
||||
}
|
||||
super({
|
||||
...toolInput,
|
||||
accessToken: args.accessToken
|
||||
})
|
||||
this.defaultParams = args.defaultParams || {}
|
||||
}
|
||||
|
||||
async _call(arg: any): Promise<string> {
|
||||
const params = { ...arg, ...this.defaultParams }
|
||||
|
||||
try {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.supportsAllDrives) queryParams.append('supportsAllDrives', params.supportsAllDrives.toString())
|
||||
|
||||
const endpoint = `files/${encodeURIComponent(params.fileId)}/permissions/${encodeURIComponent(
|
||||
params.permissionId
|
||||
)}?${queryParams.toString()}`
|
||||
|
||||
await this.makeGoogleDriveRequest({
|
||||
endpoint,
|
||||
method: 'DELETE',
|
||||
params
|
||||
})
|
||||
return `Permission removed successfully`
|
||||
} catch (error) {
|
||||
return `Error removing permission: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createGoogleDriveTools = (args?: RequestParameters): DynamicStructuredTool[] => {
|
||||
const tools: DynamicStructuredTool[] = []
|
||||
const actions = args?.actions || []
|
||||
const accessToken = args?.accessToken || ''
|
||||
const defaultParams = args?.defaultParams || {}
|
||||
|
||||
if (actions.includes('listFiles')) {
|
||||
tools.push(new ListFilesTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('getFile')) {
|
||||
tools.push(new GetFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('createFile')) {
|
||||
tools.push(new CreateFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('updateFile')) {
|
||||
tools.push(new UpdateFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('deleteFile')) {
|
||||
tools.push(new DeleteFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('copyFile')) {
|
||||
tools.push(new CopyFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('downloadFile')) {
|
||||
tools.push(new DownloadFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('createFolder')) {
|
||||
tools.push(new CreateFolderTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('listFolderContents')) {
|
||||
tools.push(new ListFolderContentsTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('deleteFolder')) {
|
||||
tools.push(new DeleteFolderTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('searchFiles')) {
|
||||
tools.push(new SearchFilesTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('shareFile')) {
|
||||
tools.push(new ShareFileTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('getPermissions')) {
|
||||
tools.push(new GetPermissionsTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
if (actions.includes('removePermission')) {
|
||||
tools.push(new RemovePermissionTool({ accessToken, defaultParams }))
|
||||
}
|
||||
|
||||
return tools
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#1e88e5" d="M38.59,39c-0.535,0.93-0.298,1.68-1.195,2.197C36.498,41.715,35.465,42,34.39,42H13.61 c-1.074,0-2.106-0.285-3.004-0.802C9.708,40.681,9.945,39.93,9.41,39l7.67-9h13.84L38.59,39z"/><path fill="#fbc02d" d="M27.463,6.999c1.073-0.002,2.104-0.716,3.001-0.198c0.897,0.519,1.66,1.27,2.197,2.201l10.39,17.996 c0.537,0.93,0.807,1.967,0.808,3.002c0.001,1.037-1.267,2.073-1.806,3.001l-11.127-3.005l-6.924-11.993L27.463,6.999z"/><path fill="#e53935" d="M43.86,30c0,1.04-0.27,2.07-0.81,3l-3.67,6.35c-0.53,0.78-1.21,1.4-1.99,1.85L30.92,30H43.86z"/><path fill="#4caf50" d="M5.947,33.001c-0.538-0.928-1.806-1.964-1.806-3c0.001-1.036,0.27-2.073,0.808-3.004l10.39-17.996 c0.537-0.93,1.3-1.682,2.196-2.2c0.897-0.519,1.929,0.195,3.002,0.197l3.459,11.009l-6.922,11.989L5.947,33.001z"/><path fill="#1565c0" d="M17.08,30l-6.47,11.2c-0.78-0.45-1.46-1.07-1.99-1.85L4.95,33c-0.54-0.93-0.81-1.96-0.81-3H17.08z"/><path fill="#2e7d32" d="M30.46,6.8L24,18L17.53,6.8c0.78-0.45,1.66-0.73,2.6-0.79L27.46,6C28.54,6,29.57,6.28,30.46,6.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user