Files
free-ide-proxy/AGENTS.md
T
renato97 0a4289cafc Initial commit: OpenCode Zen Proxy
Proxy translating OpenAI/Anthropic Messages API to OpenCode Zen's free models.
Pure stdlib Go 1.22, no external dependencies.

- OpenAI Chat Completions (/v1/chat/completions) with streaming
- Anthropic Messages API (/v1/messages) with streaming
- Model aliases for 5 free models
- Auth middleware support
- Session rotation (30min per user key)
2026-06-25 11:49:11 -03:00

4.2 KiB

OpenCode Zen Proxy

Proxy translating OpenAI and Anthropic Messages API requests to OpenCode Zen's free model API.

Build & Run

go build -o opencode-proxy .
./opencode-proxy                     # no auth
./opencode-proxy -api-key "secret"   # with auth

Auth reads OPENCODE_PROXY_KEY env var; -api-key flag takes precedence. Defaults: 127.0.0.1:6446. Use -host 0.0.0.0 for external access.

Architecture

Client → internal/server/ (HTTP, auth, routing) → internal/proxy/ (model resolve, session mgmt, forwarding, Anthropic↔OpenAI conversion) → opencode.ai/zen/v1
  • Pure stdlib Go 1.22 — no router, no deps beyond stdlib
  • Entrypoint: main.go wires proxy.NewProxy(key) into server.NewServer(p)
  • Auth middleware in server.go:88 checks Authorization: Bearer or x-api-key header
  • Model aliases in internal/proxy/models.go:59 — short names, company names, and Claude model names → full IDs
  • Session rotation: session IDs rotate every 30 min per user key (proxy.SessionID() at models.go:154)
  • Pass-through: unknown model names are forwarded as-is, not rejected

Endpoints

Method Path Description
GET /health Health check (returns hardcoded "1.0.0")
GET /v1/models List available free models (auth required if key set)
GET /v1/models/{id} Single model detail
POST /v1/chat/completions OpenAI Chat Completions (streaming + non-streaming)
POST /v1/messages Anthropic Messages API
POST /v1/v1/messages Same as above — workaround for Claude Code double-path bug

Anthropic Messages API

Fully implemented in internal/proxy/anthropic.go. Converts Anthropic → OpenAI format upstream, then converts responses back to Anthropic SSE (streaming) or JSON (non-streaming).

Claude Code quirk: Claude Code appends /v1/messages to ANTHROPIC_BASE_URL automatically. Set ANTHROPIC_BASE_URL to http://127.0.0.1:6446 (without /v1 suffix) to avoid double-path. The proxy also handles /v1/v1/messages as a fallback (server.go:62).

Claude model name aliases are defined in models.go:77-88 — Claude Code validates model names client-side, so you must set ANTHROPIC_MODEL to a valid Claude name like claude-sonnet-4-6 (maps to deepseek-v4-flash-free).

Available Models (from models.go)

Model ID Aliases Context Max Output
deepseek-v4-flash-free deepseek, deepseek-v4, ds 1M 384K
big-pickle pickle 200K 32K
mimo-v2.5-free mimo, mimo-v2.5, xiaomi 1M 32K
north-mini-code-free north, north-mini, cohere 256K 64K
nemotron-3-ultra-free nemotron, nemotron-3, nvidia 1M 16K

Source of truth is models.go, not README.md. The README may list models that differ from the code (e.g. minimax-m2.5-free, kimi-k2.5-free, gpt-5-nano, nemotron-3-super-free, qwen3.6-plus-free are NOT in the code). The code controls what works.

Quirks & Gotchas

  • No tests exist. Any change is untested unless you add them.
  • No CI/CD, no Makefile, no lint config. All manual.
  • In-memory only. Session state dies on restart. No database.
  • deploy/start-proxy.bat and deploy/CREDENCIALES.md contain a hardcoded API key — do not commit them.
  • opencode-proxy.exe~ in root is a backup artifact; ignore.
  • Upstream Zen API expects x-opencode-request, x-opencode-session, x-opencode-client, x-opencode-project headers (set in proxy.go:107).
  • Server logs request bodies to stdout (truncated to 500 chars in server.go:265-271). Verbose by design.
  • Health endpoint returns hardcoded version "1.0.0" in server.go:126. Update both main.go:12 and server.go:126 when bumping.
  • Upstream timeout: proxy.go:167 sets 10-minute HTTP client timeout — adjust if Zen models are slow on first call.
  • Unknown models are forwarded as-is (models.go:140) — useful when new models appear upstream before code is updated.
  • Reasoning models (DeepSeek, Nemotron) need max_tokens ≥ 500 — first tokens go to reasoning, not visible content.