mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-19 16:39:15 +00:00
feat(adapter): move per-source error condensing into transform_error hooks
Every upstream formats errors differently, which is adapter territory: the protocol gains an optional transform_error(status, body) hook and all built-in adapters implement their own envelope parsing (zen free-pool labels, anthropic/gemini/ollama/mistral shapes, sensenova quota notes, agentrouter WAF pages). The core keeps a single uniform fallback: when no hook yields a reason clients get "api error <status>: unknown error" and the raw body goes to server logs only.
This commit is contained in:
@ -55,6 +55,7 @@ state may be shared across workers (`log` to stdout is the only side effect).
|
||||
| `version` | string | no | Version, shown in the WebUI |
|
||||
| `endpoint` | string | no | Upstream path, default `/chat/completions`; overridable by `source.endpoint` / `source.image_endpoint` |
|
||||
| `headers` | table | no | Static default request headers; used as fallback when no `build_headers` hook is defined |
|
||||
| `transform_error(status, body)` | function | no | Error-response condensing: return a one-line reason; on nil / absence clients uniformly receive `unknown error` (raw body goes to server logs only) |
|
||||
|
||||
These fields are extracted statically at load time (compile-once); reading them never
|
||||
occupies a pooled worker.
|
||||
@ -147,6 +148,27 @@ end
|
||||
|
||||
## 4. Optional Hooks
|
||||
|
||||
### `transform_error(status, body) -> string | nil`
|
||||
|
||||
Condense this source's error response into a one-line reason. Every upstream
|
||||
formats errors differently — that is adapter territory: all built-in adapters
|
||||
implement their own envelope parsing (zen's `{error={type,message}}`,
|
||||
Anthropic's `{type="error",error={...}}`, Gemini's
|
||||
`{error={code,message,status}}`, Ollama's string `{error="..."}`, etc.).
|
||||
When the hook is absent or returns nil the core does not guess: clients get
|
||||
`api error <status>: unknown error` and the raw body is logged server-side only.
|
||||
|
||||
```lua
|
||||
function adapter.transform_error(status, body)
|
||||
local ok, resp = pcall(json.decode, body)
|
||||
if not ok or type(resp) ~= "table" then return nil end
|
||||
if resp.error and resp.error.type == "FreeUsageLimitError" then
|
||||
return "zen free pool quota exhausted"
|
||||
end
|
||||
return resp.error and resp.error.message or nil
|
||||
end
|
||||
```
|
||||
|
||||
### `build_headers(meta) -> table<string,string>`
|
||||
|
||||
Dynamically generate / sign request headers (e.g. KimiCode's HMAC signature). If the
|
||||
|
||||
@ -50,6 +50,7 @@ return adapter
|
||||
| `version` | string | 否 | 版本号,用于 WebUI 展示 |
|
||||
| `endpoint` | string | 否 | 上游请求路径,默认 `/chat/completions`;可被 `source.endpoint` / `source.image_endpoint` 覆盖 |
|
||||
| `headers` | table | 否 | 静态默认请求头;若未定义 `build_headers` 钩子则作为请求头回退 |
|
||||
| `transform_error(status, body)` | function | 否 | 错误响应收敛:返回一行短原因;返回 nil / 未定义时客户端统一收到 `unknown error`(原始响应体只进服务端日志) |
|
||||
|
||||
这些字段在加载时静态提取(compile-once),之后读它们不会占用池内 worker。
|
||||
|
||||
@ -138,6 +139,26 @@ end
|
||||
|
||||
## 4. 可选钩子
|
||||
|
||||
### `transform_error(status, body) -> string | nil`
|
||||
|
||||
把该源特有的错误响应收敛成一行短原因。每个上游的错误格式不同——这是适配器层
|
||||
的职责:内置各适配器均实现了自己的信封解析(如 zen 的
|
||||
`{error={type,message}}`、Anthropic 的 `{type="error",error={...}}`、Gemini 的
|
||||
`{error={code,message,status}}`、Ollama 的字符串 `{error="..."}` 等)。
|
||||
未定义本钩子或返回 nil 时,核心不猜测格式,客户端统一收到
|
||||
`api error <status>: unknown error`,原始响应体仅记录在服务端日志。
|
||||
|
||||
```lua
|
||||
function adapter.transform_error(status, body)
|
||||
local ok, resp = pcall(json.decode, body)
|
||||
if not ok or type(resp) ~= "table" then return nil end
|
||||
if resp.error and resp.error.type == "FreeUsageLimitError" then
|
||||
return "zen free pool quota exhausted"
|
||||
end
|
||||
return resp.error and resp.error.message or nil
|
||||
end
|
||||
```
|
||||
|
||||
### `build_headers(meta) -> table<string,string>`
|
||||
|
||||
动态生成/签名请求头(如 KimiCode 的 HMAC 签名)。若脚本未定义此函数,Go 层回退使用静态
|
||||
|
||||
Reference in New Issue
Block a user