Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed9f6e897e | ||
|
|
9c1e3c0687 | ||
|
|
2e5681ea32 | ||
|
|
52c17f03a5 | ||
|
|
d0e694d4ed | ||
|
|
506f1117dd | ||
|
|
113db3c5bf |
@@ -6,6 +6,7 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -24,6 +25,11 @@ func RequestLoggingMiddleware(logger logging.RequestLogger) gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Request.Method == http.MethodGet {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
path := c.Request.URL.Path
|
path := c.Request.URL.Path
|
||||||
if !shouldLogRequest(path) {
|
if !shouldLogRequest(path) {
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|||||||
@@ -23,6 +23,60 @@ func GetClaudeModels() []*ModelInfo {
|
|||||||
Type: "claude",
|
Type: "claude",
|
||||||
DisplayName: "Claude 4.5 Sonnet",
|
DisplayName: "Claude 4.5 Sonnet",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "claude-sonnet-4-5-thinking",
|
||||||
|
Object: "model",
|
||||||
|
Created: 1759104000, // 2025-09-29
|
||||||
|
OwnedBy: "anthropic",
|
||||||
|
Type: "claude",
|
||||||
|
DisplayName: "Claude 4.5 Sonnet Thinking",
|
||||||
|
Thinking: &ThinkingSupport{Min: 1024, Max: 100000, ZeroAllowed: false, DynamicAllowed: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "gemini-claude-sonnet-4-5-thinking",
|
||||||
|
Object: "model",
|
||||||
|
Created: 1759104000, // 2025-09-29
|
||||||
|
OwnedBy: "anthropic",
|
||||||
|
Type: "claude",
|
||||||
|
DisplayName: "Gemini Claude 4.5 Sonnet Thinking",
|
||||||
|
Thinking: &ThinkingSupport{Min: 1024, Max: 100000, ZeroAllowed: false, DynamicAllowed: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "claude-opus-4-5-thinking",
|
||||||
|
Object: "model",
|
||||||
|
Created: 1761955200, // 2025-11-01
|
||||||
|
OwnedBy: "anthropic",
|
||||||
|
Type: "claude",
|
||||||
|
DisplayName: "Claude 4.5 Opus Thinking",
|
||||||
|
Thinking: &ThinkingSupport{Min: 1024, Max: 100000, ZeroAllowed: false, DynamicAllowed: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "claude-opus-4-5-thinking-low",
|
||||||
|
Object: "model",
|
||||||
|
Created: 1761955200, // 2025-11-01
|
||||||
|
OwnedBy: "anthropic",
|
||||||
|
Type: "claude",
|
||||||
|
DisplayName: "Claude 4.5 Opus Thinking Low",
|
||||||
|
Thinking: &ThinkingSupport{Min: 1024, Max: 100000, ZeroAllowed: false, DynamicAllowed: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "claude-opus-4-5-thinking-medium",
|
||||||
|
Object: "model",
|
||||||
|
Created: 1761955200, // 2025-11-01
|
||||||
|
OwnedBy: "anthropic",
|
||||||
|
Type: "claude",
|
||||||
|
DisplayName: "Claude 4.5 Opus Thinking Medium",
|
||||||
|
Thinking: &ThinkingSupport{Min: 1024, Max: 100000, ZeroAllowed: false, DynamicAllowed: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "claude-opus-4-5-thinking-high",
|
||||||
|
Object: "model",
|
||||||
|
Created: 1761955200, // 2025-11-01
|
||||||
|
OwnedBy: "anthropic",
|
||||||
|
Type: "claude",
|
||||||
|
DisplayName: "Claude 4.5 Opus Thinking High",
|
||||||
|
Thinking: &ThinkingSupport{Min: 1024, Max: 100000, ZeroAllowed: false, DynamicAllowed: true},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ID: "claude-opus-4-5-20251101",
|
ID: "claude-opus-4-5-20251101",
|
||||||
Object: "model",
|
Object: "model",
|
||||||
|
|||||||
@@ -365,13 +365,27 @@ func FetchAntigravityModels(ctx context.Context, auth *cliproxyauth.Auth, cfg *c
|
|||||||
for id := range result.Map() {
|
for id := range result.Map() {
|
||||||
id = modelName2Alias(id)
|
id = modelName2Alias(id)
|
||||||
if id != "" {
|
if id != "" {
|
||||||
models = append(models, ®istry.ModelInfo{
|
modelInfo := ®istry.ModelInfo{
|
||||||
ID: id,
|
ID: id,
|
||||||
Object: "model",
|
Name: id,
|
||||||
Created: now,
|
Description: id,
|
||||||
OwnedBy: antigravityAuthType,
|
DisplayName: id,
|
||||||
Type: antigravityAuthType,
|
Version: id,
|
||||||
})
|
Object: "model",
|
||||||
|
Created: now,
|
||||||
|
OwnedBy: antigravityAuthType,
|
||||||
|
Type: antigravityAuthType,
|
||||||
|
}
|
||||||
|
// Add Thinking support for thinking models
|
||||||
|
if strings.HasSuffix(id, "-thinking") || strings.Contains(id, "-thinking-") {
|
||||||
|
modelInfo.Thinking = ®istry.ThinkingSupport{
|
||||||
|
Min: 1024,
|
||||||
|
Max: 100000,
|
||||||
|
ZeroAllowed: false,
|
||||||
|
DynamicAllowed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
models = append(models, modelInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return models
|
return models
|
||||||
|
|||||||
@@ -58,18 +58,24 @@ func (e *ClaudeExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, r
|
|||||||
body, _ = sjson.SetBytes(body, "model", modelOverride)
|
body, _ = sjson.SetBytes(body, "model", modelOverride)
|
||||||
modelForUpstream = modelOverride
|
modelForUpstream = modelOverride
|
||||||
}
|
}
|
||||||
|
// Inject thinking config based on model suffix for thinking variants
|
||||||
|
body = e.injectThinkingConfig(req.Model, body)
|
||||||
|
|
||||||
if !strings.HasPrefix(modelForUpstream, "claude-3-5-haiku") {
|
if !strings.HasPrefix(modelForUpstream, "claude-3-5-haiku") {
|
||||||
body, _ = sjson.SetRawBytes(body, "system", []byte(misc.ClaudeCodeInstructions))
|
body = checkSystemInstructions(body)
|
||||||
}
|
}
|
||||||
body = applyPayloadConfig(e.cfg, req.Model, body)
|
body = applyPayloadConfig(e.cfg, req.Model, body)
|
||||||
|
|
||||||
|
// Extract betas from body and convert to header
|
||||||
|
var extraBetas []string
|
||||||
|
extraBetas, body = extractAndRemoveBetas(body)
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/v1/messages?beta=true", baseURL)
|
url := fmt.Sprintf("%s/v1/messages?beta=true", baseURL)
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
applyClaudeHeaders(httpReq, auth, apiKey, false)
|
applyClaudeHeaders(httpReq, auth, apiKey, false, extraBetas)
|
||||||
var authID, authLabel, authType, authValue string
|
var authID, authLabel, authType, authValue string
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
authID = auth.ID
|
authID = auth.ID
|
||||||
@@ -154,15 +160,21 @@ func (e *ClaudeExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A
|
|||||||
if modelOverride := e.resolveUpstreamModel(req.Model, auth); modelOverride != "" {
|
if modelOverride := e.resolveUpstreamModel(req.Model, auth); modelOverride != "" {
|
||||||
body, _ = sjson.SetBytes(body, "model", modelOverride)
|
body, _ = sjson.SetBytes(body, "model", modelOverride)
|
||||||
}
|
}
|
||||||
body, _ = sjson.SetRawBytes(body, "system", []byte(misc.ClaudeCodeInstructions))
|
// Inject thinking config based on model suffix for thinking variants
|
||||||
|
body = e.injectThinkingConfig(req.Model, body)
|
||||||
|
body = checkSystemInstructions(body)
|
||||||
body = applyPayloadConfig(e.cfg, req.Model, body)
|
body = applyPayloadConfig(e.cfg, req.Model, body)
|
||||||
|
|
||||||
|
// Extract betas from body and convert to header
|
||||||
|
var extraBetas []string
|
||||||
|
extraBetas, body = extractAndRemoveBetas(body)
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/v1/messages?beta=true", baseURL)
|
url := fmt.Sprintf("%s/v1/messages?beta=true", baseURL)
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
applyClaudeHeaders(httpReq, auth, apiKey, true)
|
applyClaudeHeaders(httpReq, auth, apiKey, true, extraBetas)
|
||||||
var authID, authLabel, authType, authValue string
|
var authID, authLabel, authType, authValue string
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
authID = auth.ID
|
authID = auth.ID
|
||||||
@@ -283,15 +295,19 @@ func (e *ClaudeExecutor) CountTokens(ctx context.Context, auth *cliproxyauth.Aut
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(modelForUpstream, "claude-3-5-haiku") {
|
if !strings.HasPrefix(modelForUpstream, "claude-3-5-haiku") {
|
||||||
body, _ = sjson.SetRawBytes(body, "system", []byte(misc.ClaudeCodeInstructions))
|
body = checkSystemInstructions(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract betas from body and convert to header (for count_tokens too)
|
||||||
|
var extraBetas []string
|
||||||
|
extraBetas, body = extractAndRemoveBetas(body)
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/v1/messages/count_tokens?beta=true", baseURL)
|
url := fmt.Sprintf("%s/v1/messages/count_tokens?beta=true", baseURL)
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliproxyexecutor.Response{}, err
|
return cliproxyexecutor.Response{}, err
|
||||||
}
|
}
|
||||||
applyClaudeHeaders(httpReq, auth, apiKey, false)
|
applyClaudeHeaders(httpReq, auth, apiKey, false, extraBetas)
|
||||||
var authID, authLabel, authType, authValue string
|
var authID, authLabel, authType, authValue string
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
authID = auth.ID
|
authID = auth.ID
|
||||||
@@ -383,10 +399,65 @@ func (e *ClaudeExecutor) Refresh(ctx context.Context, auth *cliproxyauth.Auth) (
|
|||||||
return auth, nil
|
return auth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractAndRemoveBetas extracts the "betas" array from the body and removes it.
|
||||||
|
// Returns the extracted betas as a string slice and the modified body.
|
||||||
|
func extractAndRemoveBetas(body []byte) ([]string, []byte) {
|
||||||
|
betasResult := gjson.GetBytes(body, "betas")
|
||||||
|
if !betasResult.Exists() {
|
||||||
|
return nil, body
|
||||||
|
}
|
||||||
|
var betas []string
|
||||||
|
if betasResult.IsArray() {
|
||||||
|
for _, item := range betasResult.Array() {
|
||||||
|
if s := strings.TrimSpace(item.String()); s != "" {
|
||||||
|
betas = append(betas, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if s := strings.TrimSpace(betasResult.String()); s != "" {
|
||||||
|
betas = append(betas, s)
|
||||||
|
}
|
||||||
|
body, _ = sjson.DeleteBytes(body, "betas")
|
||||||
|
return betas, body
|
||||||
|
}
|
||||||
|
|
||||||
|
// injectThinkingConfig adds thinking configuration based on model name suffix
|
||||||
|
func (e *ClaudeExecutor) injectThinkingConfig(modelName string, body []byte) []byte {
|
||||||
|
// Only inject if thinking config is not already present
|
||||||
|
if gjson.GetBytes(body, "thinking").Exists() {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
var budgetTokens int
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(modelName, "-thinking-low"):
|
||||||
|
budgetTokens = 1024
|
||||||
|
case strings.HasSuffix(modelName, "-thinking-medium"):
|
||||||
|
budgetTokens = 8192
|
||||||
|
case strings.HasSuffix(modelName, "-thinking-high"):
|
||||||
|
budgetTokens = 24576
|
||||||
|
case strings.HasSuffix(modelName, "-thinking"):
|
||||||
|
// Default thinking without suffix uses medium budget
|
||||||
|
budgetTokens = 8192
|
||||||
|
default:
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ = sjson.SetBytes(body, "thinking.type", "enabled")
|
||||||
|
body, _ = sjson.SetBytes(body, "thinking.budget_tokens", budgetTokens)
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ClaudeExecutor) resolveUpstreamModel(alias string, auth *cliproxyauth.Auth) string {
|
func (e *ClaudeExecutor) resolveUpstreamModel(alias string, auth *cliproxyauth.Auth) string {
|
||||||
if alias == "" {
|
if alias == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
// Hardcoded mappings for thinking models to actual Claude model names
|
||||||
|
switch alias {
|
||||||
|
case "claude-opus-4-5-thinking", "claude-opus-4-5-thinking-low", "claude-opus-4-5-thinking-medium", "claude-opus-4-5-thinking-high":
|
||||||
|
return "claude-opus-4-5-20251101"
|
||||||
|
case "claude-sonnet-4-5-thinking":
|
||||||
|
return "claude-sonnet-4-5-20250929"
|
||||||
|
}
|
||||||
entry := e.resolveClaudeConfig(auth)
|
entry := e.resolveClaudeConfig(auth)
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return ""
|
return ""
|
||||||
@@ -530,7 +601,7 @@ func decodeResponseBody(body io.ReadCloser, contentEncoding string) (io.ReadClos
|
|||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyClaudeHeaders(r *http.Request, auth *cliproxyauth.Auth, apiKey string, stream bool) {
|
func applyClaudeHeaders(r *http.Request, auth *cliproxyauth.Auth, apiKey string, stream bool, extraBetas []string) {
|
||||||
r.Header.Set("Authorization", "Bearer "+apiKey)
|
r.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
r.Header.Set("Content-Type", "application/json")
|
r.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
@@ -539,15 +610,30 @@ func applyClaudeHeaders(r *http.Request, auth *cliproxyauth.Auth, apiKey string,
|
|||||||
ginHeaders = ginCtx.Request.Header
|
ginHeaders = ginCtx.Request.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseBetas := "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"
|
||||||
if val := strings.TrimSpace(ginHeaders.Get("Anthropic-Beta")); val != "" {
|
if val := strings.TrimSpace(ginHeaders.Get("Anthropic-Beta")); val != "" {
|
||||||
|
baseBetas = val
|
||||||
if !strings.Contains(val, "oauth") {
|
if !strings.Contains(val, "oauth") {
|
||||||
val += ",oauth-2025-04-20"
|
baseBetas += ",oauth-2025-04-20"
|
||||||
}
|
}
|
||||||
r.Header.Set("Anthropic-Beta", val)
|
|
||||||
} else {
|
|
||||||
r.Header.Set("Anthropic-Beta", "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge extra betas from request body
|
||||||
|
if len(extraBetas) > 0 {
|
||||||
|
existingSet := make(map[string]bool)
|
||||||
|
for _, b := range strings.Split(baseBetas, ",") {
|
||||||
|
existingSet[strings.TrimSpace(b)] = true
|
||||||
|
}
|
||||||
|
for _, beta := range extraBetas {
|
||||||
|
beta = strings.TrimSpace(beta)
|
||||||
|
if beta != "" && !existingSet[beta] {
|
||||||
|
baseBetas += "," + beta
|
||||||
|
existingSet[beta] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Header.Set("Anthropic-Beta", baseBetas)
|
||||||
|
|
||||||
misc.EnsureHeader(r.Header, ginHeaders, "Anthropic-Version", "2023-06-01")
|
misc.EnsureHeader(r.Header, ginHeaders, "Anthropic-Version", "2023-06-01")
|
||||||
misc.EnsureHeader(r.Header, ginHeaders, "Anthropic-Dangerous-Direct-Browser-Access", "true")
|
misc.EnsureHeader(r.Header, ginHeaders, "Anthropic-Dangerous-Direct-Browser-Access", "true")
|
||||||
misc.EnsureHeader(r.Header, ginHeaders, "X-App", "cli")
|
misc.EnsureHeader(r.Header, ginHeaders, "X-App", "cli")
|
||||||
@@ -590,3 +676,22 @@ func claudeCreds(a *cliproxyauth.Auth) (apiKey, baseURL string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkSystemInstructions(payload []byte) []byte {
|
||||||
|
system := gjson.GetBytes(payload, "system")
|
||||||
|
claudeCodeInstructions := `[{"type":"text","text":"You are Claude Code, Anthropic's official CLI for Claude.","cache_control":{"type":"ephemeral"}}]`
|
||||||
|
if system.IsArray() {
|
||||||
|
if gjson.GetBytes(payload, "system.0.text").String() != "You are Claude Code, Anthropic's official CLI for Claude." {
|
||||||
|
system.ForEach(func(_, part gjson.Result) bool {
|
||||||
|
if part.Get("type").String() == "text" {
|
||||||
|
claudeCodeInstructions, _ = sjson.SetRaw(claudeCodeInstructions, "-1", part.Raw)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
payload, _ = sjson.SetRawBytes(payload, "system", []byte(claudeCodeInstructions))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
payload, _ = sjson.SetRawBytes(payload, "system", []byte(claudeCodeInstructions))
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -120,11 +121,11 @@ func (h *BaseAPIHandler) GetContextWithCancel(handler interfaces.APIHandler, c *
|
|||||||
data := params[0]
|
data := params[0]
|
||||||
switch data.(type) {
|
switch data.(type) {
|
||||||
case []byte:
|
case []byte:
|
||||||
c.Set("API_RESPONSE", data.([]byte))
|
appendAPIResponse(c, data.([]byte))
|
||||||
case error:
|
case error:
|
||||||
c.Set("API_RESPONSE", []byte(data.(error).Error()))
|
appendAPIResponse(c, []byte(data.(error).Error()))
|
||||||
case string:
|
case string:
|
||||||
c.Set("API_RESPONSE", []byte(data.(string)))
|
appendAPIResponse(c, []byte(data.(string)))
|
||||||
case bool:
|
case bool:
|
||||||
case nil:
|
case nil:
|
||||||
}
|
}
|
||||||
@@ -135,6 +136,28 @@ func (h *BaseAPIHandler) GetContextWithCancel(handler interfaces.APIHandler, c *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// appendAPIResponse preserves any previously captured API response and appends new data.
|
||||||
|
func appendAPIResponse(c *gin.Context, data []byte) {
|
||||||
|
if c == nil || len(data) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if existing, exists := c.Get("API_RESPONSE"); exists {
|
||||||
|
if existingBytes, ok := existing.([]byte); ok && len(existingBytes) > 0 {
|
||||||
|
combined := make([]byte, 0, len(existingBytes)+len(data)+1)
|
||||||
|
combined = append(combined, existingBytes...)
|
||||||
|
if existingBytes[len(existingBytes)-1] != '\n' {
|
||||||
|
combined = append(combined, '\n')
|
||||||
|
}
|
||||||
|
combined = append(combined, data...)
|
||||||
|
c.Set("API_RESPONSE", combined)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("API_RESPONSE", bytes.Clone(data))
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteWithAuthManager executes a non-streaming request via the core auth manager.
|
// ExecuteWithAuthManager executes a non-streaming request via the core auth manager.
|
||||||
// This path is the only supported execution route.
|
// This path is the only supported execution route.
|
||||||
func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, *interfaces.ErrorMessage) {
|
func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, *interfaces.ErrorMessage) {
|
||||||
@@ -297,7 +320,7 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl
|
|||||||
func (h *BaseAPIHandler) getRequestDetails(modelName string) (providers []string, normalizedModel string, metadata map[string]any, err *interfaces.ErrorMessage) {
|
func (h *BaseAPIHandler) getRequestDetails(modelName string) (providers []string, normalizedModel string, metadata map[string]any, err *interfaces.ErrorMessage) {
|
||||||
// Resolve "auto" model to an actual available model first
|
// Resolve "auto" model to an actual available model first
|
||||||
resolvedModelName := util.ResolveAutoModel(modelName)
|
resolvedModelName := util.ResolveAutoModel(modelName)
|
||||||
|
|
||||||
providerName, extractedModelName, isDynamic := h.parseDynamicModel(resolvedModelName)
|
providerName, extractedModelName, isDynamic := h.parseDynamicModel(resolvedModelName)
|
||||||
|
|
||||||
// First, normalize the model name to handle suffixes like "-thinking-128"
|
// First, normalize the model name to handle suffixes like "-thinking-128"
|
||||||
|
|||||||
Reference in New Issue
Block a user