common

package
v0.2.0-beta.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2026 License: AGPL-3.0 Imports: 31 Imported by: 0

Documentation

Index

Constants

View Source
const (
	LastMessageTypeNone     = convmeta.LastMessageTypeNone
	LastMessageTypeText     = convmeta.LastMessageTypeText
	LastMessageTypeTools    = convmeta.LastMessageTypeTools
	LastMessageTypeThinking = convmeta.LastMessageTypeThinking
)
View Source
const MaxRequestTokens = math.MaxInt32 / 2

MaxRequestTokens is the existing max_tokens-family validation bound, shared with final outbound request checks so overrides cannot bypass that limit.

View Source
const MaxTaskDurationSeconds = 3600

MaxTaskDurationSeconds caps user-supplied video duration. Duration is used as a billing multiplier (OtherRatio "seconds"); an unbounded value could overflow quota calculation into a negative charge.

Variables

This section is empty.

Functions

func AppendRequestConversionFromRequest

func AppendRequestConversionFromRequest(info *RelayInfo, req any)

func ApplyParamOverride

func ApplyParamOverride(jsonData []byte, paramOverride map[string]interface{}, conditionContext map[string]interface{}) ([]byte, error)

func ApplyParamOverrideWithRelayInfo

func ApplyParamOverrideWithRelayInfo(jsonData []byte, info *RelayInfo) ([]byte, error)

func BuildParamOverrideContext

func BuildParamOverrideContext(info *RelayInfo) map[string]interface{}

BuildParamOverrideContext 提供 ApplyParamOverride 可用的上下文信息。 目前内置以下字段:

  • upstream_model/model:始终为通道映射后的上游模型名。
  • original_model:请求最初指定的模型名。
  • user_id:已认证用户 ID。
  • user_group:用户所属分组。
  • token_group:令牌指定的分组;未指定时回退为用户分组。
  • using_group:当前实际使用的分组,自动跨分组重试时可能变化。
  • request_path:请求路径
  • is_channel_test:是否为渠道测试请求(同 is_test)。

func GetAPIVersion

func GetAPIVersion(c *gin.Context) string

func GetEffectiveHeaderOverride

func GetEffectiveHeaderOverride(info *RelayInfo) map[string]interface{}

func GetFullRequestURL

func GetFullRequestURL(baseURL string, requestURL string, channelType int) string

func GuessRelayFormatFromRequest

func GuessRelayFormatFromRequest(req any) (types.RelayFormat, bool)

GuessRelayFormatFromRequest moved to convmeta with the converters; the delegation keeps host callers unchanged.

func IsNonBillableResponsesStatus

func IsNonBillableResponsesStatus(status []byte) bool

IsNonBillableResponsesStatus reports terminal response statuses that must not bill pending image_generation observations.

func NewAPIErrorFromParamOverride

func NewAPIErrorFromParamOverride(err *ParamOverrideReturnError) *types.NewAPIError

func NewOutboundJSONBody

func NewOutboundJSONBody(data []byte) (body common.ReplayableBody, closer io.Closer, err error)

NewOutboundJSONBody wraps the already-marshaled upstream request body into a BodyStorage. When disk cache is enabled and the payload exceeds the configured threshold, the data is written to a temp file and the original []byte can be GC'd, significantly reducing the heap residency while waiting for the upstream provider to respond (the dominant cost for large base64 payloads).

In memory mode the underlying memoryStorage reuses the same backing array, so this is equivalent to bytes.NewReader(data) in terms of memory usage.

The caller MUST invoke closer.Close() once the upstream call has finished (typically via defer) to release the disk file / memory accounting.

The returned body exposes its size and replay capability without exposing io.Closer. Request construction uses that metadata to populate ContentLength and GetBody, while the caller retains ownership of the underlying storage through the separately returned closer.

func RemoveDisabledFields

func RemoveDisabledFields(jsonData []byte, channelOtherSettings dto.ChannelOtherSettings, channelPassThroughEnabled bool) ([]byte, error)

RemoveDisabledFields 从请求 JSON 数据中移除渠道设置中禁用的字段 service_tier: 服务层级字段,可能导致额外计费(OpenAI、Claude、Responses API 支持) inference_geo: Claude 数据驻留推理区域字段(仅 Claude 支持,默认过滤) speed: Claude 推理速度模式字段(仅 Claude 支持,默认过滤) store: 数据存储授权字段,涉及用户隐私(仅 OpenAI、Responses API 支持,默认允许透传,禁用后可能导致 Codex 无法使用) safety_identifier: 安全标识符,用于向 OpenAI 报告违规用户(仅 OpenAI 支持,涉及用户隐私) stream_options.include_obfuscation: 响应流混淆控制字段(仅 OpenAI Responses API 支持)

func RemoveGeminiDisabledFields

func RemoveGeminiDisabledFields(jsonData []byte) ([]byte, error)

RemoveGeminiDisabledFields removes disabled fields from Gemini request JSON data Currently supports removing functionResponse.id field which Vertex AI does not support

func SanitizeURLForLog

func SanitizeURLForLog(rawURL string) string

func ValidateBasicTaskRequest

func ValidateBasicTaskRequest(c *gin.Context, info *RelayInfo, action string) *dto.TaskError

func ValidateMultipartDirect

func ValidateMultipartDirect(c *gin.Context, info *RelayInfo) *dto.TaskError

Types

type BillingSettler

type BillingSettler interface {
	// Settle 根据实际消耗额度进行结算,计算 delta = actualQuota - preConsumedQuota,
	// 同时调整资金来源(钱包/订阅)和令牌额度。
	Settle(actualQuota int) error

	// Refund 退还所有预扣费额度(资金来源 + 令牌),幂等安全。
	// 退款事实先持久化;只有终态已应用时才视为退款完成。
	Refund(c *gin.Context) error

	// NeedsRefund 返回会话是否存在需要退还的预扣状态(未结算且未退款)。
	NeedsRefund() bool

	// GetPreConsumedQuota 返回实际预扣的额度值(信任用户可能为 0)。
	GetPreConsumedQuota() int

	// Reserve 将预扣额度补到目标值;若目标值不高于当前预扣额度则不做任何事。
	Reserve(targetQuota int) error
}

BillingSettler 抽象计费会话的生命周期操作。 由 service.BillingSession 实现,存储在 RelayInfo 上以避免循环引用。

type BuildInToolInfo

type BuildInToolInfo struct {
	ToolName          string
	CallCount         int
	SearchContextSize string
}

type ChannelMeta

type ChannelMeta struct {
	ChannelType          int
	ChannelId            int
	ChannelIsMultiKey    bool
	ChannelMultiKeyIndex int
	ChannelBaseUrl       string
	ApiType              int
	ApiVersion           string
	ApiKey               string
	Organization         string
	ChannelCreateTime    int64
	ParamOverride        map[string]interface{}
	HeadersOverride      map[string]interface{}
	ChannelSetting       dto.ChannelSettings
	ChannelOtherSettings dto.ChannelOtherSettings
	UpstreamModelName    string
	IsModelMapped        bool
	SupportStreamOptions bool // 是否支持流式选项
}

type ClaudeConvertInfo

type ClaudeConvertInfo = convmeta.ClaudeConvertInfo

ClaudeConvertInfo now lives with the converters (convmeta); the alias keeps host code and adaptors compiling unchanged.

type ConditionOperation

type ConditionOperation struct {
	Path           string      `json:"path"`             // JSON路径
	Mode           string      `json:"mode"`             // full, prefix, suffix, contains, gt, gte, lt, lte
	Value          interface{} `json:"value"`            // 匹配的值
	Invert         bool        `json:"invert"`           // 反选功能,true表示取反结果
	PassMissingKey bool        `json:"pass_missing_key"` // 未获取到json key时的行为
}

type HasImage

type HasImage interface {
	HasImage() bool
}

type HasPrompt

type HasPrompt interface {
	GetPrompt() string
}

type ImageGenerationCallCounter

type ImageGenerationCallCounter struct {
	// contains filtered or unexported fields
}

ImageGenerationCallCounter counts completed Responses image_generation_call outputs with stream-safe identity deduplication.

func (*ImageGenerationCallCounter) Commit

func (c *ImageGenerationCallCounter) Commit(info *RelayInfo)

Commit writes the capped completed-output count into RelayInfo once. Request tool declarations alone must not become billable calls.

func (*ImageGenerationCallCounter) Count

func (c *ImageGenerationCallCounter) Count() int

Count returns the deduplicated completed image output count before commit capping.

func (*ImageGenerationCallCounter) Observe

func (c *ImageGenerationCallCounter) Observe(item *dto.ResponsesOutput, outputIndex *int)

Observe records one completed final image output when billable. outputIndex may be nil; when set and nonnegative it participates in dedup.

func (*ImageGenerationCallCounter) Reset

func (c *ImageGenerationCallCounter) Reset()

Reset clears pending observations (used when a terminal response fails).

type ParamOperation

type ParamOperation struct {
	Path       string               `json:"path"`
	Mode       string               `json:"mode"` // delete, set, move, copy, prepend, append, trim_prefix, trim_suffix, ensure_prefix, ensure_suffix, trim_space, to_lower, to_upper, replace, regex_replace, return_error, prune_objects, set_header, delete_header, copy_header, move_header, pass_headers, sync_fields
	Value      interface{}          `json:"value"`
	KeepOrigin bool                 `json:"keep_origin"`
	From       string               `json:"from,omitempty"`
	To         string               `json:"to,omitempty"`
	Conditions []ConditionOperation `json:"conditions,omitempty"` // 条件列表
	Logic      string               `json:"logic,omitempty"`      // AND, OR (默认OR)
}

type ParamOverrideReturnError

type ParamOverrideReturnError struct {
	Message    string
	StatusCode int
	Code       string
	Type       string
	SkipRetry  bool
}

func AsParamOverrideReturnError

func AsParamOverrideReturnError(err error) (*ParamOverrideReturnError, bool)

func (*ParamOverrideReturnError) Error

func (e *ParamOverrideReturnError) Error() string

type RealtimeTieredPricing

type RealtimeTieredPricing struct {
	Quota        int
	Responses    int
	InputTokens  int
	OutputTokens int
	TotalTokens  int
	Incomplete   bool
	ExprHash     string
	QuotaPerUnit float64
	GroupRatio   float64
}

RealtimeTieredPricing holds bounded totals, not an unbounded response list. Quotes remain known even if extending the billing reservation fails.

type RelayInfo

type RelayInfo struct {
	ConfirmedAPIUsageCost map[string]string

	TokenId           int
	TokenKey          string
	TokenGroup        string
	UserId            int
	UsingGroup        string // 使用的分组,当auto跨分组重试时,会变动
	UserGroup         string // 用户所在分组
	TokenUnlimited    bool
	StartTime         time.Time
	FirstResponseTime time.Time

	//SendLastReasoningResponse bool
	IsStream               bool
	IsGeminiBatchEmbedding bool
	IsPlayground           bool
	UsePrice               bool
	RelayMode              int
	OriginModelName        string
	RequestURLPath         string
	RequestHeaders         map[string]string
	ShouldIncludeUsage     bool
	DisablePing            bool // 是否禁止向下游发送自定义 Ping
	ClientWs               *websocket.Conn
	TargetWs               *websocket.Conn
	InputAudioFormat       string
	OutputAudioFormat      string
	RealtimeTools          []dto.RealTimeTool
	IsFirstRequest         bool
	AudioUsage             bool
	ReasoningEffort        string
	UserSetting            dto.UserSetting
	UserEmail              string
	UserQuota              int
	RelayFormat            types.RelayFormat
	SendResponseCount      int
	ReceivedResponseCount  int
	FinalPreConsumedQuota  int // 最终预消耗的配额
	// ForcePreConsume 为 true 时禁用 BillingSession 的信任额度旁路,
	// 强制预扣全额。用于异步任务(视频/音乐生成等),因为请求返回后任务仍在运行,
	// 必须在提交前锁定全额。
	ForcePreConsume bool
	// Billing 是计费会话,封装了预扣费/结算/退款的统一生命周期。
	// 初始免费组可为 nil;若 auto 重试切换到付费组,会在发送前创建。
	Billing           BillingSettler
	StrictTokenBudget bool
	// BillingSource indicates whether this request is billed from wallet quota or subscription.
	// "" or "wallet" => wallet; "subscription" => subscription
	BillingSource string
	// SubscriptionId is the user_subscriptions.id used when BillingSource == "subscription"
	SubscriptionId int
	// SubscriptionPreConsumed is the amount pre-consumed on subscription item (quota units or 1)
	SubscriptionPreConsumed int64
	// SubscriptionPostDelta is the post-consume delta applied to amount_used (quota units; can be negative).
	SubscriptionPostDelta int64
	// SubscriptionPlanId / SubscriptionPlanTitle are used for logging/UI display.
	SubscriptionPlanId    int
	SubscriptionPlanTitle string
	// RequestId is used for idempotent pre-consume/refund
	RequestId string
	// RealtimeConsumeSeq 记录 realtime 流式连接内的计费次数。同一连接的多个
	// response.done 共享 RequestId,该序号为 authoritative 配额写入提供
	// 稳定的按次幂等键后缀。
	RealtimeConsumeSeq int
	// RealtimeQuotedQuota is the cumulative quota of successfully reserved
	// realtime segments. It extends the existing billing reservation instead
	// of charging each segment again outside that session.
	RealtimeQuotedQuota     int
	RealtimeTieredPricing   *RealtimeTieredPricing
	RealtimeCheckpoint      *hosttypes.RealtimeUsageCheckpoint
	RealtimeUsageUnverified bool
	RealtimeReportedUsage   bool
	// SubscriptionAmountTotal / SubscriptionAmountUsedAfterPreConsume are used to compute remaining in logs.
	SubscriptionAmountTotal               int64
	SubscriptionAmountUsedAfterPreConsume int64
	IsClaudeBetaQuery                     bool // /v1/messages?beta=true
	IsChannelTest                         bool // channel test request
	RetryIndex                            int
	LastError                             *types.NewAPIError
	RuntimeHeadersOverride                map[string]interface{}
	UseRuntimeHeadersOverride             bool
	ParamOverrideAudit                    []string

	PriceData hosttypes.PriceData

	// QuotaClamp is set (non-nil) when a quota conversion saturated at the
	// int32 bound (or NaN fallback) while computing this request's charge.
	// It is surfaced onto the consume/task log's admin_info for auditing.
	QuotaClamp *common.QuotaClamp

	// TieredBillingSnapshot captures tiered billing rules at pre-consume time.
	// Auto-group retries refresh its group-dependent fields before each attempt
	// and again before settlement. Non-nil only when billing mode is "tiered_expr".
	TieredBillingSnapshot *billingexpr.BillingSnapshot
	BillingRequestInput   *billingexpr.RequestInput

	Request dto.Request

	// RequestConversionChain records request format conversions in order, e.g.
	// ["openai", "openai_responses"] or ["openai", "claude"].
	RequestConversionChain []types.RelayFormat
	// 最终请求到上游的格式。可由 adaptor 显式设置;
	// 若为空,调用 GetFinalRequestRelayFormat 会回退到 RequestConversionChain 的最后一项或 RelayFormat。
	FinalRequestRelayFormat types.RelayFormat

	StreamStatus *StreamStatus

	ThinkingContentInfo
	TokenCountMeta
	*ClaudeConvertInfo
	*RerankerInfo
	*ResponsesUsageInfo
	*ChannelMeta
	*TaskRelayInfo
	// contains filtered or unexported fields
}

func GenRelayInfo

func GenRelayInfo(c *gin.Context, relayFormat types.RelayFormat, request dto.Request, ws *websocket.Conn) (*RelayInfo, error)

func GenRelayInfoAlphaSearch

func GenRelayInfoAlphaSearch(c *gin.Context, request *dto.AlphaSearchRequest) *RelayInfo

func GenRelayInfoClaude

func GenRelayInfoClaude(c *gin.Context, request dto.Request) *RelayInfo

func GenRelayInfoEmbedding

func GenRelayInfoEmbedding(c *gin.Context, request dto.Request) *RelayInfo

func GenRelayInfoGemini

func GenRelayInfoGemini(c *gin.Context, request dto.Request) *RelayInfo

func GenRelayInfoImage

func GenRelayInfoImage(c *gin.Context, request dto.Request) *RelayInfo

func GenRelayInfoOpenAI

func GenRelayInfoOpenAI(c *gin.Context, request dto.Request) *RelayInfo

func GenRelayInfoOpenAIAudio

func GenRelayInfoOpenAIAudio(c *gin.Context, request dto.Request) *RelayInfo

func GenRelayInfoRerank

func GenRelayInfoRerank(c *gin.Context, request *dto.RerankRequest) *RelayInfo

func GenRelayInfoResponses

func GenRelayInfoResponses(c *gin.Context, request *dto.OpenAIResponsesRequest) *RelayInfo

func GenRelayInfoResponsesCompaction

func GenRelayInfoResponsesCompaction(c *gin.Context, request *dto.OpenAIResponsesCompactionRequest) *RelayInfo

func GenRelayInfoWs

func GenRelayInfoWs(c *gin.Context, ws *websocket.Conn) *RelayInfo

func (*RelayInfo) AppendRequestConversion

func (info *RelayInfo) AppendRequestConversion(format types.RelayFormat)

func (*RelayInfo) ClaudeSettingsSnapshot

func (info *RelayInfo) ClaudeSettingsSnapshot() *model_setting.ClaudeSettings

ClaudeSettingsSnapshot returns the request-private settings copy captured when a production RelayInfo was built. Hand-written RelayInfo values get a fresh read-only fallback without mutating the struct.

func (*RelayInfo) ConvOptions

func (info *RelayInfo) ConvOptions() *convmeta.Options

ConvOptions snapshots host settings for the converters. Rebuilt on each call site's first use; cached so one relay session sees one snapshot.

func (*RelayInfo) CountBillableToolCall

func (info *RelayInfo) CountBillableToolCall(itemType string, functionName string)

CountBillableToolCall is the single entry point for per-call tool billing counts. Built-in call types always count; custom function/tool_use names only count when priced.

func (*RelayInfo) EnsureClaudeConvertInfo

func (info *RelayInfo) EnsureClaudeConvertInfo() *convmeta.ClaudeConvertInfo

func (*RelayInfo) GetChannelID

func (info *RelayInfo) GetChannelID() int

func (*RelayInfo) GetChannelType

func (info *RelayInfo) GetChannelType() int

func (*RelayInfo) GetEstimatePromptTokens

func (info *RelayInfo) GetEstimatePromptTokens() int

func (*RelayInfo) GetFinalRequestRelayFormat

func (info *RelayInfo) GetFinalRequestRelayFormat() types.RelayFormat

func (*RelayInfo) GetIsStream

func (info *RelayInfo) GetIsStream() bool

func (*RelayInfo) GetOriginModelName

func (info *RelayInfo) GetOriginModelName() string

func (*RelayInfo) GetReasoningEffort

func (info *RelayInfo) GetReasoningEffort() string

func (*RelayInfo) GetSendResponseCount

func (info *RelayInfo) GetSendResponseCount() int

func (*RelayInfo) GetUpstreamModelName

func (info *RelayInfo) GetUpstreamModelName() string

func (*RelayInfo) HasChannelMeta

func (info *RelayInfo) HasChannelMeta() bool

func (*RelayInfo) HasSendResponse

func (info *RelayInfo) HasSendResponse() bool

func (*RelayInfo) IncrSendResponseCount

func (info *RelayInfo) IncrSendResponseCount()

func (*RelayInfo) InitChannelMeta

func (info *RelayInfo) InitChannelMeta(c *gin.Context)

func (*RelayInfo) InitRequestConversionChain

func (info *RelayInfo) InitRequestConversionChain()

func (*RelayInfo) SetEstimatePromptTokens

func (info *RelayInfo) SetEstimatePromptTokens(promptTokens int)

func (*RelayInfo) SetFirstResponseTime

func (info *RelayInfo) SetFirstResponseTime()

func (*RelayInfo) SetReasoningEffort

func (info *RelayInfo) SetReasoningEffort(effort string)

func (*RelayInfo) ToString

func (info *RelayInfo) ToString() string

type RerankerInfo

type RerankerInfo struct {
	Documents       []any
	ReturnDocuments bool
}

type ResponsesUsageInfo

type ResponsesUsageInfo struct {
	BuiltInTools map[string]*BuildInToolInfo
}

type StreamEndReason

type StreamEndReason string
const (
	StreamEndReasonNone        StreamEndReason = ""
	StreamEndReasonDone        StreamEndReason = "done"
	StreamEndReasonTimeout     StreamEndReason = "timeout"
	StreamEndReasonClientGone  StreamEndReason = "client_gone"
	StreamEndReasonScannerErr  StreamEndReason = "scanner_error"
	StreamEndReasonHandlerStop StreamEndReason = "handler_stop"
	StreamEndReasonEOF         StreamEndReason = "eof"
	StreamEndReasonPanic       StreamEndReason = "panic"
	StreamEndReasonPingFail    StreamEndReason = "ping_fail"
)

type StreamErrorEntry

type StreamErrorEntry struct {
	Message   string
	Timestamp time.Time
}

type StreamStatus

type StreamStatus struct {
	EndReason StreamEndReason
	EndError  error

	Errors     []StreamErrorEntry
	ErrorCount int
	// contains filtered or unexported fields
}

func NewStreamStatus

func NewStreamStatus() *StreamStatus

func (*StreamStatus) HasErrors

func (s *StreamStatus) HasErrors() bool

func (*StreamStatus) IsNormalEnd

func (s *StreamStatus) IsNormalEnd() bool

func (*StreamStatus) RecordError

func (s *StreamStatus) RecordError(msg string)

func (*StreamStatus) SetEndReason

func (s *StreamStatus) SetEndReason(reason StreamEndReason, err error)

func (*StreamStatus) Summary

func (s *StreamStatus) Summary() string

func (*StreamStatus) TotalErrorCount

func (s *StreamStatus) TotalErrorCount() int

type TaskInfo

type TaskInfo struct {
	Code             int    `json:"code"`
	TaskID           string `json:"task_id"`
	Status           string `json:"status"`
	Reason           string `json:"reason,omitempty"`
	Url              string `json:"url,omitempty"`
	RemoteUrl        string `json:"remote_url,omitempty"`
	Progress         string `json:"progress,omitempty"`
	CompletionTokens int    `json:"completion_tokens,omitempty"` // 用于按倍率计费
	TotalTokens      int    `json:"total_tokens,omitempty"`      // 用于按倍率计费

	QuotaClamp *common.QuotaClamp `json:"-"` // Internal provider-usage saturation audit; never part of the task response.
}

func FailTaskInfo

func FailTaskInfo(reason string) *TaskInfo

type TaskRelayInfo

type TaskRelayInfo struct {
	Action       string
	OriginTaskID string
	// PublicTaskID 是提交时预生成的 task_xxxx 格式公开 ID,
	// 供 DoResponse 在返回给客户端时使用(避免暴露上游真实 ID)。
	PublicTaskID string

	ConsumeQuota bool

	// LockedChannel holds the full channel object when the request is bound to
	// a specific channel (e.g., remix on origin task's channel). Stored as any
	// to avoid an import cycle with model; callers type-assert to *model.Channel.
	LockedChannel any
}

type TaskSubmitReq

type TaskSubmitReq struct {
	Prompt         string                 `json:"prompt"`
	Model          string                 `json:"model,omitempty"`
	Mode           string                 `json:"mode,omitempty"`
	Image          string                 `json:"image,omitempty"`
	Images         []string               `json:"images,omitempty"`
	Size           string                 `json:"size,omitempty"`
	Duration       int                    `json:"duration,omitempty"`
	Seconds        string                 `json:"seconds,omitempty"`
	InputReference string                 `json:"input_reference,omitempty"`
	Metadata       map[string]interface{} `json:"metadata,omitempty"`
}

func GetTaskRequest

func GetTaskRequest(c *gin.Context) (TaskSubmitReq, error)

func (*TaskSubmitReq) GetPrompt

func (t *TaskSubmitReq) GetPrompt() string

func (*TaskSubmitReq) HasImage

func (t *TaskSubmitReq) HasImage() bool

func (*TaskSubmitReq) UnmarshalJSON

func (t *TaskSubmitReq) UnmarshalJSON(data []byte) error

func (*TaskSubmitReq) UnmarshalMetadata

func (t *TaskSubmitReq) UnmarshalMetadata(v any) error

type ThinkingContentInfo

type ThinkingContentInfo struct {
	IsFirstThinkingContent  bool
	SendLastThinkingContent bool
	HasSentThinkingContent  bool
}

type TokenCountMeta

type TokenCountMeta struct {
	// contains filtered or unexported fields
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL