feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
@@ -5,6 +5,8 @@
|
||||
package convmeta
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/relaykit/dto"
|
||||
"github.com/QuantumNous/new-api/relaykit/types"
|
||||
)
|
||||
@@ -40,6 +42,15 @@ type Meta interface {
|
||||
// nil receiver may return a temporary initialized state.
|
||||
EnsureClaudeConvertInfo() *ClaudeConvertInfo
|
||||
|
||||
// ResponsesToolState returns the Responses tool encoding recorded by the
|
||||
// latest request conversion, or nil when none was recorded. Response
|
||||
// converters read it to restore Responses-only tool call shapes.
|
||||
ResponsesToolState() *ResponsesToolState
|
||||
// SetResponsesToolState replaces that record; nil clears it. Request
|
||||
// conversion calls it on every attempt so retries never inherit a record
|
||||
// from another channel.
|
||||
SetResponsesToolState(state *ResponsesToolState)
|
||||
|
||||
// GetSendResponseCount / IncrSendResponseCount expose the shared
|
||||
// downstream-chunk counter (the host may also increment it).
|
||||
GetSendResponseCount() int
|
||||
@@ -80,6 +91,60 @@ type ClaudeStreamToolCall struct {
|
||||
Started bool
|
||||
}
|
||||
|
||||
// ResponsesToolState records how Responses-only tool definitions were encoded
|
||||
// for the upstream protocol, so the matching response can be restored.
|
||||
type ResponsesToolState struct {
|
||||
// CustomToolNames lists Responses custom (freeform) tools that were sent
|
||||
// upstream as function tools taking one string "input" argument. Function
|
||||
// calls with these names are custom tool calls.
|
||||
CustomToolNames map[string]struct{}
|
||||
// Namespaces maps an upstream function name to the Responses tool
|
||||
// namespace it was flattened from; see NamespacedToolName.
|
||||
Namespaces map[string]string
|
||||
}
|
||||
|
||||
// CustomToolInputArgument is the single function argument that carries a
|
||||
// Responses custom tool input through an upstream function call.
|
||||
const CustomToolInputArgument = "input"
|
||||
|
||||
// DefaultResponsesToolNamespace is the namespace Codex declares its ordinary
|
||||
// tools in. OpenAI returns calls to its tools by bare name without a
|
||||
// namespace field, so its tools keep their names upstream.
|
||||
const DefaultResponsesToolNamespace = "functions"
|
||||
|
||||
// NamespacedToolName is the upstream function name of a tool declared in a
|
||||
// Responses tool namespace: "<namespace>__<name>", or the bare name for the
|
||||
// default namespace.
|
||||
func NamespacedToolName(namespace string, name string) string {
|
||||
if namespace == "" || namespace == DefaultResponsesToolNamespace {
|
||||
return name
|
||||
}
|
||||
return namespace + "__" + name
|
||||
}
|
||||
|
||||
// IsCustomTool reports whether name was encoded from a Responses custom tool.
|
||||
func (s *ResponsesToolState) IsCustomTool(name string) bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := s.CustomToolNames[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResponsesToolName restores the Responses namespace and tool name of an
|
||||
// upstream function name. Names that were not flattened from a namespace
|
||||
// return an empty namespace and the name unchanged.
|
||||
func (s *ResponsesToolState) ResponsesToolName(upstreamName string) (string, string) {
|
||||
if s == nil {
|
||||
return "", upstreamName
|
||||
}
|
||||
namespace, ok := s.Namespaces[upstreamName]
|
||||
if !ok {
|
||||
return "", upstreamName
|
||||
}
|
||||
return namespace, strings.TrimPrefix(upstreamName, namespace+"__")
|
||||
}
|
||||
|
||||
const (
|
||||
LastMessageTypeNone = "none"
|
||||
LastMessageTypeText = "text"
|
||||
@@ -101,6 +166,7 @@ type Values struct {
|
||||
EstimatePromptTokens int
|
||||
|
||||
ClaudeConvertInfo *ClaudeConvertInfo
|
||||
ResponsesTools *ResponsesToolState
|
||||
SendResponseCount int
|
||||
ConversionChain []types.RelayFormat
|
||||
|
||||
@@ -182,6 +248,19 @@ func (v *Values) EnsureClaudeConvertInfo() *ClaudeConvertInfo {
|
||||
return v.ClaudeConvertInfo
|
||||
}
|
||||
|
||||
func (v *Values) ResponsesToolState() *ResponsesToolState {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.ResponsesTools
|
||||
}
|
||||
|
||||
func (v *Values) SetResponsesToolState(state *ResponsesToolState) {
|
||||
if v != nil {
|
||||
v.ResponsesTools = state
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Values) GetSendResponseCount() int {
|
||||
if v == nil {
|
||||
return 0
|
||||
@@ -240,6 +319,14 @@ func OptionsOf(m Meta) *Options {
|
||||
return m.ConvOptions()
|
||||
}
|
||||
|
||||
// ResponsesToolStateOf is a nil-safe reader for Meta.ResponsesToolState.
|
||||
func ResponsesToolStateOf(m Meta) *ResponsesToolState {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return m.ResponsesToolState()
|
||||
}
|
||||
|
||||
// ReasoningStateOf is a nil-safe reader for Meta.ReasoningState.
|
||||
func ReasoningStateOf(m Meta) *dto.ReasoningConversionState {
|
||||
if m == nil {
|
||||
|
||||
@@ -23,6 +23,12 @@ type Options struct {
|
||||
// it from the channel type.
|
||||
OpenRouterDialect bool
|
||||
|
||||
// WebSearch encodes hosted web search for the upstream dialect. Nil, or a
|
||||
// nil result, keeps the default: web_search_options on Chat and the native
|
||||
// hosted tool on Responses, Claude, and Gemini. The host sets it from the
|
||||
// channel adaptor's Init.
|
||||
WebSearch WebSearchEncoder
|
||||
|
||||
// PreserveThinkingSuffix reports models whose -thinking/-nothinking/effort
|
||||
// suffix must be kept on the outgoing model name (host blacklist lookup).
|
||||
// Nil means "never preserve".
|
||||
@@ -34,9 +40,13 @@ type Options struct {
|
||||
}
|
||||
|
||||
type ClaudeOptions struct {
|
||||
// ThinkingAdapterEnabled controls whether suffix-derived reasoning intent
|
||||
// is rendered onto Claude thinking / output_config. Suffix parsing itself
|
||||
// is the host entry layer's job (standalone users call Parse* themselves).
|
||||
// ThinkingAdapterEnabled is the host thinking-suffix adapter toggle. The
|
||||
// host passes it to reasoning.ParseClaudeModelSuffix, so -thinking,
|
||||
// -nothinking, -thinking-<budget>, and effort tails such as -high on
|
||||
// claude-* names become reasoning intent only while it is on; when off the
|
||||
// model name is sent verbatim. Explicit @ modifiers are unaffected. Suffix
|
||||
// parsing itself is the host entry layer's job (standalone users call
|
||||
// Parse* themselves).
|
||||
ThinkingAdapterEnabled bool
|
||||
// ThinkingAdapterBudgetTokensPercentage sizes thinking budget_tokens as a
|
||||
// fraction of max_tokens when the adapter fires.
|
||||
@@ -57,9 +67,12 @@ type ClaudeOptions struct {
|
||||
}
|
||||
|
||||
type GeminiOptions struct {
|
||||
// ThinkingAdapterEnabled controls whether suffix-derived reasoning intent
|
||||
// is rendered onto Gemini thinkingConfig. Suffix parsing itself is the
|
||||
// host entry layer's job (standalone users call Parse* themselves).
|
||||
// ThinkingAdapterEnabled is the host thinking-suffix adapter toggle. The
|
||||
// host and gemini_chat request conversion pass it to
|
||||
// reasoning.ParseGeminiModelSuffix, so -thinking, -nothinking,
|
||||
// -thinking-<budget>, and effort tails such as -high on gemini-* names
|
||||
// become reasoning intent only while it is on; when off the model name is
|
||||
// sent verbatim. Explicit @ modifiers are unaffected.
|
||||
ThinkingAdapterEnabled bool
|
||||
// ThinkingAdapterBudgetTokensPercentage sizes thinkingBudget as a fraction
|
||||
// of maxOutputTokens when the adapter fires.
|
||||
@@ -70,6 +83,12 @@ type GeminiOptions struct {
|
||||
// SupportsImagine reports whether the model supports image generation
|
||||
// (switches response modalities). Nil means "never".
|
||||
SupportsImagine func(modelName string) bool
|
||||
// SupportsJSONSchema reports whether the upstream accepts JSON Schema in
|
||||
// parametersJsonSchema and responseJsonSchema for the model. A schema that
|
||||
// Gemini's typed Schema cannot hold without loss is then sent there
|
||||
// unchanged; otherwise it is cleaned to the typed Schema and the loss is
|
||||
// reported as a diagnostic. Nil means "never".
|
||||
SupportsJSONSchema func(modelName string) bool
|
||||
// SafetySetting returns the harm threshold for a category. Nil or empty
|
||||
// return means no safetySettings are attached.
|
||||
SafetySetting func(category string) string
|
||||
@@ -86,6 +105,10 @@ func (o *GeminiOptions) SupportsImagineModel(modelName string) bool {
|
||||
return o != nil && o.SupportsImagine != nil && o.SupportsImagine(modelName)
|
||||
}
|
||||
|
||||
func (o *GeminiOptions) SupportsJSONSchemaModel(modelName string) bool {
|
||||
return o != nil && o.SupportsJSONSchema != nil && o.SupportsJSONSchema(modelName)
|
||||
}
|
||||
|
||||
func (o *GeminiOptions) SafetySettingFor(category string) string {
|
||||
if o == nil || o.SafetySetting == nil {
|
||||
return ""
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package convmeta
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/QuantumNous/new-api/relaykit/dto"
|
||||
"github.com/QuantumNous/new-api/relaykit/types"
|
||||
)
|
||||
|
||||
// WebSearch is the protocol-neutral hosted web-search specification decoded
|
||||
// from the source request.
|
||||
type WebSearch struct {
|
||||
Location *ApproximateLocation
|
||||
AllowedDomains []string
|
||||
BlockedDomains []string
|
||||
SearchContextSize string
|
||||
MaxUses *int
|
||||
AllowedCallers []string
|
||||
ResponseInclusion string
|
||||
ExternalWebAccess *bool
|
||||
ReturnTokenBudget json.RawMessage
|
||||
}
|
||||
|
||||
type ApproximateLocation struct {
|
||||
City string
|
||||
Region string
|
||||
Country string
|
||||
Timezone string
|
||||
}
|
||||
|
||||
// WebSearchCall is one hosted web-search definition about to be encoded for
|
||||
// the target request. Exactly one of Chat, Responses, Claude, Gemini is set;
|
||||
// the encoder may write top-level fields of that request directly.
|
||||
type WebSearchCall struct {
|
||||
Source types.RelayFormat
|
||||
Target types.RelayFormat
|
||||
// NativeType is the source tool type, for example web_search_preview,
|
||||
// web_search_20250305, or googleSearch.
|
||||
NativeType string
|
||||
// Index is the position in the source tool list. Chat Completions
|
||||
// carries one hosted web search, so a Chat encoder sees only the first
|
||||
// definition; the other targets call the encoder once per definition.
|
||||
Index int
|
||||
// Forced reports that the source tool_choice named the web-search tool.
|
||||
Forced bool
|
||||
Spec WebSearch
|
||||
|
||||
Chat *dto.GeneralOpenAIRequest
|
||||
Responses *dto.OpenAIResponsesRequest
|
||||
Claude *dto.ClaudeRequest
|
||||
Gemini *dto.GeminiChatRequest
|
||||
}
|
||||
|
||||
// WebSearchEncoding is what an encoder produced for one WebSearchCall.
|
||||
type WebSearchEncoding struct {
|
||||
// Tool is appended to the target tool list in the target protocol's own
|
||||
// shape. A Chat target requires a dto.ToolCallRequest (any other type
|
||||
// fails the conversion); the others take a JSON-marshalable value (usually
|
||||
// map[string]any). Nil means the encoder wrote top-level request fields
|
||||
// instead.
|
||||
Tool any
|
||||
// Omitted reports that no hosted search reaches the upstream. relaykit
|
||||
// records hosted_web_search_omitted (error severity) so ToolLossPolicy
|
||||
// can reject it, and appends no tool.
|
||||
Omitted bool
|
||||
// Diagnostics are merged into the conversion result. Error-severity
|
||||
// diagnostics count as semantic loss: under the channel's "safe" or
|
||||
// "strict" ToolLossPolicy they reject the request, so return
|
||||
// ConversionDiagnosticError only when the search behavior the client
|
||||
// asked for is actually lost, and ConversionDiagnosticWarning for tuning
|
||||
// that does not change whether or what is searched.
|
||||
Diagnostics []types.ConversionDiagnostic
|
||||
}
|
||||
|
||||
// WebSearchEncoder encodes hosted web search for an upstream whose dialect
|
||||
// differs from the target protocol's default. A nil result keeps relaykit's
|
||||
// default encoding; an error fails the conversion and is reserved for
|
||||
// encodings that cannot be produced at all, never for ordinary loss.
|
||||
type WebSearchEncoder func(call WebSearchCall) (*WebSearchEncoding, error)
|
||||
|
||||
// Path is the diagnostic path of the definition in the source tool list.
|
||||
func (c WebSearchCall) Path() string {
|
||||
return fmt.Sprintf("tools[%d]", c.Index)
|
||||
}
|
||||
|
||||
// SemanticLoss builds an error-severity diagnostic for this definition.
|
||||
func (c WebSearchCall) SemanticLoss(code, message string) types.ConversionDiagnostic {
|
||||
return types.ConversionDiagnostic{Code: code, Path: c.Path(), Message: message, Severity: types.ConversionDiagnosticError}
|
||||
}
|
||||
|
||||
// PresentationLoss builds a warning-severity diagnostic for this definition.
|
||||
func (c WebSearchCall) PresentationLoss(code, message string) types.ConversionDiagnostic {
|
||||
return types.ConversionDiagnostic{Code: code, Path: c.Path(), Message: message, Severity: types.ConversionDiagnosticWarning}
|
||||
}
|
||||
Reference in new issue
Block a user