Files
CLIProxyAPI/examples/plugin/README_CN.md
Luis Pater 6ba444557c feat(pluginabi): support HTTP status code propagation in plugin error envelopes
- Add `Error.Error`, `Error.StatusCode`, `NewError`, and `NewErrorEnvelope` helpers in `sdk/pluginabi`.
- Support extracting and forwarding HTTP status codes in Go plugin executor examples and generator script.
- Document plugin executor error handling and client HTTP status mapping conventions.

Closes: #5809
2026-09-14 18:44:04 +08:00

7.6 KiB
Raw Blame History

标准动态库插件示例

本目录包含 CLIProxyAPI C ABI 的标准动态库插件示例。

目录布局

  • simple/:声明全部支持能力的完整骨架示例。
  • model/:只演示模型能力。
  • auth/:只演示认证提供方能力。
  • frontend-auth/:只演示前端认证提供方能力。
  • frontend-auth-exclusive/:演示被选中后成为唯一请求认证方式的前端认证提供方。
  • executor/:只演示执行器能力。
  • protocol-format/:使用最小执行器重点演示输入和输出格式声明。
  • request-translator/:只演示请求转换能力。
  • request-normalizer/:只演示请求规整能力。
  • codex-service-tier/:仅 Go 实现的请求规整插件,启用后会将 Codex gpt-5.5 请求设置为 priority service tier。
  • request-lifecycle/:仅 Go 实现的请求生命周期插件,演示并发控制、主动终止 HTTP 请求和终态回调。
  • scheduler/:仅 Go 实现的调度插件,可选择指定 auth ID、委托内置调度器或拒绝调度。
  • response-translator/:只演示响应转换能力。
  • response-normalizer/:只演示响应规整能力。
  • thinking/:只演示 Thinking 处理能力。
  • usage/:只演示 Usage 观察能力。
  • cli/:只演示命令行扩展能力。
  • management-api/:只演示 Management API 和资源扩展能力。
  • host-callback/:使用最小插件资源演示宿主回调。
  • host-callback-auth-files/:仅 Go 实现的插件资源,演示 host 凭证文件回调。
  • host-model-callback/:仅 Go 实现的插件资源,演示调用宿主模型执行回调。

多数标准能力示例都包含 go/、c/ 和 rust/ 三个子目录。专用示例可能只提供所需的实现语言。

Codex Service Tier

codex-service-tier 声明请求规整能力。当 fast 为 true 时,如果 req.ToFormat 为 codex 且 req.Model 为 gpt-5.5,它会将 service_tier 设置为 priority。

plugins:
  configs:
    codex-service-tier:
      enabled: true
      priority: 1
      fast: false

请求生命周期

request-lifecycle 同时声明 request_interceptor 和 request_lifecycle_plugin。它会在认证选择前占用并发槽位,可以直接返回自定义 403 或 429 响应而不请求上游模型,并在成功、失败、拒绝或取消时通过 request.complete 释放已接入请求的槽位。

plugins:
  configs:
    request-lifecycle:
      enabled: true
      priority: 100
      max_concurrency: 2
      reject_keyword: "blocked"

构建方式和生命周期语义详见 request-lifecycle/README.md。

Host Auth Files 回调

host-callback-auth-files 声明 Management API 能力,并暴露名为 Host Auth Files 的浏览器资源,演示 host.auth.list、host.auth.get(物理 JSON 文件)、host.auth.get_runtime 与 host.auth.save。

plugins:
  configs:
    host-callback-auth-files:
      enabled: true
      priority: 1

详见 host-callback-auth-files/README.md。

Host Model Callback

host-model-callback 声明 Management API 能力,并暴露名为 Host Model Callback 的浏览器资源。该资源在非流式请求中调用 host.model.execute,在流式请求中调用 host.model.execute_stream 和 host.model.stream_read。它演示了通过 host.model.stream_close 显式关闭流,也提供 implicit_close=true 用于演示 RPC 作用域结束时的宿主隐式清理。

当该资源转发自身收到的 host_callback_id 时,CPA 会识别发起宿主模型回调的插件,并在嵌套模型执行中跳过同一个插件的拦截器。因此宿主模型回调不会递归调用发起插件自身,但其他已启用插件仍可拦截这次嵌套请求。

plugins:
  configs:
    host-model-callback:
      enabled: true
      priority: 1

默认示例模型是 gpt-5.5,但请求能否成功取决于当前 CPA 模型和认证配置是否可以路由该模型。

Scheduler

scheduler 声明调度能力。它可以从候选列表中选择配置的 auth ID,委托内置的 fill-first 或 round-robin 调度器,或在 deny 为 true 时拒绝调度。

plugins:
  configs:
    scheduler:
      enabled: true
      priority: 1
      auth_id: ""
      delegate: ""
      deny: false

auth_id 会在 delegate 为空时选择匹配候选。delegate 支持 ""、fill-first 和 round-robin;其他非空值会让本插件不处理本次调度。deny 会返回调度错误。

插件执行器错误处理与 HTTP 状态码

当插件执行器(Executor)遇到上游调用失败(如因凭据无效返回 401 Unauthorized、因模型权限或配额限制返回 403 Forbidden,或因限流返回 429 Too Many Requests)时,应在错误信封中设置 HTTP 状态码:

  • 在 JSON RPC 错误信封中,设置 error 对象内的 http_status 字段(对应 pluginabi.Error.HTTPStatus)。
  • 若省略 http_status 或设置为 0,CPA 会默认将错误降级为 HTTP 500 Internal Server Error(server_error / internal_server_error),导致客户端将其误判为网关故障并进行退避重试。
  • 显式设置 http_status 后,CPA 会将状态码正确映射为结构化的客户端错误响应:
    • 401 -> HTTP 401,type: "authentication_error",code: "invalid_api_key"
    • 403 -> HTTP 403,type: "permission_error",code: "insufficient_quota"
    • 429 -> HTTP 429,type: "rate_limit_error",code: "rate_limit_exceeded"
    • 404 -> HTTP 404,type: "invalid_request_error",code: "model_not_found"
    • >=500 -> HTTP 5xx,type: "server_error",code: "internal_server_error"
  • 注意:非流式执行(executor.execute)和流式执行(executor.execute_stream)两处报错路径均需要设置 http_status,以保证异常分类行为一致。
  • 原生动态库插件通过 C ABI 交换序列化的 JSON 缓冲区通信,因此状态码必须编码到序列化的 JSON 信封中(例如使用 pluginabi.NewErrorEnvelope 或自定义带 http_status 字段的信封结构体)。Go 语言原生的 error 对象无法跨越 C ABI 边界传递。

Go 语言编写的插件可导入 github.com/router-for-me/CLIProxyAPI/v7/sdk/pluginabi 并直接使用 pluginabi.NewErrorEnvelope(code, message, httpStatus):

// 推荐方式:直接使用 sdk/pluginabi 构造错误信封
rawEnvelope, errMarshal := pluginabi.NewErrorEnvelope("insufficient_quota", "plan limit reached", http.StatusForbidden)

也可以在自定义信封结构体中声明 HTTPStatus 字段(json:"http_status,omitempty"):

type envelopeError struct {
	Code       string `json:"code"`
	Message    string `json:"message"`
	HTTPStatus int    `json:"http_status,omitempty"`
}

func errorEnvelope(code, message string, httpStatus ...int) []byte {
	status := 0
	if len(httpStatus) > 0 {
		status = httpStatus[0]
	}
	raw, _ := json.Marshal(envelope{
		OK: false,
		Error: &envelopeError{
			Code:       code,
			Message:    message,
			HTTPStatus: status,
		},
	})
	return raw
}

构建全部示例

make -C examples/plugin list
make -C examples/plugin build

构建产物会写入 examples/plugin/bin。

说明

protocol-format 使用最小执行器承载,因为格式声明属于执行器能力。

host-callback 使用最小插件资源承载,因为宿主回调只能从插件方法内部发起,不是独立能力。

management.register 通过 resources 字段返回的菜单资源会由 CPA 暴露在 /v0/resource/plugins/<pluginID>/... 下。需要认证的插件自有 Management API 路由仍保留在 /v0/management/... 下。