1
0

refactor: 实现 ConversionEngine 协议转换引擎,替代旧 protocol 包

引入 Canonical Model 和 ProtocolAdapter 架构,支持 OpenAI/Anthropic 协议间
无缝转换,统一 ProxyHandler 替代分散的 OpenAI/Anthropic Handler,简化
ProviderClient 为协议无关的 HTTP 发送器,Provider 新增 protocol 字段。
This commit is contained in:
2026-04-20 00:36:27 +08:00
parent 26810d9410
commit 1dac347d3b
65 changed files with 9690 additions and 2139 deletions

View File

@@ -0,0 +1,71 @@
package canonical
// CanonicalModel 规范模型
type CanonicalModel struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Created int64 `json:"created,omitempty"`
OwnedBy string `json:"owned_by,omitempty"`
}
// CanonicalModelList 规范模型列表
type CanonicalModelList struct {
Models []CanonicalModel `json:"models"`
}
// CanonicalModelInfo 规范模型详情
type CanonicalModelInfo struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Created int64 `json:"created,omitempty"`
OwnedBy string `json:"owned_by,omitempty"`
}
// CanonicalEmbeddingRequest 规范嵌入请求
type CanonicalEmbeddingRequest struct {
Model string `json:"model"`
Input any `json:"input"` // string 或 []string
EncodingFormat string `json:"encoding_format,omitempty"`
Dimensions *int `json:"dimensions,omitempty"`
}
// CanonicalEmbeddingResponse 规范嵌入响应
type CanonicalEmbeddingResponse struct {
Data []EmbeddingData `json:"data"`
Model string `json:"model"`
Usage EmbeddingUsage `json:"usage"`
}
// EmbeddingData 嵌入数据项
type EmbeddingData struct {
Index int `json:"index"`
Embedding any `json:"embedding"` // 根据格式不同可能是 []float64 或 base64 字符串
}
// EmbeddingUsage 嵌入用量
type EmbeddingUsage struct {
PromptTokens int `json:"prompt_tokens"`
TotalTokens int `json:"total_tokens"`
}
// CanonicalRerankRequest 规范重排序请求
type CanonicalRerankRequest struct {
Model string `json:"model"`
Query string `json:"query"`
Documents []string `json:"documents"`
TopN *int `json:"top_n,omitempty"`
ReturnDocuments *bool `json:"return_documents,omitempty"`
}
// CanonicalRerankResponse 规范重排序响应
type CanonicalRerankResponse struct {
Results []RerankResult `json:"results"`
Model string `json:"model"`
}
// RerankResult 重排序结果项
type RerankResult struct {
Index int `json:"index"`
RelevanceScore float64 `json:"relevance_score"`
Document *string `json:"document,omitempty"`
}

View File

@@ -0,0 +1,156 @@
package canonical
// StreamEventType 流式事件类型枚举
type StreamEventType string
const (
EventMessageStart StreamEventType = "message_start"
EventContentBlockStart StreamEventType = "content_block_start"
EventContentBlockDelta StreamEventType = "content_block_delta"
EventContentBlockStop StreamEventType = "content_block_stop"
EventMessageDelta StreamEventType = "message_delta"
EventMessageStop StreamEventType = "message_stop"
EventError StreamEventType = "error"
EventPing StreamEventType = "ping"
)
// DeltaType 增量类型枚举
type DeltaType string
const (
DeltaTypeText DeltaType = "text_delta"
DeltaTypeInputJSON DeltaType = "input_json_delta"
DeltaTypeThinking DeltaType = "thinking_delta"
)
// StreamDelta 流式增量联合体
type StreamDelta struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
PartialJSON string `json:"partial_json,omitempty"`
Thinking string `json:"thinking,omitempty"`
}
// StreamContentBlock 流式内容块联合体
type StreamContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Thinking string `json:"thinking,omitempty"`
}
// CanonicalStreamEvent 规范流式事件联合体
type CanonicalStreamEvent struct {
Type StreamEventType `json:"type"`
// MessageStartEvent
Message *StreamMessage `json:"message,omitempty"`
// ContentBlockStartEvent / ContentBlockDeltaEvent / ContentBlockStopEvent
Index *int `json:"index,omitempty"`
ContentBlock *StreamContentBlock `json:"content_block,omitempty"`
Delta *StreamDelta `json:"delta,omitempty"`
// MessageDeltaEvent
StopReason *StopReason `json:"stop_reason,omitempty"`
Usage *CanonicalUsage `json:"usage,omitempty"`
// ErrorEvent
Error *StreamError `json:"error,omitempty"`
}
// StreamMessage 流式消息摘要
type StreamMessage struct {
ID string `json:"id"`
Model string `json:"model"`
Usage *CanonicalUsage `json:"usage,omitempty"`
}
// StreamError 流式错误
type StreamError struct {
Type string `json:"type"`
Message string `json:"message"`
}
// NewMessageStartEvent 创建消息开始事件
func NewMessageStartEvent(id, model string) CanonicalStreamEvent {
return CanonicalStreamEvent{
Type: EventMessageStart,
Message: &StreamMessage{ID: id, Model: model},
}
}
// NewMessageStartEventWithUsage 创建带用量的消息开始事件
func NewMessageStartEventWithUsage(id, model string, usage *CanonicalUsage) CanonicalStreamEvent {
return CanonicalStreamEvent{
Type: EventMessageStart,
Message: &StreamMessage{ID: id, Model: model, Usage: usage},
}
}
// NewContentBlockStartEvent 创建内容块开始事件
func NewContentBlockStartEvent(index int, block StreamContentBlock) CanonicalStreamEvent {
idx := index
return CanonicalStreamEvent{
Type: EventContentBlockStart,
Index: &idx,
ContentBlock: &block,
}
}
// NewContentBlockDeltaEvent 创建内容块增量事件
func NewContentBlockDeltaEvent(index int, delta StreamDelta) CanonicalStreamEvent {
idx := index
return CanonicalStreamEvent{
Type: EventContentBlockDelta,
Index: &idx,
Delta: &delta,
}
}
// NewContentBlockStopEvent 创建内容块结束事件
func NewContentBlockStopEvent(index int) CanonicalStreamEvent {
idx := index
return CanonicalStreamEvent{
Type: EventContentBlockStop,
Index: &idx,
}
}
// NewMessageDeltaEvent 创建消息增量事件
func NewMessageDeltaEvent(stopReason StopReason) CanonicalStreamEvent {
sr := stopReason
return CanonicalStreamEvent{
Type: EventMessageDelta,
StopReason: &sr,
}
}
// NewMessageDeltaEventWithUsage 创建带用量的消息增量事件
func NewMessageDeltaEventWithUsage(stopReason StopReason, usage *CanonicalUsage) CanonicalStreamEvent {
sr := stopReason
return CanonicalStreamEvent{
Type: EventMessageDelta,
StopReason: &sr,
Usage: usage,
}
}
// NewMessageStopEvent 创建消息结束事件
func NewMessageStopEvent() CanonicalStreamEvent {
return CanonicalStreamEvent{Type: EventMessageStop}
}
// NewErrorEvent 创建错误事件
func NewErrorEvent(errType, message string) CanonicalStreamEvent {
return CanonicalStreamEvent{
Type: EventError,
Error: &StreamError{Type: errType, Message: message},
}
}
// NewPingEvent 创建心跳事件
func NewPingEvent() CanonicalStreamEvent {
return CanonicalStreamEvent{Type: EventPing}
}

View File

@@ -0,0 +1,208 @@
package canonical
import (
"encoding/json"
"fmt"
)
// MessageRole 消息角色枚举
type MessageRole string
const (
RoleSystem MessageRole = "system"
RoleUser MessageRole = "user"
RoleAssistant MessageRole = "assistant"
RoleTool MessageRole = "tool"
)
// StopReason 停止原因枚举
type StopReason string
const (
StopReasonEndTurn StopReason = "end_turn"
StopReasonMaxTokens StopReason = "max_tokens"
StopReasonToolUse StopReason = "tool_use"
StopReasonStopSequence StopReason = "stop_sequence"
StopReasonContentFilter StopReason = "content_filter"
StopReasonRefusal StopReason = "refusal"
)
// SystemBlock 系统消息块
type SystemBlock struct {
Text string `json:"text"`
}
// ContentBlock 使用 type 字段的 discriminated union
type ContentBlock struct {
Type string `json:"type"`
// TextBlock
Text string `json:"text,omitempty"`
// ToolUseBlock
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Input json.RawMessage `json:"input,omitempty"`
// ToolResultBlock
ToolUseID string `json:"tool_use_id,omitempty"`
Content json.RawMessage `json:"content,omitempty"`
IsError *bool `json:"is_error,omitempty"`
// ThinkingBlock
Thinking string `json:"thinking,omitempty"`
}
// NewTextBlock 创建文本块
func NewTextBlock(text string) ContentBlock {
return ContentBlock{Type: "text", Text: text}
}
// NewToolUseBlock 创建工具调用块
func NewToolUseBlock(id, name string, input json.RawMessage) ContentBlock {
return ContentBlock{Type: "tool_use", ID: id, Name: name, Input: input}
}
// NewToolResultBlock 创建工具结果块
func NewToolResultBlock(toolUseID string, content string, isError bool) ContentBlock {
errFlag := &isError
return ContentBlock{
Type: "tool_result",
ToolUseID: toolUseID,
Content: json.RawMessage(fmt.Sprintf("%q", content)),
IsError: errFlag,
}
}
// NewThinkingBlock 创建思考块
func NewThinkingBlock(thinking string) ContentBlock {
return ContentBlock{Type: "thinking", Thinking: thinking}
}
// CanonicalMessage 规范消息
type CanonicalMessage struct {
Role MessageRole `json:"role"`
Content []ContentBlock `json:"content"`
}
// CanonicalTool 规范工具定义
type CanonicalTool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
InputSchema json.RawMessage `json:"input_schema"`
}
// ToolChoice 工具选择联合体
type ToolChoice struct {
Type string `json:"type"`
Name string `json:"name,omitempty"`
}
// NewToolChoiceAuto 创建自动工具选择
func NewToolChoiceAuto() *ToolChoice {
return &ToolChoice{Type: "auto"}
}
// NewToolChoiceNone 创建无工具选择
func NewToolChoiceNone() *ToolChoice {
return &ToolChoice{Type: "none"}
}
// NewToolChoiceAny 创建任意工具选择
func NewToolChoiceAny() *ToolChoice {
return &ToolChoice{Type: "any"}
}
// NewToolChoiceNamed 创建指定工具选择
func NewToolChoiceNamed(name string) *ToolChoice {
return &ToolChoice{Type: "tool", Name: name}
}
// RequestParameters 请求参数
type RequestParameters struct {
MaxTokens *int `json:"max_tokens,omitempty"`
Temperature *float64 `json:"temperature,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
TopK *int `json:"top_k,omitempty"`
FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`
PresencePenalty *float64 `json:"presence_penalty,omitempty"`
StopSequences []string `json:"stop_sequences,omitempty"`
}
// ThinkingConfig 思考配置
type ThinkingConfig struct {
Type string `json:"type"`
BudgetTokens *int `json:"budget_tokens,omitempty"`
Effort string `json:"effort,omitempty"`
}
// OutputFormat 输出格式联合体
type OutputFormat struct {
Type string `json:"type"`
Name string `json:"name,omitempty"`
Schema json.RawMessage `json:"schema,omitempty"`
Strict *bool `json:"strict,omitempty"`
}
// CanonicalRequest 规范请求
type CanonicalRequest struct {
Model string `json:"model"`
System any `json:"system,omitempty"` // nil, string, or []SystemBlock
Messages []CanonicalMessage `json:"messages"`
Tools []CanonicalTool `json:"tools,omitempty"`
ToolChoice *ToolChoice `json:"tool_choice,omitempty"`
Parameters RequestParameters `json:"parameters"`
Thinking *ThinkingConfig `json:"thinking,omitempty"`
Stream bool `json:"stream"`
UserID string `json:"user_id,omitempty"`
OutputFormat *OutputFormat `json:"output_format,omitempty"`
ParallelToolUse *bool `json:"parallel_tool_use,omitempty"`
}
// CanonicalUsage 规范用量
type CanonicalUsage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens *int `json:"cache_read_tokens,omitempty"`
CacheCreationTokens *int `json:"cache_creation_tokens,omitempty"`
ReasoningTokens *int `json:"reasoning_tokens,omitempty"`
}
// CanonicalResponse 规范响应
type CanonicalResponse struct {
ID string `json:"id"`
Model string `json:"model"`
Content []ContentBlock `json:"content"`
StopReason *StopReason `json:"stop_reason,omitempty"`
Usage CanonicalUsage `json:"usage"`
}
// GetSystemString 获取系统消息字符串
func (r *CanonicalRequest) GetSystemString() string {
switch v := r.System.(type) {
case string:
return v
case []SystemBlock:
var result string
for i, b := range v {
if i > 0 {
result += "\n\n"
}
result += b.Text
}
return result
case nil:
return ""
default:
return fmt.Sprintf("%v", v)
}
}
// SetSystemString 设置系统消息字符串
func (r *CanonicalRequest) SetSystemString(s string) {
if s == "" {
r.System = nil
} else {
r.System = s
}
}