项目文件夹

文件
Ali Khokhar a0f62c598c Add Google Vertex AI with renewable ADC (#1193)
## Problem

| Before | After |
| --- | --- |
| FCC supported Google AI Studio API keys but could not route coding
agents through a Google Cloud Vertex AI project. | `vertex/...` routes
through Google's [documented OpenAI-compatible Chat Completions
endpoint](https://cloud.google.com/vertex-ai/generative-ai/docs/start/openai),
using the global endpoint by default or an explicitly configured region.
|
| A pasted Vertex access token would expire, while Application Default
Credentials were not part of provider construction. | FCC loads
[Application Default
Credentials](https://cloud.google.com/docs/authentication/application-default-credentials),
supplies a renewable credential callback to the OpenAI transport,
coalesces concurrent refreshes, and returns typed authentication or
transient failures. |
| Vertex does not expose its model catalog through the compatible OpenAI
`/models` route. | FCC translates its generic discovery operation to
Google's paginated [publisher-model list
API](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/publishers.models/list)
and converts resource names into the model IDs accepted by Chat
Completions. |
| Google thought signatures were owned by the AI Studio adapter even
though Vertex shares the same protocol behavior. | A neutral Google
OpenAI family owns shared thought-signature and request behavior; AI
Studio and Vertex retain separate endpoint and authentication ownership.
|

## Changes

- Added the Vertex provider, `VERTEX_PROJECT_ID`, optional
`VERTEX_LOCATION` and `VERTEX_PROXY`, Admin UI configuration,
model-picker discovery, smoke metadata, and customer setup
documentation.
- Added renewable ADC access tokens with refresh coalescing, proxy-aware
refresh, sanitized failure classification, and project quota headers.
- Added global/regional endpoint composition plus native model-catalog
pagination, strict response validation, response cleanup, and
repeated-page protection.
- Generalized provider readiness around declared configuration fields so
project-based and multi-field providers no longer pretend every remote
provider is configured by one API key.
- Moved shared Google request quirks out of the Gemini adapter,
preserved AI Studio behavior, and bumped the package to `4.11.0`.

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR adds Google Vertex AI as a new provider using Application
Default Credentials. The main changes are:

- New `vertex` provider with project/location endpoint construction.
- Renewable ADC access-token loading with refresh coalescing and
proxy-aware refresh.
- Native Vertex publisher-model discovery with pagination and response
validation.
- Shared Google OpenAI-compatible request behavior for Gemini and
Vertex.
- Admin UI, settings, smoke config, docs, version, lockfile, and tests
for the new provider.
</details>

<h3>Confidence Score: 5/5</h3>

Safe to merge with low risk.

No blocking correctness or security issues were identified. The new
provider follows the existing provider-runtime and Admin configuration
patterns. Endpoint, auth, model parsing, readiness, docs, version,
lockfile, and tests are updated together.

No files require special attention.

<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>

**What T-Rex did**
- The T-Rex test suite was executed to validate the code-execution
proof-of-work, generating a full verbose pytest log and recording the
run metadata, and the run completed with EXIT\_CODE: 0.

<a
href="https://app.greptile.com/trex/runs/14991235/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>

<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>

<details open><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| src/free_claude_code/providers/vertex/client.py | Adds the Vertex
provider with OpenAI-compatible chat routing and native paginated model
discovery. |
| src/free_claude_code/providers/vertex/auth.py | Implements renewable
ADC token loading, proxy-aware refresh, coalescing, and sanitized auth
failures. |
| src/free_claude_code/providers/vertex/endpoint.py | Builds validated
Vertex global/regional service, chat, and model-list endpoints. |
| src/free_claude_code/providers/vertex/models.py | Parses Vertex
publisher-model pages into OpenAI-compatible model IDs with
malformed-response checks. |
| src/free_claude_code/providers/google_openai/provider.py | Adds shared
Google thought-signature caching and thinking-budget request body
handling. |
| src/free_claude_code/providers/google_openai/quirks.py | Renames
Gemini-specific quirks to shared Google quirks and exposes model-neutral
thinking config helpers. |
| src/free_claude_code/providers/openai_chat/provider.py | Allows
OpenAI-chat providers to pass an async API-key callback into the OpenAI
SDK. |
| src/free_claude_code/providers/runtime/discovery.py | Uses
descriptor-defined readiness to choose providers eligible for model
cache/discovery. |
| src/free_claude_code/config/provider_catalog.py | Adds the Vertex
descriptor and required settings metadata, and makes Cloudflare
readiness require both token and account ID. |
| src/free_claude_code/config/admin/status.py | Generalizes Admin
provider readiness status to use each descriptor's configuration
attributes. |
| src/free_claude_code/config/admin/provider_manifest.py | Adds Admin UI
fields for Vertex project and location alongside generated provider
fields. |
| tests/providers/test_vertex.py | Adds targeted tests for Vertex
endpoints, ADC token refresh, reasoning mapping, and model discovery
pagination. |

</details>

<details open><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User as User / Admin UI
participant Settings as Settings + Provider Catalog
participant Runtime as Provider Runtime
participant Vertex as VertexProvider
participant ADC as Google ADC
participant OpenAI as OpenAI-compatible Chat Endpoint
participant Models as Vertex Publisher Models API

User->>Settings: Set VERTEX_PROJECT_ID / VERTEX_LOCATION / VERTEX_PROXY
Settings->>Runtime: Descriptor reports vertex configured by project id
Runtime->>Vertex: Construct with project, location, proxy, rate limiter
Vertex->>ADC: Load/refresh Application Default Credentials
ADC-->>Vertex: Renewable access token
Vertex->>OpenAI: Stream chat completion with bearer token + x-goog-user-project
OpenAI-->>Vertex: Streaming chat chunks
Vertex-->>Runtime: Normalized provider stream
Runtime->>Vertex: Refresh model list
Vertex->>Models: GET paginated publishers/google/models
Models-->>Vertex: publisherModels + nextPageToken
Vertex-->>Runtime: Prefixed model IDs for cache/model picker
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User as User / Admin UI
participant Settings as Settings + Provider Catalog
participant Runtime as Provider Runtime
participant Vertex as VertexProvider
participant ADC as Google ADC
participant OpenAI as OpenAI-compatible Chat Endpoint
participant Models as Vertex Publisher Models API

User->>Settings: Set VERTEX_PROJECT_ID / VERTEX_LOCATION / VERTEX_PROXY
Settings->>Runtime: Descriptor reports vertex configured by project id
Runtime->>Vertex: Construct with project, location, proxy, rate limiter
Vertex->>ADC: Load/refresh Application Default Credentials
ADC-->>Vertex: Renewable access token
Vertex->>OpenAI: Stream chat completion with bearer token + x-goog-user-project
OpenAI-->>Vertex: Streaming chat chunks
Vertex-->>Runtime: Normalized provider stream
Runtime->>Vertex: Refresh model list
Vertex->>Models: GET paginated publishers/google/models
Models-->>Vertex: publisherModels + nextPageToken
Vertex-->>Runtime: Prefixed model IDs for cache/model picker
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["feat: add Google Vertex AI
provider"](https://github.com/alishahryar1/free-claude-code/commit/97e753f0772e60377865876ca59b2fd8888d922e)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=45405432)</sub>

<!-- /greptile_comment -->
2026-07-18 21:45:07 -07:00

292 行
8.9 KiB
Bash

# NVIDIA NIM Config
NVIDIA_NIM_API_KEY=""
# OpenRouter Config
OPENROUTER_API_KEY=""
# Mistral La Plateforme Config (Experiment plan free tier – rate limits; OpenAI-compatible at api.mistral.ai/v1)
MISTRAL_API_KEY=""
# Mistral Codestral (separate key from La Plateforme; OpenAI-compatible at codestral.mistral.ai/v1)
CODESTRAL_API_KEY=""
# DeepSeek Config (OpenAI-compatible Chat Completions at api.deepseek.com)
DEEPSEEK_API_KEY=""
# Kimi Config (OpenAI-compatible Chat Completions at api.moonshot.ai/v1)
KIMI_API_KEY=""
# Kimi Code subscription (OpenAI-compatible Chat Completions at api.kimi.com/coding/v1)
KIMI_CODE_API_KEY=""
# Wafer Config (OpenAI-compatible Chat Completions at pass.wafer.ai/v1)
WAFER_API_KEY=""
# MiniMax Config (OpenAI-compatible Chat Completions at api.minimax.io/v1)
MINIMAX_API_KEY=""
# OpenCode Zen (opencode.ai/zen/v1) and OpenCode Go (opencode.ai/zen/go/v1) share OPENCODE_API_KEY
OPENCODE_API_KEY=""
# Vercel AI Gateway Config (OpenAI-compatible Chat Completions at ai-gateway.vercel.sh/v1)
AI_GATEWAY_API_KEY=""
# Amazon Bedrock Mantle (region-specific OpenAI-compatible Chat Completions)
AWS_BEARER_TOKEN_BEDROCK=""
BEDROCK_BASE_URL="https://bedrock-mantle.us-east-1.api.aws/v1"
# Hugging Face Inference Providers Config (OpenAI-compatible Chat Completions at router.huggingface.co/v1)
HUGGINGFACE_API_KEY=""
# Cohere Config (OpenAI-compatible Chat Completions at api.cohere.ai/compatibility/v1)
COHERE_API_KEY=""
# GitHub Models Config (OpenAI-compatible Chat Completions at models.github.ai/inference)
GITHUB_MODELS_TOKEN=""
# Z.ai Config (GLM Coding Plan OpenAI-compatible Chat Completions at api.z.ai/api/coding/paas/v4)
ZAI_API_KEY=""
# Fireworks AI Config (OpenAI-compatible Chat Completions at api.fireworks.ai/inference/v1)
FIREWORKS_API_KEY=""
# Cloudflare Workers AI Config (OpenAI-compatible Chat Completions at api.cloudflare.com/client/v4/accounts/<id>/ai/v1)
CLOUDFLARE_API_TOKEN=""
CLOUDFLARE_ACCOUNT_ID=""
# Gemini / Google AI Studio (OpenAI-compatible Chat Completions; see https://ai.google.dev/gemini-api/docs/openai)
GEMINI_API_KEY=""
# Google Vertex AI (uses Application Default Credentials; no API key)
# Local setup: gcloud auth application-default login
VERTEX_PROJECT_ID=""
VERTEX_LOCATION="global"
# Groq Cloud (OpenAI-compatible Chat Completions; see https://console.groq.com/docs/openai)
GROQ_API_KEY=""
# SambaNova Cloud (OpenAI-compatible Chat Completions at api.sambanova.ai/v1)
SAMBANOVA_API_KEY=""
# Cerebras Inference (OpenAI-compatible Chat Completions; see https://inference-docs.cerebras.ai/resources/openai)
CEREBRAS_API_KEY=""
# Ollama Cloud (direct OpenAI-compatible API at ollama.com/v1)
OLLAMA_API_KEY=""
# LM Studio Config (local provider, no API key required)
LM_STUDIO_BASE_URL="http://localhost:1234/v1"
# Llama.cpp Config (local provider, no API key required)
LLAMACPP_BASE_URL="http://localhost:8080/v1"
# Ollama Config (local provider, no API key required)
OLLAMA_BASE_URL="http://localhost:11434"
# All Claude model requests are mapped to these models, plain model is fallback
# Format: provider_type/model/name
# Valid providers: "nvidia_nim" | "open_router" | "gemini" | "vertex" | "deepseek" | "mistral" | "mistral_codestral" | "opencode" | "opencode_go" | "vercel" | "bedrock" | "huggingface" | "cohere" | "github_models" | "wafer" | "kimi" | "kimi_code" | "minimax" | "cerebras" | "groq" | "sambanova" | "fireworks" | "cloudflare" | "zai" | "ollama_cloud" | "lmstudio" | "llamacpp" | "ollama"
MODEL_FABLE=
MODEL_OPUS=
MODEL_SONNET=
MODEL_HAIKU=
MODEL="nvidia_nim/nvidia/nemotron-3-super-120b-a12b"
# Optional live smoke model overrides. Provider smoke runs once per configured
# provider even when MODEL/MODEL_* route to a different provider.
FCC_SMOKE_MODEL_NVIDIA_NIM=
FCC_SMOKE_MODEL_OPEN_ROUTER=
FCC_SMOKE_MODEL_MISTRAL=
FCC_SMOKE_MODEL_MISTRAL_REASONING=
FCC_SMOKE_MODEL_MISTRAL_CODESTRAL=
FCC_SMOKE_MODEL_DEEPSEEK=
FCC_SMOKE_MODEL_OLLAMA_CLOUD=
FCC_SMOKE_MODEL_LMSTUDIO=
FCC_SMOKE_MODEL_LLAMACPP=
FCC_SMOKE_MODEL_OLLAMA=
FCC_SMOKE_MODEL_KIMI=
FCC_SMOKE_MODEL_KIMI_CODE=
FCC_SMOKE_MODEL_WAFER=
FCC_SMOKE_MODEL_MINIMAX=
FCC_SMOKE_MODEL_OPENCODE=
FCC_SMOKE_MODEL_OPENCODE_GO=
FCC_SMOKE_MODEL_VERCEL=
FCC_SMOKE_MODEL_BEDROCK=
FCC_SMOKE_MODEL_HUGGINGFACE=
FCC_SMOKE_MODEL_COHERE=
FCC_SMOKE_MODEL_GITHUB_MODELS=
FCC_SMOKE_MODEL_ZAI=
FCC_SMOKE_MODEL_FIREWORKS=
FCC_SMOKE_MODEL_CLOUDFLARE=
FCC_SMOKE_MODEL_GEMINI=
FCC_SMOKE_MODEL_VERTEX=
FCC_SMOKE_MODEL_GROQ=
FCC_SMOKE_MODEL_SAMBANOVA=
FCC_SMOKE_MODEL_CEREBRAS=
FCC_SMOKE_NIM_MODELS=
FCC_SMOKE_NIM_EXTRA_MODELS=
FCC_SMOKE_OPENROUTER_FREE_MODELS=
FCC_SMOKE_OPENROUTER_FREE_EXTRA_MODELS=
# Reasoning policy
# Root: off | client | low | medium | high | xhigh | max
# Route overrides additionally accept inherit. "client" preserves the CLI's effort;
# providers translate only controls documented by their API.
REASONING_POLICY=client
REASONING_FABLE=inherit
REASONING_OPUS=inherit
REASONING_SONNET=inherit
REASONING_HAIKU=inherit
# Provider config
# Per-provider proxy support: http and socks5, example: "http://username:password@host:port"
NVIDIA_NIM_PROXY=""
OPENROUTER_PROXY=""
MISTRAL_PROXY=""
CODESTRAL_PROXY=""
LMSTUDIO_PROXY=""
LLAMACPP_PROXY=""
KIMI_PROXY=""
KIMI_CODE_PROXY=""
WAFER_PROXY=""
MINIMAX_PROXY=""
OPENCODE_PROXY=""
OPENCODE_GO_PROXY=""
VERCEL_AI_GATEWAY_PROXY=""
BEDROCK_PROXY=""
HUGGINGFACE_PROXY=""
COHERE_PROXY=""
GITHUB_MODELS_PROXY=""
ZAI_PROXY=""
FIREWORKS_PROXY=""
CLOUDFLARE_PROXY=""
GEMINI_PROXY=""
VERTEX_PROXY=""
GROQ_PROXY=""
SAMBANOVA_PROXY=""
CEREBRAS_PROXY=""
OLLAMA_CLOUD_PROXY=""
PROVIDER_RATE_LIMIT=1
PROVIDER_RATE_WINDOW=3
PROVIDER_MAX_CONCURRENCY=5
# HTTP client timeouts (seconds) for provider API requests
HTTP_READ_TIMEOUT=300
HTTP_WRITE_TIMEOUT=60
HTTP_CONNECT_TIMEOUT=60
# Optional proxy bearer token
ANTHROPIC_AUTH_TOKEN="freecc"
# Open /admin in the default browser when fcc-server becomes healthy (set 0/false/no to disable)
FCC_OPEN_BROWSER=true
# Messaging Platform: "telegram" | "discord" | "none"
MESSAGING_PLATFORM="discord"
MESSAGING_RATE_LIMIT=1
MESSAGING_RATE_WINDOW=1
# Voice Note Transcription
VOICE_NOTE_ENABLED=false
# WHISPER_DEVICE: "cpu" | "cuda" | "nvidia_nim"
# - "cpu"/"cuda": Hugging Face transformers Whisper (offline, free; install with: uv sync --extra voice_local)
# - "nvidia_nim": NVIDIA NIM Whisper via Riva gRPC (requires NVIDIA_NIM_API_KEY; install with: uv sync --extra voice)
# (Independent of MODEL=nvidia_nim/...: that selects the *chat* provider; this selects voice STT only.)
WHISPER_DEVICE="nvidia_nim"
# WHISPER_MODEL:
# - For cpu/cuda: Hugging Face ID or short name (tiny, base, small, medium, large-v2, large-v3, large-v3-turbo)
# - For nvidia_nim: NVIDIA NIM model (e.g., "nvidia/parakeet-ctc-1.1b-asr", "openai/whisper-large-v3")
# - For nvidia_nim, default to "openai/whisper-large-v3" for best performance
WHISPER_MODEL="openai/whisper-large-v3"
# Telegram Config
TELEGRAM_BOT_TOKEN=""
ALLOWED_TELEGRAM_USER_ID=""
# Optional Telegram-only proxy.
# Supported schemes: http, https, socks4, socks5, socks5h.
# Example: "socks5://127.0.0.1:1080" or "https://user:password@host:port"
TELEGRAM_PROXY_URL=""
# Discord Config
DISCORD_BOT_TOKEN=""
ALLOWED_DISCORD_CHANNELS=""
# Agent Config
ALLOWED_DIR=""
FAST_PREFIX_DETECTION=true
ENABLE_NETWORK_PROBE_MOCK=true
ENABLE_TITLE_GENERATION_SKIP=true
ENABLE_SUGGESTION_MODE_SKIP=true
ENABLE_FILEPATH_EXTRACTION_MOCK=true
# Local Anthropic web_search / web_fetch handling (performs outbound HTTP; on by default)
ENABLE_WEB_SERVER_TOOLS=true
WEB_FETCH_ALLOWED_SCHEMES=http,https
WEB_FETCH_ALLOW_PRIVATE_NETWORKS=false
# Structured traces: DEBUG lines with `"trace": true` merge
# ingress/routing/cli/provider/egress stages. Conversation text is logged in those payloads
# (verbatim). Values under keys named like ``api_key`` / ``authorization`` are redacted.
# Raw transport payloads still require the LOG_RAW_* toggles below.
#
# Minimum log level for the JSON file sink: DEBUG, INFO, WARNING, ERROR, CRITICAL.
# Defaults to INFO. Use DEBUG temporarily for detailed request traces, or WARNING for quieter logs.
# The file rotates at 50 MB and retains five rotated files (roughly 300 MB including the active file).
LOG_LEVEL=INFO
#
# Verbose diagnostics (avoid logging raw prompts / SSE bodies in production)
DEBUG_PLATFORM_EDITS=false
DEBUG_SUBAGENT_STACK=false
# When true, also allows DEBUG-level httpx/httpcore/telegram log noise (not just payload logging).
LOG_RAW_API_PAYLOADS=false
LOG_RAW_SSE_EVENTS=false
# When true, log full exception text and tracebacks for unhandled errors (may leak request-derived data).
LOG_API_ERROR_TRACEBACKS=false
# When true, log message/transcription text previews in messaging adapters only (handler ingress always TRACEs verbatim text separately).
LOG_RAW_MESSAGING_CONTENT=false
# When true, log full Claude CLI stderr, non-JSON stdout lines, and parser error text.
LOG_RAW_CLI_DIAGNOSTICS=false
# When true, log full exception and CLI error message strings in messaging (may leak user content).
LOG_MESSAGING_ERROR_DETAILS=false