|
| 1 | +import { createLogger } from '@sim/logger' |
1 | 2 | import type { GoogleDriveToolParams, GoogleDriveUploadResponse } from '@/tools/google_drive/types' |
2 | 3 | import type { ToolConfig } from '@/tools/types' |
3 | 4 |
|
| 5 | +const logger = createLogger('GoogleDriveCreateFolderTool') |
| 6 | + |
| 7 | +// All available file metadata fields from Google Drive API v3 |
| 8 | +const ALL_FILE_FIELDS = [ |
| 9 | + // Basic Info |
| 10 | + 'id', |
| 11 | + 'name', |
| 12 | + 'mimeType', |
| 13 | + 'kind', |
| 14 | + 'description', |
| 15 | + 'originalFilename', |
| 16 | + 'fullFileExtension', |
| 17 | + 'fileExtension', |
| 18 | + // Ownership & Sharing |
| 19 | + 'owners', |
| 20 | + 'permissions', |
| 21 | + 'permissionIds', |
| 22 | + 'shared', |
| 23 | + 'ownedByMe', |
| 24 | + 'writersCanShare', |
| 25 | + 'viewersCanCopyContent', |
| 26 | + 'copyRequiresWriterPermission', |
| 27 | + 'sharingUser', |
| 28 | + // Labels/Tags |
| 29 | + 'starred', |
| 30 | + 'trashed', |
| 31 | + 'explicitlyTrashed', |
| 32 | + 'properties', |
| 33 | + 'appProperties', |
| 34 | + 'folderColorRgb', |
| 35 | + // Timestamps |
| 36 | + 'createdTime', |
| 37 | + 'modifiedTime', |
| 38 | + 'modifiedByMeTime', |
| 39 | + 'viewedByMeTime', |
| 40 | + 'sharedWithMeTime', |
| 41 | + 'trashedTime', |
| 42 | + // User Info |
| 43 | + 'lastModifyingUser', |
| 44 | + 'trashingUser', |
| 45 | + 'viewedByMe', |
| 46 | + 'modifiedByMe', |
| 47 | + // Links |
| 48 | + 'webViewLink', |
| 49 | + 'webContentLink', |
| 50 | + 'iconLink', |
| 51 | + 'thumbnailLink', |
| 52 | + 'exportLinks', |
| 53 | + // Size & Storage |
| 54 | + 'size', |
| 55 | + 'quotaBytesUsed', |
| 56 | + // Checksums |
| 57 | + 'md5Checksum', |
| 58 | + 'sha1Checksum', |
| 59 | + 'sha256Checksum', |
| 60 | + // Hierarchy & Location |
| 61 | + 'parents', |
| 62 | + 'spaces', |
| 63 | + 'driveId', |
| 64 | + 'teamDriveId', |
| 65 | + // Capabilities |
| 66 | + 'capabilities', |
| 67 | + // Versions |
| 68 | + 'version', |
| 69 | + 'headRevisionId', |
| 70 | + // Media Metadata |
| 71 | + 'hasThumbnail', |
| 72 | + 'thumbnailVersion', |
| 73 | + 'imageMediaMetadata', |
| 74 | + 'videoMediaMetadata', |
| 75 | + 'contentHints', |
| 76 | + // Other |
| 77 | + 'isAppAuthorized', |
| 78 | + 'contentRestrictions', |
| 79 | + 'resourceKey', |
| 80 | + 'shortcutDetails', |
| 81 | + 'linkShareMetadata', |
| 82 | +].join(',') |
| 83 | + |
4 | 84 | export const createFolderTool: ToolConfig<GoogleDriveToolParams, GoogleDriveUploadResponse> = { |
5 | 85 | id: 'google_drive_create_folder', |
6 | 86 | name: 'Create Folder in Google Drive', |
7 | | - description: 'Create a new folder in Google Drive', |
| 87 | + description: 'Create a new folder in Google Drive with complete metadata returned', |
8 | 88 | version: '1.0', |
9 | 89 |
|
10 | 90 | oauth: { |
@@ -66,45 +146,119 @@ export const createFolderTool: ToolConfig<GoogleDriveToolParams, GoogleDriveUplo |
66 | 146 | }, |
67 | 147 | }, |
68 | 148 |
|
69 | | - transformResponse: async (response: Response) => { |
| 149 | + transformResponse: async (response: Response, params?: GoogleDriveToolParams) => { |
70 | 150 | if (!response.ok) { |
71 | 151 | const data = await response.json().catch(() => ({})) |
| 152 | + logger.error('Failed to create folder in Google Drive', { |
| 153 | + status: response.status, |
| 154 | + statusText: response.statusText, |
| 155 | + error: data, |
| 156 | + }) |
72 | 157 | throw new Error(data.error?.message || 'Failed to create folder in Google Drive') |
73 | 158 | } |
| 159 | + |
74 | 160 | const data = await response.json() |
| 161 | + const folderId = data.id |
| 162 | + const authHeader = `Bearer ${params?.accessToken || ''}` |
| 163 | + |
| 164 | + // Fetch complete folder metadata with all fields |
| 165 | + const metadataResponse = await fetch( |
| 166 | + `https://www.googleapis.com/drive/v3/files/${folderId}?supportsAllDrives=true&fields=${ALL_FILE_FIELDS}`, |
| 167 | + { |
| 168 | + headers: { |
| 169 | + Authorization: authHeader, |
| 170 | + }, |
| 171 | + } |
| 172 | + ) |
| 173 | + |
| 174 | + if (!metadataResponse.ok) { |
| 175 | + logger.warn('Failed to fetch complete metadata, returning basic response', { |
| 176 | + status: metadataResponse.status, |
| 177 | + statusText: metadataResponse.statusText, |
| 178 | + }) |
| 179 | + // Return basic response if metadata fetch fails |
| 180 | + return { |
| 181 | + success: true, |
| 182 | + output: { |
| 183 | + file: data, |
| 184 | + }, |
| 185 | + } |
| 186 | + } |
| 187 | + |
| 188 | + const fullMetadata = await metadataResponse.json() |
| 189 | + |
| 190 | + logger.info('Folder created successfully', { |
| 191 | + folderId: fullMetadata.id, |
| 192 | + name: fullMetadata.name, |
| 193 | + mimeType: fullMetadata.mimeType, |
| 194 | + hasOwners: !!fullMetadata.owners?.length, |
| 195 | + hasPermissions: !!fullMetadata.permissions?.length, |
| 196 | + }) |
75 | 197 |
|
76 | 198 | return { |
77 | 199 | success: true, |
78 | 200 | output: { |
79 | | - file: { |
80 | | - id: data.id, |
81 | | - name: data.name, |
82 | | - mimeType: data.mimeType, |
83 | | - webViewLink: data.webViewLink, |
84 | | - webContentLink: data.webContentLink, |
85 | | - size: data.size, |
86 | | - createdTime: data.createdTime, |
87 | | - modifiedTime: data.modifiedTime, |
88 | | - parents: data.parents, |
89 | | - }, |
| 201 | + file: fullMetadata, |
90 | 202 | }, |
91 | 203 | } |
92 | 204 | }, |
93 | 205 |
|
94 | 206 | outputs: { |
95 | 207 | file: { |
96 | 208 | type: 'object', |
97 | | - description: 'Created folder metadata from Google Drive', |
| 209 | + description: 'Complete created folder metadata from Google Drive', |
98 | 210 | properties: { |
| 211 | + // Basic Info |
99 | 212 | id: { type: 'string', description: 'Google Drive folder ID' }, |
100 | 213 | name: { type: 'string', description: 'Folder name' }, |
101 | 214 | mimeType: { type: 'string', description: 'MIME type (application/vnd.google-apps.folder)' }, |
102 | | - webViewLink: { type: 'string', description: 'URL to view in browser' }, |
103 | | - webContentLink: { type: 'string', description: 'Direct download URL' }, |
104 | | - size: { type: 'string', description: 'Size in bytes' }, |
105 | | - createdTime: { type: 'string', description: 'Creation time' }, |
| 215 | + kind: { type: 'string', description: 'Resource type identifier' }, |
| 216 | + description: { type: 'string', description: 'Folder description' }, |
| 217 | + // Ownership & Sharing |
| 218 | + owners: { type: 'json', description: 'List of folder owners' }, |
| 219 | + permissions: { type: 'json', description: 'Folder permissions' }, |
| 220 | + permissionIds: { type: 'json', description: 'Permission IDs' }, |
| 221 | + shared: { type: 'boolean', description: 'Whether folder is shared' }, |
| 222 | + ownedByMe: { type: 'boolean', description: 'Whether owned by current user' }, |
| 223 | + writersCanShare: { type: 'boolean', description: 'Whether writers can share' }, |
| 224 | + viewersCanCopyContent: { type: 'boolean', description: 'Whether viewers can copy' }, |
| 225 | + copyRequiresWriterPermission: { |
| 226 | + type: 'boolean', |
| 227 | + description: 'Whether copy requires writer permission', |
| 228 | + }, |
| 229 | + sharingUser: { type: 'json', description: 'User who shared the folder' }, |
| 230 | + // Labels/Tags |
| 231 | + starred: { type: 'boolean', description: 'Whether folder is starred' }, |
| 232 | + trashed: { type: 'boolean', description: 'Whether folder is in trash' }, |
| 233 | + explicitlyTrashed: { type: 'boolean', description: 'Whether explicitly trashed' }, |
| 234 | + properties: { type: 'json', description: 'Custom properties' }, |
| 235 | + appProperties: { type: 'json', description: 'App-specific properties' }, |
| 236 | + folderColorRgb: { type: 'string', description: 'Folder color' }, |
| 237 | + // Timestamps |
| 238 | + createdTime: { type: 'string', description: 'Folder creation time' }, |
106 | 239 | modifiedTime: { type: 'string', description: 'Last modification time' }, |
| 240 | + modifiedByMeTime: { type: 'string', description: 'When modified by current user' }, |
| 241 | + viewedByMeTime: { type: 'string', description: 'When last viewed by current user' }, |
| 242 | + sharedWithMeTime: { type: 'string', description: 'When shared with current user' }, |
| 243 | + // User Info |
| 244 | + lastModifyingUser: { type: 'json', description: 'User who last modified the folder' }, |
| 245 | + viewedByMe: { type: 'boolean', description: 'Whether viewed by current user' }, |
| 246 | + modifiedByMe: { type: 'boolean', description: 'Whether modified by current user' }, |
| 247 | + // Links |
| 248 | + webViewLink: { type: 'string', description: 'URL to view in browser' }, |
| 249 | + iconLink: { type: 'string', description: 'URL to folder icon' }, |
| 250 | + // Hierarchy & Location |
107 | 251 | parents: { type: 'json', description: 'Parent folder IDs' }, |
| 252 | + spaces: { type: 'json', description: 'Spaces containing folder' }, |
| 253 | + driveId: { type: 'string', description: 'Shared drive ID' }, |
| 254 | + // Capabilities |
| 255 | + capabilities: { type: 'json', description: 'User capabilities on folder' }, |
| 256 | + // Versions |
| 257 | + version: { type: 'string', description: 'Version number' }, |
| 258 | + // Other |
| 259 | + isAppAuthorized: { type: 'boolean', description: 'Whether created by requesting app' }, |
| 260 | + contentRestrictions: { type: 'json', description: 'Content restrictions' }, |
| 261 | + linkShareMetadata: { type: 'json', description: 'Link share metadata' }, |
108 | 262 | }, |
109 | 263 | }, |
110 | 264 | }, |
|
0 commit comments