From 8a91fef6ab06de16f290ea4d28106da29d2107a7 Mon Sep 17 00:00:00 2001 From: CJACK Date: Sun, 26 Apr 2026 04:58:35 +0800 Subject: [PATCH] update doc --- API.en.md | 20 ++-- API.md | 20 ++-- README.MD | 163 +++-------------------------- README.en.md | 126 ++++------------------ docs/ARCHITECTURE.en.md | 7 +- docs/ARCHITECTURE.md | 7 +- docs/CONTRIBUTING.en.md | 11 +- docs/CONTRIBUTING.md | 11 +- docs/DEPLOY.en.md | 9 +- docs/DEPLOY.md | 11 +- docs/README.md | 2 + docs/TESTING.md | 21 +++- docs/prompt-compatibility.md | 6 +- docs/toolcall-semantics.md | 2 + pow/README.md | 44 +------- tests/raw_stream_samples/README.md | 2 +- 16 files changed, 132 insertions(+), 330 deletions(-) diff --git a/API.en.md b/API.en.md index 3e0173f..ae9ae04 100644 --- a/API.en.md +++ b/API.en.md @@ -160,6 +160,7 @@ Gemini-compatible clients can also send `x-goog-api-key`, `?key=`, or `?api_key= | DELETE | `/admin/dev/captures` | Admin | Clear local packet-capture entries | | GET | `/admin/chat-history` | Admin | Read server-side conversation history | | DELETE | `/admin/chat-history` | Admin | Clear server-side conversation history | +| GET | `/admin/chat-history/{id}` | Admin | Read one server-side conversation entry | | DELETE | `/admin/chat-history/{id}` | Admin | Delete one server-side conversation entry | | PUT | `/admin/chat-history/settings` | Admin | Update conversation history retention limit | | GET | `/admin/version` | Admin | Check current version and latest Release | @@ -215,12 +216,15 @@ For `chat` / `responses` / `embeddings`, DS2API follows a wide-input/strict-outp 3. If still unmatched, fall back by known family heuristics (`o*`, `gpt-*`, `claude-*`, etc.). 4. If still unmatched, return `invalid_request_error`. -Current built-in default aliases (excerpt): +Built-in aliases come from `internal/config/models.go`; `config.model_aliases` can override or add mappings at runtime. Excerpt: -- OpenAI: `gpt-4o`, `gpt-4.1`, `gpt-5.5`, `gpt-5.4-mini`, `gpt-5.3-codex` -- OpenAI reasoning: `o1`, `o1-mini`, `o3`, `o4-mini` -- Claude: `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-6` (plus compatibility aliases `claude-3-5-sonnet` / `claude-3-5-haiku` / `claude-3-opus`) -- Gemini: `gemini-2.5-pro`, `gemini-2.5-flash` +- OpenAI / Codex: `gpt-4o`, `gpt-4.1`, `gpt-5`, `gpt-5.5`, `gpt-5-codex`, `gpt-5.3-codex`, `codex-mini-latest` +- OpenAI reasoning: `o1`, `o3`, `o3-deep-research`, `o4-mini` +- Claude: `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-3-5-sonnet-latest` +- Gemini: `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-pro-vision` +- Other compatibility families: `llama-*`, `qwen-*`, `mistral-*`, and `command-*` fall back through family heuristics + +Retired historical families such as `claude-1.*`, `claude-2.*`, `claude-instant-*`, and `gpt-3.5*` are explicitly rejected. ### `POST /v1/chat/completions` @@ -707,6 +711,7 @@ Reads runtime settings and status, including: - `compat` (`wide_input_strict_output`, `strip_reference_markers`) - `responses` / `embeddings` - `auto_delete` (`mode`: `none` / `single` / `all`; legacy `sessions=true` is still treated as `all`) +- `history_split` (`enabled`, `trigger_after_turns`) - `model_aliases` - `env_backed`, `needs_vercel_sync` - `toolcall` policy is fixed to `feature_match + high` and is no longer returned or editable via settings @@ -721,6 +726,7 @@ Hot-updates runtime settings. Supported fields: - `responses.store_ttl_seconds` - `embeddings.provider` - `auto_delete.mode` +- `history_split.enabled` / `history_split.trigger_after_turns` - `model_aliases` - `toolcall` policy is fixed and is no longer writable through settings @@ -745,9 +751,9 @@ Imports full config with: The request can send config directly, or wrapped as `{"config": {...}, "mode":"merge"}`. Query params `?mode=merge` / `?mode=replace` are also supported. -Import accepts `keys`, `api_keys`, `accounts`, `model_aliases`, `admin`, `runtime`, `responses`, `embeddings`, and `auto_delete`; legacy `toolcall` fields are ignored. +`replace` mode replaces the full config shape while preserving Vercel sync metadata. `merge` mode merges `keys`, `api_keys`, `accounts`, and `model_aliases`, and overwrites non-empty fields under `admin`, `runtime`, `responses`, and `embeddings`. Manage `compat`, `auto_delete`, and `history_split` via `/admin/settings` or the config file; legacy `toolcall` fields are ignored. -> `compat` fields are managed via `/admin/settings` or the config file; this import endpoint does not update `compat`. +> Note: `merge` mode does not update `compat`, `auto_delete`, or `history_split`. ### `GET /admin/config/export` diff --git a/API.md b/API.md index d09eb27..50299cd 100644 --- a/API.md +++ b/API.md @@ -160,6 +160,7 @@ Gemini 兼容客户端还可以使用 `x-goog-api-key`、`?key=` 或 `?api_key=` | DELETE | `/admin/dev/captures` | Admin | 清空本地抓包记录 | | GET | `/admin/chat-history` | Admin | 查看服务器端对话记录 | | DELETE | `/admin/chat-history` | Admin | 清空服务器端对话记录 | +| GET | `/admin/chat-history/{id}` | Admin | 查看单条服务器端对话记录 | | DELETE | `/admin/chat-history/{id}` | Admin | 删除单条服务器端对话记录 | | PUT | `/admin/chat-history/settings` | Admin | 更新对话记录保留条数 | | GET | `/admin/version` | Admin | 查询当前版本与最新 Release | @@ -215,14 +216,15 @@ Gemini 兼容客户端还可以使用 `x-goog-api-key`、`?key=` 或 `?api_key=` 3. 未命中时按模型家族规则回退(如 `o*`、`gpt-*`、`claude-*`)。 4. 仍未命中则返回 `invalid_request_error`。 -当前内置默认 alias(节选): +当前内置默认 alias 来自 `internal/config/models.go`,`config.model_aliases` 会在运行时覆盖或补充同名映射。节选: -- OpenAI:`gpt-4o`、`gpt-4.1`、`gpt-4.1-mini`、`gpt-4.1-nano`、`gpt-5`、`gpt-5.4`、`gpt-5.5`、`gpt-5-mini`、`gpt-5.4-mini`、`gpt-5.4-nano`、`gpt-5.5-pro`、`gpt-5-codex`、`gpt-5.3-codex` -- OpenAI Reasoning:`o1`、`o1-mini`、`o3`、`o3-mini` -- Claude:`claude-sonnet-4-6`、`claude-haiku-4-5`、`claude-opus-4-6`(及 `claude-sonnet-4-5` / `claude-3-5-sonnet` / `claude-3-5-haiku` / `claude-3-opus` 兼容别名) -- Gemini:`gemini-2.5-pro`、`gemini-2.5-flash` +- OpenAI / Codex:`gpt-4o`、`gpt-4.1`、`gpt-5`、`gpt-5.5`、`gpt-5-codex`、`gpt-5.3-codex`、`codex-mini-latest` +- OpenAI reasoning:`o1`、`o3`、`o3-deep-research`、`o4-mini` +- Claude:`claude-opus-4-6`、`claude-sonnet-4-6`、`claude-haiku-4-5`、`claude-3-5-sonnet-latest` +- Gemini:`gemini-2.5-pro`、`gemini-2.5-flash`、`gemini-pro-vision` +- 其他兼容族:`llama-*`、`qwen-*`、`mistral-*`、`command-*` 会按家族启发式回退 -> 截至 2026-04-26:OpenAI 开发者模型页当前推荐 `gpt-5.5` 作为旗舰 API 模型;ChatGPT Help Center 当前主打 `GPT-5.3 Instant / GPT-5.5 Thinking / GPT-5.5 Pro`;Anthropic 官方模型页当前主推 `claude-opus-4-6`、`claude-sonnet-4-6`、`claude-haiku-4-5`。 +退役历史模型(如 `claude-1.*`、`claude-2.*`、`claude-instant-*`、`gpt-3.5*`)会被显式拒绝。 ### `POST /v1/chat/completions` @@ -710,6 +712,7 @@ data: {"type":"message_stop"} - `compat`(`wide_input_strict_output`、`strip_reference_markers`) - `responses` / `embeddings` - `auto_delete`(`mode`:`none` / `single` / `all`;旧配置 `sessions=true` 仍按 `all` 处理) +- `history_split`(`enabled`、`trigger_after_turns`) - `model_aliases` - `env_backed`、`needs_vercel_sync` - `toolcall` 策略已固定为 `feature_match + high`,不再通过 settings 返回或修改 @@ -724,6 +727,7 @@ data: {"type":"message_stop"} - `responses.store_ttl_seconds` - `embeddings.provider` - `auto_delete.mode` +- `history_split.enabled` / `history_split.trigger_after_turns` - `model_aliases` - `toolcall` 策略已固定,不再作为可写入字段 @@ -748,9 +752,9 @@ data: {"type":"message_stop"} 请求可直接传配置对象,或使用 `{"config": {...}, "mode":"merge"}` 包裹格式。 也支持在查询参数里传 `?mode=merge` / `?mode=replace`。 -导入时会接受 `keys`、`api_keys`、`accounts`、`model_aliases`、`admin`、`runtime`、`responses`、`embeddings`、`auto_delete` 等字段;`toolcall` 相关字段会被忽略。 +`replace` 模式会按完整配置结构替换(保留 Vercel 同步元信息);`merge` 模式会合并 `keys`、`api_keys`、`accounts`、`model_aliases`,并覆盖 `admin`、`runtime`、`responses`、`embeddings` 中的非空字段。`compat`、`auto_delete`、`history_split` 建议通过 `/admin/settings` 或配置文件管理;`toolcall` 相关字段会被忽略。 -> `compat` 相关字段请通过 `/admin/settings` 或配置文件管理;该导入接口不会更新 `compat`。 +> 注意:`merge` 模式不会更新 `compat`、`auto_delete`、`history_split`。 ### `GET /admin/config/export` diff --git a/README.MD b/README.MD index e7ba7d4..b874ec0 100644 --- a/README.MD +++ b/README.MD @@ -122,7 +122,7 @@ flowchart LR | vision | `deepseek-v4-vision` | 默认开启,可由请求参数控制 | ❌ | | vision | `deepseek-v4-vision-search` | 默认开启,可由请求参数控制 | ✅ | -除原生模型外,也支持常见 alias 输入(如 `gpt-5.5`、`gpt-5.4`、`gpt-5.4-mini`、`gpt-5.3-codex`、`gpt-4.1`、`o3`、`claude-opus-4-6`、`claude-sonnet-4-6`、`gemini-2.5-pro`、`gemini-2.5-flash` 等),但 `/v1/models` 返回的是规范化后的 DeepSeek 原生模型 ID。 +除原生模型外,也支持常见 alias 输入(如 `gpt-4.1`、`gpt-5`、`gpt-5-codex`、`o3`、`claude-*`、`gemini-*` 等),但 `/v1/models` 返回的是规范化后的 DeepSeek 原生模型 ID。完整 alias 行为以 [API.md](API.md#模型-alias-解析策略) 和 `config.example.json` 为准。 ### Claude 接口(`GET /anthropic/v1/models`) @@ -133,9 +133,7 @@ flowchart LR | `claude-opus-4-6` | `deepseek-v4-pro` | 可通过配置中的 `model_aliases` 覆盖映射关系。 -`/anthropic/v1/models` 除上述当前主别名外,还会返回 Claude 4.x snapshots,以及 3.x 历史模型 ID 与常见 alias,便于旧客户端直接兼容。 - -> 截至 2026-04-26:Anthropic 官方模型页当前主推 `claude-opus-4-6`、`claude-sonnet-4-6`、`claude-haiku-4-5`;OpenAI 官方开发者模型页当前推荐从 `gpt-5.5` 开始,ChatGPT Help Center 当前主打 `GPT-5.3 Instant / GPT-5.5 Thinking / GPT-5.5 Pro`。本文档中的 alias 示例按“兼容客户端会传来的最新官方模型 ID”维护。 +`/anthropic/v1/models` 除上述主别名外,还会返回 Claude 4.x snapshots、3.x 历史模型 ID 与常见 alias,便于旧客户端直接兼容。 #### Claude Code 接入避坑(实测) @@ -265,119 +263,18 @@ go run ./cmd/ds2api ## 配置说明 -### `config.json` 示例 +`README` 只保留快速入口,完整字段请以 [config.example.json](config.example.json) 为模板,并参考 [部署指南](docs/DEPLOY.md#0-前置要求) 与 [API 配置最佳实践](API.md#配置最佳实践)。 -```json -{ - "keys": ["your-api-key-1", "your-api-key-2"], - "api_keys": [ - { - "key": "your-api-key-1", - "name": "主 Key", - "remark": "生产流量" - } - ], - "accounts": [ - { - "name": "账号 A", - "remark": "主账号", - "email": "user@example.com", - "password": "your-password" - }, - { - "mobile": "12345678901", - "password": "your-password" - } - ], - "model_aliases": { - "gpt-4o": "deepseek-v4-flash", - "gpt-5.5": "deepseek-v4-flash", - "gpt-5.4-mini": "deepseek-v4-flash", - "gpt-5.3-codex": "deepseek-v4-pro", - "o3": "deepseek-v4-pro", - "claude-opus-4-6": "deepseek-v4-pro", - "gemini-2.5-flash": "deepseek-v4-flash" - }, - "compat": { - "wide_input_strict_output": true, - "strip_reference_markers": true - }, - "responses": { - "store_ttl_seconds": 900 - }, - "embeddings": { - "provider": "deterministic" - }, - "admin": { - "jwt_expire_hours": 24 - }, - "runtime": { - "account_max_inflight": 2, - "account_max_queue": 0, - "global_max_inflight": 0, - "token_refresh_interval_hours": 6 - }, - "auto_delete": { - "mode": "none" - } -} -``` +常用字段: -- `keys`:API 访问密钥列表,客户端通过 `Authorization: Bearer ` 鉴权 -- `api_keys`:推荐使用的新结构化密钥列表,支持 `key` + `name` + `remark`(`keys` 仍兼容) -- `accounts`:DeepSeek 账号列表,支持 `email` 或 `mobile` 登录;可额外填写 `name` / `remark` 便于管理 -- `token`:配置文件中即使填写也会在加载时被清空(不会从 `config.json` 读取 token);实际 token 仅在运行时内存中维护并自动刷新 -- `model_aliases`:常见模型名(如 GPT/Codex/Claude)到 DeepSeek 模型的映射 -- `compat.wide_input_strict_output`:建议保持 `true`(当前实现默认宽进严出) -- `compat.strip_reference_markers`:建议保持 `true`,用于清理可见输出中的引用/标记 -- `toolcall`:旧字段,当前实现已固定为特征匹配 + 高置信早发;即使保留在配置里也会被忽略 -- `responses.store_ttl_seconds`:`/v1/responses/{id}` 的内存缓存 TTL -- `embeddings.provider`:embedding 提供方(当前内置 `deterministic/mock/builtin`) -- `model_aliases`:全局统一模型映射表,OpenAI / Claude / Gemini 共用;项目内只维护这一套映射入口 -- `admin`:管理后台设置(JWT 过期时间、密码哈希等),可通过 Admin Settings API 热更新 -- `runtime`:运行时参数(并发限制、队列大小、托管账号 token 刷新间隔),可通过 Admin Settings API 热更新;`account_max_queue=0`/`global_max_inflight=0` 表示按推荐值自动计算,`token_refresh_interval_hours=6` 为默认强制重登间隔 -- `auto_delete.mode`:请求结束后如何清理 DeepSeek 远端聊天记录,支持 `none`(默认,不删除)、`single`(仅删除当前会话)、`all`(清空全部会话);旧配置里的 `auto_delete.sessions=true` 仍会被视为 `all` +- `keys` / `api_keys`:客户端访问密钥,`api_keys` 支持 `name` 与 `remark` 元信息,`keys` 继续兼容。 +- `accounts`:DeepSeek 托管账号,支持 `email` 或 `mobile` 登录,可配置代理、名称和备注。 +- `model_aliases`:OpenAI / Claude / Gemini 共用的模型 alias 映射。 +- `runtime`:账号并发、队列与 token 刷新策略,可通过 Admin Settings 热更新。 +- `auto_delete.mode`:请求结束后的远端会话清理策略,支持 `none` / `single` / `all`。 +- `history_split`:多轮历史拆分策略,默认开启,避免长历史全部内联进 prompt。 -### 环境变量 - -> 建议:长期维护请优先以 `config.json`(或其 Base64)为单一配置源。环境变量仅保留部署必需项;`DS2API_CONFIG_JSON` 主要用于 Vercel/无持久盘场景,后续可能进一步收敛。 - -| 变量 | 用途 | 默认值 | -| --- | --- | --- | -| `PORT` | 服务端口 | `5001` | -| `LOG_LEVEL` | 日志级别 | `INFO`(可选:`DEBUG`/`WARN`/`ERROR`) | -| `DS2API_ADMIN_KEY` | Admin 登录密钥 | `admin` | -| `DS2API_JWT_SECRET` | Admin JWT 签名密钥 | 等同 `DS2API_ADMIN_KEY` | -| `DS2API_JWT_EXPIRE_HOURS` | Admin JWT 过期小时数 | `24` | -| `DS2API_CONFIG_PATH` | 配置文件路径 | `config.json` | -| `DS2API_CONFIG_JSON` | 直接注入配置(JSON 或 Base64) | — | -| `DS2API_CHAT_HISTORY_PATH` | 服务器端对话记录文件路径 | `data/chat_history.json` | -| `DS2API_ENV_WRITEBACK` | 环境变量模式下自动写回配置文件并切换文件模式(`1/true/yes/on`) | 关闭 | -| `DS2API_STATIC_ADMIN_DIR` | 管理台静态文件目录 | `static/admin` | -| `DS2API_AUTO_BUILD_WEBUI` | 启动时自动构建 WebUI | 本地开启,Vercel 关闭 | -| `DS2API_DEV_PACKET_CAPTURE` | 本地开发抓包开关(记录最近会话请求/响应体) | 本地非 Vercel 默认开启 | -| `DS2API_DEV_PACKET_CAPTURE_LIMIT` | 本地抓包保留条数(超出自动淘汰) | `20` | -| `DS2API_DEV_PACKET_CAPTURE_MAX_BODY_BYTES` | 单条响应体最大记录字节数 | `5242880` | -| `DS2API_ACCOUNT_MAX_INFLIGHT` | 每账号最大并发 in-flight 请求数 | `2` | -| `DS2API_ACCOUNT_MAX_QUEUE` | 等待队列上限 | `recommended_concurrency` | -| `DS2API_GLOBAL_MAX_INFLIGHT` | 全局最大 in-flight 请求数 | `recommended_concurrency` | -| `DS2API_VERCEL_INTERNAL_SECRET` | Vercel 混合流式内部鉴权密钥 | 回退用 `DS2API_ADMIN_KEY` | -| `DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS` | 流式 lease 过期秒数 | `900` | -| `VERCEL_TOKEN` | Vercel 同步 token | — | -| `VERCEL_PROJECT_ID` | Vercel 项目 ID | — | -| `VERCEL_TEAM_ID` | Vercel 团队 ID | — | -| `DS2API_VERCEL_PROTECTION_BYPASS` | Vercel 部署保护绕过密钥(内部 Node→Go 调用) | — | - -> 提示:当检测到 `DS2API_CONFIG_JSON` 时,管理台会显示当前模式风险与自动持久化状态(含 `DS2API_CONFIG_PATH` 路径与模式切换说明)。 - -#### 必填 / 可选(按部署方式) - -- **所有部署都必填**:`DS2API_ADMIN_KEY` -- **配置来源二选一(推荐前者)**: - - `config.json` 文件(推荐,持久化更直观) - - `DS2API_CONFIG_JSON`(可选,适合 Vercel;支持 JSON 或 Base64) -- **仅在环境变量配置模式建议开启**:`DS2API_ENV_WRITEBACK=1`(避免管理台改动重启后丢失) -- 其余环境变量均为可选调优项。 +环境变量完整列表见 [部署指南](docs/DEPLOY.md),接口鉴权规则见 [API.md](API.md#鉴权规则)。 ## 鉴权模式 @@ -460,44 +357,18 @@ go run ./cmd/ds2api ## 测试 -```bash -# 单元测试(Go + Node) -./tests/scripts/run-unit-all.sh - -# 一键端到端全链路测试(真实账号,生成完整请求/响应日志) -./tests/scripts/run-live.sh - -# 或自定义参数 -go run ./cmd/ds2api-tests \ - --config config.json \ - --admin-key admin \ - --out artifacts/testsuite \ - --timeout 120 \ - --retries 2 -``` - -```bash -# 发布前阻断门禁 -./tests/scripts/check-stage6-manual-smoke.sh -./tests/scripts/check-refactor-line-gate.sh -./tests/scripts/run-unit-all.sh -npm ci --prefix webui && npm run build --prefix webui -``` - -## 测试 - 详细测试指南请参阅 [docs/TESTING.md](docs/TESTING.md)。 ### 快速测试命令 ```bash -# 运行所有单元测试 -go test ./... +# 本地 PR 门禁 +./scripts/lint.sh +./tests/scripts/check-refactor-line-gate.sh +./tests/scripts/run-unit-all.sh +npm run build --prefix webui -# 运行 tool calls 相关测试(调试工具调用问题) -go test -v -run 'TestParseToolCalls|TestRepair' ./internal/toolcall/ - -# 运行端到端测试 +# 端到端全链路测试(真实账号,生成完整请求/响应日志) ./tests/scripts/run-live.sh ``` diff --git a/README.en.md b/README.en.md index 68f3017..827a3a0 100644 --- a/README.en.md +++ b/README.en.md @@ -120,7 +120,7 @@ For the full module-by-module architecture and directory responsibilities, see [ | vision | `deepseek-v4-vision` | enabled by default, request-controlled | ❌ | | vision | `deepseek-v4-vision-search` | enabled by default, request-controlled | ✅ | -Besides native IDs, DS2API also accepts common aliases as input (for example `gpt-5.5`, `gpt-5.4-mini`, `gpt-5.3-codex`, `gpt-4.1`, `o3`, `claude-opus-4-6`, `claude-sonnet-4-6`, `gemini-2.5-pro`, `gemini-2.5-flash`), but `/v1/models` returns normalized DeepSeek native model IDs. +Besides native IDs, DS2API also accepts common aliases as input (for example `gpt-4.1`, `gpt-5`, `gpt-5-codex`, `o3`, `claude-*`, `gemini-*`), but `/v1/models` returns normalized DeepSeek native model IDs. The complete alias behavior is documented in [API.en.md](API.en.md#model-alias-resolution) and `config.example.json`. ### Claude Endpoint (`GET /anthropic/v1/models`) @@ -131,7 +131,7 @@ Besides native IDs, DS2API also accepts common aliases as input (for example `gp | `claude-opus-4-6` | `deepseek-v4-pro` | Override mapping via the global `model_aliases` config. -Besides the current primary aliases above, `/anthropic/v1/models` also returns Claude 4.x snapshots plus historical 3.x IDs and common aliases for legacy client compatibility. +Besides the primary aliases above, `/anthropic/v1/models` also returns Claude 4.x snapshots plus historical 3.x IDs and common aliases for legacy client compatibility. #### Claude Code integration pitfalls (validated) @@ -261,97 +261,18 @@ The server actually binds to `0.0.0.0:5001`, so devices on the same LAN can usua ## Configuration -### `config.json` Example +`README` keeps only the onboarding path. Use [config.example.json](config.example.json) as the field template, and see the [deployment guide](docs/DEPLOY.en.md#0-prerequisites) plus [API configuration notes](API.en.md#configuration-best-practice) for full details. -```json -{ - "keys": ["your-api-key-1", "your-api-key-2"], - "accounts": [ - { - "email": "user@example.com", - "password": "your-password" - }, - { - "mobile": "12345678901", - "password": "your-password" - } - ], - "model_aliases": { - "gpt-4o": "deepseek-v4-flash", - "gpt-5": "deepseek-v4-flash", - "gpt-5-mini": "deepseek-v4-flash", - "gpt-5-codex": "deepseek-v4-pro", - "o3": "deepseek-v4-pro", - "claude-opus-4-6": "deepseek-v4-pro", - "gemini-2.5-flash": "deepseek-v4-flash" - }, - "compat": { - "wide_input_strict_output": true, - "strip_reference_markers": true - }, - "responses": { - "store_ttl_seconds": 900 - }, - "embeddings": { - "provider": "deterministic" - }, - "admin": { - "jwt_expire_hours": 24 - }, - "runtime": { - "account_max_inflight": 2, - "account_max_queue": 0, - "global_max_inflight": 0, - "token_refresh_interval_hours": 6 - }, - "auto_delete": { - "mode": "none" - } -} -``` +Common fields: -- `keys`: API access keys; clients authenticate via `Authorization: Bearer ` -- `accounts`: DeepSeek account list, supports `email` or `mobile` login -- `token`: Even if set in `config.json`, it is cleared during load (DS2API does not read persisted tokens from config); runtime tokens are maintained/refreshed in memory only -- `model_aliases`: Single global alias map shared by OpenAI / Claude / Gemini model names -- `compat.wide_input_strict_output`: Keep `true` (current default policy) -- `compat.strip_reference_markers`: Keep `true`; it strips reference markers from visible output -- `toolcall`: Legacy field; the current behavior is fixed to feature matching + high-confidence early emit, and any config value is ignored -- `responses.store_ttl_seconds`: In-memory TTL for `/v1/responses/{id}` -- `embeddings.provider`: Embeddings provider (`deterministic/mock/builtin` built-in) -- `admin`: Admin panel settings (JWT expiry, password hash, etc.), hot-reloadable via Admin Settings API -- `runtime`: Runtime parameters (concurrency limits, queue sizes, managed token refresh interval), hot-reloadable via Admin Settings API; `account_max_queue=0`/`global_max_inflight=0` means auto-calculate from recommended values, `token_refresh_interval_hours=6` is the default forced re-login interval -- `auto_delete.mode`: How to clean up DeepSeek remote chat records after each request completes. Supported values: `none` (default, no deletion), `single` (delete only the current session), `all` (delete all sessions); legacy `auto_delete.sessions=true` is still treated as `all` +- `keys` / `api_keys`: client API keys; `api_keys` adds `name` and `remark` metadata while `keys` remains compatible. +- `accounts`: managed DeepSeek accounts, supporting `email` or `mobile` login plus proxy/name/remark metadata. +- `model_aliases`: one shared alias map for OpenAI / Claude / Gemini model names. +- `runtime`: account concurrency, queueing, and token refresh behavior, hot-reloadable via Admin Settings. +- `auto_delete.mode`: remote session cleanup after each request, supporting `none` / `single` / `all`. +- `history_split`: multi-turn history split policy, enabled by default to avoid inlining all long history into the prompt. -### Environment Variables - -| Variable | Purpose | Default | -| --- | --- | --- | -| `PORT` | Service port | `5001` | -| `LOG_LEVEL` | Log level | `INFO` (`DEBUG`/`WARN`/`ERROR`) | -| `DS2API_ADMIN_KEY` | Admin login key | `admin` | -| `DS2API_JWT_SECRET` | Admin JWT signing secret | Same as `DS2API_ADMIN_KEY` | -| `DS2API_JWT_EXPIRE_HOURS` | Admin JWT TTL in hours | `24` | -| `DS2API_CONFIG_PATH` | Config file path | `config.json` | -| `DS2API_CONFIG_JSON` | Inline config (JSON or Base64) | — | -| `DS2API_CHAT_HISTORY_PATH` | Server-side conversation history file path | `data/chat_history.json` | -| `DS2API_ENV_WRITEBACK` | Auto-write env-backed config to file and transition to file mode (`1/true/yes/on`) | Disabled | -| `DS2API_STATIC_ADMIN_DIR` | Admin static assets dir | `static/admin` | -| `DS2API_AUTO_BUILD_WEBUI` | Auto-build WebUI on startup | Enabled locally, disabled on Vercel | -| `DS2API_ACCOUNT_MAX_INFLIGHT` | Max in-flight requests per account | `2` | -| `DS2API_ACCOUNT_MAX_QUEUE` | Waiting queue limit | `recommended_concurrency` | -| `DS2API_GLOBAL_MAX_INFLIGHT` | Global max in-flight requests | `recommended_concurrency` | -| `DS2API_VERCEL_INTERNAL_SECRET` | Vercel hybrid streaming internal auth | Falls back to `DS2API_ADMIN_KEY` | -| `DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS` | Stream lease TTL seconds | `900` | -| `DS2API_DEV_PACKET_CAPTURE` | Local dev packet capture switch (record recent request/response bodies) | Enabled by default on non-Vercel local runtime | -| `DS2API_DEV_PACKET_CAPTURE_LIMIT` | Number of captured sessions to retain (auto-evict overflow) | `20` | -| `DS2API_DEV_PACKET_CAPTURE_MAX_BODY_BYTES` | Max recorded bytes per captured response body | `5242880` | -| `VERCEL_TOKEN` | Vercel sync token | — | -| `VERCEL_PROJECT_ID` | Vercel project ID | — | -| `VERCEL_TEAM_ID` | Vercel team ID | — | -| `DS2API_VERCEL_PROTECTION_BYPASS` | Vercel deployment protection bypass for internal Node→Go calls | — | - -> Note: when `DS2API_CONFIG_JSON` is detected, the Admin UI shows mode risk and auto-persistence status (including `DS2API_CONFIG_PATH` and mode-transition hints). +For the full environment variable list, see [docs/DEPLOY.en.md](docs/DEPLOY.en.md). For auth behavior, see [API.en.md](API.en.md#authentication). ## Authentication Modes @@ -432,28 +353,19 @@ The save endpoint can target a chain by `query`, `chain_key`, or `capture_id`. E ## Testing -```bash -# Unit tests (Go + Node) -./tests/scripts/run-unit-all.sh +For the full testing guide, see [docs/TESTING.md](docs/TESTING.md). -# One-command live end-to-end tests (real accounts, full request/response logs) -./tests/scripts/run-live.sh - -# Or with custom flags -go run ./cmd/ds2api-tests \ - --config config.json \ - --admin-key admin \ - --out artifacts/testsuite \ - --timeout 120 \ - --retries 2 -``` +Quick commands: ```bash -# Release-blocking gates -./tests/scripts/check-stage6-manual-smoke.sh +# Local PR gates +./scripts/lint.sh ./tests/scripts/check-refactor-line-gate.sh ./tests/scripts/run-unit-all.sh -npm ci --prefix webui && npm run build --prefix webui +npm run build --prefix webui + +# Live end-to-end tests (real accounts, full request/response logs) +./tests/scripts/run-live.sh ``` ## Release Artifact Automation (GitHub Actions) diff --git a/docs/ARCHITECTURE.en.md b/docs/ARCHITECTURE.en.md index 651098f..b40d7dd 100644 --- a/docs/ARCHITECTURE.en.md +++ b/docs/ARCHITECTURE.en.md @@ -4,9 +4,9 @@ Language: [中文](ARCHITECTURE.md) | [English](ARCHITECTURE.en.md) > This file is the single architecture source for directory layout, module boundaries, and execution flow. -## 1. Top-level Layout (expanded) +## 1. Top-level Layout (core directories) -> Notes: this is the **fully expanded** project directory list (excluding metadata/dependency dirs such as `.git/` and `webui/node_modules/`), with each folder annotated by purpose. +> Notes: this lists the main business directories (excluding metadata/dependency dirs such as `.git/` and `webui/node_modules/`), with each folder annotated by purpose. Newly added directories should be verified from the code tree rather than treated as a per-file inventory here. ```text ds2api/ @@ -27,6 +27,7 @@ ds2api/ │ │ └── openai/ # OpenAI adapter and shared execution core │ ├── admin/ # Admin API (config/accounts/ops) │ ├── auth/ # Auth/JWT/credential resolution +│ ├── chathistory/ # Server-side conversation history storage/query │ ├── claudeconv/ # Claude message conversion helpers │ ├── compat/ # Compatibility and regression helpers │ ├── config/ # Config loading/validation/hot reload @@ -44,6 +45,7 @@ ds2api/ │ ├── prompt/ # Prompt composition │ ├── rawsample/ # Raw sample read/write and management │ ├── server/ # Router and middleware assembly +│ │ └── data/ # Router/runtime helper data │ ├── sse/ # SSE parsing utilities │ ├── stream/ # Unified stream consumption engine │ ├── testsuite/ # Testsuite execution framework @@ -118,6 +120,7 @@ flowchart LR - `internal/stream` + `internal/sse`: stream parsing and incremental assembly. - `internal/toolcall`: canonical XML tool-call parsing + anti-leak sieve (the only executable format is `` / `` / ``). - `internal/admin`: config/accounts/vercel sync/version/dev-capture endpoints. +- `internal/chathistory`: server-side conversation history persistence, pagination, detail lookup, and retention policy. - `internal/config`: config loading/validation + runtime settings hot-reload. - `internal/account`: managed account pool, inflight slots, waiting queue. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 757ae6b..b4392f7 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -4,9 +4,9 @@ > 本文档用于集中维护“代码目录结构 + 模块边界 + 主链路调用关系”。 -## 1. 顶层目录结构(展开) +## 1. 顶层目录结构(核心目录) -> 说明:以下为仓库内业务相关目录的**完整展开**(排除 `.git/` 与 `webui/node_modules/` 这类依赖/元数据目录),并标注每个文件夹作用。 +> 说明:以下为仓库内主要业务目录(排除 `.git/` 与 `webui/node_modules/` 这类依赖/元数据目录),并标注每个文件夹作用。新增目录以代码为准,不要求在本文做逐文件展开。 ```text ds2api/ @@ -27,6 +27,7 @@ ds2api/ │ │ └── openai/ # OpenAI 协议与统一执行核心 │ ├── admin/ # Admin API(配置/账号/运维) │ ├── auth/ # 鉴权/JWT/凭证解析 +│ ├── chathistory/ # 服务器端对话记录存储与查询 │ ├── claudeconv/ # Claude 消息格式转换工具 │ ├── compat/ # 兼容性辅助与回归支持 │ ├── config/ # 配置加载、校验、热更新 @@ -44,6 +45,7 @@ ds2api/ │ ├── prompt/ # Prompt 组装 │ ├── rawsample/ # raw sample 读写与管理 │ ├── server/ # 路由与中间件装配 +│ │ └── data/ # 路由/运行时辅助数据 │ ├── sse/ # SSE 解析工具 │ ├── stream/ # 统一流式消费引擎 │ ├── testsuite/ # 测试集执行框架 @@ -118,6 +120,7 @@ flowchart LR - `internal/stream` + `internal/sse`:流式解析与增量处理。 - `internal/toolcall`:canonical XML 工具调用解析与防泄漏筛分(唯一可执行格式:`` / `` / ``)。 - `internal/admin`:配置管理、账号管理、Vercel 同步、版本检查、开发抓包。 +- `internal/chathistory`:服务器端对话记录持久化、分页、单条详情和保留策略。 - `internal/config`:配置加载、校验、运行时 settings 热更新。 - `internal/account`:托管账号池、并发槽位、等待队列。 diff --git a/docs/CONTRIBUTING.en.md b/docs/CONTRIBUTING.en.md index aa9dd19..8dd9a40 100644 --- a/docs/CONTRIBUTING.en.md +++ b/docs/CONTRIBUTING.en.md @@ -59,10 +59,12 @@ docker-compose -f docker-compose.dev.yml up | Language | Standards | | --- | --- | -| **Go** | Run `./scripts/lint.sh` (gofmt + golangci-lint) and ensure `go test ./...` passes before committing | +| **Go** | Run `gofmt -w` after editing Go files; before committing, run `./scripts/lint.sh` (format check + golangci-lint) | | **JavaScript/React** | Follow existing project style (functional components) | | **Commit messages** | Use semantic prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `style:`, `perf:`, `chore:` | +Do not silently ignore cleanup errors from I/O-style calls such as `Close`, `Flush`, or `Sync`; return them when possible, otherwise log them explicitly. + ## Submitting a PR 1. Fork the repo @@ -85,10 +87,13 @@ Manually build WebUI to `static/admin/`: ## Running Tests ```bash -# Go + Node unit tests (recommended) +# Local PR gates (kept aligned with the quality-gates workflow) +./scripts/lint.sh +./tests/scripts/check-refactor-line-gate.sh ./tests/scripts/run-unit-all.sh +npm run build --prefix webui -# End-to-end live tests (real accounts) +# End-to-end live tests (real accounts; recommended for releases or high-risk changes) ./tests/scripts/run-live.sh ``` diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 6fae956..0a9187d 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -59,10 +59,12 @@ docker-compose -f docker-compose.dev.yml up | 语言 | 规范 | | --- | --- | -| **Go** | 提交前运行 `./scripts/lint.sh`(包含 gofmt+golangci-lint)并确保 `go test ./...` 通过 | +| **Go** | 修改 Go 文件后运行 `gofmt -w`;提交前运行 `./scripts/lint.sh`(包含格式化检查和 golangci-lint) | | **JavaScript/React** | 保持现有代码风格(函数组件) | | **提交信息** | 使用语义化前缀:`feat:`、`fix:`、`docs:`、`refactor:`、`style:`、`perf:`、`chore:` | +I/O 类清理调用(如 `Close`、`Flush`、`Sync`)的错误不要直接忽略;无法向上返回时请显式记录日志。 + ## 提交 PR 1. Fork 仓库 @@ -85,10 +87,13 @@ docker-compose -f docker-compose.dev.yml up ## 运行测试 ```bash -# Go + Node 单元测试(推荐) +# PR 本地门禁(与 quality-gates 工作流保持一致) +./scripts/lint.sh +./tests/scripts/check-refactor-line-gate.sh ./tests/scripts/run-unit-all.sh +npm run build --prefix webui -# 端到端全链路测试(真实账号) +# 端到端全链路测试(真实账号,发布或高风险改动时建议执行) ./tests/scripts/run-live.sh ``` diff --git a/docs/DEPLOY.en.md b/docs/DEPLOY.en.md index 1eb6dbd..acb43eb 100644 --- a/docs/DEPLOY.en.md +++ b/docs/DEPLOY.en.md @@ -259,12 +259,13 @@ VERCEL_TEAM_ID=team_xxxxxxxxxxxx # optional for personal accounts | `DS2API_ENV_WRITEBACK` | When `DS2API_CONFIG_JSON` is present, auto-write to `DS2API_CONFIG_PATH` and switch to file-backed mode after success (`1/true/yes/on`) | Disabled | | `DS2API_VERCEL_INTERNAL_SECRET` | Hybrid streaming internal auth | Falls back to `DS2API_ADMIN_KEY` | | `DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS` | Stream lease TTL | `900` | +| `DS2API_RAW_STREAM_SAMPLE_ROOT` | Raw stream sample root for saving/reading samples | `tests/raw_stream_samples` | | `VERCEL_TOKEN` | Vercel sync token | — | | `VERCEL_PROJECT_ID` | Vercel project ID | — | | `VERCEL_TEAM_ID` | Vercel team ID | — | | `DS2API_VERCEL_PROTECTION_BYPASS` | Deployment protection bypass for internal Node→Go calls | — | -### 3.3 Vercel Architecture +### 3.4 Vercel Architecture ```text Request ──────┐ @@ -306,7 +307,7 @@ Vercel Go Runtime applies platform-level response buffering, so this project use `vercel.json` sets `maxDuration: 300` for both `api/chat-stream.js` and `api/index.go` (subject to your Vercel plan limits). -### 3.4 Vercel Troubleshooting +### 3.5 Vercel Troubleshooting #### Go Build Failure @@ -350,7 +351,7 @@ If API responses return Vercel HTML `Authentication Required`: - **Option B**: Add `x-vercel-protection-bypass` header to requests - **Option C**: Set `VERCEL_AUTOMATION_BYPASS_SECRET` (or `DS2API_VERCEL_PROTECTION_BYPASS`) for internal Node→Go calls -### 3.5 Build Artifacts Not Committed +### 3.6 Build Artifacts Not Committed - `static/admin` directory is not in Git - Vercel / Docker automatically generate WebUI assets during build @@ -577,4 +578,4 @@ The testsuite automatically performs: - ✅ Live scenario verification (OpenAI/Claude/Admin/concurrency/toolcall/streaming) - ✅ Full request/response artifact logging for debugging -For detailed testsuite documentation, see [TESTING.md](TESTING.md). +For detailed testsuite documentation, see [TESTING.md](TESTING.md). The fixed local PR gates are listed in [TESTING.md](TESTING.md#pr-门禁--pr-gates). diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 3e85044..f726df7 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -258,7 +258,8 @@ VERCEL_TEAM_ID=team_xxxxxxxxxxxx # 个人账号可留空 | `DS2API_GLOBAL_MAX_INFLIGHT` | 全局并发上限 | `recommended_concurrency` | | `DS2API_ENV_WRITEBACK` | 检测到 `DS2API_CONFIG_JSON` 时自动写入 `DS2API_CONFIG_PATH`,并在成功后转为文件模式(`1/true/yes/on`) | 关闭 | | `DS2API_VERCEL_INTERNAL_SECRET` | 混合流式内部鉴权 | 回退用 `DS2API_ADMIN_KEY` | -| `DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS` | 流式 lease TTL | 默认与 `responses.store_ttl_seconds` 同步,若未设置则为 `900` | +| `DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS` | 流式 lease TTL | `900` | +| `DS2API_RAW_STREAM_SAMPLE_ROOT` | raw stream 样本保存/读取根目录 | `tests/raw_stream_samples` | | `VERCEL_TOKEN` | Vercel 同步 token | — | | `VERCEL_PROJECT_ID` | Vercel 项目 ID | — | | `VERCEL_TEAM_ID` | Vercel 团队 ID | — | @@ -274,7 +275,7 @@ VERCEL_TEAM_ID=team_xxxxxxxxxxxx # 个人账号可留空 详细说明参见 [API.md](../API.md#admin-接口) 中 `/admin/settings` 部分。 -### 3.3 Vercel 架构说明 +### 3.4 Vercel 架构说明 ```text 请求 ─────┐ @@ -316,7 +317,7 @@ api/index.go api/chat-stream.js `vercel.json` 已将 `api/chat-stream.js` 与 `api/index.go` 的 `maxDuration` 设为 `300`(受 Vercel 套餐上限约束)。 -### 3.4 Vercel 常见报错排查 +### 3.5 Vercel 常见报错排查 #### Go 构建失败 @@ -360,7 +361,7 @@ No Output Directory named "public" found after the Build completed. - **方案 B**:请求中添加 `x-vercel-protection-bypass` 头 - **方案 C**:设置 `VERCEL_AUTOMATION_BYPASS_SECRET`(或 `DS2API_VERCEL_PROTECTION_BYPASS`),仅影响内部 Node→Go 调用 -### 3.5 仓库不提交构建产物 +### 3.6 仓库不提交构建产物 - `static/admin` 目录不在 Git 中 - Vercel / Docker 构建阶段自动生成 WebUI 静态文件 @@ -587,4 +588,4 @@ go run ./cmd/ds2api-tests \ - ✅ 真实调用场景验证(OpenAI/Claude/Admin/并发/toolcall/流式) - ✅ 全量请求与响应日志落盘(用于故障复盘) -详细测试集说明参阅 [TESTING.md](TESTING.md)。 +详细测试集说明参阅 [TESTING.md](TESTING.md)。PR 前的固定本地门禁以 [TESTING.md](TESTING.md#pr-门禁--pr-gates) 为准。 diff --git a/docs/README.md b/docs/README.md index 837fc87..6fcd0d7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,6 +21,7 @@ ### 文档维护约定 +- 文档更新必须以实际代码实现为依据:路由看 `internal/*/handler_routes.go` 与 `internal/admin/handler.go`,配置默认值看 `internal/config/*`,模型/alias 看 `internal/config/models.go`,prompt 兼容链路看 `docs/prompt-compatibility.md` 列出的代码入口。 - `README.MD` / `README.en.md`:面向首次接触用户,保留“是什么 + 怎么快速跑起来”。 - `docs/ARCHITECTURE*.md`:面向开发者,集中维护项目结构、模块职责与调用链。 - `API*.md`:面向客户端接入者,聚焦接口行为、鉴权和示例。 @@ -50,6 +51,7 @@ Recommended reading order: ### Maintenance conventions +- Documentation updates must be grounded in the actual implementation: routes live in `internal/*/handler_routes.go` and `internal/admin/handler.go`, config defaults in `internal/config/*`, models/aliases in `internal/config/models.go`, and the prompt compatibility pipeline in the code entrypoints listed by `docs/prompt-compatibility.md`. - `README.MD` / `README.en.md`: onboarding-oriented (“what + quick start”). - `docs/ARCHITECTURE*.md`: developer-oriented source of truth for module boundaries and execution flow. - `API*.md`: integration-oriented behavior/contracts. diff --git a/docs/TESTING.md b/docs/TESTING.md index fd4e8f3..3a58e67 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -20,6 +20,25 @@ Node 单元测试脚本会先做 `node --check` 语法门禁,再以 `--test-co --- +## PR 门禁 | PR Gates + +打开或更新 PR 前,按 `.github/workflows/quality-gates.yml` 的同等本地门禁执行: + +```bash +./scripts/lint.sh +./tests/scripts/check-refactor-line-gate.sh +./tests/scripts/run-unit-all.sh +npm run build --prefix webui +``` + +说明: + +- `./scripts/lint.sh` 会运行 Go 格式化检查和 `golangci-lint`;修改 Go 文件后仍建议先执行 `gofmt -w `。 +- `run-unit-all.sh` 串行调用 Go 与 Node 单元测试入口。 +- `run-live.sh` 是真实账号端到端测试,适合作为发布或高风险改动后的补充验证,不属于每次 PR 的固定本地门禁。 + +--- + ## 快速开始 | Quick Start ### 单元测试 | Unit Tests @@ -39,7 +58,7 @@ Node 单元测试脚本会先做 `node --check` 语法门禁,再以 `--test-co ./tests/scripts/check-refactor-line-gate.sh ./tests/scripts/check-node-split-syntax.sh -# 发布阻断:阶段 6 手工烟测签字检查(默认读取 plans/stage6-manual-smoke.md) +# 历史阶段门禁:阶段 6 手工烟测签字检查(默认读取 plans/stage6-manual-smoke.md) ./tests/scripts/check-stage6-manual-smoke.sh ``` diff --git a/docs/prompt-compatibility.md b/docs/prompt-compatibility.md index e6ef59d..82a1496 100644 --- a/docs/prompt-compatibility.md +++ b/docs/prompt-compatibility.md @@ -45,7 +45,7 @@ DS2API 当前的核心思路,不是把客户端传来的 `messages`、`tools` -> 统一消息标准化 -> tool prompt 注入 -> DeepSeek 风格 prompt 拼装 - -> 文件收集 / inline 上传 / history split + -> 文件收集 / inline 上传 / history split(OpenAI 链路) -> completion payload -> 下游网页对话接口 ``` @@ -96,7 +96,7 @@ DS2API 当前的核心思路,不是把客户端传来的 `messages`、`tools` - `prompt` 才是对话上下文主载体。 - `ref_file_ids` 只承载文件引用,不承载普通文本消息。 - `tools` 不会作为“原生工具 schema”直接下发给下游,而是被改写进 `prompt`。 -- OpenAI、Responses、Claude、Gemini 等入口都会先翻译成统一的 OpenAI 兼容请求形状,再走同一套归一化与 DeepSeek payload 组装。 +- OpenAI Chat / Responses 原生走统一 OpenAI 标准化与 DeepSeek payload 组装;Claude / Gemini 会尽量复用 OpenAI prompt/tool 语义,其中 Gemini 直接复用 `openai.BuildPromptForAdapter`,Claude 消息接口在可代理场景会转换为 OpenAI chat 形态再执行。 - 客户端传入的 thinking / reasoning 开关会被归一到下游 `thinking_enabled`。Claude surface 没有 `thinking` 字段时按 Anthropic 语义视为关闭;Gemini `generationConfig.thinkingConfig.thinkingBudget` 会翻译成同一套 thinking 开关;关闭时即使上游返回 `response/thinking_content`,兼容层也不会把它当作可见正文输出。 ## 5. prompt 是怎么拼出来的 @@ -286,6 +286,7 @@ OpenAI 文件相关实现: - top-level `system` 优先作为系统提示 - `tool_use` / `tool_result` 会被转换成统一的 assistant/tool 历史语义 - `tools` 同样会被并进 system prompt +- 常规执行通过 `internal/adapter/claude/handler_messages.go` 转到 OpenAI chat 路径,模型 alias 会先解析成 DeepSeek 原生模型 - 当前代码里没有像 OpenAI 那样完整的 `ref_file_ids` 附件链路 ### 10.3 Gemini @@ -295,6 +296,7 @@ OpenAI 文件相关实现: - `systemInstruction`、`contents.parts`、`functionCall`、`functionResponse` 会先归一 - tools 会转成 OpenAI 风格 function schema - prompt 构建复用 OpenAI 的 `BuildPromptForAdapter` +- 未识别的非文本 part 会被安全序列化进 prompt,并对二进制/疑似 base64 内容做省略或截断处理 也就是说,Gemini 在“最终 prompt 语义”上,尽量和 OpenAI 保持一致。 diff --git a/docs/toolcall-semantics.md b/docs/toolcall-semantics.md index 5d0b619..477ad80 100644 --- a/docs/toolcall-semantics.md +++ b/docs/toolcall-semantics.md @@ -27,6 +27,8 @@ 任何不满足上述 canonical XML 形态的内容,都会保留为普通文本,不会执行。 +当前 parser 不把 allow-list 当作硬安全边界:即使传入了已声明工具名列表,XML 里出现未声明工具名时也会尽量解析并交给上层协议输出;真正的执行侧仍必须自行校验工具名和参数。 + ## 3) 流式与防泄漏行为 在流式链路中(Go / Node 一致): diff --git a/pow/README.md b/pow/README.md index 7467fd2..85c74e1 100644 --- a/pow/README.md +++ b/pow/README.md @@ -1,6 +1,6 @@ # DeepSeek PoW 纯算实现 -替代 `internal/deepseek/assets/sha3_wasm_bg.*.wasm` + wazero 运行时。 +当前服务端 PoW 已走纯 Go 实现:`internal/deepseek/pow.go` 负责从上游 challenge map 中取字段,调用 `ds2api/pow` 求解 nonce,并组装 `x-ds-pow-response` header。 ## 算法 @@ -17,48 +17,14 @@ hash = DeepSeekHashV1(input) → 32 bytes header = base64(json({algorithm, challenge, salt, answer, signature, target_path})) ``` -## 性能 (Apple M4, Go 1.25) +## 主要入口 -``` -BenchmarkHash 187.5 ns/op 0 alloc → 5.33M hash/s -BenchmarkSolve 13.4 ms/op 2 alloc → 75 道/秒/核 (difficulty=144000) -``` - -对比 wazero 调 WASM: hash 快 **5×**, solve 快 **2.8×**。 +- `pow/deepseek_hash.go`:DeepSeekHashV1 / Keccak-f[1600] rounds 1..23。 +- `pow/deepseek_pow.go`:`SolvePow`、`BuildPowHeader`、`SolveAndBuildHeader`。 +- `internal/deepseek/pow.go`:服务侧适配层,校验 `algorithm == DeepSeekHashV1` 并调用 `pow.SolvePow`。 ## 测试 ```bash cd pow && go test -v ./... && go test -bench=. -benchmem ``` - -## 替换 WASM - -替换 `internal/deepseek/pow.go` 中 `PowSolver.Compute`: - -```go -// 原: 调 wasm_solve(retptr, chPtr, chLen, prefixPtr, prefixLen, difficulty) -// 新: -import "ds2api/pow" - -func (c *Client) GetPow(ctx context.Context, a *auth.RequestAuth, ...) (string, error) { - // ... 省略 token/retry 逻辑,只改 compute 部分 ... - challenge, _ := bizData["challenge"].(map[string]any) - ch := &pow.Challenge{ - Algorithm: challenge["algorithm"].(string), - Challenge: challenge["challenge"].(string), - Salt: challenge["salt"].(string), - ExpireAt: int64(challenge["expire_at"].(float64)), - Difficulty: int64(challenge["difficulty"].(float64)), - Signature: challenge["signature"].(string), - TargetPath: challenge["target_path"].(string), - } - return pow.SolveAndBuildHeader(ch) -} -``` - -可删除: -- `internal/deepseek/assets/sha3_wasm_bg.*.wasm` -- `internal/deepseek/embedded_pow.go` -- `internal/deepseek/pow.go` 中 `PowSolver` 结构体、wazero 相关池化代码 -- `go.mod` 中 `github.com/tetratelabs/wazero` 依赖 diff --git a/tests/raw_stream_samples/README.md b/tests/raw_stream_samples/README.md index 9b2957e..5f89183 100644 --- a/tests/raw_stream_samples/README.md +++ b/tests/raw_stream_samples/README.md @@ -87,7 +87,7 @@ for d in tests/raw_stream_samples/*; do done ``` -回放输出会显示 `tokens=/`,并在不一致时判定失败;`report.json` 中也会包含: +回放输出会显示 `tokens=/`;默认只记录 token 差异,不因 token 不一致失败。如需把 token 差异作为失败条件,给模拟器增加 `--fail-on-token-mismatch`。`report.json` 中也会包含: - `raw_expected_output_tokens` - `raw_parsed_output_tokens`