AI 网关切换 OpenAI 兼容面并移除 chat 端点,新增模型黑白名单
This commit is contained in:
@@ -20,6 +20,13 @@ type MessagesRequest struct {
|
||||
ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
|
||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||
Thinking json.RawMessage `json:"thinking,omitempty"`
|
||||
// OutputConfig 是 Anthropic 官方输出控制(effort 等);网关映射 effort 到 OCI reasoningEffort。
|
||||
OutputConfig *AnthOutputConfig `json:"output_config,omitempty"`
|
||||
}
|
||||
|
||||
// AnthOutputConfig 是 Anthropic Messages 顶层 output_config 对象。
|
||||
type AnthOutputConfig struct {
|
||||
Effort string `json:"effort,omitempty"`
|
||||
}
|
||||
|
||||
// SystemText 把顶层 system(string 或块数组)拍平为文本。
|
||||
|
||||
+2
-209
@@ -1,35 +1,11 @@
|
||||
// Package aiwire 定义 AI 网关的线格式类型:OpenAI Chat Completions(兼作网关内部
|
||||
// 中间表示 IR,因 OCI GENERIC 格式即其镜像)与 Anthropic Messages。零内部依赖,
|
||||
// oci 层与 service 层共同引用。
|
||||
// Package aiwire 定义 AI 网关的线格式类型:OpenAI Responses / Anthropic Messages /
|
||||
// Embeddings 与通用记账、错误、模型列表结构。上游统一为 OCI OpenAI 兼容面。
|
||||
package aiwire
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ChatRequest 是 OpenAI /v1/chat/completions 请求体;TopK 为 OCI/Anthropic 扩展字段。
|
||||
type ChatRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []ChatMessage `json:"messages"`
|
||||
MaxTokens *int `json:"max_tokens,omitempty"`
|
||||
MaxCompletionTokens *int `json:"max_completion_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"`
|
||||
Stop StringList `json:"stop,omitempty"`
|
||||
Seed *int `json:"seed,omitempty"`
|
||||
N *int `json:"n,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
||||
Tools []Tool `json:"tools,omitempty"`
|
||||
ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
|
||||
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
|
||||
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
||||
}
|
||||
|
||||
// StringList 兼容 OpenAI stop 的 string 与 []string 两种线格式。
|
||||
type StringList []string
|
||||
|
||||
@@ -50,151 +26,6 @@ func (s *StringList) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StreamOptions 控制流式末尾是否附带 usage 事件。
|
||||
type StreamOptions struct {
|
||||
IncludeUsage bool `json:"include_usage"`
|
||||
}
|
||||
|
||||
// ChatMessage 是请求与非流式响应共用的消息结构。
|
||||
type ChatMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content Content `json:"content"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
||||
// Content 兼容 string 与多模态块数组两种线格式;一期仅透传文本。
|
||||
type Content struct {
|
||||
// Text 在原始值为字符串时填充
|
||||
Text string
|
||||
// Parts 在原始值为数组时填充
|
||||
Parts []ContentPart
|
||||
// isArray 记录原始形态,序列化时保形
|
||||
isArray bool
|
||||
}
|
||||
|
||||
// ContentPart 是块数组中的一段;text 与 image_url 被网关处理,其余类型拒绝。
|
||||
type ContentPart struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text,omitempty"`
|
||||
ImageURL *ImageURL `json:"image_url,omitempty"`
|
||||
}
|
||||
|
||||
// ImageURL 是 image_url 块负载;url 为 data URI(base64)或公网地址,与 OCI ImageUrl 同构。
|
||||
type ImageURL struct {
|
||||
URL string `json:"url"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Content) UnmarshalJSON(b []byte) error {
|
||||
trimmed := strings.TrimSpace(string(b))
|
||||
if trimmed == "null" {
|
||||
return nil
|
||||
}
|
||||
if len(trimmed) > 0 && trimmed[0] == '[' {
|
||||
c.isArray = true
|
||||
return json.Unmarshal(b, &c.Parts)
|
||||
}
|
||||
return json.Unmarshal(b, &c.Text)
|
||||
}
|
||||
|
||||
func (c Content) MarshalJSON() ([]byte, error) {
|
||||
if c.isArray {
|
||||
return json.Marshal(c.Parts)
|
||||
}
|
||||
return json.Marshal(c.Text)
|
||||
}
|
||||
|
||||
// NewTextContent 构造字符串形态的内容。
|
||||
func NewTextContent(text string) Content {
|
||||
return Content{Text: text}
|
||||
}
|
||||
|
||||
// NewPartsContent 构造块数组形态的内容(多模态消息用)。
|
||||
func NewPartsContent(parts []ContentPart) Content {
|
||||
return Content{Parts: parts, isArray: true}
|
||||
}
|
||||
|
||||
// JoinText 返回全部文本内容(数组形态拼接 text 块)。
|
||||
func (c Content) JoinText() string {
|
||||
if !c.isArray {
|
||||
return c.Text
|
||||
}
|
||||
var sb strings.Builder
|
||||
for _, p := range c.Parts {
|
||||
if p.Type == "" || p.Type == "text" {
|
||||
sb.WriteString(p.Text)
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// HasUnsupported 报告是否含网关无法承接的内容块(text / image_url 之外的类型)。
|
||||
func (c Content) HasUnsupported() bool {
|
||||
for _, p := range c.Parts {
|
||||
switch p.Type {
|
||||
case "", "text":
|
||||
case "image_url":
|
||||
if p.ImageURL == nil || p.ImageURL.URL == "" {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Tool 是 function 工具定义。
|
||||
type Tool struct {
|
||||
Type string `json:"type"`
|
||||
Function FunctionDef `json:"function"`
|
||||
}
|
||||
|
||||
// FunctionDef 描述工具的名称与 JSON Schema 参数。
|
||||
type FunctionDef struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Parameters json.RawMessage `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// ToolCall 是助手消息中的工具调用。
|
||||
type ToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Function FunctionCall `json:"function"`
|
||||
}
|
||||
|
||||
// FunctionCall 携带调用名与 JSON 编码的实参。
|
||||
type FunctionCall struct {
|
||||
Name string `json:"name"`
|
||||
Arguments string `json:"arguments"`
|
||||
}
|
||||
|
||||
// ResponseFormat 对应 response_format(json_object / json_schema)。
|
||||
type ResponseFormat struct {
|
||||
Type string `json:"type"`
|
||||
JSONSchema json.RawMessage `json:"json_schema,omitempty"`
|
||||
}
|
||||
|
||||
// ChatResponse 是非流式响应体。
|
||||
type ChatResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []Choice `json:"choices"`
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
// Choice 是一条候选回复。
|
||||
type Choice struct {
|
||||
Index int `json:"index"`
|
||||
Message ChatMessage `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
}
|
||||
|
||||
// Usage 是 token 用量。
|
||||
type Usage struct {
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
@@ -217,44 +48,6 @@ func (u *Usage) CachedTokens() int {
|
||||
return u.PromptTokensDetails.CachedTokens
|
||||
}
|
||||
|
||||
// ChatChunk 是流式增量事件体(chat.completion.chunk)。
|
||||
type ChatChunk struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []ChunkChoice `json:"choices"`
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
// ChunkChoice 是流式事件中的增量候选。
|
||||
type ChunkChoice struct {
|
||||
Index int `json:"index"`
|
||||
Delta Delta `json:"delta"`
|
||||
FinishReason *string `json:"finish_reason"`
|
||||
}
|
||||
|
||||
// Delta 是流式增量内容;Content 为纯文本片段。
|
||||
type Delta struct {
|
||||
Role string `json:"role,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ToolCalls []ToolCallDelta `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
// ToolCallDelta 是工具调用的流式片段;Index 标识聚合目标。
|
||||
type ToolCallDelta struct {
|
||||
Index int `json:"index"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Function FunctionCallDelta `json:"function"`
|
||||
}
|
||||
|
||||
// FunctionCallDelta 是函数名 / 实参的增量片段。
|
||||
type FunctionCallDelta struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Arguments string `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
// Model 是 /v1/models 列表项。
|
||||
type Model struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
@@ -156,39 +156,6 @@ type RespReasoning struct {
|
||||
Effort string `json:"effort,omitempty"`
|
||||
}
|
||||
|
||||
// Response 是 /responses 响应对象。
|
||||
type Response struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Status string `json:"status"`
|
||||
Model string `json:"model"`
|
||||
Output []RespOutItem `json:"output"`
|
||||
Usage *RespUsage `json:"usage,omitempty"`
|
||||
Error *RespError `json:"error"`
|
||||
IncompleteDetails *RespIncomplete `json:"incomplete_details"`
|
||||
Store bool `json:"store"`
|
||||
}
|
||||
|
||||
// RespOutItem 是 output 数组项:message 或 function_call。
|
||||
type RespOutItem struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Content []RespOutPart `json:"content,omitempty"`
|
||||
CallID string `json:"call_id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Arguments string `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
// RespOutPart 是 message item 的内容部件(output_text)。
|
||||
type RespOutPart struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
Annotations []any `json:"annotations"`
|
||||
}
|
||||
|
||||
// RespUsage 是 Responses 口径的用量(input/output 命名)。
|
||||
type RespUsage struct {
|
||||
InputTokens int `json:"input_tokens"`
|
||||
|
||||
Reference in New Issue
Block a user