mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-10 16:00:31 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8644579eda |
+58
-40
@@ -9,6 +9,9 @@ type AgentCreateReq struct {
|
|||||||
BridgePort int `json:"bridgePort" validate:"required"`
|
BridgePort int `json:"bridgePort" validate:"required"`
|
||||||
Provider string `json:"provider" validate:"required"`
|
Provider string `json:"provider" validate:"required"`
|
||||||
Model string `json:"model" validate:"required"`
|
Model string `json:"model" validate:"required"`
|
||||||
|
APIType string `json:"apiType"`
|
||||||
|
MaxTokens int `json:"maxTokens"`
|
||||||
|
ContextWindow int `json:"contextWindow"`
|
||||||
AccountID uint `json:"accountId"`
|
AccountID uint `json:"accountId"`
|
||||||
APIKey string `json:"apiKey"`
|
APIKey string `json:"apiKey"`
|
||||||
BaseURL string `json:"baseURL"`
|
BaseURL string `json:"baseURL"`
|
||||||
@@ -28,26 +31,29 @@ type AgentCreateReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AgentItem struct {
|
type AgentItem struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
ProviderName string `json:"providerName"`
|
ProviderName string `json:"providerName"`
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
BaseURL string `json:"baseUrl"`
|
APIType string `json:"apiType"`
|
||||||
APIKey string `json:"apiKey"`
|
MaxTokens int `json:"maxTokens"`
|
||||||
Token string `json:"token"`
|
ContextWindow int `json:"contextWindow"`
|
||||||
Status string `json:"status"`
|
BaseURL string `json:"baseUrl"`
|
||||||
Message string `json:"message"`
|
APIKey string `json:"apiKey"`
|
||||||
AppInstallID uint `json:"appInstallId"`
|
Token string `json:"token"`
|
||||||
AccountID uint `json:"accountId"`
|
Status string `json:"status"`
|
||||||
AppVersion string `json:"appVersion"`
|
Message string `json:"message"`
|
||||||
Container string `json:"containerName"`
|
AppInstallID uint `json:"appInstallId"`
|
||||||
WebUIPort int `json:"webUIPort"`
|
AccountID uint `json:"accountId"`
|
||||||
BridgePort int `json:"bridgePort"`
|
AppVersion string `json:"appVersion"`
|
||||||
Path string `json:"path"`
|
Container string `json:"containerName"`
|
||||||
ConfigPath string `json:"configPath"`
|
WebUIPort int `json:"webUIPort"`
|
||||||
Upgradable bool `json:"upgradable"`
|
BridgePort int `json:"bridgePort"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
Path string `json:"path"`
|
||||||
|
ConfigPath string `json:"configPath"`
|
||||||
|
Upgradable bool `json:"upgradable"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentDeleteReq struct {
|
type AgentDeleteReq struct {
|
||||||
@@ -67,20 +73,28 @@ type AgentModelConfigUpdateReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AgentAccountCreateReq struct {
|
type AgentAccountCreateReq struct {
|
||||||
Provider string `json:"provider" validate:"required"`
|
Provider string `json:"provider" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
APIKey string `json:"apiKey" validate:"required"`
|
APIKey string `json:"apiKey" validate:"required"`
|
||||||
BaseURL string `json:"baseURL"`
|
BaseURL string `json:"baseURL"`
|
||||||
Remark string `json:"remark"`
|
Model string `json:"model"`
|
||||||
|
APIType string `json:"apiType"`
|
||||||
|
MaxTokens int `json:"maxTokens"`
|
||||||
|
ContextWindow int `json:"contextWindow"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentAccountUpdateReq struct {
|
type AgentAccountUpdateReq struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
APIKey string `json:"apiKey" validate:"required"`
|
APIKey string `json:"apiKey" validate:"required"`
|
||||||
BaseURL string `json:"baseURL"`
|
BaseURL string `json:"baseURL"`
|
||||||
Remark string `json:"remark"`
|
Model string `json:"model"`
|
||||||
SyncAgents bool `json:"syncAgents"`
|
APIType string `json:"apiType"`
|
||||||
|
MaxTokens int `json:"maxTokens"`
|
||||||
|
ContextWindow int `json:"contextWindow"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
SyncAgents bool `json:"syncAgents"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentAccountVerifyReq struct {
|
type AgentAccountVerifyReq struct {
|
||||||
@@ -100,15 +114,19 @@ type AgentAccountSearch struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AgentAccountInfo struct {
|
type AgentAccountInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
ProviderName string `json:"providerName"`
|
ProviderName string `json:"providerName"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
APIKey string `json:"apiKey"`
|
APIKey string `json:"apiKey"`
|
||||||
BaseURL string `json:"baseUrl"`
|
BaseURL string `json:"baseUrl"`
|
||||||
Verified bool `json:"verified"`
|
Model string `json:"model"`
|
||||||
Remark string `json:"remark"`
|
APIType string `json:"apiType"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
MaxTokens int `json:"maxTokens"`
|
||||||
|
ContextWindow int `json:"contextWindow"`
|
||||||
|
Verified bool `json:"verified"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProviderModelInfo struct {
|
type ProviderModelInfo struct {
|
||||||
|
|||||||
+14
-11
@@ -2,15 +2,18 @@ package model
|
|||||||
|
|
||||||
type Agent struct {
|
type Agent struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name" gorm:"not null;unique"`
|
Name string `json:"name" gorm:"not null;unique"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
BaseURL string `json:"baseUrl"`
|
APIType string `json:"apiType"`
|
||||||
APIKey string `json:"apiKey"`
|
MaxTokens int `json:"maxTokens"`
|
||||||
Token string `json:"token"`
|
ContextWindow int `json:"contextWindow"`
|
||||||
Status string `json:"status"`
|
BaseURL string `json:"baseUrl"`
|
||||||
Message string `json:"message"`
|
APIKey string `json:"apiKey"`
|
||||||
AppInstallID uint `json:"appInstallId"`
|
Token string `json:"token"`
|
||||||
AccountID uint `json:"accountId"`
|
Status string `json:"status"`
|
||||||
ConfigPath string `json:"configPath"`
|
Message string `json:"message"`
|
||||||
|
AppInstallID uint `json:"appInstallId"`
|
||||||
|
AccountID uint `json:"accountId"`
|
||||||
|
ConfigPath string `json:"configPath"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package model
|
|||||||
|
|
||||||
type AgentAccount struct {
|
type AgentAccount struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
APIKey string `json:"apiKey"`
|
APIKey string `json:"apiKey"`
|
||||||
BaseURL string `json:"baseUrl"`
|
BaseURL string `json:"baseUrl"`
|
||||||
Verified bool `json:"verified"`
|
Model string `json:"model"`
|
||||||
Remark string `json:"remark"`
|
APIType string `json:"apiType"`
|
||||||
|
MaxTokens int `json:"maxTokens"`
|
||||||
|
ContextWindow int `json:"contextWindow"`
|
||||||
|
Verified bool `json:"verified"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (AgentAccount) TableName() string {
|
func (AgentAccount) TableName() string {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package provider
|
package provider
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
ID string
|
ID string
|
||||||
@@ -21,13 +23,13 @@ var catalog = map[string]Meta{
|
|||||||
"ollama": {
|
"ollama": {
|
||||||
Key: "ollama",
|
Key: "ollama",
|
||||||
DisplayName: "Ollama",
|
DisplayName: "Ollama",
|
||||||
Sort: 1,
|
Sort: 10,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
"deepseek": {
|
"deepseek": {
|
||||||
Key: "deepseek",
|
Key: "deepseek",
|
||||||
DisplayName: "DeepSeek",
|
DisplayName: "DeepSeek",
|
||||||
Sort: 2,
|
Sort: 20,
|
||||||
DefaultBaseURL: "https://api.deepseek.com/v1",
|
DefaultBaseURL: "https://api.deepseek.com/v1",
|
||||||
EnvKey: "DEEPSEEK_API_KEY",
|
EnvKey: "DEEPSEEK_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -37,10 +39,19 @@ var catalog = map[string]Meta{
|
|||||||
{ID: "deepseek/deepseek-r1:1.5b", Name: "DeepSeek R1 1.5B"},
|
{ID: "deepseek/deepseek-r1:1.5b", Name: "DeepSeek R1 1.5B"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"custom": {
|
||||||
|
Key: "custom",
|
||||||
|
DisplayName: "Custom",
|
||||||
|
Sort: 30,
|
||||||
|
DefaultBaseURL: "",
|
||||||
|
EnvKey: "CUSTOM_API_KEY",
|
||||||
|
Enabled: true,
|
||||||
|
Models: []Model{},
|
||||||
|
},
|
||||||
"openai": {
|
"openai": {
|
||||||
Key: "openai",
|
Key: "openai",
|
||||||
DisplayName: "OpenAI",
|
DisplayName: "OpenAI",
|
||||||
Sort: 3,
|
Sort: 40,
|
||||||
DefaultBaseURL: "https://api.openai.com/v1",
|
DefaultBaseURL: "https://api.openai.com/v1",
|
||||||
EnvKey: "OPENAI_API_KEY",
|
EnvKey: "OPENAI_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -56,7 +67,7 @@ var catalog = map[string]Meta{
|
|||||||
"anthropic": {
|
"anthropic": {
|
||||||
Key: "anthropic",
|
Key: "anthropic",
|
||||||
DisplayName: "Anthropic",
|
DisplayName: "Anthropic",
|
||||||
Sort: 4,
|
Sort: 50,
|
||||||
DefaultBaseURL: "https://api.anthropic.com",
|
DefaultBaseURL: "https://api.anthropic.com",
|
||||||
EnvKey: "ANTHROPIC_API_KEY",
|
EnvKey: "ANTHROPIC_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -71,7 +82,7 @@ var catalog = map[string]Meta{
|
|||||||
"gemini": {
|
"gemini": {
|
||||||
Key: "gemini",
|
Key: "gemini",
|
||||||
DisplayName: "Gemini",
|
DisplayName: "Gemini",
|
||||||
Sort: 5,
|
Sort: 60,
|
||||||
DefaultBaseURL: "https://generativelanguage.googleapis.com",
|
DefaultBaseURL: "https://generativelanguage.googleapis.com",
|
||||||
EnvKey: "GEMINI_API_KEY",
|
EnvKey: "GEMINI_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -87,7 +98,7 @@ var catalog = map[string]Meta{
|
|||||||
"minimax": {
|
"minimax": {
|
||||||
Key: "minimax",
|
Key: "minimax",
|
||||||
DisplayName: "MiniMax (CN)",
|
DisplayName: "MiniMax (CN)",
|
||||||
Sort: 6,
|
Sort: 70,
|
||||||
DefaultBaseURL: "https://api.minimaxi.com/anthropic",
|
DefaultBaseURL: "https://api.minimaxi.com/anthropic",
|
||||||
EnvKey: "MINIMAX_API_KEY",
|
EnvKey: "MINIMAX_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -99,7 +110,7 @@ var catalog = map[string]Meta{
|
|||||||
"moonshot": {
|
"moonshot": {
|
||||||
Key: "moonshot",
|
Key: "moonshot",
|
||||||
DisplayName: "Moonshot (Global)",
|
DisplayName: "Moonshot (Global)",
|
||||||
Sort: 7,
|
Sort: 80,
|
||||||
DefaultBaseURL: "https://api.moonshot.ai/v1",
|
DefaultBaseURL: "https://api.moonshot.ai/v1",
|
||||||
EnvKey: "MOONSHOT_API_KEY",
|
EnvKey: "MOONSHOT_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -112,7 +123,7 @@ var catalog = map[string]Meta{
|
|||||||
"kimi": {
|
"kimi": {
|
||||||
Key: "kimi",
|
Key: "kimi",
|
||||||
DisplayName: "Kimi (CN)",
|
DisplayName: "Kimi (CN)",
|
||||||
Sort: 8,
|
Sort: 90,
|
||||||
DefaultBaseURL: "https://api.moonshot.cn/v1",
|
DefaultBaseURL: "https://api.moonshot.cn/v1",
|
||||||
EnvKey: "KIMI_API_KEY",
|
EnvKey: "KIMI_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -125,7 +136,7 @@ var catalog = map[string]Meta{
|
|||||||
"kimi-coding": {
|
"kimi-coding": {
|
||||||
Key: "kimi-coding",
|
Key: "kimi-coding",
|
||||||
DisplayName: "Kimi Coding",
|
DisplayName: "Kimi Coding",
|
||||||
Sort: 9,
|
Sort: 100,
|
||||||
DefaultBaseURL: "https://api.moonshot.cn/anthropic/v1",
|
DefaultBaseURL: "https://api.moonshot.cn/anthropic/v1",
|
||||||
EnvKey: "KIMI_API_KEY",
|
EnvKey: "KIMI_API_KEY",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -136,7 +147,7 @@ var catalog = map[string]Meta{
|
|||||||
"qwen": {
|
"qwen": {
|
||||||
Key: "qwen",
|
Key: "qwen",
|
||||||
DisplayName: "Qwen",
|
DisplayName: "Qwen",
|
||||||
Sort: 10,
|
Sort: 110,
|
||||||
DefaultBaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
DefaultBaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
EnvKey: "QWEN_API_KEY",
|
EnvKey: "QWEN_API_KEY",
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
|
|||||||
+215
-50
@@ -81,6 +81,7 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) {
|
|||||||
if provider != "ollama" && strings.TrimSpace(account.APIKey) == "" {
|
if provider != "ollama" && strings.TrimSpace(account.APIKey) == "" {
|
||||||
return nil, buserr.New("ErrAgentApiKeyRequired")
|
return nil, buserr.New("ErrAgentApiKeyRequired")
|
||||||
}
|
}
|
||||||
|
apiType, maxTokens, contextWindow := resolveRuntimeParams(provider, account.APIType, account.MaxTokens, account.ContextWindow)
|
||||||
if err := checkPortExist(req.WebUIPort); err != nil {
|
if err := checkPortExist(req.WebUIPort); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -109,6 +110,9 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) {
|
|||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"PROVIDER": provider,
|
"PROVIDER": provider,
|
||||||
"MODEL": req.Model,
|
"MODEL": req.Model,
|
||||||
|
"API_TYPE": apiType,
|
||||||
|
"MAX_TOKENS": maxTokens,
|
||||||
|
"CONTEXT_WINDOW": contextWindow,
|
||||||
"BASE_URL": baseURL,
|
"BASE_URL": baseURL,
|
||||||
"API_KEY": account.APIKey,
|
"API_KEY": account.APIKey,
|
||||||
"OPENCLAW_GATEWAY_TOKEN": token,
|
"OPENCLAW_GATEWAY_TOKEN": token,
|
||||||
@@ -147,22 +151,25 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) {
|
|||||||
}
|
}
|
||||||
configPath := path.Join(appInstall.GetPath(), "data", "conf", "openclaw.json")
|
configPath := path.Join(appInstall.GetPath(), "data", "conf", "openclaw.json")
|
||||||
agent := &model.Agent{
|
agent := &model.Agent{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Provider: provider,
|
Provider: provider,
|
||||||
Model: req.Model,
|
Model: req.Model,
|
||||||
BaseURL: baseURL,
|
APIType: apiType,
|
||||||
APIKey: account.APIKey,
|
MaxTokens: maxTokens,
|
||||||
Token: token,
|
ContextWindow: contextWindow,
|
||||||
Status: appInstall.Status,
|
BaseURL: baseURL,
|
||||||
Message: appInstall.Message,
|
APIKey: account.APIKey,
|
||||||
AppInstallID: appInstall.ID,
|
Token: token,
|
||||||
AccountID: account.ID,
|
Status: appInstall.Status,
|
||||||
ConfigPath: configPath,
|
Message: appInstall.Message,
|
||||||
|
AppInstallID: appInstall.ID,
|
||||||
|
AccountID: account.ID,
|
||||||
|
ConfigPath: configPath,
|
||||||
}
|
}
|
||||||
if err := agentRepo.Create(agent); err != nil {
|
if err := agentRepo.Create(agent); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
go a.writeConfigWithRetry(appInstall, provider, req.Model, baseURL, req.APIKey, token, agent.ID)
|
go a.writeConfigWithRetry(appInstall, provider, req.Model, apiType, maxTokens, contextWindow, baseURL, account.APIKey, token, agent.ID)
|
||||||
|
|
||||||
item := buildAgentItem(agent, appInstall, nil)
|
item := buildAgentItem(agent, appInstall, nil)
|
||||||
return &item, nil
|
return &item, nil
|
||||||
@@ -287,6 +294,7 @@ func (a AgentService) UpdateModelConfig(req dto.AgentModelConfigUpdateReq) error
|
|||||||
if provider != "ollama" && strings.TrimSpace(account.APIKey) == "" {
|
if provider != "ollama" && strings.TrimSpace(account.APIKey) == "" {
|
||||||
return buserr.New("ErrAgentApiKeyRequired")
|
return buserr.New("ErrAgentApiKeyRequired")
|
||||||
}
|
}
|
||||||
|
apiType, maxTokens, contextWindow := resolveRuntimeParams(provider, account.APIType, account.MaxTokens, account.ContextWindow)
|
||||||
confDir := ""
|
confDir := ""
|
||||||
if agent.ConfigPath != "" {
|
if agent.ConfigPath != "" {
|
||||||
confDir = path.Dir(agent.ConfigPath)
|
confDir = path.Dir(agent.ConfigPath)
|
||||||
@@ -299,11 +307,14 @@ func (a AgentService) UpdateModelConfig(req dto.AgentModelConfigUpdateReq) error
|
|||||||
if confDir == "" {
|
if confDir == "" {
|
||||||
return buserr.New("ErrRecordNotFound")
|
return buserr.New("ErrRecordNotFound")
|
||||||
}
|
}
|
||||||
if err := writeOpenclawConfig(confDir, provider, modelName, baseURL, account.APIKey, agent.Token); err != nil {
|
if err := writeOpenclawConfig(confDir, provider, modelName, apiType, maxTokens, contextWindow, baseURL, account.APIKey, agent.Token); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
agent.Provider = provider
|
agent.Provider = provider
|
||||||
agent.Model = modelName
|
agent.Model = modelName
|
||||||
|
agent.APIType = apiType
|
||||||
|
agent.MaxTokens = maxTokens
|
||||||
|
agent.ContextWindow = contextWindow
|
||||||
agent.BaseURL = baseURL
|
agent.BaseURL = baseURL
|
||||||
agent.APIKey = account.APIKey
|
agent.APIKey = account.APIKey
|
||||||
agent.AccountID = account.ID
|
agent.AccountID = account.ID
|
||||||
@@ -338,7 +349,10 @@ func (a AgentService) CreateAccount(req dto.AgentAccountCreateReq) error {
|
|||||||
return buserr.New("ErrAgentApiKeyRequired")
|
return buserr.New("ErrAgentApiKeyRequired")
|
||||||
}
|
}
|
||||||
baseURL := strings.TrimSpace(req.BaseURL)
|
baseURL := strings.TrimSpace(req.BaseURL)
|
||||||
if baseURL == "" {
|
if provider == "custom" && baseURL == "" {
|
||||||
|
return buserr.New("ErrAgentBaseURLRequired")
|
||||||
|
}
|
||||||
|
if provider != "custom" && baseURL == "" {
|
||||||
if defaultURL, ok := providerDefaultBaseURL(provider); ok {
|
if defaultURL, ok := providerDefaultBaseURL(provider); ok {
|
||||||
baseURL = defaultURL
|
baseURL = defaultURL
|
||||||
}
|
}
|
||||||
@@ -349,16 +363,36 @@ func (a AgentService) CreateAccount(req dto.AgentAccountCreateReq) error {
|
|||||||
if exist, _ := agentAccountRepo.GetFirst(repo.WithByProvider(provider), repo.WithByName(req.Name)); exist != nil && exist.ID > 0 {
|
if exist, _ := agentAccountRepo.GetFirst(repo.WithByProvider(provider), repo.WithByName(req.Name)); exist != nil && exist.ID > 0 {
|
||||||
return buserr.New("ErrRecordExist")
|
return buserr.New("ErrRecordExist")
|
||||||
}
|
}
|
||||||
|
modelName := strings.TrimSpace(req.Model)
|
||||||
|
apiType := normalizeAPIType(req.APIType)
|
||||||
|
if provider == "custom" {
|
||||||
|
if modelName == "" {
|
||||||
|
return fmt.Errorf("model is required")
|
||||||
|
}
|
||||||
|
if !isSupportedAPIType(apiType) {
|
||||||
|
return fmt.Errorf("apiType is invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := a.VerifyAccount(dto.AgentAccountVerifyReq{Provider: provider, BaseURL: baseURL, APIKey: apiKey}); err != nil {
|
if err := a.VerifyAccount(dto.AgentAccountVerifyReq{Provider: provider, BaseURL: baseURL, APIKey: apiKey}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, maxTokens, contextWindow := resolveRuntimeParams(provider, apiType, req.MaxTokens, req.ContextWindow)
|
||||||
account := &model.AgentAccount{
|
account := &model.AgentAccount{
|
||||||
Provider: provider,
|
Provider: provider,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
APIKey: apiKey,
|
APIKey: apiKey,
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
Verified: true,
|
Model: "",
|
||||||
Remark: req.Remark,
|
APIType: apiType,
|
||||||
|
MaxTokens: 0,
|
||||||
|
ContextWindow: 0,
|
||||||
|
Verified: true,
|
||||||
|
Remark: req.Remark,
|
||||||
|
}
|
||||||
|
if provider == "custom" {
|
||||||
|
account.Model = normalizeCustomModel(modelName)
|
||||||
|
account.MaxTokens = maxTokens
|
||||||
|
account.ContextWindow = contextWindow
|
||||||
}
|
}
|
||||||
return agentAccountRepo.Create(account)
|
return agentAccountRepo.Create(account)
|
||||||
}
|
}
|
||||||
@@ -370,7 +404,10 @@ func (a AgentService) UpdateAccount(req dto.AgentAccountUpdateReq) error {
|
|||||||
}
|
}
|
||||||
provider := strings.ToLower(strings.TrimSpace(account.Provider))
|
provider := strings.ToLower(strings.TrimSpace(account.Provider))
|
||||||
baseURL := strings.TrimSpace(req.BaseURL)
|
baseURL := strings.TrimSpace(req.BaseURL)
|
||||||
if baseURL == "" {
|
if provider == "custom" && baseURL == "" {
|
||||||
|
return buserr.New("ErrAgentBaseURLRequired")
|
||||||
|
}
|
||||||
|
if provider != "custom" && baseURL == "" {
|
||||||
if defaultURL, ok := providerDefaultBaseURL(provider); ok {
|
if defaultURL, ok := providerDefaultBaseURL(provider); ok {
|
||||||
baseURL = defaultURL
|
baseURL = defaultURL
|
||||||
}
|
}
|
||||||
@@ -378,12 +415,31 @@ func (a AgentService) UpdateAccount(req dto.AgentAccountUpdateReq) error {
|
|||||||
if provider == "ollama" && baseURL == "" {
|
if provider == "ollama" && baseURL == "" {
|
||||||
return buserr.New("ErrAgentBaseURLRequired")
|
return buserr.New("ErrAgentBaseURLRequired")
|
||||||
}
|
}
|
||||||
|
apiType := normalizeAPIType(req.APIType)
|
||||||
|
if provider == "custom" && strings.TrimSpace(req.Model) == "" {
|
||||||
|
return fmt.Errorf("model is required")
|
||||||
|
}
|
||||||
|
if provider == "custom" && !isSupportedAPIType(apiType) {
|
||||||
|
return fmt.Errorf("apiType is invalid")
|
||||||
|
}
|
||||||
|
if provider != "custom" {
|
||||||
|
apiType = normalizeAPIType(account.APIType)
|
||||||
|
}
|
||||||
|
_, maxTokens, contextWindow := resolveRuntimeParams(provider, apiType, req.MaxTokens, req.ContextWindow)
|
||||||
if err := a.VerifyAccount(dto.AgentAccountVerifyReq{Provider: provider, BaseURL: baseURL, APIKey: req.APIKey}); err != nil {
|
if err := a.VerifyAccount(dto.AgentAccountVerifyReq{Provider: provider, BaseURL: baseURL, APIKey: req.APIKey}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
account.Name = req.Name
|
account.Name = req.Name
|
||||||
account.APIKey = req.APIKey
|
account.APIKey = req.APIKey
|
||||||
account.BaseURL = baseURL
|
account.BaseURL = baseURL
|
||||||
|
if provider == "custom" {
|
||||||
|
account.Model = normalizeCustomModel(req.Model)
|
||||||
|
}
|
||||||
|
account.APIType = apiType
|
||||||
|
if provider == "custom" {
|
||||||
|
account.MaxTokens = maxTokens
|
||||||
|
account.ContextWindow = contextWindow
|
||||||
|
}
|
||||||
account.Remark = req.Remark
|
account.Remark = req.Remark
|
||||||
account.Verified = true
|
account.Verified = true
|
||||||
if err := agentAccountRepo.Save(account); err != nil {
|
if err := agentAccountRepo.Save(account); err != nil {
|
||||||
@@ -412,15 +468,19 @@ func (a AgentService) PageAccounts(req dto.AgentAccountSearch) (int64, []dto.Age
|
|||||||
items := make([]dto.AgentAccountInfo, 0, len(list))
|
items := make([]dto.AgentAccountInfo, 0, len(list))
|
||||||
for _, item := range list {
|
for _, item := range list {
|
||||||
items = append(items, dto.AgentAccountInfo{
|
items = append(items, dto.AgentAccountInfo{
|
||||||
ID: item.ID,
|
ID: item.ID,
|
||||||
Provider: item.Provider,
|
Provider: item.Provider,
|
||||||
ProviderName: providerDisplayName(item.Provider),
|
ProviderName: providerDisplayName(item.Provider),
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
APIKey: item.APIKey,
|
APIKey: item.APIKey,
|
||||||
BaseURL: item.BaseURL,
|
BaseURL: item.BaseURL,
|
||||||
Verified: item.Verified,
|
Model: item.Model,
|
||||||
Remark: item.Remark,
|
APIType: item.APIType,
|
||||||
CreatedAt: item.CreatedAt,
|
MaxTokens: item.MaxTokens,
|
||||||
|
ContextWindow: item.ContextWindow,
|
||||||
|
Verified: item.Verified,
|
||||||
|
Remark: item.Remark,
|
||||||
|
CreatedAt: item.CreatedAt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return count, items, nil
|
return count, items, nil
|
||||||
@@ -447,6 +507,9 @@ func (a AgentService) VerifyAccount(req dto.AgentAccountVerifyReq) error {
|
|||||||
if provider == "ollama" {
|
if provider == "ollama" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if provider == "custom" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return verifyProvider(provider, baseURL, apiKey)
|
return verifyProvider(provider, baseURL, apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,12 +705,16 @@ func (a AgentService) syncAgentsByAccount(account *model.AgentAccount) error {
|
|||||||
if confDir == "" {
|
if confDir == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := writeOpenclawConfig(confDir, account.Provider, agent.Model, baseURL, account.APIKey, agent.Token); err != nil {
|
apiType, maxTokens, contextWindow := resolveRuntimeParams(account.Provider, account.APIType, account.MaxTokens, account.ContextWindow)
|
||||||
|
if err := writeOpenclawConfig(confDir, account.Provider, agent.Model, apiType, maxTokens, contextWindow, baseURL, account.APIKey, agent.Token); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
agent.BaseURL = baseURL
|
agent.BaseURL = baseURL
|
||||||
agent.APIKey = account.APIKey
|
agent.APIKey = account.APIKey
|
||||||
agent.Provider = account.Provider
|
agent.Provider = account.Provider
|
||||||
|
agent.APIType = apiType
|
||||||
|
agent.MaxTokens = maxTokens
|
||||||
|
agent.ContextWindow = contextWindow
|
||||||
_ = agentRepo.Save(&agent)
|
_ = agentRepo.Save(&agent)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -713,20 +780,23 @@ func verifyMinimax(baseURL, apiKey string) error {
|
|||||||
|
|
||||||
func buildAgentItem(agent *model.Agent, appInstall *model.AppInstall, envMap map[string]interface{}) dto.AgentItem {
|
func buildAgentItem(agent *model.Agent, appInstall *model.AppInstall, envMap map[string]interface{}) dto.AgentItem {
|
||||||
item := dto.AgentItem{
|
item := dto.AgentItem{
|
||||||
ID: agent.ID,
|
ID: agent.ID,
|
||||||
Name: agent.Name,
|
Name: agent.Name,
|
||||||
Provider: agent.Provider,
|
Provider: agent.Provider,
|
||||||
ProviderName: providerDisplayName(agent.Provider),
|
ProviderName: providerDisplayName(agent.Provider),
|
||||||
Model: agent.Model,
|
Model: agent.Model,
|
||||||
BaseURL: agent.BaseURL,
|
APIType: agent.APIType,
|
||||||
APIKey: maskKey(agent.APIKey),
|
MaxTokens: agent.MaxTokens,
|
||||||
Token: agent.Token,
|
ContextWindow: agent.ContextWindow,
|
||||||
Status: agent.Status,
|
BaseURL: agent.BaseURL,
|
||||||
Message: agent.Message,
|
APIKey: maskKey(agent.APIKey),
|
||||||
AppInstallID: agent.AppInstallID,
|
Token: agent.Token,
|
||||||
AccountID: agent.AccountID,
|
Status: agent.Status,
|
||||||
ConfigPath: agent.ConfigPath,
|
Message: agent.Message,
|
||||||
CreatedAt: agent.CreatedAt,
|
AppInstallID: agent.AppInstallID,
|
||||||
|
AccountID: agent.AccountID,
|
||||||
|
ConfigPath: agent.ConfigPath,
|
||||||
|
CreatedAt: agent.CreatedAt,
|
||||||
}
|
}
|
||||||
if appInstall != nil && appInstall.ID > 0 {
|
if appInstall != nil && appInstall.ID > 0 {
|
||||||
item.Container = appInstall.ContainerName
|
item.Container = appInstall.ContainerName
|
||||||
@@ -792,7 +862,7 @@ func (a AgentService) waitAndDeleteAgent(agentID uint, appInstallID uint) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AgentService) writeConfigWithRetry(appInstall *model.AppInstall, provider, modelName, baseURL, apiKey, token string, agentID uint) {
|
func (a AgentService) writeConfigWithRetry(appInstall *model.AppInstall, provider, modelName, apiType string, maxTokens, contextWindow int, baseURL, apiKey, token string, agentID uint) {
|
||||||
if appInstall == nil {
|
if appInstall == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -805,7 +875,7 @@ func (a AgentService) writeConfigWithRetry(appInstall *model.AppInstall, provide
|
|||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
confDir := path.Join(appInstall.GetPath(), "data", "conf")
|
confDir := path.Join(appInstall.GetPath(), "data", "conf")
|
||||||
if err := writeOpenclawConfig(confDir, provider, modelName, baseURL, apiKey, token); err != nil {
|
if err := writeOpenclawConfig(confDir, provider, modelName, apiType, maxTokens, contextWindow, baseURL, apiKey, token); err != nil {
|
||||||
global.LOG.Errorf("write openclaw config failed: %v", err)
|
global.LOG.Errorf("write openclaw config failed: %v", err)
|
||||||
agent, errGet := agentRepo.GetFirst(repo.WithByID(agentID))
|
agent, errGet := agentRepo.GetFirst(repo.WithByID(agentID))
|
||||||
if errGet == nil && agent != nil {
|
if errGet == nil && agent != nil {
|
||||||
@@ -848,7 +918,8 @@ type gatewayConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type gatewayControlUi struct {
|
type gatewayControlUi struct {
|
||||||
AllowInsecureAuth bool `json:"allowInsecureAuth"`
|
DangerouslyDisableDeviceAuth bool `json:"dangerouslyDisableDeviceAuth"`
|
||||||
|
DangerouslyAllowHostHeaderOriginFallback bool `json:"dangerouslyAllowHostHeaderOriginFallback"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type gatewayAuth struct {
|
type gatewayAuth struct {
|
||||||
@@ -897,7 +968,7 @@ type modelCost struct {
|
|||||||
CacheWrite float64 `json:"cacheWrite"`
|
CacheWrite float64 `json:"cacheWrite"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeOpenclawConfig(confDir, provider, modelName, baseURL, apiKey, token string) error {
|
func writeOpenclawConfig(confDir, provider, modelName, apiType string, maxTokens, contextWindow int, baseURL, apiKey, token string) error {
|
||||||
if strings.TrimSpace(confDir) == "" {
|
if strings.TrimSpace(confDir) == "" {
|
||||||
return fmt.Errorf("config dir is required")
|
return fmt.Errorf("config dir is required")
|
||||||
}
|
}
|
||||||
@@ -924,7 +995,8 @@ func writeOpenclawConfig(confDir, provider, modelName, baseURL, apiKey, token st
|
|||||||
Token: token,
|
Token: token,
|
||||||
},
|
},
|
||||||
ControlUi: gatewayControlUi{
|
ControlUi: gatewayControlUi{
|
||||||
AllowInsecureAuth: true,
|
DangerouslyDisableDeviceAuth: true,
|
||||||
|
DangerouslyAllowHostHeaderOriginFallback: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Agents: agentsConfig{
|
Agents: agentsConfig{
|
||||||
@@ -1038,6 +1110,43 @@ func writeOpenclawConfig(confDir, provider, modelName, baseURL, apiKey, token st
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
} else if provider == "custom" {
|
||||||
|
primary := modelName
|
||||||
|
if !strings.Contains(primary, "/") {
|
||||||
|
primary = "custom/" + strings.TrimSpace(primary)
|
||||||
|
}
|
||||||
|
cfg.Agents.Defaults.Model.Primary = primary
|
||||||
|
base := strings.TrimSpace(baseURL)
|
||||||
|
plainKey := strings.TrimSpace(apiKey)
|
||||||
|
if !strings.Contains(modelName, "/") {
|
||||||
|
modelName = primary
|
||||||
|
}
|
||||||
|
customModelID := modelID
|
||||||
|
if parts := strings.SplitN(modelName, "/", 2); len(parts) == 2 {
|
||||||
|
customModelID = parts[1]
|
||||||
|
}
|
||||||
|
useAPIType, useMaxTokens, useContextWindow := resolveRuntimeParams(provider, apiType, maxTokens, contextWindow)
|
||||||
|
cfg.Models = &modelsConfig{
|
||||||
|
Mode: "merge",
|
||||||
|
Providers: map[string]modelProvider{
|
||||||
|
"custom": {
|
||||||
|
ApiKey: plainKey,
|
||||||
|
BaseUrl: base,
|
||||||
|
Api: useAPIType,
|
||||||
|
Models: []modelEntry{
|
||||||
|
{
|
||||||
|
ID: customModelID,
|
||||||
|
Name: customModelID,
|
||||||
|
Reasoning: strings.Contains(strings.ToLower(customModelID), "reason") || strings.Contains(strings.ToLower(customModelID), "thinking"),
|
||||||
|
Input: []string{"text"},
|
||||||
|
ContextWindow: useContextWindow,
|
||||||
|
MaxTokens: useMaxTokens,
|
||||||
|
Cost: modelCost{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
} else if provider == "ollama" {
|
} else if provider == "ollama" {
|
||||||
cfg.Agents.Defaults.Model.Primary = modelName
|
cfg.Agents.Defaults.Model.Primary = modelName
|
||||||
cfg.Models = &modelsConfig{
|
cfg.Models = &modelsConfig{
|
||||||
@@ -1275,6 +1384,62 @@ func toInt(value interface{}) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func normalizeCustomModel(modelName string) string {
|
||||||
|
trim := strings.TrimSpace(modelName)
|
||||||
|
if parts := strings.SplitN(trim, "/", 2); len(parts) == 2 {
|
||||||
|
if strings.EqualFold(parts[0], "custom") {
|
||||||
|
return strings.TrimSpace(parts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trim
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeAPIType(apiType string) string {
|
||||||
|
trim := strings.ToLower(strings.TrimSpace(apiType))
|
||||||
|
if trim == "" {
|
||||||
|
return "openai-completions"
|
||||||
|
}
|
||||||
|
return trim
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSupportedAPIType(apiType string) bool {
|
||||||
|
switch normalizeAPIType(apiType) {
|
||||||
|
case "openai-completions", "openai-responses":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveRuntimeParams(provider, apiType string, maxTokens, contextWindow int) (string, int, int) {
|
||||||
|
resolvedAPI := normalizeAPIType(apiType)
|
||||||
|
resolvedMaxTokens := maxTokens
|
||||||
|
resolvedContextWindow := contextWindow
|
||||||
|
if resolvedMaxTokens <= 0 {
|
||||||
|
switch provider {
|
||||||
|
case "deepseek":
|
||||||
|
resolvedMaxTokens = 8192
|
||||||
|
case "minimax", "kimi-coding", "custom":
|
||||||
|
resolvedMaxTokens = 8192
|
||||||
|
default:
|
||||||
|
resolvedMaxTokens = 8192
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resolvedContextWindow <= 0 {
|
||||||
|
switch provider {
|
||||||
|
case "deepseek":
|
||||||
|
resolvedContextWindow = 128000
|
||||||
|
case "minimax", "kimi-coding":
|
||||||
|
resolvedContextWindow = 200000
|
||||||
|
case "custom":
|
||||||
|
resolvedContextWindow = 128000
|
||||||
|
default:
|
||||||
|
resolvedContextWindow = 256000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resolvedAPI, resolvedMaxTokens, resolvedContextWindow
|
||||||
|
}
|
||||||
|
|
||||||
func generateToken() string {
|
func generateToken() string {
|
||||||
bytes := make([]byte, 24)
|
bytes := make([]byte, 24)
|
||||||
if _, err := rand.Read(bytes); err != nil {
|
if _, err := rand.Read(bytes); err != nil {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ func InitAgentDB() {
|
|||||||
migrations.AddWebsiteAcmeAccountColumn,
|
migrations.AddWebsiteAcmeAccountColumn,
|
||||||
migrations.AddAgentTables,
|
migrations.AddAgentTables,
|
||||||
migrations.MigrateOpenclawAgents,
|
migrations.MigrateOpenclawAgents,
|
||||||
|
migrations.AddAgentCustomModelFields,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
|||||||
@@ -941,3 +941,19 @@ var MigrateOpenclawAgents = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var AddAgentCustomModelFields = &gormigrate.Migration{
|
||||||
|
ID: "20260224-add-agent-custom-model-fields",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.Agent{}, &model.AgentAccount{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Model(&model.AgentAccount{}).Where("api_type = '' OR api_type IS NULL").Update("api_type", "openai-completions").Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Model(&model.Agent{}).Where("api_type = '' OR api_type IS NULL").Update("api_type", "openai-completions").Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@@ -243,6 +243,9 @@ export namespace AI {
|
|||||||
bridgePort: number;
|
bridgePort: number;
|
||||||
provider: string;
|
provider: string;
|
||||||
model: string;
|
model: string;
|
||||||
|
apiType: string;
|
||||||
|
maxTokens: number;
|
||||||
|
contextWindow: number;
|
||||||
accountId: number;
|
accountId: number;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
@@ -267,6 +270,9 @@ export namespace AI {
|
|||||||
provider: string;
|
provider: string;
|
||||||
providerName: string;
|
providerName: string;
|
||||||
model: string;
|
model: string;
|
||||||
|
apiType: string;
|
||||||
|
maxTokens: number;
|
||||||
|
contextWindow: number;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
token: string;
|
token: string;
|
||||||
@@ -317,6 +323,10 @@ export namespace AI {
|
|||||||
name: string;
|
name: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
|
model: string;
|
||||||
|
apiType: string;
|
||||||
|
maxTokens: number;
|
||||||
|
contextWindow: number;
|
||||||
remark: string;
|
remark: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,6 +335,10 @@ export namespace AI {
|
|||||||
name: string;
|
name: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
|
model: string;
|
||||||
|
apiType: string;
|
||||||
|
maxTokens: number;
|
||||||
|
contextWindow: number;
|
||||||
remark: string;
|
remark: string;
|
||||||
syncAgents: boolean;
|
syncAgents: boolean;
|
||||||
}
|
}
|
||||||
@@ -343,6 +357,10 @@ export namespace AI {
|
|||||||
name: string;
|
name: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
model: string;
|
||||||
|
apiType: string;
|
||||||
|
maxTokens: number;
|
||||||
|
contextWindow: number;
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
remark: string;
|
remark: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|||||||
@@ -713,6 +713,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'For custom model accounts, model names must start with custom/.',
|
||||||
|
customProviderHelper: 'Custom model providers do not validate whether the account is available.',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'Models',
|
model: 'Models',
|
||||||
|
|||||||
@@ -709,6 +709,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'En la cuenta de modelo personalizada, el nombre del modelo debe empezar por custom/',
|
||||||
|
customProviderHelper: 'En el proveedor de modelo personalizado no se valida si la cuenta está disponible',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'Modelo',
|
model: 'Modelo',
|
||||||
|
|||||||
@@ -698,6 +698,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'カスタムモデルアカウントでは、モデル名は必ず custom/ で始めてください',
|
||||||
|
customProviderHelper: 'カスタムモデルプロバイダーでは、アカウントの有効性を検証しません',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'モデル',
|
model: 'モデル',
|
||||||
|
|||||||
@@ -695,6 +695,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: '사용자 정의 모델 계정의 모델명은 반드시 custom/ 로 시작해야 합니다',
|
||||||
|
customProviderHelper: '사용자 정의 모델 공급자는 계정 사용 가능 여부를 검증하지 않습니다',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: '모델',
|
model: '모델',
|
||||||
|
|||||||
@@ -710,6 +710,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'Akaun model tersuai, nama model mesti bermula dengan custom/',
|
||||||
|
customProviderHelper: 'Penyedia model tersuai tidak mengesahkan sama ada akaun boleh digunakan',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'Model',
|
model: 'Model',
|
||||||
|
|||||||
@@ -707,6 +707,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'Conta de modelo personalizada: o nome do modelo deve começar com custom/',
|
||||||
|
customProviderHelper: 'Provedores de modelo personalizados não validam se a conta está disponível',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'Modelo',
|
model: 'Modelo',
|
||||||
|
|||||||
@@ -703,6 +703,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'Для пользовательской учетной записи модели имя модели должно начинаться с custom/',
|
||||||
|
customProviderHelper: 'Для пользовательского провайдера модели доступность учетной записи не проверяется',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'Модель',
|
model: 'Модель',
|
||||||
|
|||||||
@@ -717,6 +717,8 @@ const message = {
|
|||||||
feishuSaveSuccess: 'Saved successfully',
|
feishuSaveSuccess: 'Saved successfully',
|
||||||
pairingCodeRequired: 'Please enter pairing code',
|
pairingCodeRequired: 'Please enter pairing code',
|
||||||
pairingApproveSuccess: 'Pairing approved successfully',
|
pairingApproveSuccess: 'Pairing approved successfully',
|
||||||
|
customModelHelper: 'Özel model hesabında model adı custom/ ile başlamalıdır',
|
||||||
|
customProviderHelper: 'Özel model sağlayıcısında hesabın kullanılabilirliği doğrulanmaz',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: 'Model',
|
model: 'Model',
|
||||||
|
|||||||
@@ -685,6 +685,8 @@ const message = {
|
|||||||
feishuSaveSuccess: '保存成功',
|
feishuSaveSuccess: '保存成功',
|
||||||
pairingCodeRequired: '請輸入配對碼',
|
pairingCodeRequired: '請輸入配對碼',
|
||||||
pairingApproveSuccess: '配對成功',
|
pairingApproveSuccess: '配對成功',
|
||||||
|
customModelHelper: '自訂模型帳號,模型需固定以 custom/ 開頭',
|
||||||
|
customProviderHelper: '自訂模型供應商不驗證帳號是否可用',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: '模型',
|
model: '模型',
|
||||||
|
|||||||
@@ -687,6 +687,8 @@ const message = {
|
|||||||
feishuSaveSuccess: '保存成功',
|
feishuSaveSuccess: '保存成功',
|
||||||
pairingCodeRequired: '请输入配对码',
|
pairingCodeRequired: '请输入配对码',
|
||||||
pairingApproveSuccess: '配对成功',
|
pairingApproveSuccess: '配对成功',
|
||||||
|
customModelHelper: '自定义模型账号,模型固定以 custom/ 开头',
|
||||||
|
customProviderHelper: '自定义模型供应商不验证账号是否可用',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
model: '模型',
|
model: '模型',
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import i18n from '@/lang';
|
||||||
|
|
||||||
|
export const getAgentProviderDisplayName = (provider: string, displayName?: string): string => {
|
||||||
|
if (provider === 'custom' || displayName === 'Custom') {
|
||||||
|
return i18n.global.t('container.custom');
|
||||||
|
}
|
||||||
|
return displayName || provider;
|
||||||
|
};
|
||||||
@@ -44,9 +44,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('aiTools.model.model')" prop="model">
|
<el-form-item :label="$t('aiTools.model.model')" prop="model">
|
||||||
<el-input v-if="manualModel" v-model="form.model" />
|
<el-input v-if="manualModel" v-model="form.model" />
|
||||||
|
|
||||||
<el-select v-else v-model="form.model" filterable @change="handleModelChange">
|
<el-select v-else v-model="form.model" filterable @change="handleModelChange">
|
||||||
<el-option v-for="item in filteredModels" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in filteredModels" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<span class="input-help" v-if="form.provider == 'custom'">
|
||||||
|
{{ $t('aiTools.agents.customModelHelper') }}
|
||||||
|
</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('aiTools.agents.account')" prop="accountId">
|
<el-form-item :label="$t('aiTools.agents.account')" prop="accountId">
|
||||||
<el-select v-model="form.accountId" @change="handleAccountChange">
|
<el-select v-model="form.accountId" @change="handleAccountChange">
|
||||||
@@ -95,6 +99,7 @@ import { createAgent, getAgentProviders, pageAgentAccounts } from '@/api/modules
|
|||||||
import { AI } from '@/api/interface/ai';
|
import { AI } from '@/api/interface/ai';
|
||||||
import { getAppByKey, getAppDetail } from '@/api/modules/app';
|
import { getAppByKey, getAppDetail } from '@/api/modules/app';
|
||||||
import { getRandomStr, newUUID } from '@/utils/util';
|
import { getRandomStr, newUUID } from '@/utils/util';
|
||||||
|
import { getAgentProviderDisplayName } from '@/utils/agent';
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import AdvancedSetting from '@/components/advanced-setting/index.vue';
|
import AdvancedSetting from '@/components/advanced-setting/index.vue';
|
||||||
import AccountAddDialog from '@/views/ai/agents/model/add/index.vue';
|
import AccountAddDialog from '@/views/ai/agents/model/add/index.vue';
|
||||||
@@ -120,6 +125,9 @@ const form = reactive({
|
|||||||
provider: 'deepseek',
|
provider: 'deepseek',
|
||||||
accountId: undefined as unknown as number,
|
accountId: undefined as unknown as number,
|
||||||
model: '',
|
model: '',
|
||||||
|
apiType: 'openai-completions',
|
||||||
|
maxTokens: 8192,
|
||||||
|
contextWindow: 128000,
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
baseURL: '',
|
baseURL: '',
|
||||||
token: '',
|
token: '',
|
||||||
@@ -175,7 +183,7 @@ const loadProviders = async () => {
|
|||||||
const data = res.data || [];
|
const data = res.data || [];
|
||||||
providerOptions.value = data.map((item) => ({
|
providerOptions.value = data.map((item) => ({
|
||||||
value: item.provider,
|
value: item.provider,
|
||||||
label: item.displayName || item.provider,
|
label: getAgentProviderDisplayName(item.provider, item.displayName),
|
||||||
}));
|
}));
|
||||||
providerModels.value = data.reduce((acc, item) => {
|
providerModels.value = data.reduce((acc, item) => {
|
||||||
acc[item.provider] = item.models || [];
|
acc[item.provider] = item.models || [];
|
||||||
@@ -246,6 +254,12 @@ const handleAccountChange = () => {
|
|||||||
if (selected) {
|
if (selected) {
|
||||||
form.baseURL = selected.baseUrl || '';
|
form.baseURL = selected.baseUrl || '';
|
||||||
form.apiKey = selected.apiKey || '';
|
form.apiKey = selected.apiKey || '';
|
||||||
|
form.apiType = selected.apiType || 'openai-completions';
|
||||||
|
form.maxTokens = selected.maxTokens || 8192;
|
||||||
|
form.contextWindow = selected.contextWindow || 128000;
|
||||||
|
if (selected.provider === 'custom' && selected.model && !manualModel.value) {
|
||||||
|
form.model = `custom/${selected.model}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setDefaultModel();
|
setDefaultModel();
|
||||||
};
|
};
|
||||||
@@ -257,6 +271,13 @@ const setDefaultModel = () => {
|
|||||||
const models = filteredModels.value;
|
const models = filteredModels.value;
|
||||||
if (models.length > 0 && !form.model) {
|
if (models.length > 0 && !form.model) {
|
||||||
form.model = models[0].id;
|
form.model = models[0].id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (form.provider === 'custom') {
|
||||||
|
const selected = accountOptions.value.find((item) => item.id === form.accountId);
|
||||||
|
if (selected?.model && !form.model) {
|
||||||
|
form.model = `custom/${selected.model}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -276,6 +297,9 @@ const submit = async () => {
|
|||||||
bridgePort: form.bridgePort,
|
bridgePort: form.bridgePort,
|
||||||
provider: form.provider,
|
provider: form.provider,
|
||||||
model: form.model,
|
model: form.model,
|
||||||
|
apiType: form.apiType,
|
||||||
|
maxTokens: form.maxTokens,
|
||||||
|
contextWindow: form.contextWindow,
|
||||||
accountId: form.accountId,
|
accountId: form.accountId,
|
||||||
apiKey: form.apiKey,
|
apiKey: form.apiKey,
|
||||||
baseURL: form.baseURL,
|
baseURL: form.baseURL,
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
<el-select v-else v-model="form.model" filterable>
|
<el-select v-else v-model="form.model" filterable>
|
||||||
<el-option v-for="item in modelOptions" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in modelOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<span class="input-help" v-if="provdier == 'custom'">
|
||||||
|
{{ $t('aiTools.agents.customModelHelper') }}
|
||||||
|
</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" :loading="saving" @click="saveModel">
|
<el-button type="primary" :loading="saving" @click="saveModel">
|
||||||
@@ -44,6 +47,7 @@ const agentId = ref(0);
|
|||||||
const providerModels = ref<Record<string, AI.ProviderModelInfo[]>>({});
|
const providerModels = ref<Record<string, AI.ProviderModelInfo[]>>({});
|
||||||
const accountOptions = ref<AI.AgentAccountItem[]>([]);
|
const accountOptions = ref<AI.AgentAccountItem[]>([]);
|
||||||
const modelOptions = ref<AI.ProviderModelInfo[]>([]);
|
const modelOptions = ref<AI.ProviderModelInfo[]>([]);
|
||||||
|
const provdier = ref('');
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
accountId: undefined as unknown as number,
|
accountId: undefined as unknown as number,
|
||||||
@@ -89,6 +93,13 @@ const handleAccountChange = () => {
|
|||||||
form.model = '';
|
form.model = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
provdier.value = selected.provider;
|
||||||
|
if (selected.provider === 'custom') {
|
||||||
|
form.manualModel = true;
|
||||||
|
form.model = selected.model ? `custom/${selected.model}` : form.model;
|
||||||
|
modelOptions.value = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
setModelsByProvider(selected.provider);
|
setModelsByProvider(selected.provider);
|
||||||
if (!form.manualModel && (!form.model || !form.model.startsWith(`${selected.provider}/`))) {
|
if (!form.manualModel && (!form.model || !form.model.startsWith(`${selected.provider}/`))) {
|
||||||
form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : '';
|
form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : '';
|
||||||
@@ -96,10 +107,14 @@ const handleAccountChange = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleManualModelChange = (val: unknown) => {
|
const handleManualModelChange = (val: unknown) => {
|
||||||
|
const selected = accountOptions.value.find((item) => item.id === form.accountId);
|
||||||
|
if (selected?.provider === 'custom' && !Boolean(val)) {
|
||||||
|
form.manualModel = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (Boolean(val)) {
|
if (Boolean(val)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selected = accountOptions.value.find((item) => item.id === form.accountId);
|
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
form.model = '';
|
form.model = '';
|
||||||
return;
|
return;
|
||||||
@@ -126,12 +141,15 @@ const load = async (agent: AI.AgentItem) => {
|
|||||||
form.accountId = currentAccount.id;
|
form.accountId = currentAccount.id;
|
||||||
setModelsByProvider(currentAccount.provider);
|
setModelsByProvider(currentAccount.provider);
|
||||||
const inProviderModels = modelOptions.value.some((item) => item.id === agent.model);
|
const inProviderModels = modelOptions.value.some((item) => item.id === agent.model);
|
||||||
form.manualModel = !inProviderModels;
|
form.manualModel = currentAccount.provider === 'custom' || !inProviderModels;
|
||||||
if (agent.model && (form.manualModel || agent.model.startsWith(`${currentAccount.provider}/`))) {
|
if (agent.model && (form.manualModel || agent.model.startsWith(`${currentAccount.provider}/`))) {
|
||||||
form.model = agent.model;
|
form.model = agent.model;
|
||||||
} else {
|
} else {
|
||||||
form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : '';
|
form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : '';
|
||||||
}
|
}
|
||||||
|
if (currentAccount.provider === 'custom' && currentAccount.model && !form.model) {
|
||||||
|
form.model = `custom/${currentAccount.model}`;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
min-width="120"
|
min-width="120"
|
||||||
>
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.providerName || row.provider }}
|
<span>{{ getAgentProviderDisplayName(row.provider, row.providerName) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<span>{{ row.model }}</span>
|
<span>{{ row.model }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,6 +115,7 @@ import TerminalDialog from '@/views/container/container/terminal/index.vue';
|
|||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import PortJumpDialog from '@/components/port-jump/index.vue';
|
import PortJumpDialog from '@/components/port-jump/index.vue';
|
||||||
import DockerStatus from '@/views/container/docker-status/index.vue';
|
import DockerStatus from '@/views/container/docker-status/index.vue';
|
||||||
|
import { getAgentProviderDisplayName } from '@/utils/agent';
|
||||||
|
|
||||||
const items = ref<AI.AgentItem[]>([]);
|
const items = ref<AI.AgentItem[]>([]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|||||||
@@ -16,9 +16,25 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('aiTools.agents.apiKey')" prop="apiKey">
|
<el-form-item :label="$t('aiTools.agents.apiKey')" prop="apiKey">
|
||||||
<el-input v-model="form.apiKey" type="password" show-password />
|
<el-input v-model="form.apiKey" type="password" show-password />
|
||||||
|
<span class="input-help">{{ $t('aiTools.agents.customProviderHelper') }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('aiTools.agents.baseUrl')" prop="baseURL">
|
<el-form-item :label="$t('aiTools.agents.baseUrl')" prop="baseURL">
|
||||||
<el-input v-model="form.baseURL" :disabled="form.provider !== 'ollama'" />
|
<el-input v-model="form.baseURL" :disabled="form.provider !== 'ollama' && form.provider !== 'custom'" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('aiTools.model.model')" prop="model" v-if="form.provider === 'custom'">
|
||||||
|
<el-input v-model="form.model" placeholder="gpt-4o-mini" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="'API ' + $t('commons.table.type')" prop="apiType" v-if="form.provider === 'custom'">
|
||||||
|
<el-select v-model="form.apiType">
|
||||||
|
<el-option label="openai-completions" value="openai-completions" />
|
||||||
|
<el-option label="openai-responses" value="openai-responses" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="Max Tokens" prop="maxTokens" v-if="form.provider === 'custom'">
|
||||||
|
<el-input-number v-model="form.maxTokens" :min="1" :max="2000000" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="Context Window" prop="contextWindow" v-if="form.provider === 'custom'">
|
||||||
|
<el-input-number v-model="form.contextWindow" :min="1" :max="2000000" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('website.remark')" prop="remark">
|
<el-form-item :label="$t('website.remark')" prop="remark">
|
||||||
<el-input v-model="form.remark" />
|
<el-input v-model="form.remark" />
|
||||||
@@ -45,6 +61,7 @@ import { FormInstance } from 'element-plus';
|
|||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import { createAgentAccount, getAgentProviders, updateAgentAccount } from '@/api/modules/ai';
|
import { createAgentAccount, getAgentProviders, updateAgentAccount } from '@/api/modules/ai';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
|
import { getAgentProviderDisplayName } from '@/utils/agent';
|
||||||
|
|
||||||
const emit = defineEmits(['search']);
|
const emit = defineEmits(['search']);
|
||||||
|
|
||||||
@@ -59,6 +76,10 @@ const form = reactive({
|
|||||||
provider: '',
|
provider: '',
|
||||||
name: '',
|
name: '',
|
||||||
baseURL: '',
|
baseURL: '',
|
||||||
|
model: '',
|
||||||
|
apiType: 'openai-completions',
|
||||||
|
maxTokens: 8192,
|
||||||
|
contextWindow: 128000,
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
syncAgents: false,
|
syncAgents: false,
|
||||||
@@ -73,6 +94,8 @@ const rules = reactive({
|
|||||||
name: [Rules.requiredInput],
|
name: [Rules.requiredInput],
|
||||||
apiKey: [Rules.requiredInput],
|
apiKey: [Rules.requiredInput],
|
||||||
baseURL: [Rules.requiredInput],
|
baseURL: [Rules.requiredInput],
|
||||||
|
model: [Rules.requiredInput],
|
||||||
|
apiType: [Rules.requiredSelect],
|
||||||
});
|
});
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
@@ -88,6 +111,10 @@ const submit = async () => {
|
|||||||
name: form.name,
|
name: form.name,
|
||||||
baseURL: form.baseURL,
|
baseURL: form.baseURL,
|
||||||
apiKey: form.apiKey,
|
apiKey: form.apiKey,
|
||||||
|
model: form.model,
|
||||||
|
apiType: form.apiType,
|
||||||
|
maxTokens: form.maxTokens,
|
||||||
|
contextWindow: form.contextWindow,
|
||||||
remark: form.remark,
|
remark: form.remark,
|
||||||
syncAgents: form.syncAgents,
|
syncAgents: form.syncAgents,
|
||||||
});
|
});
|
||||||
@@ -97,6 +124,10 @@ const submit = async () => {
|
|||||||
name: form.name,
|
name: form.name,
|
||||||
baseURL: form.baseURL,
|
baseURL: form.baseURL,
|
||||||
apiKey: form.apiKey,
|
apiKey: form.apiKey,
|
||||||
|
model: form.model,
|
||||||
|
apiType: form.apiType,
|
||||||
|
maxTokens: form.maxTokens,
|
||||||
|
contextWindow: form.contextWindow,
|
||||||
remark: form.remark,
|
remark: form.remark,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -111,6 +142,10 @@ const handleClose = () => {
|
|||||||
formRef.value?.resetFields();
|
formRef.value?.resetFields();
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
form.id = 0;
|
form.id = 0;
|
||||||
|
form.model = '';
|
||||||
|
form.apiType = 'openai-completions';
|
||||||
|
form.maxTokens = 8192;
|
||||||
|
form.contextWindow = 128000;
|
||||||
form.syncAgents = false;
|
form.syncAgents = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,6 +155,10 @@ interface OpenParams {
|
|||||||
name?: string;
|
name?: string;
|
||||||
baseURL?: string;
|
baseURL?: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
|
model?: string;
|
||||||
|
apiType?: string;
|
||||||
|
maxTokens?: number;
|
||||||
|
contextWindow?: number;
|
||||||
remark?: string;
|
remark?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +171,10 @@ const openDrawer = async (params?: OpenParams) => {
|
|||||||
form.name = params.name || '';
|
form.name = params.name || '';
|
||||||
form.baseURL = params.baseURL || '';
|
form.baseURL = params.baseURL || '';
|
||||||
form.apiKey = params.apiKey || '';
|
form.apiKey = params.apiKey || '';
|
||||||
|
form.model = params.model || '';
|
||||||
|
form.apiType = params.apiType || 'openai-completions';
|
||||||
|
form.maxTokens = params.maxTokens || 8192;
|
||||||
|
form.contextWindow = params.contextWindow || 128000;
|
||||||
form.remark = params.remark || '';
|
form.remark = params.remark || '';
|
||||||
form.syncAgents = false;
|
form.syncAgents = false;
|
||||||
return;
|
return;
|
||||||
@@ -140,6 +183,10 @@ const openDrawer = async (params?: OpenParams) => {
|
|||||||
form.name = '';
|
form.name = '';
|
||||||
form.baseURL = '';
|
form.baseURL = '';
|
||||||
form.apiKey = '';
|
form.apiKey = '';
|
||||||
|
form.model = '';
|
||||||
|
form.apiType = 'openai-completions';
|
||||||
|
form.maxTokens = 8192;
|
||||||
|
form.contextWindow = 128000;
|
||||||
form.remark = '';
|
form.remark = '';
|
||||||
form.syncAgents = false;
|
form.syncAgents = false;
|
||||||
if (providerOptions.value.length === 0) {
|
if (providerOptions.value.length === 0) {
|
||||||
@@ -158,7 +205,7 @@ const loadProviders = async () => {
|
|||||||
const data = res.data || [];
|
const data = res.data || [];
|
||||||
providerOptions.value = data.map((item) => ({
|
providerOptions.value = data.map((item) => ({
|
||||||
value: item.provider,
|
value: item.provider,
|
||||||
label: item.displayName || item.provider,
|
label: getAgentProviderDisplayName(item.provider, item.displayName),
|
||||||
}));
|
}));
|
||||||
providerBaseURL.value = data.reduce((acc, item) => {
|
providerBaseURL.value = data.reduce((acc, item) => {
|
||||||
acc[item.provider] = item.baseUrl || '';
|
acc[item.provider] = item.baseUrl || '';
|
||||||
@@ -171,6 +218,14 @@ const loadProviders = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleProviderChange = () => {
|
const handleProviderChange = () => {
|
||||||
|
if (form.provider === 'custom') {
|
||||||
|
form.baseURL = '';
|
||||||
|
form.apiType = form.apiType || 'openai-completions';
|
||||||
|
form.maxTokens = form.maxTokens || 8192;
|
||||||
|
form.contextWindow = form.contextWindow || 128000;
|
||||||
|
form.model = form.model || '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (form.provider !== 'ollama') {
|
if (form.provider !== 'ollama') {
|
||||||
form.baseURL = providerBaseURL.value[form.provider] || '';
|
form.baseURL = providerBaseURL.value[form.provider] || '';
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<el-table-column :label="$t('commons.table.name')" prop="name" min-width="200" />
|
<el-table-column :label="$t('commons.table.name')" prop="name" min-width="200" />
|
||||||
<el-table-column :label="$t('aiTools.agents.provider')" prop="provider" width="120">
|
<el-table-column :label="$t('aiTools.agents.provider')" prop="provider" width="120">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.providerName || row.provider }}
|
{{ getAgentProviderDisplayName(row.provider, row.providerName) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('aiTools.agents.baseUrl')" prop="baseUrl" min-width="200" />
|
<el-table-column :label="$t('aiTools.agents.baseUrl')" prop="baseUrl" min-width="200" />
|
||||||
@@ -53,6 +53,7 @@ import AddDialog from '@/views/ai/agents/model/add/index.vue';
|
|||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from 'element-plus';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { dateFormat } from '@/utils/util';
|
import { dateFormat } from '@/utils/util';
|
||||||
|
import { getAgentProviderDisplayName } from '@/utils/agent';
|
||||||
|
|
||||||
const items = ref<AI.AgentAccountItem[]>([]);
|
const items = ref<AI.AgentAccountItem[]>([]);
|
||||||
const addRef = ref();
|
const addRef = ref();
|
||||||
@@ -103,6 +104,10 @@ const onEdit = (row: AI.AgentAccountItem) => {
|
|||||||
name: row.name,
|
name: row.name,
|
||||||
baseURL: row.baseUrl,
|
baseURL: row.baseUrl,
|
||||||
apiKey: row.apiKey,
|
apiKey: row.apiKey,
|
||||||
|
model: row.model,
|
||||||
|
apiType: row.apiType,
|
||||||
|
maxTokens: row.maxTokens,
|
||||||
|
contextWindow: row.contextWindow,
|
||||||
remark: row.remark,
|
remark: row.remark,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user