Documentation
¶
Index ¶
- Constants
- Variables
- func ExtractOrGenerateRequestID(headers http.Header) string
- func GetPluginDSN(ctx PluginContext) string
- func InitLogger(module, level, format string)
- func IsKnownCapability(c Capability) bool
- func LogFormat() string
- func LoggerFromContext(ctx context.Context) *slog.Logger
- func LoggerWithRequestID(ctx context.Context) (context.Context, *slog.Logger)
- func RemainingSecondsUntil(resetAt *time.Time, now time.Time) int
- func RequestIDFromContext(ctx context.Context) string
- func ResetAtFromBase(base time.Time, resetAfterSeconds int) *time.Time
- func WithLogger(ctx context.Context, logger *slog.Logger) context.Context
- func WithRequestID(ctx context.Context, id string) context.Context
- type Account
- type AccountTodayStats
- type AccountType
- type AccountUsageAccountsResponse
- type AccountUsageCredits
- type AccountUsageError
- type AccountUsageInfo
- type AccountUsageWindow
- type BackgroundTask
- type Capability
- type CapabilityValidationReport
- type ConfigField
- type ConfigWatcher
- type CostInput
- type CostResult
- type CredentialField
- type DecisionAction
- type ExtensionPlugin
- type ForwardOutcome
- type ForwardRequest
- type FrontendPage
- type FrontendWidget
- type GatewayPlugin
- type HealthChecker
- type Host
- type HostAssetBytes
- type HostAware
- type HostForwardChunk
- type HostForwardRequest
- type HostForwardResponse
- type HostForwardUsage
- type HostGroup
- type HostPlatform
- type HostProbeForwardRequest
- type HostProbeForwardResult
- type HostSelectAccountRequest
- type HostSelectAccountResult
- type HostStoreAssetRequest
- type HostStoredAsset
- type HostUserInfo
- type MiddlewareDecision
- type MiddlewareEvent
- type MiddlewarePlugin
- type MiddlewareRequest
- type ModelInfo
- type OutcomeKind
- type Plugin
- type PluginConfig
- type PluginContext
- type PluginDSNAware
- type PluginInfo
- type PluginType
- type QuotaInfo
- type RequestHandler
- type RouteDefinition
- type RouteRegistrar
- type UpstreamResponse
- type Usage
- type WebAssetsProvider
- type WebSocketConn
- type WebSocketConnectInfo
Constants ¶
const ( WSMessageText = 1 WSMessageBinary = 2 )
WebSocket 消息类型(与 gorilla/websocket 的 TextMessage / BinaryMessage 对齐)。
const ( HeaderRequestID = "X-Request-ID" LogFieldRequestID = "request_id" LogFieldUserID = "user_id" LogFieldGroupID = "group_id" LogFieldAccountID = "account_id" LogFieldAPIKeyID = "api_key_id" LogFieldPluginID = "plugin_id" LogFieldModel = "model" LogFieldPlatform = "platform" LogFieldStatus = "status_code" LogFieldDurationMs = "duration_ms" LogFieldError = "error" LogFieldMethod = "method" LogFieldPath = "path" LogFieldReason = "reason" )
日志相关 HTTP header 与字段名约定。
字段命名一律 snake_case,事件名一律 snake_case,由 slog 统一输出。 全局 module 字段由 InitLogger 注入("core" 或 "plugin.<id>")。
const ( DefaultMiddlewareDeadline = 200 * time.Millisecond DefaultMiddlewareChainBudget = 500 * time.Millisecond )
DefaultMiddlewareDeadline / DefaultMiddlewareChainBudget 单 hook / 整条链的默认超时预算。 Core 侧按此兜底,middleware 超时不得 block 主流程,只会被跳过并 log warn。
const ( SlotAccountForm = "account-form" SlotAccountDetail = "account-detail" )
前端组件插槽。
const ConfigKeyLogLevel = "_log_level"
ConfigKeyLogLevel Core 通过此配置键把日志级别传给插件。
const PluginDSNConfigKey = "plugin_dsn"
PluginDSNConfigKey Core 注入"插件专属数据库 DSN"时使用的 config key。 插件作者应通过 GetPluginDSN(ctx) 访问,而非直接拼字符串。
const SDKVersion = "0.3.0"
SDKVersion 当前 SDK 版本,插件编译时嵌入到 PluginInfo。 0.3.0 起强制 Capability 声明:未声明 capability 的插件调用 HostService 会被拒绝。
Variables ¶
var ErrInvalidCredentials = errors.New("invalid credentials")
ErrInvalidCredentials ValidateAccount 判定凭证格式/语义不合法时返回。
var ErrNotSupported = errors.New("not supported")
ErrNotSupported 插件不支持某项可选能力时返回(如 QueryQuota / HandleWebSocket)。
Functions ¶
func ExtractOrGenerateRequestID ¶ added in v0.1.1
ExtractOrGenerateRequestID 从 HTTP header 抽取 X-Request-ID;缺失则生成新 UUID。
用于 core 入口、插件 HTTP 处理器等所有"链路开始"的位置:
- core 接到客户端请求 → 抽取/生成 → 写回 header → 透传给插件
- 插件回调入口(webhook 等) → 同样抽取/生成
func GetPluginDSN ¶
func GetPluginDSN(ctx PluginContext) string
GetPluginDSN PluginDSNAware 的便利访问器:ctx 实现了接口就返回 DSN,否则回退读 Config。
func InitLogger ¶
func InitLogger(module, level, format string)
InitLogger 初始化全局 slog。 module 日志来源标识(如 "core"、"plugin.gateway-openai");level: debug/info/warn/error;format: text/json。
text 格式且 stdout 是 TTY 时自动启用 ANSI 颜色(按等级染色 + request_id 高亮); 重定向到文件 / 管道、或设置 NO_COLOR=1 时自动退化为纯文本。
func IsKnownCapability ¶
func IsKnownCapability(c Capability) bool
IsKnownCapability 判断 capability 是否在当前 SDK 版本的已知集合内。
func LoggerFromContext ¶ added in v0.1.1
LoggerFromContext 从 context 取 logger;不存在则返回 slog.Default()。
该函数永远不返回 nil,调用方可直接 .Info/.Error。
func LoggerWithRequestID ¶ added in v0.1.1
LoggerWithRequestID 为 ctx 派生一个带 request_id 字段的 logger 并写回 ctx。
典型用法(HTTP 中间件):
rid := sdk.ExtractOrGenerateRequestID(r.Header)
ctx = sdk.WithRequestID(ctx, rid)
ctx, logger := sdk.LoggerWithRequestID(ctx)
logger.Info("http_request_received", "method", r.Method, "path", r.URL.Path)
func RemainingSecondsUntil ¶
RemainingSecondsUntil 返回从 now 到 resetAt 的剩余秒数。 过期或 nil 一律返回 0。
func RequestIDFromContext ¶ added in v0.1.1
RequestIDFromContext 从 context 取 request_id;不存在返回空串。
func ResetAtFromBase ¶
ResetAtFromBase 根据基准时间和 reset_after_seconds 计算绝对重置时间。 负数会被钳制为 0。
func WithLogger ¶ added in v0.1.1
WithLogger 把 logger 绑到 context;通常由 HTTP/gRPC 入口构造请求级 logger 后调用。
Types ¶
type Account ¶
type Account struct {
ID int64 `json:"id"`
Name string `json:"name"`
Platform string `json:"platform"`
Type string `json:"type"` // 对应 AccountType.Key(apikey / oauth / ...)
Credentials map[string]string `json:"credentials"` // JSONB 透传,结构由 Type 决定
ProxyURL string `json:"proxy_url"`
}
Account 上游账户(Core 调度后传给插件的最小视图)。
type AccountTodayStats ¶
type AccountTodayStats struct {
Requests int64 `json:"requests"`
Tokens int64 `json:"tokens"`
AccountCost float64 `json:"account_cost"`
UserCost float64 `json:"user_cost"`
}
AccountTodayStats 账号当天(本地时区自然日)在 usage_logs 中的聚合统计。 由 Core 基于 usage_logs 计算,插件不需要生成。
- Requests 请求总数(count)
- Tokens token 总数(input + output + cache_read + cache_creation)
- AccountCost 账号成本 = SUM(account_cost)(上游账号的真实消耗,不受用户侧倍率影响)
- UserCost 用户消耗 = SUM(actual_cost)(扣 User.balance 的金额)
type AccountType ¶
type AccountType struct {
Key string `json:"key"`
Label string `json:"label"`
Description string `json:"description"`
Fields []CredentialField `json:"fields"`
}
AccountType 账号类型声明。
type AccountUsageAccountsResponse ¶
type AccountUsageAccountsResponse struct {
Accounts map[string]AccountUsageInfo `json:"accounts"`
Errors []AccountUsageError `json:"errors,omitempty"`
}
AccountUsageAccountsResponse 是 usage/accounts 之类账号批量用量接口的通用响应。
type AccountUsageCredits ¶
type AccountUsageCredits struct {
Balance float64 `json:"balance"`
Unlimited bool `json:"unlimited"`
}
AccountUsageCredits 描述账号的额度信息。
type AccountUsageError ¶
AccountUsageError 描述插件在探测账号用量时发现的单账号错误。
type AccountUsageInfo ¶
type AccountUsageInfo struct {
UpdatedAt string `json:"updated_at,omitempty"`
Windows []AccountUsageWindow `json:"windows,omitempty"`
Credits *AccountUsageCredits `json:"credits,omitempty"`
TodayStats *AccountTodayStats `json:"today_stats,omitempty"`
}
AccountUsageInfo 描述单个账号的通用用量视图。
TodayStats 是 Core 本地聚合的当天统计(从 usage_logs 按自然日计算), 和 Windows 是两码事:Windows 反映上游 quota 百分比,TodayStats 反映 本地 gateway 视角的账号当天真实消耗。
type AccountUsageWindow ¶
type AccountUsageWindow struct {
Key string `json:"key,omitempty"`
Label string `json:"label"`
UsedPercent float64 `json:"used_percent"`
ResetAt string `json:"reset_at,omitempty"`
ResetSeconds int `json:"reset_seconds,omitempty"`
}
AccountUsageWindow 描述账号的单个用量窗口。 插件负责把平台专属窗口语义归一化到这个结构,Core 只做通用展示。
func NewAccountUsageWindow ¶
func NewAccountUsageWindow(key, label string, usedPercent float64, resetAt *time.Time, now time.Time) AccountUsageWindow
NewAccountUsageWindow 构建通用用量窗口,并同时填充 reset_at / reset_seconds。
type BackgroundTask ¶
type BackgroundTask struct {
Name string
Interval time.Duration
Handler func(ctx context.Context) error
}
BackgroundTask 后台任务声明(Core 负责调度)。
type Capability ¶
type Capability string
Capability 类型化的能力标识符(命名规范:<domain>.<action>)。 所有 capability 常量必须用此类型以便编译期捕获拼写错误。
运行时授权由 Core 的 gRPC interceptor 强制执行;本类型是 SDK 侧的强类型入口, 并不绕过 Core 的准入校验。
const ( CapabilityHostListGroups Capability = "host.list_groups" CapabilityHostSelectAccount Capability = "host.select_account" CapabilityHostProbeForward Capability = "host.probe_forward" CapabilityHostReportAccountResult Capability = "host.report_account_result" CapabilityHostForward Capability = "host.forward" CapabilityHostListPlatforms Capability = "host.list_platforms" CapabilityHostListModels Capability = "host.list_models" CapabilityHostGetUserInfo Capability = "host.get_user_info" CapabilityHostAssetStorage Capability = "host.asset_storage" CapabilityMiddlewareReadBody Capability = "middleware.read_body" )
func KnownCapabilities ¶
func KnownCapabilities() []Capability
KnownCapabilities 返回所有已知 capability,按字典序排序。
func (Capability) String ¶
func (c Capability) String() string
type CapabilityValidationReport ¶
type CapabilityValidationReport struct {
// Effective 当前 plugin type 下实际生效的 capability = 声明 ∩ 类型允许,去重+排序。
Effective []Capability
// Unknown SDK 不认识的 capability(多半是拼写错)。
Unknown []Capability
// Denied SDK 认识但当前 plugin type 不允许的 capability(配置错误)。
Denied []Capability
}
CapabilityValidationReport ValidateCapabilities 的输出。
func ValidateCapabilities ¶
func ValidateCapabilities(typ PluginType, declared []Capability) CapabilityValidationReport
ValidateCapabilities 对一组声明做 self-check。授权决策仍由 Core 的 interceptor 负责, 这里只做"声明 vs 已知 vs 类型允许"的纸面检查。
func (CapabilityValidationReport) HasIssues ¶
func (r CapabilityValidationReport) HasIssues() bool
HasIssues 报告是否检测到任何问题。
type ConfigField ¶
type ConfigField struct {
Key string `json:"key"`
Label string `json:"label"`
Type string `json:"type"` // string / int / bool / float / duration / password
Required bool `json:"required"`
Default string `json:"default,omitempty"`
Description string `json:"description,omitempty"`
Placeholder string `json:"placeholder,omitempty"`
}
ConfigField 配置项声明。
type ConfigWatcher ¶
type ConfigWatcher interface {
OnConfigUpdate(config PluginConfig) error
}
ConfigWatcher 可选:支持配置热更新的插件实现。
type CostInput ¶
type CostInput struct {
InputTokens int
OutputTokens int
CachedInputTokens int // cache read tokens
CacheCreationTokens int // cache write 总数(= 5m + 1h;breakdown 缺失时作为 5m 计价的兜底)
CacheCreation5mTokens int // cache write(5 分钟 TTL,1.25x input)
CacheCreation1hTokens int // cache write(1 小时 TTL,2.00x input)
ServiceTier string // "priority" 使用优先级价格
}
CostInput 费用计算输入。
type CostResult ¶
type CostResult struct {
InputCost float64
OutputCost float64
CachedInputCost float64 // cache read 费用
CacheCreationCost float64 // cache write 费用
}
CostResult 费用计算结果(美元)
func CalculateCost ¶
func CalculateCost(input CostInput, model ModelInfo) CostResult
CalculateCost 根据 token 数和模型价格计算费用 ModelInfo 中的价格单位为"每百万 token",此函数自动转换为每 token
输入约定:
- input.InputTokens 已经是 **扣除 cached 后** 的非缓存输入(插件负责扣除)
- input.CachedInputTokens 是命中缓存的 token 数
- 完整 input_tokens = InputTokens + CachedInputTokens,长上下文阈值基于此
计费顺序(对齐 OpenAI 官方):
- 按 service_tier 选单价:standard / priority(配置价,缺省 ×2) / fast(×2.5) / flex|batch(×0.5)
- 命中长上下文阈值 → 再乘长上下文倍率(input/cached/output 独立系数)
- 三项独立计价后相加,cached 不重复计入 input
type CredentialField ¶
type CredentialField struct {
Key string `json:"key"`
Label string `json:"label"`
Type string `json:"type"` // text / password / textarea / select
Required bool `json:"required"`
Placeholder string `json:"placeholder"`
EditDisabled bool `json:"edit_disabled,omitempty"`
}
CredentialField 凭证字段声明。
type DecisionAction ¶
type DecisionAction int32
DecisionAction 对应 proto MiddlewareDecision.Action。
const ( DecisionAllow DecisionAction = 0 DecisionDeny DecisionAction = 1 DecisionMutate DecisionAction = 2 )
type ExtensionPlugin ¶
type ExtensionPlugin interface {
Plugin
RegisterRoutes(r RouteRegistrar)
Migrate() error
BackgroundTasks() []BackgroundTask
}
ExtensionPlugin 通用扩展插件接口:注册自定义路由、执行迁移、声明后台任务。
type ForwardOutcome ¶
type ForwardOutcome struct {
Kind OutcomeKind
Upstream UpstreamResponse
Usage *Usage
Duration time.Duration
RetryAfter time.Duration
Reason string
UpdatedCredentials map[string]string
}
ForwardOutcome 是插件对一次 Forward 的完整判决结果。
字段填写约定:
Kind 必填,零值视为 Unknown(Core 保守处理) Upstream 必填(StatusCode 至少填;Headers/Body 按 Kind 决定是否透传) Usage 仅 Success(偶尔 ClientError)下非 nil RetryAfter 仅 AccountRateLimited 下有意义 Duration 插件测得的耗时,Core 仅用于日志 Reason 人类可读原因,Core 仅落日志,不做任何判断 UpdatedCredentials 插件若在 Forward 中刷新了凭证(OAuth 轮转等)通过此字段带回
type ForwardRequest ¶
type ForwardRequest struct {
Account *Account
Body []byte
Headers http.Header
Model string
Stream bool
// Writer 流式响应写入目标。
// TODO(PR3): 替换为 StreamSink 抽象,让 Core 能在首字节落地前决定是否 failover。
Writer http.ResponseWriter
}
ForwardRequest 转发请求(Core → 插件)。
type FrontendPage ¶
type FrontendPage struct {
Path string `json:"path"`
Title string `json:"title"`
Icon string `json:"icon"`
Description string `json:"description"`
// Audience 决定页面可见范围:
// "admin" / "" 仅管理员(默认)
// "user" 仅普通登录用户
// "all" 所有登录用户
Audience string `json:"audience,omitempty"`
}
FrontendPage 前端独立页面声明。
type FrontendWidget ¶
type FrontendWidget struct {
Slot string `json:"slot"`
EntryFile string `json:"entry_file"`
Title string `json:"title"`
}
FrontendWidget 前端组件嵌入声明。
type GatewayPlugin ¶
type GatewayPlugin interface {
Plugin
Platform() string
Models() []ModelInfo
Routes() []RouteDefinition
Forward(ctx context.Context, req *ForwardRequest) (ForwardOutcome, error)
ValidateAccount(ctx context.Context, credentials map[string]string) error
QueryQuota(ctx context.Context, credentials map[string]string) (*QuotaInfo, error)
// HandleWebSocket 处理 WebSocket 双向通信。连接结束后返回 ForwardOutcome。
// 不支持时返回 ErrNotSupported。
HandleWebSocket(ctx context.Context, conn WebSocketConn) (ForwardOutcome, error)
}
GatewayPlugin 网关插件接口。
Core 负责:账号调度、并发/RPM 限流、计费、failover。 插件负责:声明模型/路由、转发请求、验证凭证、查询额度。
Forward 的返回契约:
- ForwardOutcome 表达业务判决(成功 / 客户端错 / 账号限流 / 账号死 / 上游抖动 / 流中断)
- error 仅表达"插件自身无法完成此次调用"(进程异常、gRPC 层故障),不承担业务语义
详见 outcome.go 的 OutcomeKind 文档。
type HealthChecker ¶
HealthChecker 可选:Core 定期调用以探测插件存活。
type Host ¶
type Host interface {
// SelectAccount 走和真实用户请求完全相同的调度路径选出一个账号。
SelectAccount(ctx context.Context, req HostSelectAccountRequest) (*HostSelectAccountResult, error)
// ReportAccountResult 把账号调用结果反馈给 scheduler 状态机。
ReportAccountResult(ctx context.Context, accountID int64, success bool, errMsg string) error
// ProbeForward 内部组装一次最小 chat completion 请求执行黑盒探测:
// 跳过 usage_log 与余额扣款,但仍 ReportResult 反哺账号状态机。
ProbeForward(ctx context.Context, req HostProbeForwardRequest) (*HostProbeForwardResult, error)
// Forward 非流式业务转发:走完整管线(调度 → 网关 → 计费 → usage_log)。
Forward(ctx context.Context, req HostForwardRequest) (*HostForwardResponse, error)
// ForwardStream 流式业务转发:结果通过 callback 逐块回调。
// callback 返回 error 时 Core 侧中断流。最后一块 Done=true 携带 Usage。
ForwardStream(ctx context.Context, req HostForwardRequest, callback func(chunk HostForwardChunk) error) error
// ListGroups 列出 Core 当前所有分组。
ListGroups(ctx context.Context) ([]HostGroup, error)
// ListPlatforms 列出已加载的网关平台。
ListPlatforms(ctx context.Context) ([]HostPlatform, error)
// ListModels 列出指定平台的模型列表。
ListModels(ctx context.Context, platform string) ([]ModelInfo, error)
// GetUserInfo 获取用户基本信息。
GetUserInfo(ctx context.Context, userID int64) (*HostUserInfo, error)
// StoreAsset 由 Core 根据全局 storage 设置保存资产并返回可访问 URL。
StoreAsset(ctx context.Context, req HostStoreAssetRequest) (*HostStoredAsset, error)
// GetAssetURL 根据 object key 返回当前配置下的可访问 URL。
GetAssetURL(ctx context.Context, objectKey string) (string, error)
// GetAssetBytes 根据 object key 返回资产原始内容。
GetAssetBytes(ctx context.Context, objectKey string) (*HostAssetBytes, error)
}
Host Core 暴露给插件的反向调用接口(plugin → core)。
通过 hashicorp/go-plugin 的 GRPCBroker 架起子进程隧道,插件无需 admin HTTP / Bearer 鉴权。
在插件 Init 里通过 HostAware 拿到:
func (p *MyPlugin) Init(ctx sdk.PluginContext) error {
if h, ok := ctx.(sdk.HostAware); ok {
p.host = h.Host() // 可能为 nil
}
return nil
}
type HostAssetBytes ¶ added in v0.1.3
HostAssetBytes 资产读取结果。
type HostAware ¶
type HostAware interface {
// Host 返回 Host 客户端;可能为 nil(Core 版本不支持 / 未启用)。
Host() Host
}
HostAware 可选接口:PluginContext 实现它就能暴露 Host。老 dev server / 测试 mock 可忽略。
type HostForwardChunk ¶ added in v0.1.1
type HostForwardChunk struct {
Data []byte
Done bool
StatusCode int
Headers http.Header
Usage HostForwardUsage
}
HostForwardChunk 流式转发的单块数据。
type HostForwardRequest ¶ added in v0.1.1
type HostForwardRequest struct {
UserID int64
GroupID int64
Model string
Method string
Path string
Headers http.Header
Body []byte
Stream bool
}
HostForwardRequest 业务转发入参。
type HostForwardResponse ¶ added in v0.1.1
type HostForwardResponse struct {
StatusCode int
Headers http.Header
Body []byte
Usage HostForwardUsage
}
HostForwardResponse 非流式转发结果。
type HostForwardUsage ¶ added in v0.1.1
HostForwardUsage 转发的 token / 费用摘要。
type HostGroup ¶
type HostGroup struct {
ID int64
Name string
Platform string
IsExclusive bool
RateMultiplier float64
}
HostGroup Host.ListGroups 返回的分组摘要。
type HostPlatform ¶ added in v0.1.1
HostPlatform 已加载的网关平台。
type HostProbeForwardRequest ¶
HostProbeForwardRequest 黑盒探测入参。
type HostProbeForwardResult ¶
type HostProbeForwardResult struct {
Success bool
AccountID int64
Platform string
Model string
StatusCode int64
LatencyMs int64
ErrorKind string
ErrorMsg string
}
HostProbeForwardResult 黑盒探测结果。
type HostSelectAccountRequest ¶
type HostSelectAccountRequest struct {
GroupID int64
Model string
SessionID string
ExcludeAccountIDs []int64
}
HostSelectAccountRequest 调度选号入参。
type HostSelectAccountResult ¶
HostSelectAccountResult 调度选号结果。
type HostStoreAssetRequest ¶ added in v0.1.2
type HostStoreAssetRequest struct {
UserID int64
Scope string
ContentType string
Data []byte
FileExtension string
}
HostStoreAssetRequest 资产存储入参。
type HostStoredAsset ¶ added in v0.1.2
type HostStoredAsset struct {
AssetID string
ObjectKey string
PublicURL string
SizeBytes int64
ContentType string
}
HostStoredAsset 资产存储结果。
type HostUserInfo ¶ added in v0.1.1
type HostUserInfo struct {
UserID int64
Username string
Email string
Role string
Balance float64
Status string
}
HostUserInfo 用户基本信息。
type MiddlewareDecision ¶
type MiddlewareDecision struct {
Action DecisionAction
// DenyStatusCode / DenyMessage 仅 DecisionDeny 使用;默认 403。
DenyStatusCode int32
DenyMessage string
// SetHeaders 仅 DecisionMutate 使用:追加或覆盖的请求头。
SetHeaders http.Header
// Metadata 无论 Action 是什么都会 merge 进请求上下文的 bag。
Metadata map[string]string
}
MiddlewareDecision OnForwardBegin 的返回值。nil 等价于 DecisionAllow 且不改任何东西。
type MiddlewareEvent ¶
type MiddlewareEvent struct {
RequestID string
UserID int64
GroupID int64
AccountID int64
Platform string
Model string
Stream bool
InputTokensEst int64
StatusCode int32
Duration time.Duration
InputTokens int64
OutputTokens int64
CachedInputTokens int64
FirstTokenMs int64
ErrorKind string // "" / "upstream_5xx" / "timeout" / "no_account" / ...
ErrorMsg string
InputCost float64
OutputCost float64
CachedInputCost float64
Metadata map[string]string
// ResponseBody / ResponseHeaders 仅在插件声明 CapabilityMiddlewareReadBody 时填充。
// 流式响应下 ResponseBody 只含摘要(首个非空 chunk)。
ResponseBody []byte
ResponseHeaders http.Header
}
MiddlewareEvent OnForwardEnd 的入参。
type MiddlewarePlugin ¶
type MiddlewarePlugin interface {
Plugin
OnForwardBegin(ctx context.Context, req *MiddlewareRequest) (*MiddlewareDecision, error)
OnForwardEnd(ctx context.Context, evt *MiddlewareEvent) error
}
MiddlewarePlugin 中间件插件接口。
PluginInfo.Type = PluginTypeMiddleware 时注册为"请求/响应拦截层"。Core 在每次 forward 的 前后回调 OnForwardBegin / OnForwardEnd,按 PluginInfo.Priority 升序进 Begin、降序出 End。
失败语义:Begin/End 返回 error 只会被 log warn,不 block 主流程。唯一例外是 OnForwardBegin 返回 DecisionDeny——此时请求被拒绝,用户看到的错误文案来自 Decision。
Payload:默认只给元数据;插件声明 CapabilityMiddlewareReadBody 才会收到 request_body / response_body。流式响应的 response_body 只给摘要。
type MiddlewareRequest ¶
type MiddlewareRequest struct {
RequestID string
UserID int64
GroupID int64
AccountID int64
Platform string
Model string
Stream bool
InputTokensEst int64
// Metadata 贯穿 Begin/End 的 KV bag,多个 middleware 之间共享。
Metadata map[string]string
// RequestBody / RequestHeaders 仅在插件声明 CapabilityMiddlewareReadBody 时填充。
RequestBody []byte
RequestHeaders http.Header
}
MiddlewareRequest OnForwardBegin 的入参。
type ModelInfo ¶
type ModelInfo struct {
ID string `json:"id"`
Name string `json:"name"`
ContextWindow int `json:"context_window"`
MaxOutputTokens int `json:"max_output_tokens"`
InputPrice float64 `json:"input_price"` // $/1M token
OutputPrice float64 `json:"output_price"` // $/1M token
CachedInputPrice float64 `json:"cached_input_price"` // cache read,$/1M token
CacheCreationPrice float64 `json:"cache_creation_price"` // cache write 5m TTL(1.25x input)
CacheCreation1hPrice float64 `json:"cache_creation_1h_price"` // cache write 1h TTL(2.00x input)
InputPricePriority float64 `json:"input_price_priority,omitempty"`
OutputPricePriority float64 `json:"output_price_priority,omitempty"`
CachedInputPricePriority float64 `json:"cached_input_price_priority,omitempty"`
InputPriceFast float64 `json:"input_price_fast,omitempty"`
OutputPriceFast float64 `json:"output_price_fast,omitempty"`
CachedInputPriceFast float64 `json:"cached_input_price_fast,omitempty"`
InputPriceFlex float64 `json:"input_price_flex,omitempty"`
OutputPriceFlex float64 `json:"output_price_flex,omitempty"`
CachedInputPriceFlex float64 `json:"cached_input_price_flex,omitempty"`
// 长上下文阶梯(仅 gpt-5.4 家族启用;判定基于完整 input_tokens = 非缓存+缓存命中)
LongContextThreshold int `json:"long_context_threshold,omitempty"`
LongContextInputMultiplier float64 `json:"long_context_input_multiplier,omitempty"`
LongContextOutputMultiplier float64 `json:"long_context_output_multiplier,omitempty"`
LongContextCachedMultiplier float64 `json:"long_context_cached_multiplier,omitempty"`
}
ModelInfo 插件声明的模型信息(Core 缓存用于调度/展示,不再做计费)。
定价档位(对齐 OpenAI 官方):
- 标准档:InputPrice / OutputPrice / CachedInputPrice
- Priority 档:*Priority 字段;未配置时 CalculateCost 以标准价 × 2 兜底
- Fast 档:*Fast 字段;未配置时 CalculateCost 以标准价 × 2.5 兜底
- Flex / Batch 档:*Flex 字段;未配置时以标准价 × 0.5 兜底
- 长上下文档(仅 gpt-5.4 家族):完整 input_tokens 超过 LongContextThreshold 且非 priority 时整次请求按倍率计费
type OutcomeKind ¶
type OutcomeKind int
OutcomeKind 一次 Forward 调用的判决类型。
插件必须在返回的 ForwardOutcome 里显式声明 Kind;零值 OutcomeUnknown 等于 "插件未声明",Core 会按"可疑上游错误"保守处理(不透传响应给客户端、也不把账号标死)。 这是 SDK 契约的核心:插件只做判决,Core 只做执行。
const ( // OutcomeUnknown 保留给零值:插件未声明判决。Core 将保守处理。 OutcomeUnknown OutcomeKind = iota // OutcomeSuccess 上游返回 2xx,Usage 必填。 OutcomeSuccess // OutcomeClientError 4xx,错在客户端请求本身(model 不存在、context 过长、参数非法)。 // 换账号救不回来,Core 会把 Upstream 原样透传给客户端,不罚账号。 OutcomeClientError // OutcomeAccountRateLimited 账号被上游限流(通常 429),冷却一段时间后可恢复。 // Core 会把账号打入 RateLimited 状态 + 尝试 failover 到其它账号。 OutcomeAccountRateLimited // OutcomeAccountDead 账号凭证失效(401/403,或上游语义化消息),需要人工处理。 // Core 会把账号打入 Disabled 状态 + 尝试 failover。 OutcomeAccountDead // OutcomeUpstreamTransient 上游抽风(5xx、连接抖动、超时),账号本身没问题。 // Core 尝试 failover;累计多次后由状态机决定是否升级为 AccountDead。 OutcomeUpstreamTransient // OutcomeStreamAborted 流式响应已经开始写入客户端,中途断开。 // 不能 failover(字节已经发出去了),也不能把账号直接标死。 OutcomeStreamAborted )
func (OutcomeKind) IsAccountFault ¶
func (k OutcomeKind) IsAccountFault() bool
IsAccountFault 本次判决是否归咎于账号自身(RateLimited / Dead)。 Core 据此决定是否推进账号状态机。
func (OutcomeKind) ShouldFailover ¶
func (k OutcomeKind) ShouldFailover() bool
ShouldFailover 是否允许换账号重试。 ClientError 不应 failover(换号也救不回来);StreamAborted 不能 failover(已写入); Success / Unknown 显然不该 failover。
type Plugin ¶
type Plugin interface {
Info() PluginInfo
Init(ctx PluginContext) error
Start(ctx context.Context) error
Stop(ctx context.Context) error
}
Plugin 所有插件的基础接口。
type PluginConfig ¶
type PluginConfig interface {
GetString(key string) string
GetInt(key string) int
GetBool(key string) bool
GetFloat64(key string) float64
GetDuration(key string) time.Duration
// GetAll 返回 JSONB 原始 map。
GetAll() map[string]string
}
PluginConfig 配置读取接口。
type PluginContext ¶
type PluginContext interface {
Logger() *slog.Logger
Config() PluginConfig
}
PluginContext Core 注入给插件的最小上下文:Logger + Config。 其它能力(Host 反向调用、插件专属 DB DSN 等)通过可选接口(HostAware / PluginDSNAware)暴露, 避免给 PluginContext 加方法造成 breaking change。
type PluginDSNAware ¶
type PluginDSNAware interface {
// PluginDSN 返回 DSN;空字符串 = 未启用插件 DB。调用方需 nil/empty check。
PluginDSN() string
}
PluginDSNAware 可选接口:实现它表示能拿到 Core 注入的插件专属 DB DSN。 DSN 已预设 search_path 到独立 schema(plugin_<id>),核心业务表在 PostgreSQL 层被 REVOKE。
type PluginInfo ¶
type PluginInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
SDKVersion string `json:"sdk_version"`
Description string `json:"description"`
Author string `json:"author"`
Type PluginType `json:"type"`
Dependencies []string `json:"dependencies"`
ConfigSchema []ConfigField `json:"config_schema"`
AccountTypes []AccountType `json:"account_types"`
FrontendPages []FrontendPage `json:"frontend_pages"`
FrontendWidgets []FrontendWidget `json:"frontend_widgets"`
InstructionPresets []string `json:"instruction_presets"`
Capabilities []Capability `json:"capabilities"`
// Priority 仅对 type=middleware 生效:Begin 升序、End 降序(LIFO)。默认 100。
Priority int32 `json:"priority"`
}
PluginInfo 插件元信息。
type PluginType ¶
type PluginType string
PluginType 插件扮演的角色。
gateway 上游适配器(airgate-openai / claude 等) extension 后台任务 + 自定义 HTTP 路由(airgate-health / epay 等) middleware forward 路径上的旁路拦截层(审计 / 脱敏 / 记账等)
const ( PluginTypeGateway PluginType = "gateway" PluginTypeExtension PluginType = "extension" PluginTypeMiddleware PluginType = "middleware" )
type QuotaInfo ¶
type QuotaInfo struct {
Total float64 `json:"total"`
Used float64 `json:"used"`
Remaining float64 `json:"remaining"`
Currency string `json:"currency"` // 如 "USD"
ExpiresAt string `json:"expires_at"` // ISO 8601
Extra map[string]string `json:"extra"`
}
QuotaInfo 账号额度信息。
type RequestHandler ¶
type RequestHandler interface {
HandleRequest(ctx context.Context, method, path, query string, headers http.Header, body []byte) (statusCode int, respHeaders http.Header, respBody []byte, err error)
}
RequestHandler 可选:Core 将 /api/v1/admin/plugins/:name/rpc/* 透传给插件自行路由。
type RouteDefinition ¶
type RouteDefinition struct {
Method string `json:"method"`
Path string `json:"path"`
Description string `json:"description"`
}
RouteDefinition 网关插件声明的 API 端点。
type RouteRegistrar ¶
type RouteRegistrar interface {
Handle(method, path string, handler http.HandlerFunc)
Group(prefix string) RouteRegistrar
}
RouteRegistrar 扩展插件使用的路由注册器。
type UpstreamResponse ¶
UpstreamResponse 上游返回的原始 HTTP 快照。
语义:Success / ClientError 时 Core 会把 Body + Headers 原样透传给客户端。 其他 Kind 下 Upstream 仅作为诊断信息保留,不透传。 StreamAborted 场景 Body 通常为空(字节已经流给客户端)。
type Usage ¶
type Usage struct {
InputTokens int
OutputTokens int
CachedInputTokens int
CacheCreationTokens int
CacheCreation5mTokens int
CacheCreation1hTokens int
ReasoningOutputTokens int
InputCost float64
OutputCost float64
CachedInputCost float64
CacheCreationCost float64
InputPrice float64
OutputPrice float64
CachedInputPrice float64
CacheCreationPrice float64
CacheCreation1hPrice float64
Model string
ServiceTier string
FirstTokenMs int64
// ImageSize 图像生成请求的实际出图尺寸("WxH",例如 "1024x1024"、"3840x2160")。
// 网关侧按 1K/2K/4K 三档计费,把分档来源(实际尺寸)记下来,admin 后台 usage_log
// 显示费用时旁边带上 size,用户能直观看出"为什么这次扣了 0.40"。非图像请求留空。
ImageSize string
}
Usage 单次调用的 token / 费用统计。
只有 OutcomeSuccess 下 Usage 必填;OutcomeClientError 如果上游也计费(如部分重置 context 后仍计 token)可填;其他 Kind 下应为 nil。
费用字段(*Cost)由插件根据单价 × token 计算后传回,Core 不再关心模型定价。 单价字段(*Price)纯粹透传存储,便于 usage_log 审计。
type WebAssetsProvider ¶
WebAssetsProvider 可选:插件通过此接口提供前端静态资源。