mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
remove Vercel AI Gateway and Vercel Sandbox (#33067)
* remove Vercel AI Gateway provider and Vercel Sandbox terminal backend Both Vercel-hosted integrations are removed end-to-end. Users on the AI Gateway should switch to OpenRouter or one of the other aggregators (Nous Portal, Kilo Code). Users on the Vercel Sandbox backend should switch to Docker, Modal, Daytona, or SSH. What's removed: - `plugins/model-providers/ai-gateway/` provider plugin - `hermes_cli/vercel_auth.py` Vercel-Sandbox auth helper - `tools/environments/vercel_sandbox.py` terminal backend - `ai-gateway` provider wiring across auth, doctor, setup, models, config, status, providers, main, web_server, model_normalize, dump - `vercel_sandbox` backend wiring across terminal_tool, file_tools, code_execution_tool, file_operations, approval, skills_tool, environments/local, credential_files, lazy_deps, prompt_builder, cli, gateway/run - `AI_GATEWAY_BASE_URL` constant, `_AI_GATEWAY_HEADERS` auxiliary-client header set, run_agent base-URL header/reasoning special-cases - `[vercel]` pyproject extra and `vercel`/`vercel-workers` from uv.lock - env vars: `AI_GATEWAY_API_KEY`, `AI_GATEWAY_BASE_URL`, `VERCEL_TOKEN`, `VERCEL_PROJECT_ID`, `VERCEL_TEAM_ID`, `VERCEL_OIDC_TOKEN`, `TERMINAL_VERCEL_RUNTIME` - Tests: deletes test_ai_gateway_models.py and test_vercel_sandbox_environment.py; scrubs references across 23 surviving test files (no entire tests deleted unless they were dedicated to AI Gateway / Sandbox) - Docs: provider tables, env-var reference, setup guides, security notes, tool config, terminal-backend tables — English plus zh-Hans i18n parity - `hermes-agent` skill: provider table entry and remote-backend list What stays (intentional): - `popular-web-designs/templates/vercel.md` — CSS design reference, unrelated to Vercel-the-AI-product - `x-vercel-id` in `stream_diag.py` headers — generic Vercel CDN response header, useful diag signal on any Vercel-hosted endpoint - `vercel-labs/agent-browser` URL in browser config — lightpanda browser project, different OSS effort - `userStories.json` historical contributor entry mentioning Vercel Sandbox — archive, not active docs Validation: - 1153 tests in the 22 targeted files pass (`scripts/run_tests.sh`) - Full repo `py_compile` clean - Live import of every touched module + invariant check (no `ai-gateway` in `PROVIDER_REGISTRY`, no `_AI_GATEWAY_HEADERS`, no `vercel_sandbox` in `_REMOTE_TERMINAL_BACKENDS`) * test: convert profile-count check from change-detector to invariant The hardcoded "== 34" assertion broke when ai-gateway was removed. Per AGENTS.md change-detector-test guidance, assert the relationship (registry count >= number of plugin dirs) instead of a literal count. Counts shift when providers are added/removed; that's expected.
This commit is contained in:
parent
cb38ce28cb
commit
febc4cfec0
95 changed files with 111 additions and 3088 deletions
|
|
@ -101,7 +101,6 @@ _DEFAULT_PROVIDER_MODELS = {
|
|||
"arcee": ["trinity-large-thinking", "trinity-large-preview", "trinity-mini"],
|
||||
"minimax": ["MiniMax-M2.7", "MiniMax-M2.5", "MiniMax-M2.1", "MiniMax-M2"],
|
||||
"minimax-cn": ["MiniMax-M2.7", "MiniMax-M2.5", "MiniMax-M2.1", "MiniMax-M2"],
|
||||
"ai-gateway": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5", "google/gemini-3-flash"],
|
||||
"kilocode": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "google/gemini-3-pro-preview", "google/gemini-3-flash-preview"],
|
||||
"opencode-zen": ["gpt-5.4", "gpt-5.3-codex", "claude-sonnet-4-6", "gemini-3-flash", "glm-5", "kimi-k2.5", "minimax-m2.7"],
|
||||
"opencode-go": ["kimi-k2.6", "kimi-k2.5", "glm-5.1", "glm-5", "mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.7", "minimax-m2.5", "qwen3.7-max", "qwen3.6-plus", "qwen3.5-plus"],
|
||||
|
|
@ -679,102 +678,6 @@ def _prompt_container_resources(config: dict):
|
|||
pass
|
||||
|
||||
|
||||
def _prompt_vercel_sandbox_settings(config: dict):
|
||||
"""Prompt for Vercel Sandbox settings without exposing unsupported disk sizing."""
|
||||
terminal = config.setdefault("terminal", {})
|
||||
|
||||
print()
|
||||
print_info("Vercel Sandbox settings:")
|
||||
print_info(" Filesystem persistence uses Vercel snapshots.")
|
||||
print_info(" Snapshots restore files only; live processes do not continue after sandbox recreation.")
|
||||
|
||||
from tools.terminal_tool import _SUPPORTED_VERCEL_RUNTIMES
|
||||
|
||||
current_runtime = terminal.get("vercel_runtime") or "node24"
|
||||
supported_label = ", ".join(_SUPPORTED_VERCEL_RUNTIMES)
|
||||
runtime = prompt(f" Runtime ({supported_label})", current_runtime).strip() or current_runtime
|
||||
if runtime not in _SUPPORTED_VERCEL_RUNTIMES:
|
||||
print_warning(f"Unsupported Vercel runtime '{runtime}', keeping {current_runtime}.")
|
||||
runtime = current_runtime if current_runtime in _SUPPORTED_VERCEL_RUNTIMES else "node24"
|
||||
terminal["vercel_runtime"] = runtime
|
||||
save_env_value("TERMINAL_VERCEL_RUNTIME", runtime)
|
||||
|
||||
current_persist = terminal.get("container_persistent", True)
|
||||
persist_label = "yes" if current_persist else "no"
|
||||
terminal["container_persistent"] = prompt(
|
||||
" Persist filesystem with snapshots? (yes/no)", persist_label
|
||||
).lower() in {"yes", "true", "y", "1"}
|
||||
|
||||
current_cpu = terminal.get("container_cpu", 1)
|
||||
cpu_str = prompt(" CPU cores", str(current_cpu))
|
||||
try:
|
||||
terminal["container_cpu"] = float(cpu_str)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
current_mem = terminal.get("container_memory", 5120)
|
||||
mem_str = prompt(" Memory in MB (5120 = 5GB)", str(current_mem))
|
||||
try:
|
||||
terminal["container_memory"] = int(mem_str)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if terminal.get("container_disk", 51200) not in {0, 51200}:
|
||||
print_warning("Vercel Sandbox does not support custom disk sizing; resetting container_disk to 51200.")
|
||||
terminal["container_disk"] = 51200
|
||||
|
||||
print()
|
||||
print_info("Vercel authentication:")
|
||||
print_info(" Use a long-lived Vercel access token plus project/team IDs.")
|
||||
linked_project = _read_nearest_vercel_project()
|
||||
if linked_project:
|
||||
print_info(" Found defaults in nearest .vercel/project.json.")
|
||||
|
||||
remove_env_value("VERCEL_OIDC_TOKEN")
|
||||
token = prompt(" Vercel access token", get_env_value("VERCEL_TOKEN") or "", password=True)
|
||||
project = prompt(
|
||||
" Vercel project ID",
|
||||
get_env_value("VERCEL_PROJECT_ID") or linked_project.get("projectId", ""),
|
||||
)
|
||||
team = prompt(
|
||||
" Vercel team ID",
|
||||
get_env_value("VERCEL_TEAM_ID") or linked_project.get("orgId", ""),
|
||||
)
|
||||
if token:
|
||||
save_env_value("VERCEL_TOKEN", token)
|
||||
if project:
|
||||
save_env_value("VERCEL_PROJECT_ID", project)
|
||||
if team:
|
||||
save_env_value("VERCEL_TEAM_ID", team)
|
||||
|
||||
|
||||
def _read_nearest_vercel_project(start: Path | None = None) -> dict[str, str]:
|
||||
"""Read project/team defaults from the nearest Vercel link file."""
|
||||
current = (start or Path.cwd()).resolve()
|
||||
if current.is_file():
|
||||
current = current.parent
|
||||
|
||||
for directory in (current, *current.parents):
|
||||
project_file = directory / ".vercel" / "project.json"
|
||||
if not project_file.exists():
|
||||
continue
|
||||
try:
|
||||
data = json.loads(project_file.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return {}
|
||||
if not isinstance(data, dict):
|
||||
return {}
|
||||
return {
|
||||
key: value
|
||||
for key, value in {
|
||||
"projectId": data.get("projectId"),
|
||||
"orgId": data.get("orgId"),
|
||||
}.items()
|
||||
if isinstance(value, str) and value.strip()
|
||||
}
|
||||
return {}
|
||||
|
||||
|
||||
# Tool categories and provider config are now in tools_config.py (shared
|
||||
# between `hermes tools` and `hermes setup tools`).
|
||||
|
||||
|
|
@ -936,7 +839,6 @@ def setup_model_provider(config: dict, *, quick: bool = False):
|
|||
"minimax": "MiniMax",
|
||||
"minimax-cn": "MiniMax CN",
|
||||
"anthropic": "Anthropic",
|
||||
"ai-gateway": "Vercel AI Gateway",
|
||||
"custom": "your custom endpoint",
|
||||
}
|
||||
_prov_display = _prov_names.get(selected_provider, selected_provider or "your provider")
|
||||
|
|
@ -1407,12 +1309,11 @@ def setup_terminal_backend(config: dict):
|
|||
"Modal - serverless cloud sandbox",
|
||||
"SSH - run on a remote machine",
|
||||
"Daytona - persistent cloud development environment",
|
||||
"Vercel Sandbox - cloud microVM with snapshot filesystem persistence",
|
||||
]
|
||||
idx_to_backend = {0: "local", 1: "docker", 2: "modal", 3: "ssh", 4: "daytona", 5: "vercel_sandbox"}
|
||||
backend_to_idx = {"local": 0, "docker": 1, "modal": 2, "ssh": 3, "daytona": 4, "vercel_sandbox": 5}
|
||||
idx_to_backend = {0: "local", 1: "docker", 2: "modal", 3: "ssh", 4: "daytona"}
|
||||
backend_to_idx = {"local": 0, "docker": 1, "modal": 2, "ssh": 3, "daytona": 4}
|
||||
|
||||
next_idx = 6
|
||||
next_idx = 5
|
||||
if is_linux:
|
||||
terminal_choices.append("Singularity/Apptainer - HPC-friendly container")
|
||||
idx_to_backend[next_idx] = "singularity"
|
||||
|
|
@ -1658,39 +1559,6 @@ def setup_terminal_backend(config: dict):
|
|||
|
||||
_prompt_container_resources(config)
|
||||
|
||||
elif selected_backend == "vercel_sandbox":
|
||||
print_success("Terminal backend: Vercel Sandbox")
|
||||
print_info("Cloud microVM sandboxes with snapshot-backed filesystem persistence.")
|
||||
print_info("Requires the optional SDK: pip install 'hermes-agent[vercel]'")
|
||||
|
||||
try:
|
||||
__import__("vercel")
|
||||
except ImportError:
|
||||
print_info("Installing vercel SDK...")
|
||||
import subprocess
|
||||
|
||||
uv_bin = shutil.which("uv")
|
||||
if uv_bin:
|
||||
result = subprocess.run(
|
||||
[uv_bin, "pip", "install", "--python", sys.executable, "vercel"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
else:
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "pip", "install", "vercel"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
print_success("vercel SDK installed")
|
||||
else:
|
||||
print_warning("Install failed — run manually: pip install 'hermes-agent[vercel]'")
|
||||
if result.stderr:
|
||||
print_info(f" Error: {result.stderr.strip().splitlines()[-1]}")
|
||||
|
||||
_prompt_vercel_sandbox_settings(config)
|
||||
|
||||
elif selected_backend == "ssh":
|
||||
print_success("Terminal backend: SSH")
|
||||
print_info("Run commands on a remote machine via SSH.")
|
||||
|
|
@ -1744,8 +1612,6 @@ def setup_terminal_backend(config: dict):
|
|||
save_env_value("TERMINAL_ENV", selected_backend)
|
||||
if selected_backend == "modal":
|
||||
save_env_value("TERMINAL_MODAL_MODE", config["terminal"].get("modal_mode", "auto"))
|
||||
if selected_backend == "vercel_sandbox":
|
||||
save_env_value("TERMINAL_VERCEL_RUNTIME", config["terminal"].get("vercel_runtime", "node24"))
|
||||
save_config(config)
|
||||
print()
|
||||
print_success(f"Terminal backend set to: {selected_backend}")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue