From b63a8464f787aeedc72f78444ebab2e8d62ff6a9 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Thu, 10 Apr 2025 19:01:07 +0700 Subject: [PATCH] feat: add @agentic/google-docs Google Docs client --- docs/mint.json | 1 + docs/tools/google-docs.mdx | 45 +++++++++++ docs/tools/google-drive.mdx | 12 +-- packages/google-docs/package.json | 48 ++++++++++++ packages/google-docs/readme.md | 24 ++++++ .../google-docs/src/google-docs-client.ts | 76 +++++++++++++++++++ packages/google-docs/src/index.ts | 1 + packages/google-docs/tsconfig.json | 5 ++ packages/google-drive/package.json | 5 +- .../google-drive/src/google-drive-client.ts | 30 +++++--- packages/stdlib/package.json | 1 + packages/stdlib/src/index.ts | 1 + pnpm-lock.yaml | 46 ++++++----- readme.md | 1 + 14 files changed, 257 insertions(+), 39 deletions(-) create mode 100644 docs/tools/google-docs.mdx create mode 100644 packages/google-docs/package.json create mode 100644 packages/google-docs/readme.md create mode 100644 packages/google-docs/src/google-docs-client.ts create mode 100644 packages/google-docs/src/index.ts create mode 100644 packages/google-docs/tsconfig.json diff --git a/docs/mint.json b/docs/mint.json index e91754c5..3b859963 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -71,6 +71,7 @@ "tools/hacker-news", "tools/gravatar", "tools/google-custom-search", + "tools/google-docs", "tools/google-drive", "tools/hunter", "tools/jina", diff --git a/docs/tools/google-docs.mdx b/docs/tools/google-docs.mdx new file mode 100644 index 00000000..6c773d13 --- /dev/null +++ b/docs/tools/google-docs.mdx @@ -0,0 +1,45 @@ +--- +title: Google Docs +description: Simplified Google Docs API. +--- + +- package: `@agentic/google-docs` +- exports: `class GoogleDocsClient`, `namespace googleDocs` +- [source](https://github.com/transitive-bullshit/agentic/blob/main/packages/google-docs/src/google-docs-client.ts) +- [google docs docs](https://developers.google.com/workspace/docs/api) + +## Install + + +```bash npm +npm install @agentic/google-docs googleapis @google-cloud/local-auth +``` + +```bash yarn +yarn add @agentic/google-docs googleapis @google-cloud/local-auth +``` + +```bash pnpm +pnpm add @agentic/google-docs googleapis @google-cloud/local-auth +``` + + + +## Example Usage + +```ts +import { GoogleDriveClient } from '@agentic/google-drive' +import { authenticate } from '@google-cloud/local-auth' +import { google } from 'googleapis' + +// (in a real app, store these auth credentials and reuse them) +const auth = await authenticate({ + scopes: ['https://www.googleapis.com/auth/documents.readonly'], + keyfilePath: process.env.GOOGLE_CREDENTIALS_PATH +}) +const docs = google.docs({ version: 'v1', auth }) +const client = new GoogleDocsClient({ docs }) + +const document = await client.getDocument({ documentId: 'TODO' }) +console.log(document) +``` diff --git a/docs/tools/google-drive.mdx b/docs/tools/google-drive.mdx index deeaff55..590f1f8d 100644 --- a/docs/tools/google-drive.mdx +++ b/docs/tools/google-drive.mdx @@ -12,15 +12,15 @@ description: Simplified Google Drive API. ```bash npm -npm install @agentic/google-drive google-auth-library googleapis +npm install @agentic/google-drive googleapis google-auth-library ``` ```bash yarn -yarn add @agentic/google-drive google-auth-library googleapis +yarn add @agentic/google-drive googleapis google-auth-library ``` ```bash pnpm -pnpm add @agentic/google-drive google-auth-library googleapis +pnpm add @agentic/google-drive googleapis google-auth-library ``` @@ -36,11 +36,11 @@ 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 result = await client.listFiles() const file = result.files[0]! -const metadata = await googleDrive.getFile({ fileId: file.id }) -const content = await googleDrive.exportFile({ +const metadata = await client.getFile({ fileId: file.id }) +const content = await client.exportFile({ fileId: file.id, mimeType: 'application/pdf' }) diff --git a/packages/google-docs/package.json b/packages/google-docs/package.json new file mode 100644 index 00000000..15fbe256 --- /dev/null +++ b/packages/google-docs/package.json @@ -0,0 +1,48 @@ +{ + "name": "@agentic/google-docs", + "version": "7.6.3", + "description": "Agentic SDK for Google Docs.", + "author": "Travis Fischer ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/transitive-bullshit/agentic.git", + "directory": "packages/google-docs" + }, + "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:*", + "type-fest": "catalog:" + }, + "devDependencies": { + "googleapis": "catalog:" + }, + "peerDependencies": { + "googleapis": "catalog:", + "zod": "catalog:" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/google-docs/readme.md b/packages/google-docs/readme.md new file mode 100644 index 00000000..38781f32 --- /dev/null +++ b/packages/google-docs/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-docs/src/google-docs-client.ts b/packages/google-docs/src/google-docs-client.ts new file mode 100644 index 00000000..3af72036 --- /dev/null +++ b/packages/google-docs/src/google-docs-client.ts @@ -0,0 +1,76 @@ +import type * as google from 'googleapis' +import type { SetNonNullable, Simplify } from 'type-fest' +import { + aiFunction, + AIFunctionsProvider, + pruneNullOrUndefinedDeep, + type SetRequired +} from '@agentic/core' +import { z } from 'zod' + +export namespace googleDocs { + export type Document = Simplify< + SetNonNullable + > +} + +/** + * Simplified Google Docs API client. + * + * @see https://developers.google.com/workspace/drive/api + * + * @example + * ```ts + * import { GoogleDocsClient } from '@agentic/google-docs' + * import { authenticate } from '@google-cloud/local-auth' + * import { google } from 'googleapis' + * + * // (in a real app, store these auth credentials and reuse them) + * const auth = await authenticate({ + * scopes: ['https://www.googleapis.com/auth/documents.readonly'], + * keyfilePath: process.env.GOOGLE_CREDENTIALS_PATH + * }) + * const docs = google.docs({ version: 'v1', auth }) + * const client = new GoogleDocsClient({ docs }) + * ``` + */ +export class GoogleDocsClient extends AIFunctionsProvider { + protected readonly docs: google.docs_v1.Docs + + constructor({ docs }: { docs: google.docs_v1.Docs }) { + super() + + this.docs = docs + } + + /** + * Gets a Google Docs document by ID. + */ + @aiFunction({ + name: 'google_docs_get_document', + description: 'Gets a Google Docs document by ID.', + inputSchema: z.object({ + documentId: z.string() + }) + }) + async getDocument( + args: Simplify< + SetRequired + > + ): Promise { + const { documentId, ...opts } = args + + const { data } = await this.docs.documents.get({ + ...opts, + documentId + }) + + return convertDocument(data) + } +} + +function convertDocument( + data: google.docs_v1.Schema$Document +): googleDocs.Document { + return pruneNullOrUndefinedDeep(data) +} diff --git a/packages/google-docs/src/index.ts b/packages/google-docs/src/index.ts new file mode 100644 index 00000000..71596a9d --- /dev/null +++ b/packages/google-docs/src/index.ts @@ -0,0 +1 @@ +export * from './google-docs-client' diff --git a/packages/google-docs/tsconfig.json b/packages/google-docs/tsconfig.json new file mode 100644 index 00000000..51348fa1 --- /dev/null +++ b/packages/google-docs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@fisch0920/config/tsconfig-node", + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/google-drive/package.json b/packages/google-drive/package.json index b3f98ba0..4faf40b0 100644 --- a/packages/google-drive/package.json +++ b/packages/google-drive/package.json @@ -32,14 +32,13 @@ "test:typecheck": "tsc --noEmit" }, "dependencies": { - "@agentic/core": "workspace:*" + "@agentic/core": "workspace:*", + "type-fest": "catalog:" }, "devDependencies": { - "google-auth-library": "catalog:", "googleapis": "catalog:" }, "peerDependencies": { - "google-auth-library": "catalog:", "googleapis": "catalog:", "zod": "catalog:" }, diff --git a/packages/google-drive/src/google-drive-client.ts b/packages/google-drive/src/google-drive-client.ts index 931f0815..83d75e9d 100644 --- a/packages/google-drive/src/google-drive-client.ts +++ b/packages/google-drive/src/google-drive-client.ts @@ -1,4 +1,5 @@ import type * as google from 'googleapis' +import type { SetNonNullable, Simplify } from 'type-fest' import { aiFunction, AIFunctionsProvider, @@ -9,17 +10,22 @@ import { 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 type File = Simplify< + SetNonNullable< + Pick< + google.drive_v3.Schema$File, + | 'id' + | 'name' + | 'mimeType' + | 'webViewLink' + | 'webContentLink' + | 'size' + | 'createdTime' + | 'modifiedTime' + | 'parents' + > + > + > export const fileFields: readonly (keyof File)[] = [ 'id', @@ -53,7 +59,7 @@ export namespace googleDrive { } /** - * Simplified Drive API client. + * Simplified Google Drive API client. * * @see https://developers.google.com/workspace/drive/api * diff --git a/packages/stdlib/package.json b/packages/stdlib/package.json index bdefaafd..ef3abb46 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-docs": "workspace:*", "@agentic/google-drive": "workspace:*", "@agentic/gravatar": "workspace:*", "@agentic/hacker-news": "workspace:*", diff --git a/packages/stdlib/src/index.ts b/packages/stdlib/src/index.ts index e1d4966a..6e78edc2 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-docs' export * from '@agentic/google-drive' export * from '@agentic/gravatar' export * from '@agentic/hacker-news' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7c15578..0dcd1a35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,9 +96,6 @@ 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 @@ -702,23 +699,39 @@ importers: version: link:../core '@googleapis/customsearch': specifier: 'catalog:' - version: 3.2.0 + version: 3.2.0(encoding@0.1.13) zod: specifier: 'catalog:' version: 3.24.2 + packages/google-docs: + dependencies: + '@agentic/core': + specifier: workspace:* + version: link:../core + type-fest: + specifier: 'catalog:' + version: 4.39.1 + zod: + specifier: 'catalog:' + version: 3.24.2 + devDependencies: + googleapis: + specifier: 'catalog:' + version: 148.0.0(encoding@0.1.13) + packages/google-drive: dependencies: '@agentic/core': specifier: workspace:* version: link:../core + type-fest: + specifier: 'catalog:' + version: 4.39.1 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) @@ -1150,6 +1163,9 @@ importers: '@agentic/google-custom-search': specifier: workspace:* version: link:../google-custom-search + '@agentic/google-docs': + specifier: workspace:* + version: link:../google-docs '@agentic/google-drive': specifier: workspace:* version: link:../google-drive @@ -6502,10 +6518,6 @@ packages: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} - type-fest@4.39.0: - resolution: {integrity: sha512-w2IGJU1tIgcrepg9ZJ82d8UmItNQtOFJG0HCUE3SzMokKkTsruVDALl2fAdiEzJlfduoU+VyXJWIIUZ+6jV+nw==} - engines: {node: '>=16'} - type-fest@4.39.1: resolution: {integrity: sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==} engines: {node: '>=16'} @@ -7670,7 +7682,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@googleapis/customsearch@3.2.0': + '@googleapis/customsearch@3.2.0(encoding@0.1.13)': dependencies: googleapis-common: 7.2.0(encoding@0.1.13) transitivePeerDependencies: @@ -11229,7 +11241,7 @@ snapshots: decircular: 0.1.1 is-obj: 3.0.0 sort-keys: 5.1.0 - type-fest: 4.39.0 + type-fest: 4.39.1 hasown@2.0.2: dependencies: @@ -12119,7 +12131,7 @@ snapshots: dependencies: '@babel/code-frame': 7.26.2 index-to-position: 0.1.2 - type-fest: 4.39.0 + type-fest: 4.39.1 parse-ms@4.0.0: {} @@ -12382,14 +12394,14 @@ snapshots: dependencies: find-up-simple: 1.0.1 read-pkg: 9.0.1 - type-fest: 4.39.0 + type-fest: 4.39.1 read-pkg@9.0.1: dependencies: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.2 parse-json: 8.1.0 - type-fest: 4.39.0 + type-fest: 4.39.1 unicorn-magic: 0.1.0 readable-stream@4.7.0: @@ -13081,8 +13093,6 @@ snapshots: type-fest@0.13.1: {} - type-fest@4.39.0: {} - type-fest@4.39.1: {} type-flag@3.0.0: {} diff --git a/readme.md b/readme.md index ea2d2db5..ad89a0c6 100644 --- a/readme.md +++ b/readme.md @@ -195,6 +195,7 @@ Full docs are available at [agentic.so](https://agentic.so). | [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. | +| [Google Docs](https://developers.google.com/workspace/docs/api) | `@agentic/google-docs` | [docs](https://agentic.so/tools/google-docs) | Simplified Google Docs 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. |