diff --git a/docs/mint.json b/docs/mint.json index 6b8e000..e91754c 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -71,6 +71,7 @@ "tools/hacker-news", "tools/gravatar", "tools/google-custom-search", + "tools/google-drive", "tools/hunter", "tools/jina", "tools/leadmagic", diff --git a/docs/tools/google-drive.mdx b/docs/tools/google-drive.mdx new file mode 100644 index 0000000..deeaff5 --- /dev/null +++ b/docs/tools/google-drive.mdx @@ -0,0 +1,47 @@ +--- +title: Google Drive +description: Simplified Google Drive API. +--- + +- package: `@agentic/google-drive` +- exports: `class GoogleDriveClient`, `namespace googleDrive` +- [source](https://github.com/transitive-bullshit/agentic/blob/main/packages/google-drive/src/google-drive-client.ts) +- [google drive docs](https://developers.google.com/workspace/drive/api) + +## Install + + +```bash npm +npm install @agentic/google-drive google-auth-library googleapis +``` + +```bash yarn +yarn add @agentic/google-drive google-auth-library googleapis +``` + +```bash pnpm +pnpm add @agentic/google-drive google-auth-library googleapis +``` + + + +## Example Usage + +```ts +import { GoogleDriveClient } from '@agentic/google-drive' +import { GoogleAuth } from 'google-auth-library' +import { google } from 'googleapis' + +const auth = new GoogleAuth({ scopes: 'https://www.googleapis.com/auth/drive' }) +const drive = google.drive({ version: 'v3', auth }) +const client = new GoogleDriveClient({ drive }) + +const result = await googleDrive.listFiles() + +const file = result.files[0]! +const metadata = await googleDrive.getFile({ fileId: file.id }) +const content = await googleDrive.exportFile({ + fileId: file.id, + mimeType: 'application/pdf' +}) +``` diff --git a/packages/airtable/package.json b/packages/airtable/package.json index d859b89..43e511d 100644 --- a/packages/airtable/package.json +++ b/packages/airtable/package.json @@ -33,8 +33,7 @@ }, "dependencies": { "@agentic/core": "workspace:*", - "ky": "catalog:", - "p-throttle": "catalog:" + "ky": "catalog:" }, "peerDependencies": { "zod": "catalog:" diff --git a/packages/google-drive/package.json b/packages/google-drive/package.json new file mode 100644 index 0000000..b3f98ba --- /dev/null +++ b/packages/google-drive/package.json @@ -0,0 +1,49 @@ +{ + "name": "@agentic/google-drive", + "version": "7.6.3", + "description": "Agentic SDK for Google Drive.", + "author": "Travis Fischer ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/transitive-bullshit/agentic.git", + "directory": "packages/google-drive" + }, + "type": "module", + "source": "./src/index.ts", + "types": "./dist/index.d.ts", + "sideEffects": false, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "clean": "del dist", + "test": "run-s test:*", + "test:lint": "eslint .", + "test:typecheck": "tsc --noEmit" + }, + "dependencies": { + "@agentic/core": "workspace:*" + }, + "devDependencies": { + "google-auth-library": "catalog:", + "googleapis": "catalog:" + }, + "peerDependencies": { + "google-auth-library": "catalog:", + "googleapis": "catalog:", + "zod": "catalog:" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/google-drive/readme.md b/packages/google-drive/readme.md new file mode 100644 index 0000000..38781f3 --- /dev/null +++ b/packages/google-drive/readme.md @@ -0,0 +1,24 @@ +

+ + Agentic + +

+ +

+ AI agent stdlib that works with any LLM and TypeScript AI SDK. +

+ +

+ Build Status + NPM + MIT License + Prettier Code Formatting +

+ +# Agentic + +**See the [github repo](https://github.com/transitive-bullshit/agentic) or [docs](https://agentic.so) for more info.** + +## License + +MIT © [Travis Fischer](https://x.com/transitive_bs) diff --git a/packages/google-drive/src/google-drive-client.ts b/packages/google-drive/src/google-drive-client.ts new file mode 100644 index 0000000..7f32264 --- /dev/null +++ b/packages/google-drive/src/google-drive-client.ts @@ -0,0 +1,156 @@ +import type * as google from 'googleapis' +import { + aiFunction, + AIFunctionsProvider, + pick, + pruneNullOrUndefinedDeep +} from '@agentic/core' +import { z } from 'zod' + +export namespace googleDrive { + export interface File { + id?: string + name: string + mimeType: string + webViewLink?: string + webContentLink?: string + size?: string + createdTime?: string + modifiedTime?: string + parents?: string[] + } + + export const fileFields: (keyof File)[] = [ + 'id', + 'name', + 'mimeType', + 'webViewLink', + 'webContentLink', + 'size', + 'createdTime', + 'modifiedTime', + 'parents' + ] + + export interface ListFilesResponse { + files: File[] + nextPageToken?: string + } + + export interface DownloadResponse { + content: string + metadata: File + } + + export const ListFilesParamsSchema = z.object({ + folderId: z.string().optional(), + query: z.string().optional(), + pageSize: z.number().optional(), + pageToken: z.string().optional() + }) +} + +/** + * Simplified Drive API client. + * + * @see https://developers.google.com/workspace/drive/api + * + * @example + * ```ts + * import { GoogleAuth } from 'google-auth-library' + * import { google } from 'googleapis' + * + * const auth = new GoogleAuth({ scopes: 'https://www.googleapis.com/auth/drive' }) + * const drive = google.drive({ version: 'v3', auth }) + * const client = new GoogleDriveClient({ drive }) + * ``` + */ +export class GoogleDriveClient extends AIFunctionsProvider { + protected readonly drive: google.drive_v3.Drive + + constructor({ drive }: { drive: google.drive_v3.Drive }) { + super() + + this.drive = drive + } + + /** + * Lists files and folders in a Google Drive folder. + */ + @aiFunction({ + name: 'google_drive_list_files', + description: 'Lists files and folders in a Google Drive folder.', + inputSchema: googleDrive.ListFilesParamsSchema + }) + async listFiles( + args: { + folderId?: string + query?: string + } & google.drive_v3.Params$Resource$Files$Get + ): Promise { + const { folderId, query, ...opts } = args + // Build the query conditions + const conditions = ['trashed = false'] // Always exclude trashed files + + if (folderId) { + conditions.push(`'${folderId}' in parents`) + } + + if (query) { + conditions.push(`name contains '${query}'`) + } + + // Combine all conditions with AND + const q = conditions.join(' and ') + + const { data } = await this.drive.files.list({ + ...opts, + q + }) + const files = (data.files ?? []).map((file) => + pick(file, ...googleDrive.fileFields) + ) + + return pruneNullOrUndefinedDeep({ + files, + nextPageToken: data.nextPageToken + }) as any + } + + /** + * Gets a file's metadata from Google Drive. + */ + @aiFunction({ + name: 'google_drive_get_file', + description: "Gets a file's metadata from Google Drive.", + inputSchema: z.object({ fileId: z.string() }) + }) + async getFile( + opts: google.drive_v3.Params$Resource$Files$Get + ): Promise { + const { data } = await this.drive.files.get(opts) + + return pruneNullOrUndefinedDeep( + pick(data, ...googleDrive.fileFields) + ) as any + } + + /** + * Exports a file from Google Drive. + */ + @aiFunction({ + name: 'google_drive_export_file', + description: 'Exports a file from Google Drive to a given mime-type.', + inputSchema: z.object({ + fileId: z.string().describe('The ID of the file to export.'), + mimeType: z + .string() + .describe('The MIME type of the format requested for this export.') + }) + }) + async exportFile( + opts: google.drive_v3.Params$Resource$Files$Export + ): Promise { + return this.drive.files.export(opts) + } +} diff --git a/packages/google-drive/src/index.ts b/packages/google-drive/src/index.ts new file mode 100644 index 0000000..8666b9b --- /dev/null +++ b/packages/google-drive/src/index.ts @@ -0,0 +1 @@ +export * from './google-drive-client' diff --git a/packages/google-drive/tsconfig.json b/packages/google-drive/tsconfig.json new file mode 100644 index 0000000..51348fa --- /dev/null +++ b/packages/google-drive/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@fisch0920/config/tsconfig-node", + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/reddit/package.json b/packages/reddit/package.json index f9a1c43..c8048e7 100644 --- a/packages/reddit/package.json +++ b/packages/reddit/package.json @@ -33,8 +33,7 @@ }, "dependencies": { "@agentic/core": "workspace:*", - "ky": "catalog:", - "p-throttle": "catalog:" + "ky": "catalog:" }, "peerDependencies": { "zod": "catalog:" diff --git a/packages/stdlib/package.json b/packages/stdlib/package.json index 1845707..bdefaaf 100644 --- a/packages/stdlib/package.json +++ b/packages/stdlib/package.json @@ -48,6 +48,7 @@ "@agentic/firecrawl": "workspace:*", "@agentic/github": "workspace:*", "@agentic/google-custom-search": "workspace:*", + "@agentic/google-drive": "workspace:*", "@agentic/gravatar": "workspace:*", "@agentic/hacker-news": "workspace:*", "@agentic/hunter": "workspace:*", diff --git a/packages/stdlib/src/index.ts b/packages/stdlib/src/index.ts index b8cd4e0..e1d4966 100644 --- a/packages/stdlib/src/index.ts +++ b/packages/stdlib/src/index.ts @@ -13,6 +13,7 @@ export * from '@agentic/exa' export * from '@agentic/firecrawl' export * from '@agentic/github' export * from '@agentic/google-custom-search' +export * from '@agentic/google-drive' export * from '@agentic/gravatar' export * from '@agentic/hacker-news' export * from '@agentic/hunter' diff --git a/packages/typeform/package.json b/packages/typeform/package.json index 8046e3c..6a9daf3 100644 --- a/packages/typeform/package.json +++ b/packages/typeform/package.json @@ -33,8 +33,7 @@ }, "dependencies": { "@agentic/core": "workspace:*", - "ky": "catalog:", - "p-throttle": "catalog:" + "ky": "catalog:" }, "peerDependencies": { "zod": "catalog:" diff --git a/packages/youtube/package.json b/packages/youtube/package.json index 19ae810..6c754c9 100644 --- a/packages/youtube/package.json +++ b/packages/youtube/package.json @@ -33,8 +33,7 @@ }, "dependencies": { "@agentic/core": "workspace:*", - "ky": "catalog:", - "p-throttle": "catalog:" + "ky": "catalog:" }, "peerDependencies": { "zod": "catalog:" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 564394b..b7c1557 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,6 +96,12 @@ catalogs: genkitx-openai: specifier: ^0.20.2 version: 0.20.2 + google-auth-library: + specifier: ^9.15.1 + version: 9.15.1 + googleapis: + specifier: ^148.0.0 + version: 148.0.0 json-schema-to-zod: specifier: ^2.6.1 version: 2.6.1 @@ -453,9 +459,6 @@ importers: ky: specifier: 'catalog:' version: 1.8.0 - p-throttle: - specifier: 'catalog:' - version: 6.2.0 zod: specifier: 'catalog:' version: 3.24.2 @@ -699,11 +702,27 @@ importers: version: link:../core '@googleapis/customsearch': specifier: 'catalog:' - version: 3.2.0(encoding@0.1.13) + version: 3.2.0 zod: specifier: 'catalog:' version: 3.24.2 + packages/google-drive: + dependencies: + '@agentic/core': + specifier: workspace:* + version: link:../core + zod: + specifier: 'catalog:' + version: 3.24.2 + devDependencies: + google-auth-library: + specifier: 'catalog:' + version: 9.15.1(encoding@0.1.13) + googleapis: + specifier: 'catalog:' + version: 148.0.0(encoding@0.1.13) + packages/gravatar: dependencies: '@agentic/core': @@ -999,9 +1018,6 @@ importers: ky: specifier: 'catalog:' version: 1.8.0 - p-throttle: - specifier: 'catalog:' - version: 6.2.0 zod: specifier: 'catalog:' version: 3.24.2 @@ -1134,6 +1150,9 @@ importers: '@agentic/google-custom-search': specifier: workspace:* version: link:../google-custom-search + '@agentic/google-drive': + specifier: workspace:* + version: link:../google-drive '@agentic/gravatar': specifier: workspace:* version: link:../gravatar @@ -1296,9 +1315,6 @@ importers: ky: specifier: 'catalog:' version: 1.8.0 - p-throttle: - specifier: 'catalog:' - version: 6.2.0 zod: specifier: 'catalog:' version: 3.24.2 @@ -1378,9 +1394,6 @@ importers: ky: specifier: 'catalog:' version: 1.8.0 - p-throttle: - specifier: 'catalog:' - version: 6.2.0 zod: specifier: 'catalog:' version: 3.24.2 @@ -4578,6 +4591,10 @@ packages: resolution: {integrity: sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==} engines: {node: '>=14.0.0'} + googleapis@148.0.0: + resolution: {integrity: sha512-8PDG5VItm6E1TdZWDqtRrUJSlBcNwz0/MwCa6AL81y/RxPGXJRUwKqGZfCoVX1ZBbfr3I4NkDxBmeTyOAZSWqw==} + engines: {node: '>=14.0.0'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -5045,10 +5062,6 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - ky@1.7.5: - resolution: {integrity: sha512-HzhziW6sc5m0pwi5M196+7cEBtbt0lCYi67wNsiwMUmz833wloE0gbzJPWKs1gliFKQb34huItDQX97LyOdPdA==} - engines: {node: '>=18'} - ky@1.8.0: resolution: {integrity: sha512-DoKGmG27nT8t/1F9gV8vNzggJ3mLAyD49J8tTMWHeZvS8qLc7GlyTieicYtFzvDznMe/q2u38peOjkWc5/pjvw==} engines: {node: '>=18'} @@ -7440,7 +7453,7 @@ snapshots: dedent: 1.5.3 hash-object: 5.0.1 jsonrepair: 3.12.0 - ky: 1.7.5 + ky: 1.8.0 openai-fetch: 3.4.2 openai-zod-to-json-schema: 1.0.3(zod@3.24.2) p-map: 7.0.3 @@ -7657,7 +7670,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@googleapis/customsearch@3.2.0(encoding@0.1.13)': + '@googleapis/customsearch@3.2.0': dependencies: googleapis-common: 7.2.0(encoding@0.1.13) transitivePeerDependencies: @@ -11161,6 +11174,14 @@ snapshots: - encoding - supports-color + googleapis@148.0.0(encoding@0.1.13): + dependencies: + google-auth-library: 9.15.1(encoding@0.1.13) + googleapis-common: 7.2.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + - supports-color + gopd@1.2.0: {} gpt-tokenizer@2.8.1: @@ -11565,8 +11586,6 @@ snapshots: dependencies: json-buffer: 3.0.1 - ky@1.7.5: {} - ky@1.8.0: {} langchain@0.3.21(@langchain/core@0.3.44(openai@4.93.0(encoding@0.1.13)(ws@8.18.0)(zod@3.24.2)))(axios@1.7.9)(encoding@0.1.13)(handlebars@4.7.8)(openai@4.93.0(encoding@0.1.13)(ws@8.18.0)(zod@3.24.2))(ws@8.18.0): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 43689bc..72c0464 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,19 +6,20 @@ updateConfig: - p-throttle - eslint catalog: - '@ai-sdk/openai': ^1.3.9 - '@apidevtools/swagger-parser': ^10.1.1 - '@dexaai/dexter': ^4.1.1 - '@e2b/code-interpreter': ^1.1.0 - '@fisch0920/config': ^1.0.2 - '@langchain/core': ^0.3.44 - '@langchain/openai': ^0.5.5 - '@mastra/core': ^0.8.1 - '@modelcontextprotocol/sdk': ^1.9.0 - '@nangohq/node': 0.42.22 # pinned for now - '@types/jsrsasign': ^10.5.15 - '@types/node': ^22.14.0 - '@xsai/tool': ^0.2.0-beta.3 + "@ai-sdk/openai": ^1.3.9 + "@apidevtools/swagger-parser": ^10.1.1 + "@dexaai/dexter": ^4.1.1 + "@e2b/code-interpreter": ^1.1.0 + "@fisch0920/config": ^1.0.2 + "@googleapis/customsearch": ^3.2.0 + "@langchain/core": ^0.3.44 + "@langchain/openai": ^0.5.5 + "@mastra/core": ^0.8.1 + "@modelcontextprotocol/sdk": ^1.9.0 + "@nangohq/node": 0.42.22 + "@types/jsrsasign": ^10.5.15 + "@types/node": ^22.14.0 + "@xsai/tool": ^0.2.0-beta.3 ai: ^4.3.4 bumpp: ^10.1.0 camelcase: ^8.0.0 @@ -35,7 +36,8 @@ catalog: fast-xml-parser: ^5.2.0 genkit: ^1.6.0 genkitx-openai: ^0.20.2 - '@googleapis/customsearch': ^3.2.0 + google-auth-library: ^9.15.1 + googleapis: ^148.0.0 json-schema-to-zod: ^2.6.1 jsonrepair: ^3.12.0 jsrsasign: ^10.9.0 @@ -52,7 +54,7 @@ catalog: openai-zod-to-json-schema: ^1.0.3 openapi-types: ^12.1.3 p-map: ^7.0.3 - p-throttle: 6.2.0 # pinned for now + p-throttle: 6.2.0 prettier: ^3.5.3 restore-cursor: ^5.1.0 simple-git-hooks: ^2.12.1 diff --git a/readme.md b/readme.md index f174195..ea2d2db 100644 --- a/readme.md +++ b/readme.md @@ -194,6 +194,7 @@ Full docs are available at [agentic.so](https://agentic.so). | [Exa](https://docs.exa.ai) | `@agentic/exa` | [docs](https://agentic.so/tools/exa) | Web search tailored for LLMs. | | [Firecrawl](https://www.firecrawl.dev) | `@agentic/firecrawl` | [docs](https://agentic.so/tools/firecrawl) | Website scraping and structured data extraction. | | [Google Custom Search](https://developers.google.com/custom-search/v1/overview) | `@agentic/google-custom-search` | [docs](https://agentic.so/tools/google-custom-search) | Official Google Custom Search API. | +| [Google Drive](https://developers.google.com/workspace/drive/api) | `@agentic/google-drive` | [docs](https://agentic.so/tools/google-drive) | Simplified Google Drive API. | | [Gravatar](https://docs.gravatar.com/api/profiles/rest-api/) | `@agentic/gravatar` | [docs](https://agentic.so/tools/gravatar) | Gravatar profile API. | | [HackerNews](https://github.com/HackerNews/API) | `@agentic/hacker-news` | [docs](https://agentic.so/tools/hacker-news) | Official HackerNews API. | | [Hunter](https://hunter.io) | `@agentic/hunter` | [docs](https://agentic.so/tools/hunter) | Email finder, verifier, and enrichment. |