From f9c2a5f1021714213177c69ec53ec2a9ac402a67 Mon Sep 17 00:00:00 2001 From: zhengkunwang223 <1paneldev@sina.com> Date: Thu, 13 Aug 2026 16:14:30 +0800 Subject: [PATCH 1/3] feat: Optimize application upgrade logic --- agent/app/provider/catalog.go | 21 +++++++-- agent/app/provider/verify.go | 15 ++++++ agent/app/service/agents_utils.go | 2 +- agent/utils/docker/compose.go | 46 ++++--------------- .../src/components/api-type-tag/index.vue | 19 ++++++-- frontend/src/lang/modules/en.ts | 2 + frontend/src/lang/modules/es-es.ts | 2 + frontend/src/lang/modules/fa.ts | 2 + frontend/src/lang/modules/ja.ts | 2 + frontend/src/lang/modules/ko.ts | 2 + frontend/src/lang/modules/lo.ts | 2 + frontend/src/lang/modules/ms.ts | 2 + frontend/src/lang/modules/pt-br.ts | 2 + frontend/src/lang/modules/ru.ts | 2 + frontend/src/lang/modules/tr.ts | 2 + frontend/src/lang/modules/zh-Hant.ts | 2 + frontend/src/lang/modules/zh.ts | 2 + .../src/views/ai/agents/model/add/index.vue | 8 +++- 18 files changed, 87 insertions(+), 48 deletions(-) diff --git a/agent/app/provider/catalog.go b/agent/app/provider/catalog.go index ccc598e35023..b59d80ec6e06 100644 --- a/agent/app/provider/catalog.go +++ b/agent/app/provider/catalog.go @@ -40,20 +40,21 @@ type Meta struct { var catalog = map[string]Meta{ "custom": { Key: "custom", DisplayName: "Custom", Sort: 10, DefaultAPIType: "openai-completions", EnvKey: "CUSTOM_API_KEY", - APIConfigs: editableAPIConfigs(true, "openai-completions", "openai-responses", "anthropic-messages", "openai-images"), + APIConfigs: editableAPIConfigs(true, "openai-completions", "openai-responses", "anthropic-messages", "openai-images", "openai-embeddings"), }, "ollama": { Key: "ollama", DisplayName: "Ollama", Sort: 15, DefaultAPIType: "openai-responses", - APIConfigs: editableAPIConfigs(false, "openai-responses", "openai-completions"), + APIConfigs: editableAPIConfigs(false, "openai-responses", "openai-completions", "openai-embeddings"), }, "vllm": { Key: "vllm", DisplayName: "vLLM", Sort: 20, DefaultAPIType: "openai-completions", EnvKey: "VLLM_API_KEY", - APIConfigs: editableAPIConfigs(false, "openai-completions", "openai-responses", "anthropic-messages", "openai-images"), + APIConfigs: editableAPIConfigs(false, "openai-completions", "openai-responses", "anthropic-messages", "openai-images", "openai-embeddings"), }, "deepseek": { Key: "deepseek", DisplayName: "DeepSeek", Sort: 25, DefaultAPIType: "openai-completions", EnvKey: "DEEPSEEK_API_KEY", APIConfigs: []APIConfig{ {APIType: "openai-completions", BaseURL: "https://api.deepseek.com"}, + {APIType: "openai-responses", BaseURL: "https://api.deepseek.com"}, anthropicAPIConfig("https://api.deepseek.com/anthropic", AuthModeXAPIKey), }, Models: []Model{{ID: "deepseek-v4-flash", Name: "deepseek-v4-flash"}, {ID: "deepseek-v4-pro", Name: "deepseek-v4-pro"}}, @@ -131,6 +132,10 @@ var catalog = map[string]Meta{ {APIType: "openai-responses", BaseURL: "https://api.openai.com/v1"}, {APIType: "openai-completions", BaseURL: "https://api.openai.com/v1"}, {APIType: "openai-images", BaseURL: "https://api.openai.com/v1"}, + {APIType: "openai-embeddings", BaseURL: "https://api.openai.com/v1", Models: []Model{ + {ID: "text-embedding-3-small", Name: "text-embedding-3-small"}, + {ID: "text-embedding-3-large", Name: "text-embedding-3-large"}, + }}, }, Models: []Model{{ID: "gpt-5.4", Name: "gpt-5.4"}, {ID: "gpt-5.4-pro", Name: "gpt-5.4-pro"}, {ID: "gpt-5.4-mini", Name: "gpt-5.4-mini"}, {ID: "gpt-5.4-nano", Name: "gpt-5.4-nano"}}, }, @@ -296,7 +301,7 @@ func DefaultModels(key, apiType string) []Model { if len(config.Models) > 0 { return append([]Model(nil), config.Models...) } - if IsImageAPIType(config.APIType) { + if IsImageAPIType(config.APIType) || IsEmbeddingAPIType(config.APIType) { return nil } break @@ -359,7 +364,7 @@ func ResolveBaseURL(key, apiType, requested string) (string, error) { if err != nil || parsed.Scheme == "" || parsed.Host == "" { return "", fmt.Errorf("invalid base url") } - if key == "custom" && IsImageAPIType(config.APIType) { + if key == "custom" && (IsImageAPIType(config.APIType) || IsEmbeddingAPIType(config.APIType)) { return baseURL, nil } parsed.Path = normalizeEndpointPath(config.APIType, parsed.Path) @@ -381,6 +386,8 @@ func normalizeEndpointPath(apiType, value string) string { suffixes = []string{"/responses"} case "anthropic-messages": suffixes = []string{"/v1/messages", "/messages"} + case "openai-embeddings": + suffixes = []string{"/v1/embeddings", "/embeddings"} } for _, suffix := range suffixes { if strings.HasSuffix(strings.ToLower(path), suffix) { @@ -390,6 +397,10 @@ func normalizeEndpointPath(apiType, value string) string { return path } +func IsEmbeddingAPIType(apiType string) bool { + return apiType == "openai-embeddings" +} + func IsImageAPIType(apiType string) bool { switch apiType { case "openai-images", "dashscope-images", "minimax-images", "openrouter-images": diff --git a/agent/app/provider/verify.go b/agent/app/provider/verify.go index 318c50ba3f5c..148847eb299b 100644 --- a/agent/app/provider/verify.go +++ b/agent/app/provider/verify.go @@ -81,6 +81,10 @@ func BuildVerifyRequest(provider, apiType, authMode, baseURL, apiKey, model stri } switch apiType { + case "openai-embeddings": + request.URL = embeddingVerifyURL(baseURL) + headers["Authorization"] = "Bearer " + apiKey + request.Body = mustJSON(map[string]interface{}{"model": model, "input": "ping"}) case "openai-images": request.URL = imageVerifyURL(provider, baseURL, "/images/generations") headers["Authorization"] = "Bearer " + apiKey @@ -131,6 +135,17 @@ func BuildVerifyRequest(provider, apiType, authMode, baseURL, apiKey, model stri return request } +func embeddingVerifyURL(baseURL string) string { + lowerBaseURL := strings.ToLower(baseURL) + if strings.HasSuffix(lowerBaseURL, "/embeddings") { + return baseURL + } + if strings.HasSuffix(lowerBaseURL, "/v1") { + return baseURL + "/embeddings" + } + return baseURL + "/v1/embeddings" +} + func imageVerifyURL(provider, baseURL, endpoint string) string { if provider == "custom" || strings.HasSuffix(strings.ToLower(baseURL), endpoint) { return baseURL diff --git a/agent/app/service/agents_utils.go b/agent/app/service/agents_utils.go index dac2e63acf9e..7153f5824ace 100644 --- a/agent/app/service/agents_utils.go +++ b/agent/app/service/agents_utils.go @@ -116,7 +116,7 @@ func resolveAgentAccountInput(provider, apiType, authMode, apiKey, baseURL, mode return resolvedAgentAccountInput{}, buserr.New("ErrAgentAccountModelsRequired") } imageAPI := providercatalog.IsImageAPIType(resolvedAPIType) - if validateAvailability && (imageAPI || !providercatalog.SkipVerification(provider)) { + if validateAvailability && (imageAPI || providercatalog.IsEmbeddingAPIType(resolvedAPIType) || !providercatalog.SkipVerification(provider)) { if err := providercatalog.VerifyAccount(provider, resolvedAPIType, resolvedAuthMode, resolvedBaseURL, resolvedAPIKey, modelID); err != nil { return resolvedAgentAccountInput{}, err } diff --git a/agent/utils/docker/compose.go b/agent/utils/docker/compose.go index 14c475d9604a..715a51da1eba 100644 --- a/agent/utils/docker/compose.go +++ b/agent/utils/docker/compose.go @@ -1,14 +1,15 @@ package docker import ( - "bufio" "bytes" "context" "fmt" "path" "strings" + "github.com/compose-spec/compose-go/v2/dotenv" "github.com/compose-spec/compose-go/v2/loader" + "github.com/compose-spec/compose-go/v2/template" "github.com/compose-spec/compose-go/v2/types" "github.com/joho/godotenv" "gopkg.in/yaml.v3" @@ -91,7 +92,7 @@ func (e *Environment) UnmarshalYAML(value *yaml.Node) error { } func GetImagesFromDockerCompose(env, yml []byte) ([]string, error) { - envVars, err := loadEnvFile(env) + envVars, err := dotenv.Parse(bytes.NewReader(env)) if err != nil { return nil, fmt.Errorf("load env failed: %v", err) } @@ -104,43 +105,16 @@ func GetImagesFromDockerCompose(env, yml []byte) ([]string, error) { var images []string for _, service := range compose.Services { if service.Image != "" { - resolvedImage := replaceEnvVars(service.Image, envVars) + resolvedImage, err := template.Substitute(service.Image, func(key string) (string, bool) { + value, ok := envVars[key] + return value, ok + }) + if err != nil { + return nil, fmt.Errorf("resolve image failed: %v", err) + } images = append(images, resolvedImage) } } return images, nil } - -func loadEnvFile(env []byte) (map[string]string, error) { - envVars := make(map[string]string) - - scanner := bufio.NewScanner(bytes.NewReader(env)) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - - if line == "" || strings.HasPrefix(line, "#") { - continue - } - - parts := strings.SplitN(line, "=", 2) - if len(parts) == 2 { - key := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) - value = strings.Trim(value, `"'`) - envVars[key] = value - } - } - - return envVars, scanner.Err() -} - -func replaceEnvVars(input string, envVars map[string]string) string { - return re.GetRegex(re.ComposeEnvVarPattern).ReplaceAllStringFunc(input, func(match string) string { - varName := match[2 : len(match)-1] - if value, exists := envVars[varName]; exists { - return value - } - return match - }) -} diff --git a/frontend/src/components/api-type-tag/index.vue b/frontend/src/components/api-type-tag/index.vue index 58a8fc244ff5..9b75e942742c 100644 --- a/frontend/src/components/api-type-tag/index.vue +++ b/frontend/src/components/api-type-tag/index.vue @@ -1,9 +1,12 @@