feat: add Google Drive skills with Docker compatibility#1775
Conversation
MarkHoch
commented
Apr 2, 2026
- Add Google Drive API dependencies to backend pyproject.toml
- Mount Google Drive credentials volume in Docker for token refresh
- Add GOOGLE_DRIVE_TOKEN_PATH environment variable for runtime configuration
- Supports token persistence and automatic refresh in Docker environment
|
@aallGH thanks for your contribution, but your patch ignores the recent change on the main branch when you resolve the conflicts. Can you double-check your merging strategy? |
There was a problem hiding this comment.
Pull request overview
Adds a new custom Google Drive skill (scripts + docs + evals) and updates the Docker compose setup to support persisting/refreshing OAuth tokens inside containers, alongside adding Google API dependencies to the backend.
Changes:
- Introduces
skills/custom/google-drive/with CLI scripts for auth, listing, reading, creating, updating, and searching Drive files. - Updates Docker compose (prod + dev) to mount a writable location for Google Drive token persistence and sets
GOOGLE_DRIVE_TOKEN_PATH. - Adds Google Drive client/auth dependencies to
backend/pyproject.toml.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| skills/custom/google-drive/SKILL.md | Skill definition + usage guidance for triggering the skill. |
| skills/custom/google-drive/README.md | Full setup and usage documentation for the skill. |
| skills/custom/google-drive/QUICKSTART.md | Short quickstart guide for setup/testing. |
| skills/custom/google-drive/FINAL_VERSION.md | “Final version” packaging/usage notes and Docker guidance. |
| skills/custom/google-drive/install.sh | Helper installer script for copying the skill into a DeerFlow checkout. |
| skills/custom/google-drive/requirements.txt | Standalone dependency list for running scripts outside DeerFlow. |
| skills/custom/google-drive/test_document.txt | Sample document for manual upload/read testing. |
| skills/custom/google-drive/references/google-drive-api.md | API/query/scope reference documentation. |
| skills/custom/google-drive/scripts/utils.py | Shared OAuth credential handling + Drive service helpers. |
| skills/custom/google-drive/scripts/auth_setup.py | First-time OAuth flow helper. |
| skills/custom/google-drive/scripts/list_files.py | CLI for listing files/folders. |
| skills/custom/google-drive/scripts/read_file.py | CLI for reading/exporting/downloading files. |
| skills/custom/google-drive/scripts/create_file.py | CLI for creating folders/docs and uploading files. |
| skills/custom/google-drive/scripts/update_file.py | CLI for rename/move/content update. |
| skills/custom/google-drive/scripts/search_files.py | CLI for query-based search. |
| skills/custom/google-drive/evals/test_drive_basic.py | Pytest-based evals for utils/import smoke tests. |
| skills/custom/google-drive/assets/langgraph_integration_example.py | Example showing how to wrap Drive ops as LangGraph tools. |
| docker/docker-compose.yaml | Adds Drive token mount/env; modifies frontend env; adds healthchecks; adjusts langgraph config mounts. |
| docker/docker-compose-dev.yaml | Mirrors compose changes for dev environment. |
| backend/pyproject.toml | Adds google-api-python-client + auth deps (and websockets). |
| healthcheck: | ||
| test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8001/health" ] | ||
| interval: 2s | ||
| timeout: 2s | ||
| retries: 15 | ||
| start_period: 5s |
There was a problem hiding this comment.
The healthcheck uses wget, but the backend image (backend/Dockerfile) only installs curl (no wget). This will cause the gateway container to be marked unhealthy even when /health is serving. Use curl -f (as done for the provisioner healthcheck) or install wget in the image.
| healthcheck: | ||
| test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:2024/health" ] | ||
| interval: 2s | ||
| timeout: 2s | ||
| retries: 15 | ||
| start_period: 5s |
There was a problem hiding this comment.
Same issue as the gateway service: this healthcheck uses wget but the backend image doesn't include it, so the langgraph container will be reported unhealthy. Switch the test command to curl -f or ensure wget is installed in the image.
| NPM_REGISTRY: ${NPM_REGISTRY:-} | ||
| container_name: deer-flow-frontend | ||
| environment: | ||
| - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} |
There was a problem hiding this comment.
Removing DEER_FLOW_INTERNAL_GATEWAY_BASE_URL / DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL from the frontend container breaks frontend/next.config.js rewrites in Docker: the fallback URLs are http://127.0.0.1:*, which point to the frontend container itself (not gateway/langgraph). Either keep these env vars (set to http://gateway:8001 / http://langgraph:2024) or set NEXT_PUBLIC_*_BASE_URL so rewrites are not used.
| - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} | |
| - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} | |
| - DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=${DEER_FLOW_INTERNAL_GATEWAY_BASE_URL:-http://gateway:8001} | |
| - DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL=${DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL:-http://langgraph:2024} |
| bind: | ||
| create_host_path: true | ||
| # Google Drive credentials (writeable for token refresh) | ||
| - ../skills/custom/google-drive:/app/google-drive-credentials |
There was a problem hiding this comment.
This volume mounts the entire skill directory writable into the container for token refresh. That means container processes can modify skill code/docs on the host checkout (and it also risks accidentally committing refreshed token.json). Prefer mounting a dedicated credentials/token directory or a named volume (e.g., ${DEER_FLOW_HOME}/google-drive), and keep the skills tree mounted read-only.
| - ../skills/custom/google-drive:/app/google-drive-credentials | |
| - ${DEER_FLOW_HOME}/google-drive:/app/google-drive-credentials |
| parser.add_argument('--desc', | ||
| action='store_true', | ||
| default=True, | ||
| help='降序排列 (默认)') | ||
| parser.add_argument('--asc', | ||
| action='store_true', | ||
| help='升序排列') |
There was a problem hiding this comment.
--desc is declared as store_true with default=True, which makes it always true even when the flag is omitted, and the value isn’t used anyway (ordering is determined solely by args.asc). This makes the CLI misleading. Prefer a mutually-exclusive group (--asc/--desc) with a sane default, or remove --desc entirely and default to descending when --asc is not set.
| | 功能 | 命令 | | ||
| |------|------| | ||
| | **列出文件** | `python scripts/list_files.py` | | ||
| | **读取文件** | `python scripts/read_file.py <file-id>` | | ||
| | **上传文件** | `python scripts/create_file.py upload <local-file>` | | ||
| | **创建文件夹** | `python scripts/create_file.py folder <name>` | | ||
| | **搜索文件** | `python scripts/search_files.py <query>` | | ||
|
|
There was a problem hiding this comment.
The command examples here don’t match the actual CLI in scripts/read_file.py, which requires --file-id or --file-name flags (there is no positional <file-id>). Update the examples to reflect the real invocation so users can follow the guide successfully.
| services: | ||
| backend: | ||
| volumes: | ||
| - ./skills:/app/backend/skills # ✅ 需要这行 |
There was a problem hiding this comment.
The Docker volume example mounts ./skills to /app/backend/skills, but the repo’s docker-compose mounts skills at /app/skills (and gateway/langgraph use that path). Update the example to match the actual container path, otherwise users will configure Docker incorrectly.
| - ./skills:/app/backend/skills # ✅ 需要这行 | |
| - ./skills:/app/skills # ✅ 需要这行 |
| echo "" | ||
| echo "1. 检查 Docker 卷挂载配置:" | ||
| echo " 编辑 $DEERFLOW_DIR/docker-compose.yml" | ||
| echo " 确认 backend 服务有类似配置:" | ||
| echo " volumes:" | ||
| echo " - ./skills:/app/backend/skills" | ||
| echo "" |
There was a problem hiding this comment.
This installer script tells users to edit $DEERFLOW_DIR/docker-compose.yml, but in this repo the compose files are docker/docker-compose.yaml and docker/docker-compose-dev.yaml (different path and extension). Update the guidance so it points at the actual compose file(s) used by DeerFlow.
| environment: | ||
| - NODE_ENV=development | ||
| - WATCHPACK_POLLING=true | ||
| - CI=true |
There was a problem hiding this comment.
Same frontend rewrite issue as in production compose: without DEER_FLOW_INTERNAL_GATEWAY_BASE_URL / DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL, Next.js rewrites fall back to 127.0.0.1 inside the frontend container. Add these env vars back (pointing to gateway/langgraph) or set NEXT_PUBLIC_*_BASE_URL to bypass rewrites.
| - CI=true | |
| - CI=true | |
| - DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://gateway:8001 | |
| - DEER_FLOW_INTERNAL_LANGGRAPH_BASE_URL=http://langgraph:2024 |
| SCOPES = [ | ||
| 'https://www.googleapis.com/auth/drive', | ||
| 'https://www.googleapis.com/auth/drive.file', | ||
| 'https://www.googleapis.com/auth/drive.readonly' |
There was a problem hiding this comment.
SCOPES requests full https://www.googleapis.com/auth/drive access in addition to narrower scopes. Because scopes are additive, this effectively prompts for full Drive access and negates the least-privilege benefit of drive.file/drive.readonly. Consider defaulting to the minimal scope(s) needed (e.g., drive.file for create/update, or drive.readonly for read-only operations) and documenting when broader scopes are required.
| SCOPES = [ | |
| 'https://www.googleapis.com/auth/drive', | |
| 'https://www.googleapis.com/auth/drive.file', | |
| 'https://www.googleapis.com/auth/drive.readonly' | |
| # 默认仅请求最小必要权限: | |
| # - drive.file: 允许应用创建和管理其创建或打开的文件 | |
| # - drive.readonly: 允许只读访问用户可用的文件 | |
| # 如需对整个 Drive 进行完全访问,请显式将 | |
| # 'https://www.googleapis.com/auth/drive' 添加到 SCOPES,并重新生成 token.json | |
| SCOPES = [ | |
| 'https://www.googleapis.com/auth/drive.file', | |
| 'https://www.googleapis.com/auth/drive.readonly', |
19908c2 to
3715847
Compare
e7b029d to
9a2a453
Compare
## Overview Adds a complete, self-contained Google Drive integration skill that works out-of-the-box with DeerFlow's custom skill loading system without requiring any core infrastructure modifications. ## Key Features - 🔐 OAuth 2.0 authentication with automatic token refresh - 📁 File listing with pagination and filtering support - 📄 File reading (supports Google Docs/Sheets/Slides conversion) - ✨ File creation (folders, Google docs, local file uploads) - 🔄 File updates (rename, move, content modification) - 🔍 Powerful search capabilities with multiple filters - 📦 LangGraph integration examples - 📚 Complete documentation and quickstart guide ## Usage 1. Place this skill in your DeerFlow skills/custom/ directory 2. Run the included install.sh for setup 3. Complete OAuth authentication via auth_setup.py 4. The skill will be automatical4. The sk by4. The skill will bit4. The skill will be automatie exclud4. The skill will beMinimal permission scopes requested - Includes comprehensive error handling ## References - SKILL.md - Skill definition and trigger patterns - README.md - Complete usage documentation - QUICKSTART.md - Fast setup guide - FINAL_VERSION.md - Packaging and deployment notes
9a2a453 to
5592664
Compare
PR Update - Major RevisionResponse to Review CommentsThank you for your review! You're absolutely right - I did overlook the recent changes on the main branch when resolving merge conflicts. I've completely redesigned this PR with a minimal change strategy: Changes Made✅ Removed all core file modifications :
Design ApproachThis skill uses a fully self-contained architecture :
Verification Results
|