From 39cf6893b9f7f026ba4c52c6c862b5661b7114a4 Mon Sep 17 00:00:00 2001
From: samson910022
Date: Fri, 11 Sep 2026 05:27:14 +0800
Subject: [PATCH 1/2] docs(readme): trim to principles and cross-link docs
- README EN/zh-CN trimmed to feature brief + minimal usage (2 examples)
- Full env/config/bridge/allowlist details live in docs/configuration.md
- Add bidirectional nav: Root<->Docker<->GettingStarted, Root<->Development<->CONTRIBUTING, Index<->AI_BOT
- Fix zh anchor, docs index self-links, docker-compose inline-code ref
---
CONTRIBUTING.md | 2 +
README.md | 278 ++++---------------------------------
README.zh-CN.md | 296 +++++-----------------------------------
docker-compose.yml | 2 +-
docs/AI_BOT.md | 2 +
docs/README.md | 2 +-
docs/README.zh-CN.md | 4 +-
docs/api-reference.md | 2 +
docs/configuration.md | 2 +
docs/development.md | 4 +
docs/docker.md | 4 +
docs/getting-started.md | 1 +
docs/troubleshooting.md | 1 +
13 files changed, 86 insertions(+), 514 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7302c37..0203ff4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -83,6 +83,8 @@ npm run dev
npm start
```
+See also [Development guide](./docs/development.md) and [Main README](./README.md).
+
## Testing
- Unit tests: `npm run test:unit`
diff --git a/README.md b/README.md
index 9fedb6f..c7caeb6 100644
--- a/README.md
+++ b/README.md
@@ -19,17 +19,17 @@ Turn a local [OpenCode](https://opencode.ai) runtime into an OpenAI-, Anthropic-
| Feature | Description |
|:-----|:-----|
| 🟢 **OpenAI compatible** | `/v1/models`, `/v1/chat/completions`, `/v1/responses` |
-| 🟣 **Anthropic compatible** | `/v1/messages` (with `tool_use` / `thinking` / SSE streaming) |
-| 🔁 **Gemini compatible (thin)** | `POST /v1beta/interactions` (alias `POST /v1/interactions`, text + `google_search` grounding) |
-| 🌐 **Server-side web search** | `/v1/responses` `tools: [{type: "web_search"}]` drives opencode websearch, returns `web_search_call` + honest `url_citation` |
-| 🔑 **Multi-key auth** | `API_KEY` + `OPENCODE_API_KEYS` / `API_KEYS` merge; `Bearer` or `x-api-key`, any match passes; empty means no auth |
-| 🔀 **Free-limit fallback proxy** | Direct-only until a 429 free-limit error engages `OPENCODE_UPSTREAM_PROXIES` (`failover-rr`, cooldown, loopback bypass) |
-| 📡 **Streaming** | Full SSE streaming for Chat Completions, Responses, Messages, and Interactions APIs |
-| 🧠 **Reasoning control** | Supports `reasoning_effort` and `reasoning: { "effort": "high" }` |
-| 🐳 **Docker deploy** | One-command deploy, auto-starts the OpenCode backend |
-| 🛡️ **Tool safety** | Tool calling disabled by default |
-| 🔧 **External tool bridge** | External `tools` from clients are bridged by the proxy into OpenAI-compatible `tool_calls` / `function_call`, without hitting OpenCode built-in tools |
-| 🌐 **Built-in web_fetch passthrough** | When a request carries no `tools` and the feature is explicitly enabled, only the OpenCode built-in `web_fetch` may participate in that request |
+| 🟣 **Anthropic compatible** | `/v1/messages` (`tool_use` / `thinking` / SSE) |
+| 🔁 **Gemini compatible (thin)** | `POST /v1beta/interactions` (alias `POST /v1/interactions`) |
+| 🌐 **Server-side web search** | `web_search` with `web_search_call` + `url_citation` |
+| 🔑 **Multi-key auth** | `API_KEY` + `OPENCODE_API_KEYS` merge; `Bearer` or `x-api-key`; empty skips auth |
+| 🔀 **Fallback proxy** | 429-only `OPENCODE_UPSTREAM_PROXIES` rotation |
+| 📡 **Streaming** | SSE for Chat, Responses, Messages, Interactions |
+| 🧠 **Reasoning control** | `reasoning_effort` / `reasoning: {"effort": "high"}` |
+| 🐳 **Docker deploy** | One-command with auto backend |
+| 🛡️ **Tool safety** | Disabled by default |
+| 🔧 **External tool bridge** | Client `tools` as `tool_calls` / `function_call`, isolated built-ins |
+| 🌐 **Built-in passthrough** | Opt-in `web_fetch` only when no `tools` |
---
@@ -53,7 +53,7 @@ docker compose up -d
curl http://127.0.0.1:10000/health
```
-> The default `docker-compose.yml` does not mount the host project directory into the container, because that would shadow the image's installed `node_modules` and force the container to rely on a host-side `npm install`. For live local-source reload, use a dedicated dev Compose override instead.
+> No host mount by default (keeps container `node_modules` intact); Docker is production, local Node is dev — see [Docker](./docs/docker.md) and [Getting Started](./docs/getting-started.md).
### Node.js (local dev)
@@ -71,6 +71,8 @@ npm run build
npm start
```
+> 📖 Full guide: [Docker Deployment](./docs/docker.md)
+
---
## 💡 Usage Examples
@@ -102,208 +104,19 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
}'
```
-### Chat Completions + external tools
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1/chat/completions \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/big-pickle",
- "messages": [{"role": "user", "content": "Fetch the title of https://example.com"}],
- "tools": [
- {
- "type": "function",
- "function": {
- "name": "web_fetch",
- "description": "Fetch a URL and return its content summary",
- "parameters": {
- "type": "object",
- "properties": {
- "url": {"type": "string"}
- },
- "required": ["url"]
- }
- }
- }
- ]
- }'
-```
-
-### Responses API + external tools (streaming)
-
-```bash
-curl -N -X POST http://127.0.0.1:10000/v1/responses \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "input": "Look up the weather in Tokyo",
- "stream": true,
- "tools": [
- {
- "type": "function",
- "function": {
- "name": "weather_lookup",
- "description": "Look up weather by city",
- "parameters": {
- "type": "object",
- "properties": {
- "city": {"type": "string"},
- "unit": {"type": "string"}
- },
- "required": ["city"]
- }
- }
- }
- ]
- }'
-```
-
-### Messages API (Anthropic compatible)
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1/messages \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "anthropic-version: 2023-06-01" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "max_tokens": 1024,
- "system": "You are a helpful assistant.",
- "messages": [{"role": "user", "content": "Say hi in one sentence"}]
- }'
-```
-
-> You may use `x-api-key: YOUR_API_KEY` instead of `Authorization: Bearer`; `max_tokens` is required; on stream the API returns `message_start/content_block_start/content_block_delta/content_block_stop/message_delta/message_stop` (no `[DONE]`).
-
-### Responses API + web_search grounding
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1/responses \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "input": "What is the latest PostgreSQL release?",
- "tools": [{"type": "web_search"}]
- }'
-```
-
-> `web_search` (also `web_search_preview` / `web_search_*` / `google_search`) is an explicit grant: the proxy drives the opencode built-in `websearch` and returns `web_search_call` + `url_citation` annotations only for sources actually cited (no fabrication). `web_search` on chat/messages is rejected with 400 + a pointer to this endpoint.
-
-### Interactions API (Gemini-compatible thin layer)
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1beta/interactions \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "input": "What is the latest PostgreSQL release?",
- "tools": [{"type": "google_search"}]
- }'
-```
-
-> Alias `POST /v1/interactions`; supports `system_instruction`, `previous_interaction_id`, `store: false` (ephemeral), and SSE (`interaction.created` / `step.delta` / `interaction.completed`, no `[DONE]`). Client-executed function tools are rejected with 400 — use `/v1/responses` for those.
-
----
-
-## 📦 Deployment Modes
-
-| Mode | Description | Best for |
-|:-----|:-----|:---------|
-| 🐳 **Docker** | Full stack, auto-starts the OpenCode backend | Production, minimal config |
-| 💻 **Standalone Node** | You manage the backend yourself | Development, custom integrations |
+> More examples: [API Reference](./docs/api-reference.md)
---
## ⚙️ Configuration
-### Quick reference
-
-| Env var | Default | Description |
-|:--------|:-------|:------|
-| `PORT` / `OPENCODE_PROXY_PORT` | `10000` | Proxy listen port |
-| `OPENCODE_SERVER_PORT` | `10001` | OpenCode backend port |
-| `API_KEY` | - | Bearer token secret |
-| `API_KEYS` / `OPENCODE_API_KEYS` | `(none)` | Extra client keys, comma-separated; merged with `API_KEY`, any match passes; empty falls back to no auth |
-| `BIND_HOST` | `0.0.0.0` | Bind address |
-| `DISABLE_TOOLS` | `true` | Disable OpenCode tool calling |
-| `OPENCODE_EXTERNAL_TOOLS_MODE` | `proxy-bridge` | External tool bridge mode; only `proxy-bridge` is supported |
-| `OPENCODE_EXTERNAL_TOOLS_CONFLICT_POLICY` | `namespace` | Conflict isolation for external vs built-in tools; only `namespace` is supported |
-| `OPENCODE_INTERNAL_WEB_FETCH_ENABLED` | `false` | Legacy shortcut; when no allowlist is configured, enabling it defaults the allowlist to `web_fetch` |
-| `OPENCODE_INTERNAL_ALLOWED_TOOLS` | `(none)` | OpenCode built-in tools allowed when a request carries no `tools`, comma-separated |
-| `OPENCODE_INTERNAL_TOOL_METRICS_ENABLED` | `true` | Emit debug/metric logs for internal-allowlist mode |
-| `OPENCODE_TOOL_DISCOVERY_FIXTURE` | `(none)` | Fixed backend tool-ID list for integration tests / local debugging, comma-separated |
-| `OPENCODE_HEALTH_DETAILS_ENABLED` | `true` | Whether `/health/details` is exposed |
-| `OPENCODE_HEALTH_DETAILS_REQUIRE_AUTH` | `true` | Whether `/health/details` requires Bearer auth |
-| `OPENCODE_METRICS_ENABLED` | `false` | Whether `/metrics` is exposed |
-| `OPENCODE_METRICS_REQUIRE_AUTH` | `true` | Whether `/metrics` requires Bearer auth |
-| `OPENCODE_USE_ISOLATED_HOME` | `false` | Use an isolated OpenCode config directory (`USE_ISOLATED_HOME` in `config.json`) |
-| `OPENCODE_PROXY_PROMPT_MODE` | `standard` | Prompt handling mode |
-| `OPENCODE_PROXY_OMIT_SYSTEM_PROMPT` | `false` | Drop the incoming system prompt |
-| `OPENCODE_PROXY_AUTO_CLEANUP_CONVERSATIONS` | `false` | Auto-clean conversation storage |
-| `OPENCODE_PROXY_CLEANUP_INTERVAL_MS` | `43200000` | Cleanup interval (ms) |
-| `OPENCODE_PROXY_CLEANUP_MAX_AGE_MS` | `86400000` | Max retention (ms) |
-| `OPENCODE_PROXY_REQUEST_TIMEOUT_MS` | `180000` | Request timeout (ms) |
-| `OPENCODE_PROXY_RETRY_MAX_RETRIES` | `3` | Retries after the first attempt (0-5, total attempts 1+n; exponential backoff+jitter, honors `retry-after`) |
-| `OPENCODE_UPSTREAM_PROXIES` | `(none)` | Fallback proxy URLs, comma-separated (`socks5://` preferred, `http(s)://` ok; file key `UPSTREAM_PROXIES`) |
-| `OPENCODE_UPSTREAM_PROXY_STRATEGY` | `failover-rr` | `failover-rr` / `round-robin` (aliases) / `random`; rotates on consecutive free-limit 429s |
-| `OPENCODE_UPSTREAM_PROXY_COOLDOWN_MS` | `300000` | How long an engaged proxy sticks before returning to direct (ms) |
-| `OPENCODE_UPSTREAM_PROXY_NO_PROXY` | `localhost,127.0.0.1,::1` | Target hosts that never use the proxy (backend `127.0.0.1` always direct) |
-| `OPENCODE_SERVER_URL` | `http://127.0.0.1:10001` | OpenCode backend address |
-| `OPENCODE_SERVER_PASSWORD` | - | OpenCode backend password |
-| `OPENCODE_PATH` | `opencode` | OpenCode binary path |
-| `OPENCODE_ZEN_API_KEY` | - | Zen API key passthrough |
-| `OPENCODE_PROXY_DEBUG` | `false` | Debug logs (`DEBUG` in `config.json`) |
+- Base: `API_KEY`, `OPENCODE_SERVER_PASSWORD`, `OPENCODE_SERVER_URL`, `OPENCODE_PROXY_PORT` (`PORT`).
+- Tool safety: `DISABLE_TOOLS=true` default; external `tools` bridged/isolated, built-ins disabled unless allowlisted.
+- Observability: `/health/details` and `/metrics` with configurable exposure/auth.
+- Timeout & retry: `OPENCODE_PROXY_REQUEST_TIMEOUT_MS`, `OPENCODE_PROXY_RETRY_MAX_RETRIES`; `OPENCODE_UPSTREAM_PROXIES` only on 429.
> 📄 Full reference: [Configuration](./docs/configuration.md)
-### Recommended production config
-
-```env
-API_KEY=your-secret-key
-OPENCODE_SERVER_PASSWORD=your-password
-DISABLE_TOOLS=true
-OPENCODE_EXTERNAL_TOOLS_MODE=proxy-bridge
-OPENCODE_EXTERNAL_TOOLS_CONFLICT_POLICY=namespace
-OPENCODE_INTERNAL_ALLOWED_TOOLS=web_fetch
-OPENCODE_INTERNAL_TOOL_METRICS_ENABLED=true
-OPENCODE_TOOL_DISCOVERY_FIXTURE=
-OPENCODE_HEALTH_DETAILS_ENABLED=true
-OPENCODE_HEALTH_DETAILS_REQUIRE_AUTH=true
-OPENCODE_METRICS_ENABLED=false
-OPENCODE_METRICS_REQUIRE_AUTH=true
-OPENCODE_PROXY_PROMPT_MODE=plugin-inject
-OPENCODE_PROXY_OMIT_SYSTEM_PROMPT=true
-OPENCODE_PROXY_AUTO_CLEANUP_CONVERSATIONS=true
-```
-
-### External tool bridge
-
-- External `tools` sent by clients are never registered as OpenCode built-in tools.
-- The proxy virtualizes them for the model and reshapes model output into OpenAI-compatible `tool_calls` / `function_call`.
-- Same-name conflicts are isolated via an internal namespace (e.g. a client-side `web_fetch` never triggers the in-container OpenCode tool).
-- Internal namespace names (e.g. `external__web_fetch`) are proxy implementation details, not public API.
-
-### Built-in tool allowlist
-
-- When a request carries **no** `tools`, the proxy enters internal-allowlist mode and only enables the OpenCode built-in tools listed in `OPENCODE_INTERNAL_ALLOWED_TOOLS`.
-- `OPENCODE_INTERNAL_WEB_FETCH_ENABLED=true` is only a legacy shortcut: when `OPENCODE_INTERNAL_ALLOWED_TOOLS` is unset, the allowlist defaults to `web_fetch`.
-- The proxy reads the backend tool list and resolves the final set via exact or `.` / `/` suffix match.
-- If nothing in the allowlist matches the backend tool list, the proxy falls back to the safe mode with all built-in tools disabled.
-- With `OPENCODE_INTERNAL_TOOL_METRICS_ENABLED=true`, the proxy logs internal-allowlist debug/metric info (mode selection, backend discovery, allowlist hits, downgrade reasons) without logging tool outputs.
-- `OPENCODE_TOOL_DISCOVERY_FIXTURE` bypasses the real `client.tool.ids()` with a fixed tool-ID list for integration tests / local debugging.
-- Once a client explicitly passes `tools`, the request returns to the external-tool bridge path and OpenCode built-in tools stay disabled.
-
-### Structured diagnostics & Prometheus metrics
-
-- `/health` stays a lightweight health check.
-- `/health/details` returns structured JSON diagnostics; exposure via `OPENCODE_HEALTH_DETAILS_ENABLED`, auth via `OPENCODE_HEALTH_DETAILS_REQUIRE_AUTH`.
-- `/metrics` returns Prometheus text metrics; exposure via `OPENCODE_METRICS_ENABLED`, auth via `OPENCODE_METRICS_REQUIRE_AUTH`.
-- `/metrics` currently exposes internal tool mode, tool discovery failures, fallback counts, and tool-ID cache size.
-
---
## 🔌 API Reference
@@ -324,32 +137,17 @@ OPENCODE_PROXY_AUTO_CLEANUP_CONVERSATIONS=true
### Protocol fidelity
-Use the endpoint native to your client (OpenAI SDKs → `/v1/chat/completions` or `/v1/responses`, Anthropic SDKs → `/v1/messages`, Gemini SDKs → `/v1beta/interactions`). Cross-protocol conversion is best-effort and only wired where documented (currently `POST /v1/messages` inbound): non-native paths may drop or zero-fill tool deltas, thinking signatures, token usage, and truncation signals (see [Architecture](./docs/architecture.md#5-nn-translator-registry-srcconverters)). If output looks wrong, first reproduce on the native endpoint and rule out backend flakiness (retry, check `/health/details`); if it persists, file an issue with a minimal repro (see [Troubleshooting](./docs/troubleshooting.md)).
+Use each client's native endpoint; cross-protocol conversion is best-effort — see [Architecture](./docs/architecture.md) and [Troubleshooting](./docs/troubleshooting.md).
### Model name formats
-- Direct: `opencode/big-pickle`
-- Aliased: `gpt5-nano` (auto-resolved to `gpt-5-nano`)
-- Prefixed: `opencode/gpt5-nano`
-
-> 📖 See [API Reference](./docs/api-reference.md)
+Formats: `opencode/big-pickle`, `gpt5-nano` (auto-resolved) and `opencode/gpt5-nano` — see [API Reference](./docs/api-reference.md).
---
## 🔧 Troubleshooting
-### Requests hang but `/v1/models` works
-```bash
-OPENCODE_USE_ISOLATED_HOME=false # Let OpenCode reuse the local login state
-```
-
-### Model not found
-- List models: `curl http://127.0.0.1:10000/v1/models`
-- Confirm the model ID matches exactly
-
-### No reasoning output
-- Use the Responses API with `stream: true`
-- Send `reasoning.effort` or `reasoning_effort`
+Hangs: try `OPENCODE_USE_ISOLATED_HOME=false`. Missing model: check `/v1/models`. No reasoning: use Responses API with `stream: true`.
> 📖 Full guide: [Troubleshooting](./docs/troubleshooting.md)
@@ -358,26 +156,15 @@ OPENCODE_USE_ISOLATED_HOME=false # Let OpenCode reuse the local login state
## 🔨 Development
```bash
-# Typecheck (tsc --noEmit)
-npm run typecheck
-
-# Build (tsc -> dist/, entry dist/index.js)
-npm run build
-
-# Local dev (tsx watch, source entry index.ts)
-npm run dev
-
-# Production start (run build output)
-npm start
-
-# Run tests
+npm run typecheck # tsc --noEmit
+npm run build # tsc -> dist/
+npm run dev # tsx watch index.ts
+npm start # node dist/index.js
npm test -- --runInBand
-
-# Docker dev
-docker compose up -d --build
+docker compose up -d --build # Docker dev
```
-> TypeScript sources: `index.ts` + `src/**/*.ts`; build output: `dist/` (`dist/index.js` is the runtime entry; local `dist/` is not committed and stays out of the Docker context).
+> 📖 Full guide: [Development](./docs/development.md) · 🤝 [CONTRIBUTING](./CONTRIBUTING.md)
---
@@ -389,11 +176,6 @@ MIT · See [LICENSE](./LICENSE.md)
## 🙏 Acknowledgments
-This project is independently maintained at [samson910022/OpenCode2API](https://github.com/samson910022/OpenCode2API),
-forked from [TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api) and inspired by
-[dxxzst/opencode-to-openai](https://github.com/dxxzst/opencode-to-openai) and
-[lucasliet/opencode-openai-proxy](https://github.com/lucasliet/opencode-openai-proxy).
+Maintained at [samson910022/OpenCode2API](https://github.com/samson910022/OpenCode2API), forked from [TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api)
+and inspired by [dxxzst/opencode-to-openai](https://github.com/dxxzst/opencode-to-openai) and [lucasliet/opencode-openai-proxy](https://github.com/lucasliet/opencode-openai-proxy).
Upstream code remains under its original MIT license; see [LICENSE](./LICENSE.md).
-
-本项目由 [samson910022/OpenCode2API](https://github.com/samson910022/OpenCode2API) 独立维护,复刻(Fork)自
-[TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api);另受以下开源项目启发:[dxxzst/opencode-to-openai](https://github.com/dxxzst/opencode-to-openai)、[lucasliet/opencode-openai-proxy](https://github.com/lucasliet/opencode-openai-proxy)。中文版见 [README.zh-CN.md](./README.zh-CN.md)。
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 347b278..67cda1b 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -6,9 +6,9 @@
-> **語言:** [English](./README.md) | [简体中文](./README.zh-CN.md)
+> **语言:** [English](./README.md) | [简体中文](./README.zh-CN.md)
>
-> 📖 [文档](./docs/README.zh-CN.md)([English index](./docs/README.md)) | 🚀 [快速开始](#-快速开始) | 🐛 [Issues](https://github.com/samson910022/OpenCode2API/issues)
+> 📖 [文档](./docs/README.zh-CN.md) | 🚀 [快速开始](#快速开始) | 🐛 [Issues](https://github.com/samson910022/OpenCode2API/issues)
将本地 [OpenCode](https://opencode.ai) 运行时转换为 OpenAI、Anthropic 与 Gemini 兼容 API 网关。在任何 OpenAI、Anthropic 或 Gemini 客户端中使用免费模型(Big Pickle、Ling、MiMo、Muse Spark、Nemotron)——免费阵容会轮换,以 `/v1/models` 实时列表为准。
@@ -19,17 +19,17 @@
| 特性 | 说明 |
|:-----|:-----|
| 🟢 **OpenAI 兼容** | `/v1/models`, `/v1/chat/completions`, `/v1/responses` |
-| 🟣 **Anthropic 兼容** | `/v1/messages`(含 `tool_use` / `thinking` / SSE 流式) |
-| 🔁 **Gemini 兼容(薄层)** | `POST /v1beta/interactions`(别名 `POST /v1/interactions`,文本 + `google_search` 联网) |
-| 🌐 **服务端联网搜索** | `/v1/responses` 的 `tools: [{type: "web_search"}]` 驱动 opencode websearch,返回 `web_search_call` + 诚实 `url_citation` |
-| 🔑 **多 Key 认证** | `API_KEY` 与 `OPENCODE_API_KEYS` / `API_KEYS` 合并;`Bearer` 或 `x-api-key` 任一通过;为空回退免认证 |
-| 🔀 **免费限流 fallback 代理** | 默认直连,仅 429 免费限流错误时启用 `OPENCODE_UPSTREAM_PROXIES`(`failover-rr`、cooldown、回环 bypass) |
-| 📡 **流式输出** | Chat Completions、Responses、Messages 与 Interactions API 的完整 SSE 流式支持 |
-| 🧠 **推理控制** | 支持 `reasoning_effort` 和 `reasoning: { "effort": "high" }` |
-| 🐳 **Docker 部署** | 一键部署,自动启动 OpenCode 后端 |
+| 🟣 **Anthropic 兼容** | `/v1/messages`(`tool_use` / `thinking` / SSE) |
+| 🔁 **Gemini 兼容(薄层)** | `POST /v1beta/interactions`(别名 `POST /v1/interactions`) |
+| 🌐 **服务端联网搜索** | `web_search`,返回 `web_search_call` + `url_citation` |
+| 🔑 **多 Key 认证** | `API_KEY` 与 `OPENCODE_API_KEYS` 合并;`Bearer` 或 `x-api-key`;为空免认证 |
+| 🔀 **免费限流 fallback 代理** | 仅 429 时轮换 `OPENCODE_UPSTREAM_PROXIES` |
+| 📡 **流式输出** | Chat、Responses、Messages、Interactions 全支持 SSE |
+| 🧠 **推理控制** | `reasoning_effort` / `reasoning: {"effort": "high"}` |
+| 🐳 **Docker 部署** | 一键部署,自动启动后端 |
| 🛡️ **工具安全** | 默认禁用工具调用 |
-| 🔧 **外部工具桥接** | 支持外部客户端传入 `tools`,由代理桥接为 OpenAI-compatible `tool_calls` / `function_call`,避免命中 OpenCode 内置工具 |
-| 🌐 **内置 web_fetch 透传** | 当请求未传入 `tools` 且显式开启特性时,仅允许 OpenCode 内置 `web_fetch` 参与该次请求 |
+| 🔧 **外部工具桥接** | 外部 `tools` 桥接为 `tool_calls` / `function_call`,隔离内置工具 |
+| 🌐 **内置 web_fetch 透传** | 无 `tools` 且显式开启时,仅放行内置 `web_fetch` |
---
@@ -53,7 +53,7 @@ docker compose up -d
curl http://127.0.0.1:10000/health
```
-> 默认 `docker-compose.yml` 不会把宿主机项目目录挂载到容器内,因为那会覆盖镜像里已安装的 `node_modules`,导致容器依赖宿主机先执行 `npm install`。如果你需要本地源码热更新,建议单独使用开发专用的 Compose 覆盖配置。
+> 默认不挂载宿主机目录以避免覆盖容器内 `node_modules`;Docker 面向生产、本地 Node 面向开发——详见 [Docker 部署](./docs/docker.md) 与 [快速开始](./docs/getting-started.md)。
### Node.js (本地开发)
@@ -71,6 +71,8 @@ npm run build
npm start
```
+> 📖 完整指南:[Docker 部署](./docs/docker.md)
+
---
## 💡 使用示例
@@ -102,208 +104,18 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
}'
```
-### Chat Completions + 外部工具
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1/chat/completions \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/big-pickle",
- "messages": [{"role": "user", "content": "帮我获取 https://example.com 的标题"}],
- "tools": [
- {
- "type": "function",
- "function": {
- "name": "web_fetch",
- "description": "Fetch a URL and return its content summary",
- "parameters": {
- "type": "object",
- "properties": {
- "url": {"type": "string"}
- },
- "required": ["url"]
- }
- }
- }
- ]
- }'
-```
-
-### Responses API + 外部工具流式
-
-```bash
-curl -N -X POST http://127.0.0.1:10000/v1/responses \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "input": "查询东京天气",
- "stream": true,
- "tools": [
- {
- "type": "function",
- "function": {
- "name": "weather_lookup",
- "description": "Look up weather by city",
- "parameters": {
- "type": "object",
- "properties": {
- "city": {"type": "string"},
- "unit": {"type": "string"}
- },
- "required": ["city"]
- }
- }
- }
- ]
- }'
-```
-
-### Messages API (Anthropic 兼容)
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1/messages \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "anthropic-version: 2023-06-01" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "max_tokens": 1024,
- "system": "You are a helpful assistant.",
- "messages": [{"role": "user", "content": "用一句话打招呼"}]
- }'
-```
-
-> 也可用 `x-api-key: YOUR_API_KEY` 代替 `Authorization: Bearer`;`max_tokens` 必填;流式时返回 `message_start/content_block_start/content_block_delta/content_block_stop/message_delta/message_stop`(无 `[DONE]`)。
-
-### Responses API + 联网搜索
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1/responses \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "input": "PostgreSQL 最新版本是多少?",
- "tools": [{"type": "web_search"}]
- }'
-```
-
-> `web_search`(亦接受 `web_search_preview` / `web_search_*` / `google_search`)是显式授权:代理驱动 opencode 内置 `websearch`,返回 `web_search_call` + 仅标注实际引用来源的 `url_citation`(无编造)。chat/messages 传入 `web_search` 会 400 并指引到此端点。
-
-### Interactions API(Gemini 兼容薄层)
-
-```bash
-curl -X POST http://127.0.0.1:10000/v1beta/interactions \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "opencode/muse-spark-1.3-contributor-free",
- "input": "PostgreSQL 最新版本是多少?",
- "tools": [{"type": "google_search"}]
- }'
-```
-
-> 别名 `POST /v1/interactions`;支持 `system_instruction`、`previous_interaction_id`、`store: false`(不持久化)与 SSE(`interaction.created` / `step.delta` / `interaction.completed`,无 `[DONE]`)。客户端执行的 function 工具会被 400 拒绝——请改用 `/v1/responses`。
-
----
-
-## 📦 部署方式
-
-| 模式 | 说明 | 适用场景 |
-|:-----|:-----|:---------|
-| 🐳 **Docker** | 完整栈,自动启动 OpenCode 后端 | 生产环境,最简配置 |
-| 💻 **独立 Node** | 手动管理后端 | 开发、自定义集成 |
+> 更多示例:[API 参考](./docs/api-reference.md)
---
## ⚙️ 配置
-### 快速参考
-
-| 环境变量 | 默认值 | 说明 |
-|:--------|:-------|:------|
-| `PORT` / `OPENCODE_PROXY_PORT` | `10000` | 代理服务端口 |
-| `OPENCODE_SERVER_PORT` | `10001` | OpenCode 后端服务端口 |
-| `API_KEY` | - | Bearer Token 认证密钥 |
-| `API_KEYS` / `OPENCODE_API_KEYS` | `(none)` | 额外客户端 keys,逗号分隔;与 `API_KEY` 合并,任一通过;为空回退免认证 |
-| `BIND_HOST` | `0.0.0.0` | 绑定地址 |
-| `DISABLE_TOOLS` | `true` | 禁用 OpenCode 工具调用 |
-| `OPENCODE_EXTERNAL_TOOLS_MODE` | `proxy-bridge` | 外部工具桥接模式;当前仅支持 `proxy-bridge` |
-| `OPENCODE_EXTERNAL_TOOLS_CONFLICT_POLICY` | `namespace` | 外部工具与 OpenCode 内置工具的冲突隔离策略;当前仅支持 `namespace` |
-| `OPENCODE_INTERNAL_WEB_FETCH_ENABLED` | `false` | 兼容旧开关;当未显式配置 allowlist 时,启用后默认放行 `web_fetch` |
-| `OPENCODE_INTERNAL_ALLOWED_TOOLS` | `(none)` | 当请求未传入 `tools` 时,允许使用的 OpenCode 内置工具列表,逗号分隔 |
-| `OPENCODE_INTERNAL_TOOL_METRICS_ENABLED` | `true` | 输出 internal allowlist 模式的调试/指标日志 |
-| `OPENCODE_TOOL_DISCOVERY_FIXTURE` | `(none)` | 集成测试/本地调试用的后端工具 ID 固定列表,逗号分隔 |
-| `OPENCODE_HEALTH_DETAILS_ENABLED` | `true` | 控制 `/health/details` 是否暴露 |
-| `OPENCODE_HEALTH_DETAILS_REQUIRE_AUTH` | `true` | 控制 `/health/details` 是否要求 Bearer 认证 |
-| `OPENCODE_METRICS_ENABLED` | `false` | 控制 `/metrics` 是否暴露 |
-| `OPENCODE_METRICS_REQUIRE_AUTH` | `true` | 控制 `/metrics` 是否要求 Bearer 认证 |
-| `OPENCODE_USE_ISOLATED_HOME` | `false` | 使用隔离的 OpenCode 配置目录(`config.json` 中用短键 `USE_ISOLATED_HOME`) |
-| `OPENCODE_PROXY_PROMPT_MODE` | `standard` | 提示词处理模式 |
-| `OPENCODE_PROXY_OMIT_SYSTEM_PROMPT` | `false` | 忽略传入的 system prompt |
-| `OPENCODE_PROXY_AUTO_CLEANUP_CONVERSATIONS` | `false` | 自动清理会话存储 |
-| `OPENCODE_PROXY_CLEANUP_INTERVAL_MS` | `43200000` | 清理间隔 (毫秒) |
-| `OPENCODE_PROXY_CLEANUP_MAX_AGE_MS` | `86400000` | 最大存储时间 (毫秒) |
-| `OPENCODE_PROXY_REQUEST_TIMEOUT_MS` | `180000` | 请求超时时间 (毫秒) |
-| `OPENCODE_PROXY_RETRY_MAX_RETRIES` | `3` | 首次失败后重试次数 (0-5,总尝试 1+n;退避指数+jitter 并优先 `retry-after`) |
-| `OPENCODE_UPSTREAM_PROXIES` | `(none)` | Fallback 代理 URL,逗号分隔(`socks5://` 优先,`http(s)://` 可用;`config.json` 用短键 `UPSTREAM_PROXIES`) |
-| `OPENCODE_UPSTREAM_PROXY_STRATEGY` | `failover-rr` | `failover-rr` / `round-robin`(别名)/ `random`;连续免费限流即轮换下一个 |
-| `OPENCODE_UPSTREAM_PROXY_COOLDOWN_MS` | `300000` | 代理粘滞时长(毫秒),到期回直连 |
-| `OPENCODE_UPSTREAM_PROXY_NO_PROXY` | `localhost,127.0.0.1,::1` | 永不走代理的目标 host(后端 `127.0.0.1` 恒直连) |
-| `OPENCODE_SERVER_URL` | `http://127.0.0.1:10001` | OpenCode 后端地址 |
-| `OPENCODE_SERVER_PASSWORD` | - | OpenCode 后端密码 |
-| `OPENCODE_PATH` | `opencode` | OpenCode 可执行文件路径 |
-| `OPENCODE_ZEN_API_KEY` | - | Zen API Key 透传 |
-| `OPENCODE_PROXY_DEBUG` | `false` | 调试日志(`config.json` 中用短键 `DEBUG`) |
-
-> 📄 完整配置参考: [配置详解](./docs/configuration.md)
-
-### 推荐生产配置
-
-```env
-API_KEY=your-secret-key
-OPENCODE_SERVER_PASSWORD=your-password
-DISABLE_TOOLS=true
-OPENCODE_EXTERNAL_TOOLS_MODE=proxy-bridge
-OPENCODE_EXTERNAL_TOOLS_CONFLICT_POLICY=namespace
-OPENCODE_INTERNAL_ALLOWED_TOOLS=web_fetch
-OPENCODE_INTERNAL_TOOL_METRICS_ENABLED=true
-OPENCODE_TOOL_DISCOVERY_FIXTURE=
-OPENCODE_HEALTH_DETAILS_ENABLED=true
-OPENCODE_HEALTH_DETAILS_REQUIRE_AUTH=true
-OPENCODE_METRICS_ENABLED=false
-OPENCODE_METRICS_REQUIRE_AUTH=true
-OPENCODE_PROXY_PROMPT_MODE=plugin-inject
-OPENCODE_PROXY_OMIT_SYSTEM_PROMPT=true
-OPENCODE_PROXY_AUTO_CLEANUP_CONVERSATIONS=true
-```
-
-
-### 外部工具桥接说明
-
-- 外部客户端传入的 `tools` 不会被注册为 OpenCode 内置工具。
-- 代理会把这些工具虚拟化后交给模型使用,并把模型输出重新整理为 OpenAI-compatible `tool_calls` / `function_call`。
-- 同名冲突默认通过内部命名空间隔离处理,例如客户端的 `web_fetch` 不会误触发 OpenCode 容器内工具。
-- 内部命名空间名(如 `external__web_fetch`)是代理内部实现细节,不属于公开 API。
+- 基础:`API_KEY`、`OPENCODE_SERVER_PASSWORD`、`OPENCODE_SERVER_URL`、`OPENCODE_PROXY_PORT`(`PORT`)。
+- 工具安全:默认 `DISABLE_TOOLS=true`;外部 `tools` 经桥接隔离,内置工具默认禁用,按需 allowlist 放行。
+- 可观测性:`/health/details` 与 `/metrics` 均可配置开关与鉴权。
+- 超时与重试:`OPENCODE_PROXY_REQUEST_TIMEOUT_MS`、`OPENCODE_PROXY_RETRY_MAX_RETRIES`;仅 429 时启用 `OPENCODE_UPSTREAM_PROXIES`。
-### 内置工具 allowlist 说明
-
-- 当请求 **未传入** `tools` 时,代理会进入 internal allowlist 模式,并只允许 `OPENCODE_INTERNAL_ALLOWED_TOOLS` 中声明的 OpenCode 内置工具。
-- `OPENCODE_INTERNAL_WEB_FETCH_ENABLED=true` 仅作为兼容旧配置的快捷方式:当未显式配置 `OPENCODE_INTERNAL_ALLOWED_TOOLS` 时,会默认把 allowlist 视为 `web_fetch`。
-- 代理会读取后端工具列表,并通过精确匹配或 `.` / `/` 后缀匹配解析最终可用工具。
-- 如果配置的 allowlist 在后端工具列表中一个也匹配不到,代理会自动回退到“全部内置工具禁用”的安全模式。
-- `OPENCODE_INTERNAL_TOOL_METRICS_ENABLED=true` 时,代理会输出 internal allowlist 模式的调试/指标日志,包括模式选择、后端工具发现、allowlist 命中结果和降级原因,但不会记录工具返回内容。
-- `OPENCODE_TOOL_DISCOVERY_FIXTURE` 可用于集成测试或本地调试,绕过真实 `client.tool.ids()` 返回固定工具 ID 列表。
-- 一旦客户端显式传入 `tools`,请求立即回到现有外部工具桥接逻辑,OpenCode 内置工具继续保持禁用。
-
-### 结构化诊断与 Prometheus 指标
-
-- `/health` 始终保持为轻量健康检查接口。
-- `/health/details` 返回结构化 JSON 诊断数据,可通过 `OPENCODE_HEALTH_DETAILS_ENABLED` 控制是否暴露,并通过 `OPENCODE_HEALTH_DETAILS_REQUIRE_AUTH` 控制是否要求 Bearer 认证。
-- `/metrics` 返回 Prometheus 文本格式指标,可通过 `OPENCODE_METRICS_ENABLED` 控制是否暴露,并通过 `OPENCODE_METRICS_REQUIRE_AUTH` 控制是否要求 Bearer 认证。
-- `/metrics` 目前暴露 internal tool mode、tool discovery failures、fallback count 和 tool-id cache 数量等指标。
+> 📄 完整配置参考:[配置详解](./docs/configuration.md)
---
@@ -325,60 +137,34 @@ OPENCODE_PROXY_AUTO_CLEANUP_CONVERSATIONS=true
### 协议保真度
-请使用与客户端原生对应的端点(OpenAI SDK → `/v1/chat/completions` 或 `/v1/responses`,Anthropic SDK → `/v1/messages`,Gemini SDK → `/v1beta/interactions`)。跨协议转换是 best-effort,且仅在已接线处生效(目前为 `POST /v1/messages` 入站):非原生路径可能丢失或零填充工具增量、thinking 签名、token 用量与截断信号(见 [Architecture](./docs/architecture.md#5-nn-translator-registry-srcconverters))。若输出异常,请先在原生端点复现并排除后端波动(重试、检查 `/health/details`);确认存在后再附最小复现提 issue(见 [故障排查](./docs/troubleshooting.md))。
+请使用与客户端原生对应的端点,跨协议转换为 best-effort(详见 [架构](./docs/architecture.md) 与 [故障排查](./docs/troubleshooting.md))。
### 模型名称格式
-- 直接使用: `opencode/big-pickle`
-- 带别名: `gpt5-nano` (自动解析为 `gpt-5-nano`)
-- 带前缀: `opencode/gpt5-nano`
-
-> 📖 详见 [API 参考文档](./docs/api-reference.md)
+支持 `opencode/big-pickle`、`gpt5-nano`(自动解析)与 `opencode/gpt5-nano`;详见 [API 参考文档](./docs/api-reference.md)。
---
## 🔧 故障排查
-### 请求卡住但 `/v1/models` 正常
-```bash
-OPENCODE_USE_ISOLATED_HOME=false # 让 OpenCode 复用本地登录态
-```
-
-### 模型找不到
-- 查看可用模型: `curl http://127.0.0.1:10000/v1/models`
-- 确认模型 ID 完全匹配
-
-### 没有推理输出
-- 使用 `stream: true` 的 Responses API
-- 发送 `reasoning.effort` 或 `reasoning_effort`
+卡住:试 `OPENCODE_USE_ISOLATED_HOME=false`。模型缺失:检查 `/v1/models`。无推理:用 `stream: true` 的 Responses API。
-> 📖 完整指南: [故障排查](./docs/troubleshooting.md)
+> 📖 完整指南:[故障排查](./docs/troubleshooting.md)
---
## 🔨 开发
```bash
-# 类型检查(tsc --noEmit)
-npm run typecheck
-
-# 构建(tsc -> dist/,入口 dist/index.js)
-npm run build
-
-# 本地开发(tsx watch,源码入口 index.ts)
-npm run dev
-
-# 生产启动(运行构建产物)
-npm start
-
-# 运行测试
-npm test -- --runInBand
-
-# Docker 开发
-docker compose up -d --build
+npm run typecheck # 类型检查
+npm run build # 构建到 dist/
+npm run dev # 本地开发
+npm start # node dist/index.js
+npm test -- --runInBand # 测试
+docker compose up -d --build # Docker 开发
```
-> TypeScript 源码:`index.ts` + `src/**/*.ts`;构建产物:`dist/`(`dist/index.js` 为运行时入口,本地 `dist/` 不进 git/docker context)。
+> 📖 完整指南:[开发指南](./docs/development.md) · 🤝 [CONTRIBUTING](./CONTRIBUTING.md)
---
@@ -388,20 +174,6 @@ MIT · 详见 [LICENSE](./LICENSE.md)
---
-## 🙏 致谢 / Acknowledgments
-
-本项目由 [samson910022/OpenCode2API](https://github.com/samson910022/OpenCode2API) 独立维护,复刻(Fork)自
-[TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api):
-
-- [TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api) — 直接上游,本项目的起点(MIT)
-
-另受以下开源项目启发:
-
-- [dxxzst/opencode-to-openai](https://github.com/dxxzst/opencode-to-openai) — 早期设计参考(MIT)
-- [lucasliet/opencode-openai-proxy](https://github.com/lucasliet/opencode-openai-proxy) — 早期设计参考(MIT)
+## 🙏 致谢
-This project is independently maintained at [samson910022/OpenCode2API](https://github.com/samson910022/OpenCode2API),
-forked from [TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api) and inspired by
-[dxxzst/opencode-to-openai](https://github.com/dxxzst/opencode-to-openai) and
-[lucasliet/opencode-openai-proxy](https://github.com/lucasliet/opencode-openai-proxy).
-Upstream code remains under its original MIT license; see [LICENSE](./LICENSE.md).
+本项目由 [samson910022/OpenCode2API](https://github.com/samson910022/OpenCode2API) 独立维护,复刻(Fork)自 [TiaraBasori/opencode2api](https://github.com/TiaraBasori/opencode2api),并受 [dxxzst/opencode-to-openai](https://github.com/dxxzst/opencode-to-openai) 与 [lucasliet/opencode-openai-proxy](https://github.com/lucasliet/opencode-openai-proxy) 启发。上游代码保留其原始 MIT 许可;详见 [LICENSE](./LICENSE.md)。
diff --git a/docker-compose.yml b/docker-compose.yml
index 0f94c68..450b79e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -51,7 +51,7 @@ services:
- opencode-config:/home/node/.config/opencode
restart: unless-stopped
# Guard small (1GB) hosts: cap memory/CPU so one slow request cannot wedge
- # the whole machine (see docs/host-deployments.md §9). Raw `docker run`
+ # the whole machine (see `docs/host-deployments.md` §9). Raw `docker run`
# hosts should pass the equivalents: --memory=768m --memory-reservation=256m
# --cpus=1.5 --pids-limit=256.
mem_limit: 768m
diff --git a/docs/AI_BOT.md b/docs/AI_BOT.md
index 7ca2c83..9db9fbe 100644
--- a/docs/AI_BOT.md
+++ b/docs/AI_BOT.md
@@ -1,5 +1,7 @@
# AI Bot (GitHub Actions)
+> 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)
+
In-repo advisory bot for OpenCode2API: issue investigation, multi-agent PR
review, PR explanations, scheduled repo scans with auto-issue, and fix-plan
proposals with opt-in draft PRs.
diff --git a/docs/README.md b/docs/README.md
index af4b0ba..ad2c4af 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -4,7 +4,7 @@
-> **Language:** [English](./README.md) | [简体中文](./README.zh-CN.md) *(per-guide Chinese versions, see Translation status below)*
+> **Language:** **English** | [简体中文](./README.zh-CN.md) *(per-guide Chinese versions, see Translation status below)*
>
> 🏠 [Main README](../README.md) | [简体中文 README](../README.zh-CN.md) | 🐛 [Issues](https://github.com/samson910022/OpenCode2API/issues)
diff --git a/docs/README.zh-CN.md b/docs/README.zh-CN.md
index a10ed61..ef3a083 100644
--- a/docs/README.zh-CN.md
+++ b/docs/README.zh-CN.md
@@ -4,9 +4,9 @@
-> **語言:** [English](./README.md) | [简体中文](./README.zh-CN.md)
+> **语言:** [English](./README.md) | **简体中文**
>
-> 🏠 [主 README(English)](../README.md) | [主 README(简体中文)](../README.zh-CN.md)
+> 🏠 [主 README(English)](../README.md) | [主 README(简体中文)](../README.zh-CN.md) | 🐛 [Issues](https://github.com/samson910022/OpenCode2API/issues)
>
> 欢迎查看 OpenCode2API 文档
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 902eccb..aa83b80 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -4,6 +4,8 @@
+> 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)
+
---
## 📋 基础信息
diff --git a/docs/configuration.md b/docs/configuration.md
index 097bbc5..ce53c56 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -10,6 +10,8 @@
> 配置优先级:**环境变量 > config.json > 默认值**
+> 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)
+
---
## 🔧 环境变量
diff --git a/docs/development.md b/docs/development.md
index c4e36f4..ed0b4fe 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -136,3 +136,7 @@ OpenCode2API/
## 📄 许可证
MIT License - 详见 [LICENSE](../LICENSE.md)
+
+---
+
+> 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md) | 🤝 [CONTRIBUTING](../CONTRIBUTING.md)
diff --git a/docs/docker.md b/docs/docker.md
index bcd595d..5a6007e 100644
--- a/docs/docker.md
+++ b/docs/docker.md
@@ -154,3 +154,7 @@ docker compose logs
### 挂载权限问题
确保 PUID/PGID 配置正确 (默认 1000:1000)。
+
+---
+
+> 📖 [Docs Index](./README.md) | 🚀 [Getting Started](./getting-started.md)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index cdc6999..0f9c2fa 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -96,3 +96,4 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
- ⚙️ 查看 [Configuration](./configuration.md) 了解更多配置选项
- 🐳 查看 [Docker Deployment](./docker.md) 了解 Docker 部署详情
+- 📖 回 [Docs Index](./README.md)
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 71dc8eb..081551c 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -157,3 +157,4 @@ OPENCODE_PROXY_DEBUG=true
## 🆘 获取帮助
- 🐛 [GitHub Issues](https://github.com/samson910022/OpenCode2API/issues)
+- 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)
From 271d907144d49caab95c7c2ed0f06e099ab848de Mon Sep 17 00:00:00 2001
From: samson910022
Date: Fri, 11 Sep 2026 06:09:42 +0800
Subject: [PATCH 2/2] docs(readme): address PR review findings
- Node footer: Docker Deployment -> Development + Getting Started
- Fallback: restore free-limit 429 qualifier (EN/ZH, table + config bullets)
- Troubleshooting: restore reasoning.effort requirement
- Footers: list items -> blockquote style, align Docs Index pattern
---
README.md | 8 ++++----
README.zh-CN.md | 8 ++++----
docs/getting-started.md | 3 ++-
docs/troubleshooting.md | 3 ++-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index c7caeb6..ed3dde1 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ Turn a local [OpenCode](https://opencode.ai) runtime into an OpenAI-, Anthropic-
| 🔁 **Gemini compatible (thin)** | `POST /v1beta/interactions` (alias `POST /v1/interactions`) |
| 🌐 **Server-side web search** | `web_search` with `web_search_call` + `url_citation` |
| 🔑 **Multi-key auth** | `API_KEY` + `OPENCODE_API_KEYS` merge; `Bearer` or `x-api-key`; empty skips auth |
-| 🔀 **Fallback proxy** | 429-only `OPENCODE_UPSTREAM_PROXIES` rotation |
+| 🔀 **Fallback proxy** | free-limit 429-only `OPENCODE_UPSTREAM_PROXIES` rotation |
| 📡 **Streaming** | SSE for Chat, Responses, Messages, Interactions |
| 🧠 **Reasoning control** | `reasoning_effort` / `reasoning: {"effort": "high"}` |
| 🐳 **Docker deploy** | One-command with auto backend |
@@ -71,7 +71,7 @@ npm run build
npm start
```
-> 📖 Full guide: [Docker Deployment](./docs/docker.md)
+> 📖 Full guide: [Development](./docs/development.md) · 🚀 [Getting Started](./docs/getting-started.md)
---
@@ -113,7 +113,7 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
- Base: `API_KEY`, `OPENCODE_SERVER_PASSWORD`, `OPENCODE_SERVER_URL`, `OPENCODE_PROXY_PORT` (`PORT`).
- Tool safety: `DISABLE_TOOLS=true` default; external `tools` bridged/isolated, built-ins disabled unless allowlisted.
- Observability: `/health/details` and `/metrics` with configurable exposure/auth.
-- Timeout & retry: `OPENCODE_PROXY_REQUEST_TIMEOUT_MS`, `OPENCODE_PROXY_RETRY_MAX_RETRIES`; `OPENCODE_UPSTREAM_PROXIES` only on 429.
+- Timeout & retry: `OPENCODE_PROXY_REQUEST_TIMEOUT_MS`, `OPENCODE_PROXY_RETRY_MAX_RETRIES`; `OPENCODE_UPSTREAM_PROXIES` only on free-limit 429.
> 📄 Full reference: [Configuration](./docs/configuration.md)
@@ -147,7 +147,7 @@ Formats: `opencode/big-pickle`, `gpt5-nano` (auto-resolved) and `opencode/gpt5-n
## 🔧 Troubleshooting
-Hangs: try `OPENCODE_USE_ISOLATED_HOME=false`. Missing model: check `/v1/models`. No reasoning: use Responses API with `stream: true`.
+Hangs: try `OPENCODE_USE_ISOLATED_HOME=false`. Missing model: check `/v1/models`. No reasoning: use Responses API with `stream: true` + `reasoning.effort`.
> 📖 Full guide: [Troubleshooting](./docs/troubleshooting.md)
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 67cda1b..3742d66 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -23,7 +23,7 @@
| 🔁 **Gemini 兼容(薄层)** | `POST /v1beta/interactions`(别名 `POST /v1/interactions`) |
| 🌐 **服务端联网搜索** | `web_search`,返回 `web_search_call` + `url_citation` |
| 🔑 **多 Key 认证** | `API_KEY` 与 `OPENCODE_API_KEYS` 合并;`Bearer` 或 `x-api-key`;为空免认证 |
-| 🔀 **免费限流 fallback 代理** | 仅 429 时轮换 `OPENCODE_UPSTREAM_PROXIES` |
+| 🔀 **免费限流 fallback 代理** | 仅免费限流 429 时轮换 `OPENCODE_UPSTREAM_PROXIES` |
| 📡 **流式输出** | Chat、Responses、Messages、Interactions 全支持 SSE |
| 🧠 **推理控制** | `reasoning_effort` / `reasoning: {"effort": "high"}` |
| 🐳 **Docker 部署** | 一键部署,自动启动后端 |
@@ -71,7 +71,7 @@ npm run build
npm start
```
-> 📖 完整指南:[Docker 部署](./docs/docker.md)
+> 📖 完整指南:[开发指南](./docs/development.md) · 🚀 [快速开始](./docs/getting-started.md)
---
@@ -113,7 +113,7 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
- 基础:`API_KEY`、`OPENCODE_SERVER_PASSWORD`、`OPENCODE_SERVER_URL`、`OPENCODE_PROXY_PORT`(`PORT`)。
- 工具安全:默认 `DISABLE_TOOLS=true`;外部 `tools` 经桥接隔离,内置工具默认禁用,按需 allowlist 放行。
- 可观测性:`/health/details` 与 `/metrics` 均可配置开关与鉴权。
-- 超时与重试:`OPENCODE_PROXY_REQUEST_TIMEOUT_MS`、`OPENCODE_PROXY_RETRY_MAX_RETRIES`;仅 429 时启用 `OPENCODE_UPSTREAM_PROXIES`。
+- 超时与重试:`OPENCODE_PROXY_REQUEST_TIMEOUT_MS`、`OPENCODE_PROXY_RETRY_MAX_RETRIES`;仅免费限流 429 时启用 `OPENCODE_UPSTREAM_PROXIES`。
> 📄 完整配置参考:[配置详解](./docs/configuration.md)
@@ -147,7 +147,7 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
## 🔧 故障排查
-卡住:试 `OPENCODE_USE_ISOLATED_HOME=false`。模型缺失:检查 `/v1/models`。无推理:用 `stream: true` 的 Responses API。
+卡住:试 `OPENCODE_USE_ISOLATED_HOME=false`。模型缺失:检查 `/v1/models`。无推理:用 `stream: true` + `reasoning.effort` 的 Responses API。
> 📖 完整指南:[故障排查](./docs/troubleshooting.md)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 0f9c2fa..f386eef 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -96,4 +96,5 @@ curl -N -X POST http://127.0.0.1:10000/v1/responses \
- ⚙️ 查看 [Configuration](./configuration.md) 了解更多配置选项
- 🐳 查看 [Docker Deployment](./docker.md) 了解 Docker 部署详情
-- 📖 回 [Docs Index](./README.md)
+
+> 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 081551c..7410ac1 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -157,4 +157,5 @@ OPENCODE_PROXY_DEBUG=true
## 🆘 获取帮助
- 🐛 [GitHub Issues](https://github.com/samson910022/OpenCode2API/issues)
-- 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)
+
+> 📖 [Docs Index](./README.md) | 🏠 [Main README](../README.md)