deer-flow/.env.example
kongxin cee54cdd49
fix(web-fetch): stop sending .env.example placeholder keys to providers (#8206)
* fix(web-fetch): stop sending .env.example placeholder keys to providers

make config and make setup copy .env.example into .env, and the template
set nine search/fetch provider keys to example values such as
JINA_API_KEY=your-jina-api-key. The default keyless Jina Reader sent
that text as a Bearer key, so every web_fetch on a fresh install failed
with 401 while make doctor reported web fetch as configured.

- .env.example comments those nine lines out, like every other credential
  in the template already is.
- provider_credentials.resolve_api_key reads a your-...-key/-token/-secret
  value as unset, so existing .env files that still hold the placeholders
  recover without editing, for every provider that resolves keys there.

* chore: leave the changelog entry to merge time

Per CONTRIBUTING.md (#8202), maintainers add changelog entries when they
merge a pull request.

* fix(web-search): route every provider key and doctor through one placeholder rule

Review follow-up for #8206:

- provider_credentials exposes is_template_placeholder(), the single
  definition of an .env.example example value. key/token/secret must be
  a whole hyphen-separated word, so a real value such as your-monkey or
  your-passkey is no longer dropped.
- Serper, Serply, Sofya, SpecStream, Unbrowse, Webz, Brave, Tencent WSA
  and You.com resolve config and environment keys through
  resolve_api_key instead of private strip-and-send copies, so an old
  .env that still holds the template value no longer sends it.
- make doctor asks the same predicate: a placeholder key is reported as
  still holding the .env.example value instead of "set", and a literal
  placeholder in config.yaml falls back to the environment key as the
  runtime does.
- A census test keeps credential environment reads under community/
  wrapped in resolve_api_key.

* fix(web-search): match shipped placeholders exactly and mirror Browserless precedence in doctor

Second review follow-up for #8206:

- is_template_placeholder() matches exactly the your-... values that
  .env.example ships instead of a pattern, so a token an operator chose
  (a self-hosted Browserless TOKEN such as your-review-team-token) is
  sent again. A test keeps the set equal to the template.
- make doctor mirrors Browserless: a configured token field is
  authoritative, blank or not, and BROWSERLESS_TOKEN is read only when
  the field is omitted. A blank or placeholder token now warns instead
  of reporting the variable, cross-checked against the client.
- The keyless Jina and You.com providers stay ok but name JINA_API_KEY
  or YDC_API_KEY when a placeholder there is ignored, and a literal
  placeholder api_key in config.yaml is named when no env key backs it.

* fix(doctor): match each web provider's key precedence; drop the dead Jina api_key from docs

Found while re-checking #8206 against every provider's runtime:

- Browserless used as web_fetch had no doctor key check; it now gets the
  same authoritative token handling as web_capture.
- InfoQuest reads only INFOQUEST_API_KEY, so doctor no longer counts an
  api_key field in its tool config as configured.
- GroundRoute needs a key for every call but had no doctor entry, so a
  missing key reported ok.
- You.com names a placeholder api_key in config that it ignores.
- The Jina web_fetch docs snippet carried api_key: $JINA_API_KEY, which
  the tool never reads. With JINA_API_KEY now commented out in
  .env.example, that line made config loading fail on a fresh install.
- The provider_credentials docstring now scopes doctor's use of the
  predicate to web provider keys, and the scripts guide no longer says
  .env.example ships live placeholder keys.
2026-11-13 23:23:29 +08:00

167 lines
8.1 KiB
Plaintext

# Serper API Key (Google Search) - https://serper.dev
# SERPER_API_KEY=your-serper-api-key
# Optional operator-controlled Serper-compatible API base URL, without /search or /images.
# The configured API key is sent in X-API-KEY to this host; use a trusted provider.
SERPER_BASE_URL=https://google.serper.dev
# Exa API Key - https://exa.ai
# EXA_API_KEY=your-exa-api-key
# Optional operator-controlled Exa-compatible API base URL for the Exa web_search and web_fetch tools.
# The configured API key is sent in x-api-key to this host; use a trusted provider.
EXA_BASE_URL=https://api.exa.ai
# Serply API Key (Google Search, News and Scholar) - https://serply.io
# SERPLY_API_KEY=your-serply-api-key
# TAVILY API Key
# TAVILY_API_KEY=your-tavily-api-key
# Optional Webz.io News Search key (select Webz in make setup)
# WEBZ_API_KEY=your-webz-api-key
# Jina API Key (optional; the Jina Reader web_fetch works without one at a lower rate limit)
# JINA_API_KEY=your-jina-api-key
# InfoQuest API Key
# INFOQUEST_API_KEY=your-infoquest-api-key
# Sofya API Key (web search and fetch) - https://sofya.co
# SOFYA_API_KEY=your-sofya-api-key
# SpecStream API Key (web search and fetch) - https://specstream.ai
# SPECSTREAM_API_KEY=your-specstream-api-key
# Unbrowse API Key (web fetch) - https://unbrowse.ai/app
# UNBROWSE_API_KEY=your-unbrowse-api-key
# Browser CORS allowlist for split-origin or port-forwarded deployments (comma-separated exact origins).
# Leave unset when using the unified nginx endpoint, e.g. http://localhost:2026.
# GATEWAY_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
# Local make dev/start Gateway readiness wait, in positive integer seconds (default: 30).
# Increase for slow cold starts; does not change Docker health checks or request timeouts.
# DEER_FLOW_GATEWAY_STARTUP_TIMEOUT=240
# Host interface the nginx entry port listens on, for the Docker stack and for
# local `make dev` / `make start` (where the Gateway and frontend always stay on
# loopback). Defaults to 127.0.0.1 (loopback only), matching the
# local-trusted-environment deployment model documented in README.md -- the
# agent can execute commands.
# Set 0.0.0.0 only when the host is protected by your own TLS/auth front door
# or firewall, and complete first-run setup before it becomes reachable.
# Local runs accept an IPv4 or IPv6 address or a hostname.
# BIND_HOST=0.0.0.0
# PORT=2026
# Proxies whose X-Real-IP the Gateway trusts when it counts failed logins per
# client (comma-separated IPs, CIDRs or hostnames; a hostname is re-resolved
# every 10s). The Docker stack defaults to its bundled `nginx` service; without
# it every browser login shares nginx's address, so five wrong passwords from
# anyone lock everyone out. Behind your own front door, nginx sees that proxy's
# address instead: configure nginx's real_ip module for it as well.
# Outside Docker, unset or empty is direct mode: X-Real-IP is ignored. In the
# Docker stack an empty value also falls back to `nginx`, since every browser
# request arrives through it.
# AUTH_TRUSTED_PROXIES=nginx
# Optional:
# FIRECRAWL_API_KEY=your-firecrawl-api-key
# VOLCENGINE_API_KEY=your-volcengine-api-key
# OPENAI_API_KEY=your-openai-api-key
# OPENVIKING_API_KEY=your-openviking-user-api-key
# GEMINI_API_KEY=your-gemini-api-key
# DEEPSEEK_API_KEY=your-deepseek-api-key
# NOVITA_API_KEY=your-novita-api-key # OpenAI-compatible, see https://novita.ai
# MINIMAX_API_KEY=your-minimax-api-key # OpenAI-compatible, see https://platform.minimax.io
# MiniMax API host (choose by region):
# China: https://api.minimaxi.com (default)
# International: https://api.minimax.io
# MINIMAX_API_HOST=https://api.minimax.io
# OPPER_API_KEY=your-opper-api-key # OpenAI-compatible, see https://opper.ai
# OpenAI-compatible Images API (used by the image-generation skill)
# IMAGE_GENERATION_PROVIDER=openai # openai-compatible is also accepted
# IMAGE_GENERATION_API_KEY=your-image-generation-api-key
# IMAGE_GENERATION_BASE_URL=https://api.openai.com/v1
# IMAGE_GENERATION_MODEL=gpt-image-2.5-flare
# IMAGE_GENERATION_SIZE=1536x1024
# STEPFUN_API_KEY=your-stepfun-api-key # OpenAI-compatible, see https://platform.stepfun.com
# VLLM_API_KEY=your-vllm-api-key # OpenAI-compatible
# E2B cloud sandbox API key — required only when using E2BSandboxProvider.
# Sign up at https://e2b.dev/dashboard
# E2B_API_KEY=your-e2b-api-key
# FEISHU_APP_ID=your-feishu-app-id
# FEISHU_APP_SECRET=your-feishu-app-secret
# SLACK_BOT_TOKEN=your-slack-bot-token
# SLACK_APP_TOKEN=your-slack-app-token
# TELEGRAM_BOT_TOKEN=your-telegram-bot-token
# DISCORD_BOT_TOKEN=your-discord-bot-token
# Enable LangSmith to monitor and debug your LLM calls, agent runs, and tool executions.
# LANGSMITH_TRACING=true
# LANGSMITH_ENDPOINT=https://api.smith.langchain.com
# LANGSMITH_API_KEY=your-langsmith-api-key
# LANGSMITH_PROJECT=your-langsmith-project
# GitHub API Token
# GITHUB_TOKEN=your-github-token
# Database (only needed when config.yaml has database.backend: postgres)
# DATABASE_URL=postgresql://deerflow:password@localhost:5432/deerflow
#
# WECOM_BOT_ID=your-wecom-bot-id
# WECOM_BOT_SECRET=your-wecom-bot-secret
# DINGTALK_CLIENT_ID=your-dingtalk-client-id
# DINGTALK_CLIENT_SECRET=your-dingtalk-client-secret
# Set to "false" to disable Swagger UI, ReDoc, and OpenAPI schema in production
# GATEWAY_ENABLE_DOCS=false
# Shared internal Gateway auth token for multi-worker deployments.
# `make up` honors a value set here (as it does for BETTER_AUTH_SECRET) and
# otherwise generates one and persists it under DEER_FLOW_HOME; set it
# manually when Gateway workers also run outside the bundled deploy script.
# DEER_FLOW_INTERNAL_AUTH_TOKEN=your-shared-internal-token
# At-rest encryption key for stored credentials (a Fernet key). Comma-separate
# several to rotate: the first encrypts, all decrypt. Unset, a single instance
# generates DEER_FLOW_HOME/.credentials_key (`make up` persists the same file);
# instances that do not share DEER_FLOW_HOME must all set the same value.
# Back it up: losing it makes stored credentials unreadable. Generate:
# python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# DEER_FLOW_CREDENTIALS_KEY=your-fernet-key
# Provisioner API key for sandbox authentication (required when using provisioner/K8s sandbox mode).
# The same value must be set on the provisioner container and in config.yaml sandbox.provisioner_api_key.
# Generate: openssl rand -hex 32
# PROVISIONER_API_KEY=your-provisioner-api-key
# ── Frontend SSR → Gateway wiring ─────────────────────────────────────────────
# The Next.js server uses these to reach the Gateway during SSR (auth checks,
# /api/* rewrites). They default to localhost values that match `make dev` and
# `make start`, so most local users do not need to set them.
#
# Override only when the Gateway is not on localhost:8001 (e.g. when the
# frontend and gateway run on different hosts, in containers with a service
# alias, or behind a different port). docker-compose already sets these.
# DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://localhost:8001
# DEER_FLOW_TRUSTED_ORIGINS=http://localhost:3000,http://localhost:2026
# ── Claude Code / Codex CLI subscription as a model provider (optional) ───────
# If you configure a ClaudeChatModel / Codex model provider (or an ACP agent)
# that reuses your CLI subscription login, prefer passing a token via env over
# bind-mounting your whole ~/.claude / ~/.codex into the container. The Gateway
# credential loader reads these first, so no directory mount is needed.
# CLAUDE_CODE_CREDENTIALS_PATH points at a single .credentials.json (Claude)
# rather than the whole dir. docker-compose.cli-auth.yaml is the opt-in
# directory-mount fallback for adapters that need the full CLI config.
# ACP adapters often take their own env API key (e.g. ANTHROPIC_API_KEY) and
# need no mount at all — check the adapter's docs. See SECURITY.md.
# CLAUDE_CODE_OAUTH_TOKEN=your-claude-code-oauth-token
# ANTHROPIC_AUTH_TOKEN=your-anthropic-auth-token
# CLAUDE_CODE_CREDENTIALS_PATH=/path/to/.claude/.credentials.json
# CODEX_AUTH_PATH=/path/to/codex/auth.json