",
+ "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 @@
+
+
+
+
+
+
+
+ AI agent stdlib that works with any LLM and TypeScript AI SDK.
+
+
+
+
+
+
+
+
+
+# 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. |