From 4bd170992a98e408ebe1af4db76fc5912fa89bd8 Mon Sep 17 00:00:00 2001
From: zhengkunwang223 <1paneldev@sina.com>
Date: Wed, 5 Aug 2026 14:01:44 +0800
Subject: [PATCH] feat: QwenPaw support config username/password
---
agent/app/dto/agents.go | 4 +-
agent/app/service/agents.go | 41 ++++--
agent/app/service/agents_copaw.go | 128 ++++++++++++++++++
agent/app/service/agents_hermes.go | 53 --------
agent/app/service/agents_utils.go | 85 +++++++++++-
agent/i18n/lang/en.yaml | 3 +
agent/i18n/lang/es-ES.yaml | 3 +
agent/i18n/lang/fa.yaml | 3 +
agent/i18n/lang/ja.yaml | 3 +
agent/i18n/lang/ko.yaml | 3 +
agent/i18n/lang/lo.yaml | 3 +
agent/i18n/lang/ms.yaml | 3 +
agent/i18n/lang/pt-BR.yaml | 3 +
agent/i18n/lang/ru.yaml | 3 +
agent/i18n/lang/tr.yaml | 3 +
agent/i18n/lang/zh-Hant.yaml | 3 +
agent/i18n/lang/zh.yaml | 3 +
frontend/src/api/interface/ai.ts | 4 +-
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 | 1 +
frontend/src/lang/modules/zh.ts | 1 +
frontend/src/utils/agent.ts | 4 +
.../src/views/ai/agents/agent/add/index.vue | 15 +-
.../views/ai/agents/agent/config/index.vue | 9 +-
.../agent/config/tabs/settings/other.vue | 28 +++-
frontend/src/views/ai/agents/agent/index.vue | 6 +-
35 files changed, 346 insertions(+), 89 deletions(-)
create mode 100644 agent/app/service/agents_copaw.go
diff --git a/agent/app/dto/agents.go b/agent/app/dto/agents.go
index 6d2afd869e04..5a3e69709cd6 100644
--- a/agent/app/dto/agents.go
+++ b/agent/app/dto/agents.go
@@ -730,9 +730,9 @@ type AgentSecurityConfig struct {
type AgentOtherConfigUpdateReq struct {
AgentID uint `json:"agentId" validate:"required"`
- UserTimezone string `json:"userTimezone" validate:"required"`
+ UserTimezone string `json:"userTimezone"`
BrowserEnabled bool `json:"browserEnabled"`
- NPMRegistry string `json:"npmRegistry" validate:"required"`
+ NPMRegistry string `json:"npmRegistry"`
DashboardUsername string `json:"dashboardUsername"`
DashboardPassword string `json:"dashboardPassword"`
}
diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go
index 4495f31eeb63..e6ada78f571f 100644
--- a/agent/app/service/agents.go
+++ b/agent/app/service/agents.go
@@ -181,7 +181,7 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) {
var allowedOrigins []string
var account *model.AgentAccount
var installHooks *appInstallHooks
- var hermesAuth hermesDashboardAuth
+ var dashboardAuth agentDashboardAuth
if agentType == constant.AppOpenclaw || agentType == constant.AppHermesAgent {
if req.AccountID == 0 {
@@ -226,15 +226,17 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) {
},
}
} else if agentType == constant.AppHermesAgent {
- hermesAuth = normalizeHermesDashboardAuth(req.DashboardUsername, req.DashboardPassword)
+ dashboardAuth = normalizeAgentDashboardAuth(req.DashboardUsername, req.DashboardPassword)
installHooks = &appInstallHooks{
AfterCopyData: func(appInstall *model.AppInstall) error {
if err := prepareHermesInstallFiles(appInstall, account, storedModel); err != nil {
return err
}
- return writeHermesDashboardAuthEnv(path.Join(appInstall.GetPath(), ".env"), hermesAuth, false)
+ return writeAgentDashboardAuthEnv(appInstall.GetEnvPath(), agentType, dashboardAuth, false)
},
}
+ } else if agentType == constant.AppCopaw {
+ dashboardAuth = normalizeAgentDashboardAuth(req.DashboardUsername, req.DashboardPassword)
}
params := map[string]interface{}{
@@ -254,9 +256,12 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) {
params["API_KEY"] = apiKey
params["OPENCLAW_GATEWAY_TOKEN"] = token
}
- if agentType == constant.AppHermesAgent {
- params[hermesDashboardUsernameEnvKey] = hermesAuth.Username
- params[hermesDashboardPasswordEnvKey] = hermesAuth.Password
+ if usernameKey, passwordKey, ok := agentDashboardAuthEnvKeys(agentType); ok {
+ params[usernameKey] = dashboardAuth.Username
+ params[passwordKey] = dashboardAuth.Password
+ if agentType == constant.AppCopaw {
+ params[qwenPawAuthEnabledEnvKey] = "true"
+ }
}
if req.EditCompose && strings.TrimSpace(req.DockerCompose) == "" {
@@ -1435,7 +1440,7 @@ func (a AgentService) GetOtherConfig(req dto.AgentIDReq) (*dto.AgentOtherConfig,
if err != nil {
return nil, err
}
- auth := readHermesDashboardAuthFromInstall(install)
+ auth := readAgentDashboardAuthFromInstall(install, agent.AgentType)
return &dto.AgentOtherConfig{
UserTimezone: cfg.Timezone,
BrowserEnabled: true,
@@ -1444,6 +1449,13 @@ func (a AgentService) GetOtherConfig(req dto.AgentIDReq) (*dto.AgentOtherConfig,
DashboardPassword: auth.Password,
}, nil
}
+ if agent.AgentType == constant.AppCopaw {
+ auth := readAgentDashboardAuthFromInstall(install, agent.AgentType)
+ return &dto.AgentOtherConfig{
+ DashboardUsername: auth.Username,
+ DashboardPassword: auth.Password,
+ }, nil
+ }
conf, err := readOpenclawConfig(agent.ConfigPath)
if err != nil {
return nil, err
@@ -1462,16 +1474,19 @@ func (a AgentService) UpdateOtherConfig(req dto.AgentOtherConfigUpdateReq) error
return err
}
if agent.AgentType == constant.AppHermesAgent {
+ if strings.TrimSpace(req.UserTimezone) == "" {
+ return buserr.New("ErrInvalidParams")
+ }
account, err := agentAccountRepo.GetFirst(repo.WithByID(agent.AccountID))
if err != nil {
return err
}
- previousAuth := readHermesDashboardAuthFromInstall(install)
- nextAuth := normalizeHermesDashboardAuth(req.DashboardUsername, req.DashboardPassword)
+ previousAuth := readAgentDashboardAuthFromInstall(install, agent.AgentType)
+ nextAuth := normalizeAgentDashboardAuth(req.DashboardUsername, req.DashboardPassword)
if err := writeHermesConfig(path.Dir(agent.ConfigPath), account, agent.Model, strings.TrimSpace(req.UserTimezone)); err != nil {
return err
}
- if err := writeHermesDashboardAuthEnv(path.Join(install.GetPath(), ".env"), nextAuth, true); err != nil {
+ if err := writeAgentDashboardAuthEnv(install.GetEnvPath(), agent.AgentType, nextAuth, true); err != nil {
return err
}
operate := constant.Restart
@@ -1483,6 +1498,12 @@ func (a AgentService) UpdateOtherConfig(req dto.AgentOtherConfigUpdateReq) error
Operate: operate,
})
}
+ if agent.AgentType == constant.AppCopaw {
+ return updateQwenPawDashboardAuth(install, normalizeAgentDashboardAuth(req.DashboardUsername, req.DashboardPassword))
+ }
+ if strings.TrimSpace(req.UserTimezone) == "" || strings.TrimSpace(req.NPMRegistry) == "" {
+ return buserr.New("ErrInvalidParams")
+ }
if err := ensureContainerRunning(install.ContainerName); err != nil {
return err
}
diff --git a/agent/app/service/agents_copaw.go b/agent/app/service/agents_copaw.go
new file mode 100644
index 000000000000..f9889aa9e62a
--- /dev/null
+++ b/agent/app/service/agents_copaw.go
@@ -0,0 +1,128 @@
+package service
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/1Panel-dev/1Panel/agent/app/model"
+ "github.com/1Panel-dev/1Panel/agent/buserr"
+ "github.com/1Panel-dev/1Panel/agent/constant"
+)
+
+type qwenPawAuthStatus struct {
+ Enabled bool `json:"enabled"`
+ HasUsers bool `json:"has_users"`
+}
+
+type qwenPawLoginResponse struct {
+ Token string `json:"token"`
+}
+
+func updateQwenPawDashboardAuth(install *model.AppInstall, next agentDashboardAuth) error {
+ if install == nil || install.ID == 0 {
+ return buserr.New("ErrRecordNotFound")
+ }
+ current, err := readAgentDashboardAuthEnv(install.GetEnvPath(), constant.AppCopaw)
+ if err != nil {
+ return err
+ }
+ if current == next {
+ return writeAgentDashboardAuthEnv(install.GetEnvPath(), constant.AppCopaw, next, true)
+ }
+ if err := ensureContainerRunning(install.ContainerName); err != nil {
+ return err
+ }
+
+ baseURL := fmt.Sprintf("http://127.0.0.1:%d/api/auth", install.HttpPort)
+ var status qwenPawAuthStatus
+ if _, err := requestQwenPawAuth(http.MethodGet, baseURL+"/status", nil, "", &status); err != nil {
+ return buserr.WithMap("ErrQwenPawAuthRequest", map[string]interface{}{"err": err.Error()}, err)
+ }
+ if !status.Enabled {
+ return buserr.New("ErrQwenPawAuthDisabled")
+ }
+
+ if !status.HasUsers {
+ payload := map[string]string{"username": next.Username, "password": next.Password}
+ if _, err := requestQwenPawAuth(http.MethodPost, baseURL+"/register", payload, "", nil); err != nil {
+ return buserr.WithMap("ErrQwenPawAuthRequest", map[string]interface{}{"err": err.Error()}, err)
+ }
+ } else {
+ var login qwenPawLoginResponse
+ payload := map[string]string{"username": current.Username, "password": current.Password}
+ statusCode, err := requestQwenPawAuth(http.MethodPost, baseURL+"/login", payload, "", &login)
+ if statusCode == http.StatusUnauthorized {
+ return buserr.New("ErrQwenPawAuthOutOfSync")
+ }
+ if err != nil {
+ return buserr.WithMap("ErrQwenPawAuthRequest", map[string]interface{}{"err": err.Error()}, err)
+ }
+ payload = map[string]string{"current_password": current.Password}
+ if current.Username != next.Username {
+ payload["new_username"] = next.Username
+ }
+ if current.Password != next.Password {
+ payload["new_password"] = next.Password
+ }
+ if _, err := requestQwenPawAuth(http.MethodPost, baseURL+"/update-profile", payload, login.Token, nil); err != nil {
+ return buserr.WithMap("ErrQwenPawAuthRequest", map[string]interface{}{"err": err.Error()}, err)
+ }
+ }
+ return writeAgentDashboardAuthEnv(install.GetEnvPath(), constant.AppCopaw, next, true)
+}
+
+func requestQwenPawAuth(method, reqURL string, payload interface{}, token string, result interface{}) (int, error) {
+ var body io.Reader
+ if payload != nil {
+ data, err := json.Marshal(payload)
+ if err != nil {
+ return 0, err
+ }
+ body = bytes.NewReader(data)
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ req, err := http.NewRequestWithContext(ctx, method, reqURL, body)
+ if err != nil {
+ return 0, err
+ }
+ req.Header.Set("Content-Type", "application/json")
+ if token != "" {
+ req.Header.Set("Authorization", "Bearer "+token)
+ }
+ resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
+ if err != nil {
+ return 0, err
+ }
+ defer resp.Body.Close()
+ data, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return resp.StatusCode, err
+ }
+ if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
+ detail := strings.TrimSpace(string(data))
+ var errorResponse struct {
+ Detail string `json:"detail"`
+ }
+ if json.Unmarshal(data, &errorResponse) == nil && strings.TrimSpace(errorResponse.Detail) != "" {
+ detail = strings.TrimSpace(errorResponse.Detail)
+ }
+ if detail == "" {
+ detail = resp.Status
+ }
+ return resp.StatusCode, errors.New(detail)
+ }
+ if result != nil && len(data) > 0 {
+ if err := json.Unmarshal(data, result); err != nil {
+ return resp.StatusCode, err
+ }
+ }
+ return resp.StatusCode, nil
+}
diff --git a/agent/app/service/agents_hermes.go b/agent/app/service/agents_hermes.go
index e07bc7e2cf45..d17ede18100b 100644
--- a/agent/app/service/agents_hermes.go
+++ b/agent/app/service/agents_hermes.go
@@ -19,13 +19,6 @@ import (
const hermesWorkspaceDir = "/opt/data/workspace"
const hermesExecutablePath = "/opt/hermes/.venv/bin/hermes"
-const hermesDashboardUsernameEnvKey = "HERMES_DASHBOARD_USERNAME"
-const hermesDashboardPasswordEnvKey = "HERMES_DASHBOARD_PASSWORD"
-
-type hermesDashboardAuth struct {
- Username string
- Password string
-}
type hermesConfig struct {
Model hermesModelConfig `yaml:"model"`
@@ -117,52 +110,6 @@ func prepareHermesInstallFiles(appInstall *model.AppInstall, account *model.Agen
return files.NewFileOp().ChownR(dataDir, "1000", "1000", true)
}
-func normalizeHermesDashboardAuth(username, password string) hermesDashboardAuth {
- auth := hermesDashboardAuth{
- Username: strings.TrimSpace(username),
- Password: strings.TrimSpace(password),
- }
- if auth.Username == "" {
- auth.Username = "admin"
- }
- if auth.Password == "" {
- auth.Password = common.RandStr(8)
- }
- return auth
-}
-
-func writeHermesDashboardAuthEnv(envPath string, auth hermesDashboardAuth, overwrite bool) error {
- return upsertAgentEnv(envPath, map[string]string{
- hermesDashboardUsernameEnvKey: auth.Username,
- hermesDashboardPasswordEnvKey: auth.Password,
- }, []string{
- hermesDashboardUsernameEnvKey,
- hermesDashboardPasswordEnvKey,
- }, overwrite)
-}
-
-func readHermesDashboardAuthEnv(envPath string) (hermesDashboardAuth, error) {
- envMap, err := readAgentEnvMap(envPath)
- if err != nil {
- return hermesDashboardAuth{}, err
- }
- return hermesDashboardAuth{
- Username: strings.TrimSpace(envMap[hermesDashboardUsernameEnvKey]),
- Password: strings.TrimSpace(envMap[hermesDashboardPasswordEnvKey]),
- }, nil
-}
-
-func readHermesDashboardAuthFromInstall(appInstall *model.AppInstall) hermesDashboardAuth {
- if appInstall == nil || appInstall.ID == 0 {
- return hermesDashboardAuth{}
- }
- auth, err := readHermesDashboardAuthEnv(path.Join(appInstall.GetPath(), ".env"))
- if err != nil {
- return hermesDashboardAuth{}
- }
- return auth
-}
-
func readHermesConfig(configPath string) (*hermesConfig, error) {
content, err := files.NewFileOp().GetContent(configPath)
if err != nil {
diff --git a/agent/app/service/agents_utils.go b/agent/app/service/agents_utils.go
index e2de1335e52c..dac2e63acf9e 100644
--- a/agent/app/service/agents_utils.go
+++ b/agent/app/service/agents_utils.go
@@ -422,8 +422,8 @@ func buildAgentItem(agent *model.Agent, appInstall *model.AppInstall, envMap map
item.BridgePort = toInt(bridge)
}
}
- if agentType == constant.AppHermesAgent {
- auth := readHermesDashboardAuthFromInstall(appInstall)
+ if _, _, ok := agentDashboardAuthEnvKeys(agentType); ok {
+ auth := readAgentDashboardAuthFromInstall(appInstall, agentType)
item.DashboardUsername = auth.Username
item.DashboardPassword = auth.Password
}
@@ -1463,6 +1463,87 @@ func readInstallEnv(envStr string) map[string]interface{} {
return data
}
+const (
+ hermesDashboardUsernameEnvKey = "HERMES_DASHBOARD_USERNAME"
+ hermesDashboardPasswordEnvKey = "HERMES_DASHBOARD_PASSWORD"
+ qwenPawAuthEnabledEnvKey = "QWENPAW_AUTH_ENABLED"
+ qwenPawAuthUsernameEnvKey = "QWENPAW_AUTH_USERNAME"
+ qwenPawAuthPasswordEnvKey = "QWENPAW_AUTH_PASSWORD"
+)
+
+type agentDashboardAuth struct {
+ Username string
+ Password string
+}
+
+func normalizeAgentDashboardAuth(username, password string) agentDashboardAuth {
+ auth := agentDashboardAuth{
+ Username: strings.TrimSpace(username),
+ Password: strings.TrimSpace(password),
+ }
+ if auth.Username == "" {
+ auth.Username = "admin"
+ }
+ if auth.Password == "" {
+ auth.Password = common.RandStr(8)
+ }
+ return auth
+}
+
+func agentDashboardAuthEnvKeys(agentType string) (string, string, bool) {
+ switch agentType {
+ case constant.AppHermesAgent:
+ return hermesDashboardUsernameEnvKey, hermesDashboardPasswordEnvKey, true
+ case constant.AppCopaw:
+ return qwenPawAuthUsernameEnvKey, qwenPawAuthPasswordEnvKey, true
+ default:
+ return "", "", false
+ }
+}
+
+func writeAgentDashboardAuthEnv(envPath, agentType string, auth agentDashboardAuth, overwrite bool) error {
+ usernameKey, passwordKey, ok := agentDashboardAuthEnvKeys(agentType)
+ if !ok {
+ return fmt.Errorf("dashboard auth is not supported for %s", agentType)
+ }
+ values := map[string]string{
+ usernameKey: auth.Username,
+ passwordKey: auth.Password,
+ }
+ order := []string{usernameKey, passwordKey}
+ if agentType == constant.AppCopaw {
+ values[qwenPawAuthEnabledEnvKey] = "true"
+ order = append([]string{qwenPawAuthEnabledEnvKey}, order...)
+ }
+ return upsertAgentEnv(envPath, values, order, overwrite)
+}
+
+func readAgentDashboardAuthEnv(envPath, agentType string) (agentDashboardAuth, error) {
+ usernameKey, passwordKey, ok := agentDashboardAuthEnvKeys(agentType)
+ if !ok {
+ return agentDashboardAuth{}, fmt.Errorf("dashboard auth is not supported for %s", agentType)
+ }
+ envMap, err := readAgentEnvMap(envPath)
+ if err != nil {
+ return agentDashboardAuth{}, err
+ }
+ return agentDashboardAuth{
+ Username: strings.TrimSpace(envMap[usernameKey]),
+ Password: strings.TrimSpace(envMap[passwordKey]),
+ }, nil
+}
+
+func readAgentDashboardAuthFromInstall(appInstall *model.AppInstall, agentType string) agentDashboardAuth {
+ if appInstall == nil || appInstall.ID == 0 {
+ return agentDashboardAuth{}
+ }
+ auth, err := readAgentDashboardAuthEnv(appInstall.GetEnvPath(), agentType)
+ if err != nil {
+ return agentDashboardAuth{}
+ }
+ return auth
+}
+
func readAgentEnvMap(envPath string) (map[string]string, error) {
fileOp := files.NewFileOp()
if !fileOp.Stat(envPath) {
diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml
index e9023cdaa864..d072e6cd7596 100644
--- a/agent/i18n/lang/en.yaml
+++ b/agent/i18n/lang/en.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'This agent is already bound to a website'
ErrAgentWebsiteTypeUnsupported: 'Only proxy or static websites can be bound'
ErrAgentWebsiteInUse: 'This website is already bound to another agent'
ErrAgentWebsiteUnbindUnsupported: 'Deployment websites cannot be unbound manually'
+ErrQwenPawAuthRequest: 'Failed to update QwenPaw credentials: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'The current QwenPaw credentials do not match the 1Panel record. Reset the QwenPaw password or restore the credentials in the application .env file'
+ErrQwenPawAuthDisabled: 'Login authentication is not enabled in QwenPaw'
ErrHermesPairingCodeUnavailable: 'The pairing code is temporarily unavailable in Hermes, possibly due to network issues. Please try again later.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'When the Feishu group policy is Allowlist, the DM policy cannot be Pairing Code.'
diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml
index c17bb71971b1..8f2cb006ee21 100644
--- a/agent/i18n/lang/es-ES.yaml
+++ b/agent/i18n/lang/es-ES.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'Este agente ya está vinculado a un sitio web'
ErrAgentWebsiteTypeUnsupported: 'Solo se pueden vincular sitios proxy o estáticos'
ErrAgentWebsiteInUse: 'Este sitio web ya está vinculado a otro agente'
ErrAgentWebsiteUnbindUnsupported: 'Los sitios web de despliegue no se pueden desvincular manualmente'
+ErrQwenPawAuthRequest: 'No se pudieron actualizar las credenciales de QwenPaw: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'Las credenciales actuales de QwenPaw no coinciden con el registro de 1Panel. Restablezca la contraseña de QwenPaw o restaure las credenciales en el archivo .env de la aplicación'
+ErrQwenPawAuthDisabled: 'La autenticación de inicio de sesión no está habilitada en QwenPaw'
ErrHermesPairingCodeUnavailable: 'El código de emparejamiento no está disponible temporalmente en Hermes, posiblemente por un problema de red. Inténtalo de nuevo más tarde.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Cuando la política de grupo de Feishu es Lista permitida, la política de MD no puede ser Código de emparejamiento.'
diff --git a/agent/i18n/lang/fa.yaml b/agent/i18n/lang/fa.yaml
index 3be9e698ec39..dc626cb5abf8 100644
--- a/agent/i18n/lang/fa.yaml
+++ b/agent/i18n/lang/fa.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'این عامل قبلاً به یک وبسایت مت
ErrAgentWebsiteTypeUnsupported: 'فقط وبسایتهای پراکسی یا استاتیک قابل اتصال هستند'
ErrAgentWebsiteInUse: 'این وبسایت قبلاً به عامل دیگری متصل است'
ErrAgentWebsiteUnbindUnsupported: 'وبسایتهای استقرار یافته را نمیتوان به صورت دستی قطع اتصال کرد'
+ErrQwenPawAuthRequest: 'بهروزرسانی اطلاعات ورود QwenPaw ناموفق بود: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'اطلاعات ورود فعلی QwenPaw با رکورد 1Panel مطابقت ندارد. گذرواژه QwenPaw را بازنشانی کنید یا اطلاعات ورود فایل .env برنامه را بازیابی کنید'
+ErrQwenPawAuthDisabled: 'احراز هویت ورود در QwenPaw فعال نشده است'
ErrHermesPairingCodeUnavailable: 'کد جفتسازی به طور موقت در هرمس در دسترس نیست، احتمالاً به دلیل مشکلات شبکه. لطفاً بعداً دوباره تلاش کنید.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'وقتی خط مشی گروه فیشو لیست سفید باشد، خط مشی DM نمیتواند کد جفتسازی باشد.'
diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml
index fda61fb8798e..54ea1b05d8ee 100644
--- a/agent/i18n/lang/ja.yaml
+++ b/agent/i18n/lang/ja.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'このエージェントはすでにサイトに関連付
ErrAgentWebsiteTypeUnsupported: '関連付けできるのはプロキシサイトまたは静的サイトのみです'
ErrAgentWebsiteInUse: 'このサイトはすでに別のエージェントに関連付けられています'
ErrAgentWebsiteUnbindUnsupported: 'ワンクリックデプロイのサイトは手動で関連解除できません'
+ErrQwenPawAuthRequest: 'QwenPaw 認証情報の更新に失敗しました: {{ .err }}'
+ErrQwenPawAuthOutOfSync: '現在の QwenPaw 認証情報が 1Panel の記録と一致しません。QwenPaw のパスワードをリセットするか、アプリケーションの .env にある認証情報を復元してください'
+ErrQwenPawAuthDisabled: 'QwenPaw でログイン認証が有効になっていません'
ErrHermesPairingCodeUnavailable: 'Hermes でペアリングコードが一時的に見つかりません。ネットワーク要因の可能性があるため、しばらくしてから再試行してください。'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Feishu のグループポリシーが許可リストの場合、DM ポリシーをペアリングコードにはできません。'
diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml
index 78e79ea74608..c5676076e206 100644
--- a/agent/i18n/lang/ko.yaml
+++ b/agent/i18n/lang/ko.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: '이 에이전트는 이미 웹사이트에 연결되어
ErrAgentWebsiteTypeUnsupported: '프록시 또는 정적 웹사이트만 연결할 수 있습니다'
ErrAgentWebsiteInUse: '이 웹사이트는 이미 다른 에이전트에 연결되어 있습니다'
ErrAgentWebsiteUnbindUnsupported: '원클릭 배포 웹사이트는 수동으로 연결 해제할 수 없습니다'
+ErrQwenPawAuthRequest: 'QwenPaw 인증 정보 업데이트에 실패했습니다: {{ .err }}'
+ErrQwenPawAuthOutOfSync: '현재 QwenPaw 자격 증명이 1Panel 기록과 일치하지 않습니다. QwenPaw 비밀번호를 재설정하거나 애플리케이션 .env의 자격 증명을 복원하세요'
+ErrQwenPawAuthDisabled: 'QwenPaw에서 로그인 인증이 활성화되어 있지 않습니다'
ErrHermesPairingCodeUnavailable: 'Hermes에서 페어링 코드가 일시적으로 존재하지 않습니다. 네트워크 문제일 수 있으니 잠시 후 다시 시도해 주세요.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Feishu 그룹 정책이 허용 목록이면 DM 정책을 페어링 코드로 설정할 수 없습니다.'
diff --git a/agent/i18n/lang/lo.yaml b/agent/i18n/lang/lo.yaml
index 63517702838b..a955d304f522 100644
--- a/agent/i18n/lang/lo.yaml
+++ b/agent/i18n/lang/lo.yaml
@@ -78,6 +78,9 @@ ErrAgentWebsiteBound: 'ຕົວແທນນີ້ຖືກຜູກມັດກ
ErrAgentWebsiteTypeUnsupported: 'ສາມາດຜູກມັດໄດ້ສະເພາະເວັບໄຊປະເພດ Proxy ຫຼື Static ເທົ່ານັ້ນ'
ErrAgentWebsiteInUse: 'ເວັບໄຊນີ້ຖືກຜູກມັດກັບຕົວແທນອື່ນແລ້ວ'
ErrAgentWebsiteUnbindUnsupported: 'ເວັບໄຊທີ່ຕິດຕັ້ງແລ້ວບໍ່ສາມາດຍົກເລີກການຜູກມັດດ້ວຍຕົນເອງໄດ້'
+ErrQwenPawAuthRequest: 'ອັບເດດຂໍ້ມູນຢືນຢັນ QwenPaw ບໍ່ສຳເລັດ: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'ຂໍ້ມູນຢືນຢັນ QwenPaw ປັດຈຸບັນບໍ່ກົງກັບບັນທຶກຂອງ 1Panel. ກະລຸນາຣີເຊັດລະຫັດຜ່ານ QwenPaw ຫຼືກູ້ຄືນຂໍ້ມູນໃນໄຟລ໌ .env ຂອງແອັບ'
+ErrQwenPawAuthDisabled: 'QwenPaw ຍັງບໍ່ໄດ້ເປີດໃຊ້ການຢືນຢັນການເຂົ້າລະບົບ'
ErrHermesPairingCodeUnavailable: 'ລະຫັດການຈັບຄູ່ໃນ Hermes ບໍ່ສາມາດໃຊ້ງານໄດ້ຊົ່ວຄາວ, ອາດຈະເກີດຈາກບັນຫາເຄືອຂ່າຍ. ກະລຸນາລອງໃໝ່ພາຍຫຼັງ.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'ເມື່ອນະໂຍບາຍກຸ່ມ Feishu ແມ່ນ Allowlist, ນະໂຍບາຍ DM ບໍ່ສາມາດເປັນ Pairing Code ໄດ້.'
diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml
index af4cd09a0990..62d0641259e9 100644
--- a/agent/i18n/lang/ms.yaml
+++ b/agent/i18n/lang/ms.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'Ejen ini sudah dipautkan ke laman web'
ErrAgentWebsiteTypeUnsupported: 'Hanya laman web proxy atau statik boleh dipautkan'
ErrAgentWebsiteInUse: 'Laman web ini sudah dipautkan ke ejen lain'
ErrAgentWebsiteUnbindUnsupported: 'Laman web one-click deployment tidak menyokong nyahikat manual'
+ErrQwenPawAuthRequest: 'Gagal mengemas kini kelayakan QwenPaw: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'Kelayakan QwenPaw semasa tidak sepadan dengan rekod 1Panel. Tetapkan semula kata laluan QwenPaw atau pulihkan kelayakan dalam fail .env aplikasi'
+ErrQwenPawAuthDisabled: 'Pengesahan log masuk belum didayakan dalam QwenPaw'
ErrHermesPairingCodeUnavailable: 'Kod pasangan buat sementara waktu tidak wujud dalam Hermes, mungkin disebabkan masalah rangkaian. Sila cuba lagi sebentar nanti.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Apabila dasar kumpulan Feishu ialah senarai benarkan, dasar DM tidak boleh menggunakan kod pasangan.'
diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml
index 7919bca2bed3..8a2e511d12a6 100644
--- a/agent/i18n/lang/pt-BR.yaml
+++ b/agent/i18n/lang/pt-BR.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'Este agente já está vinculado a um site'
ErrAgentWebsiteTypeUnsupported: 'Somente sites proxy ou estáticos podem ser vinculados'
ErrAgentWebsiteInUse: 'Este site já está vinculado a outro agente'
ErrAgentWebsiteUnbindUnsupported: 'Sites implantados em um clique não podem ser desvinculados manualmente'
+ErrQwenPawAuthRequest: 'Falha ao atualizar as credenciais do QwenPaw: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'As credenciais atuais do QwenPaw não correspondem ao registro do 1Panel. Redefina a senha do QwenPaw ou restaure as credenciais no arquivo .env do aplicativo'
+ErrQwenPawAuthDisabled: 'A autenticação de login não está ativada no QwenPaw'
ErrHermesPairingCodeUnavailable: 'O código de pareamento está temporariamente indisponível no Hermes, possivelmente por causa de rede. Tente novamente mais tarde.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Quando a política de grupo do Feishu é Lista de permissões, a política de DM não pode ser Código de pareamento.'
diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml
index b90682bdeda3..d34aec3a5784 100644
--- a/agent/i18n/lang/ru.yaml
+++ b/agent/i18n/lang/ru.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'Этот агент уже связан с сайтом'
ErrAgentWebsiteTypeUnsupported: 'Можно связывать только proxy- или static-сайты'
ErrAgentWebsiteInUse: 'Этот сайт уже связан с другим агентом'
ErrAgentWebsiteUnbindUnsupported: 'Сайты one-click deployment нельзя отвязать вручную'
+ErrQwenPawAuthRequest: 'Не удалось обновить учетные данные QwenPaw: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'Текущие учетные данные QwenPaw не совпадают с записью 1Panel. Сбросьте пароль QwenPaw или восстановите учетные данные в файле .env приложения'
+ErrQwenPawAuthDisabled: 'В QwenPaw не включена аутентификация при входе'
ErrHermesPairingCodeUnavailable: 'Код сопряжения временно недоступен в Hermes, возможно из-за проблем с сетью. Повторите попытку позже.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Когда групповая политика Feishu — белый список, политика личных сообщений не может быть кодом сопряжения.'
diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml
index c4cd3215f96f..fc02e64a4baa 100644
--- a/agent/i18n/lang/tr.yaml
+++ b/agent/i18n/lang/tr.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: 'Bu ajan zaten bir web sitesine bağlı'
ErrAgentWebsiteTypeUnsupported: 'Yalnızca proxy veya statik web siteleri bağlanabilir'
ErrAgentWebsiteInUse: 'Bu web sitesi zaten başka bir ajana bağlı'
ErrAgentWebsiteUnbindUnsupported: 'Tek tıkla dağıtılan web sitelerinin bağlantısı manuel olarak kaldırılamaz'
+ErrQwenPawAuthRequest: 'QwenPaw kimlik bilgileri güncellenemedi: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'Geçerli QwenPaw kimlik bilgileri 1Panel kaydıyla eşleşmiyor. QwenPaw parolasını sıfırlayın veya uygulamanın .env dosyasındaki kimlik bilgilerini geri yükleyin'
+ErrQwenPawAuthDisabled: 'QwenPaw oturum açma kimlik doğrulaması etkin değil'
ErrHermesPairingCodeUnavailable: 'Eşleştirme kodu Hermes içinde geçici olarak bulunamıyor; bu durum ağ kaynaklı olabilir. Lütfen daha sonra tekrar deneyin.'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: 'Feishu grup ilkesi izin listesi olduğunda, DM ilkesi eşleştirme kodu olamaz.'
diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml
index c8de466289c0..09e666f6d907 100644
--- a/agent/i18n/lang/zh-Hant.yaml
+++ b/agent/i18n/lang/zh-Hant.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: '該智能體已關聯網站'
ErrAgentWebsiteTypeUnsupported: '只能關聯反向代理或靜態網站'
ErrAgentWebsiteInUse: '該網站已被其他智能體關聯'
ErrAgentWebsiteUnbindUnsupported: '一鍵部署網站不支援手動解綁'
+ErrQwenPawAuthRequest: 'QwenPaw 驗證資訊更新失敗: {{ .err }}'
+ErrQwenPawAuthOutOfSync: 'QwenPaw 目前憑據與 1Panel 記錄不一致,請先重設 QwenPaw 密碼或還原應用程式 .env 中的憑據'
+ErrQwenPawAuthDisabled: 'QwenPaw 尚未啟用登入驗證'
ErrHermesPairingCodeUnavailable: '配對碼在 Hermes 中暫時不存在,可能是由於網路原因,請稍後再試'
ErrHermesFeishuGroupAllowlistRequiresAllowlist: '飛書群組策略為白名單時,私聊策略不能為配對碼'
diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml
index 01397210ab9e..0139057f77f6 100644
--- a/agent/i18n/lang/zh.yaml
+++ b/agent/i18n/lang/zh.yaml
@@ -93,6 +93,9 @@ ErrAgentWebsiteBound: "该智能体已关联网站"
ErrAgentWebsiteTypeUnsupported: "只能关联反向代理或静态网站"
ErrAgentWebsiteInUse: "该网站已被其他智能体关联"
ErrAgentWebsiteUnbindUnsupported: "一键部署网站不支持手动解绑"
+ErrQwenPawAuthRequest: "QwenPaw 认证信息更新失败: {{ .err }}"
+ErrQwenPawAuthOutOfSync: "QwenPaw 当前凭据与 1Panel 记录不一致,请先重置 QwenPaw 密码或恢复应用 .env 中的凭据"
+ErrQwenPawAuthDisabled: "QwenPaw 尚未启用登录认证"
ErrHermesPairingCodeUnavailable: "配对码在 hermes 中暂时不存在,可能是由于网络原因,请稍后尝试"
ErrHermesFeishuGroupAllowlistRequiresAllowlist: "飞书群组策略为白名单时,私聊策略不能为配对码"
diff --git a/frontend/src/api/interface/ai.ts b/frontend/src/api/interface/ai.ts
index 4b44d040ab35..1f7b835a36ab 100644
--- a/frontend/src/api/interface/ai.ts
+++ b/frontend/src/api/interface/ai.ts
@@ -969,9 +969,9 @@ export namespace AI {
export interface AgentOtherConfigUpdateReq {
agentId: number;
- userTimezone: string;
+ userTimezone?: string;
browserEnabled: boolean;
- npmRegistry: string;
+ npmRegistry?: string;
dashboardUsername?: string;
dashboardPassword?: string;
}
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index b59fa9bbdd30..a322750cceb7 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -922,6 +922,8 @@ const message = {
channelAutoRestartHelper: 'Saving will automatically restart the container so the changes take effect.',
dashboardAuthAutoRebuildHelper:
'Saving the username or password will automatically rebuild the container so the changes take effect.',
+ dashboardAuthImmediateHelper:
+ 'Saving updates the QwenPaw login credentials immediately without restarting the container.',
channelDeleteConfirm: 'Delete the {0} channel configuration?',
apiTypeBaseURLHelper: 'This type sends requests to {0}. Recommended Base URL: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts
index 3cd29e3db910..ff2c33e23da0 100644
--- a/frontend/src/lang/modules/es-es.ts
+++ b/frontend/src/lang/modules/es-es.ts
@@ -925,6 +925,8 @@ const message = {
'Al guardar, el contenedor se reiniciará automáticamente para que la configuración surta efecto.',
dashboardAuthAutoRebuildHelper:
'Al guardar el usuario o la contraseña, el contenedor se reconstruirá automáticamente para que los cambios surtan efecto.',
+ dashboardAuthImmediateHelper:
+ 'Al guardar, las credenciales de QwenPaw se actualizan de inmediato sin reiniciar el contenedor.',
channelDeleteConfirm: '¿Eliminar la configuración del canal {0}?',
apiTypeBaseURLHelper: 'Este tipo envía solicitudes a {0}. Base URL recomendada: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts
index 308d06856579..650d74345a66 100644
--- a/frontend/src/lang/modules/fa.ts
+++ b/frontend/src/lang/modules/fa.ts
@@ -910,6 +910,8 @@ const message = {
channelAutoRestartHelper: 'ذخیره به طور خودکار کانتینر را مجدداً راهاندازی میکند تا تغییرات اعمال شوند.',
dashboardAuthAutoRebuildHelper:
'ذخیره نام کاربری یا رمز عبور، کانتینر را بهطور خودکار بازسازی میکند تا تغییرات اعمال شوند.',
+ dashboardAuthImmediateHelper:
+ 'با ذخیرهسازی، اطلاعات ورود QwenPaw بدون راهاندازی مجدد کانتینر فوراً بهروزرسانی میشود.',
channelDeleteConfirm: 'پیکربندی کانال {0} حذف شود؟',
apiTypeBaseURLHelper: 'این نوع درخواستها را به {0} ارسال میکند. Base URL پیشنهادی: {1}',
apiTypeBaseURLMismatch: 'Base URL فعلی شبیه مسیر {0} است، اما {1} انتخاب شده است. URL پیشنهادی: {2}',
diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts
index 054649026a87..24b65927f459 100644
--- a/frontend/src/lang/modules/ja.ts
+++ b/frontend/src/lang/modules/ja.ts
@@ -914,6 +914,8 @@ const message = {
channelAutoRestartHelper: '保存後、設定を反映するためにコンテナが自動で再起動されます。',
dashboardAuthAutoRebuildHelper:
'ユーザー名またはパスワードを保存すると、変更を反映するためにコンテナが自動で再作成されます。',
+ dashboardAuthImmediateHelper:
+ '保存すると QwenPaw のログイン認証情報がすぐに更新され、コンテナの再起動は不要です。',
channelDeleteConfirm: '{0} チャンネルの設定を削除しますか?',
apiTypeBaseURLHelper: 'このタイプは最終的に {0} にリクエストします。推奨 Base URL: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts
index 262d84007a4e..83e4a7aee3d8 100644
--- a/frontend/src/lang/modules/ko.ts
+++ b/frontend/src/lang/modules/ko.ts
@@ -904,6 +904,8 @@ const message = {
channelAutoRestartHelper: '저장하면 설정 적용을 위해 컨테이너가 자동으로 재시작됩니다.',
dashboardAuthAutoRebuildHelper:
'사용자 이름 또는 비밀번호를 저장하면 변경 사항 적용을 위해 컨테이너가 자동으로 재생성됩니다.',
+ dashboardAuthImmediateHelper:
+ '저장하면 컨테이너를 다시 시작하지 않고 QwenPaw 로그인 자격 증명이 즉시 업데이트됩니다.',
channelDeleteConfirm: '{0} 채널 구성을 삭제하시겠습니까?',
apiTypeBaseURLHelper: '이 유형은 최종적으로 {0}에 요청합니다. 권장 Base URL: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts
index 8ec170d1aa1c..47615761a4f8 100644
--- a/frontend/src/lang/modules/lo.ts
+++ b/frontend/src/lang/modules/lo.ts
@@ -904,6 +904,8 @@ const message = {
channelAutoRestartHelper: 'ການບັນທຶກຈະຣີສະຕາດຄອນເທນເນີອັດຕະໂນມັດເພື່ອໃຫ້ການປ່ຽນແປງມີຜົນ.',
dashboardAuthAutoRebuildHelper:
'ການບັນທຶກຊື່ຜູ້ໃຊ້ ຫຼື ລະຫັດຜ່ານ Dashboard ຈະສ້າງຄອນເທນເນີໃໝ່ອັດຕະໂນມັດເພື່ອໃຫ້ການປ່ຽນແປງມີຜົນ.',
+ dashboardAuthImmediateHelper:
+ 'ເມື່ອບັນທຶກ ຂໍ້ມູນເຂົ້າລະບົບ QwenPaw ຈະຖືກອັບເດດທັນທີໂດຍບໍ່ຕ້ອງຣີສະຕາດຄອນເທນເນີ.',
channelDeleteConfirm: 'ລຶບການຕັ້ງຄ່າຊ່ອງທາງ {0}?',
apiTypeBaseURLHelper: 'ປະເພດນີ້ຈະສົ່ງການຮ້ອງຂໍໄປທີ່ {0}. Base URL ທີ່ແນະນຳ: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts
index 84d22a9468de..4fe384d27c0d 100644
--- a/frontend/src/lang/modules/ms.ts
+++ b/frontend/src/lang/modules/ms.ts
@@ -933,6 +933,8 @@ const message = {
'Menyimpan akan memulakan semula bekas secara automatik supaya konfigurasi berkuat kuasa.',
dashboardAuthAutoRebuildHelper:
'Menyimpan nama pengguna atau kata laluan akan membina semula bekas secara automatik supaya perubahan berkuat kuasa.',
+ dashboardAuthImmediateHelper:
+ 'Apabila disimpan, kelayakan log masuk QwenPaw dikemas kini serta-merta tanpa memulakan semula bekas.',
channelDeleteConfirm: 'Padam konfigurasi saluran {0}?',
apiTypeBaseURLHelper: 'Jenis ini menghantar permintaan ke {0}. Base URL yang disyorkan: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts
index c8ff91220348..58b66d7d921e 100644
--- a/frontend/src/lang/modules/pt-br.ts
+++ b/frontend/src/lang/modules/pt-br.ts
@@ -929,6 +929,8 @@ const message = {
'Ao salvar, o contêiner será reiniciado automaticamente para que a configuração entre em vigor.',
dashboardAuthAutoRebuildHelper:
'Ao salvar o usuário ou a senha, o contêiner será reconstruído automaticamente para que as alterações entrem em vigor.',
+ dashboardAuthImmediateHelper:
+ 'Ao salvar, as credenciais do QwenPaw são atualizadas imediatamente, sem reiniciar o contêiner.',
channelDeleteConfirm: 'Excluir a configuração do canal {0}?',
apiTypeBaseURLHelper: 'Este tipo envia requisições para {0}. Base URL recomendada: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts
index d58792ef9a2a..cb3b8531f87c 100644
--- a/frontend/src/lang/modules/ru.ts
+++ b/frontend/src/lang/modules/ru.ts
@@ -922,6 +922,8 @@ const message = {
'После сохранения контейнер будет автоматически перезапущен, чтобы настройки вступили в силу.',
dashboardAuthAutoRebuildHelper:
'После сохранения имени пользователя или пароля контейнер будет автоматически пересобран, чтобы изменения вступили в силу.',
+ dashboardAuthImmediateHelper:
+ 'После сохранения учетные данные QwenPaw обновляются сразу, без перезапуска контейнера.',
channelDeleteConfirm: 'Удалить конфигурацию канала {0}?',
apiTypeBaseURLHelper: 'Этот тип отправляет запросы в {0}. Рекомендуемый Base URL: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts
index d91293c1cb7a..8a39d3c7549b 100644
--- a/frontend/src/lang/modules/tr.ts
+++ b/frontend/src/lang/modules/tr.ts
@@ -931,6 +931,8 @@ const message = {
'Kaydettiğinizde ayarların etkili olması için konteyner otomatik olarak yeniden başlatılır.',
dashboardAuthAutoRebuildHelper:
'Kullanıcı adı veya parola kaydedildiğinde değişikliklerin etkili olması için konteyner otomatik olarak yeniden oluşturulur.',
+ dashboardAuthImmediateHelper:
+ 'Kaydedildiğinde QwenPaw oturum açma bilgileri konteyner yeniden başlatılmadan hemen güncellenir.',
channelDeleteConfirm: '{0} kanal yapılandırması silinsin mi?',
apiTypeBaseURLHelper: 'Bu tür istekleri {0} yoluna gönderir. Önerilen Base URL: {1}',
customImageURLHelper:
diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts
index e35b153b63ca..e83a7a1b9a22 100644
--- a/frontend/src/lang/modules/zh-Hant.ts
+++ b/frontend/src/lang/modules/zh-Hant.ts
@@ -877,6 +877,7 @@ const message = {
scanConnectHelper: '點擊後將在任務日誌中顯示 QR Code,掃碼確認成功後將自動重新啟動容器。',
channelAutoRestartHelper: '保存後將自動重新啟動容器以使設定生效。',
dashboardAuthAutoRebuildHelper: '保存使用者名稱或密碼後將自動重建容器以使設定生效。',
+ dashboardAuthImmediateHelper: '保存後將立即更新 QwenPaw 登入憑據,無需重新啟動容器。',
channelDeleteConfirm: '確認刪除 {0} 頻道設定?',
apiTypeBaseURLHelper: '目前類型最終請求 {0},Base URL 建議填寫 {1}',
customImageURLHelper: 'Custom 圖片帳號請填寫完整的圖片產生介面 URL,系統不會自動補全路徑,例如:{0}',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index 779da9e04718..0c61b7fc179b 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -890,6 +890,7 @@ const message = {
scanConnectHelper: '点击后将在任务日志中显示二维码,扫码确认成功后将自动重启容器。',
channelAutoRestartHelper: '保存后将自动重启容器以使配置生效。',
dashboardAuthAutoRebuildHelper: '保存用户名密码后将自动重建容器以使配置生效。',
+ dashboardAuthImmediateHelper: '保存后将立即更新 QwenPaw 登录凭据,无需重启容器。',
channelDeleteConfirm: '确认删除 {0} 频道配置?',
apiTypeBaseURLHelper: '当前类型最终请求 {0},Base URL 建议填写 {1}',
customImageURLHelper: 'Custom 图片账号请填写完整的图片生成接口 URL,系统不会自动补全路径,例如:{0}',
diff --git a/frontend/src/utils/agent.ts b/frontend/src/utils/agent.ts
index f5a971b62370..3dba06c471de 100644
--- a/frontend/src/utils/agent.ts
+++ b/frontend/src/utils/agent.ts
@@ -26,6 +26,10 @@ export const supportsAgentToken = (agentType: string): boolean => {
return agentType === 'openclaw';
};
+export const supportsAgentDashboardAuth = (agentType: string): boolean => {
+ return agentType === 'hermes-agent' || agentType === 'copaw';
+};
+
export const isOpenclawHTTPSWindowVersion = (version: string): boolean => {
return compareVersion(version, openclawHTTPSVersion) && !compareVersion(version, openclawHTTPVersion);
};
diff --git a/frontend/src/views/ai/agents/agent/add/index.vue b/frontend/src/views/ai/agents/agent/add/index.vue
index 9255fcc9a813..c8b9eaa99e76 100644
--- a/frontend/src/views/ai/agents/agent/add/index.vue
+++ b/frontend/src/views/ai/agents/agent/add/index.vue
@@ -23,7 +23,7 @@
-
+
@@ -131,6 +131,7 @@ import {
buildDefaultAllowedOrigin,
getAgentProviderDisplayName,
parseAllowedOriginsInput,
+ supportsAgentDashboardAuth,
validateAllowedOriginsInput,
} from '@/utils/agent';
import { App } from '@/api/interface/app';
@@ -187,8 +188,8 @@ const generateDashboardPassword = () => {
form.dashboardPassword = getRandomStr(8);
};
-const ensureHermesDashboardAuth = () => {
- if (form.agentType !== 'hermes-agent') {
+const ensureDashboardAuth = () => {
+ if (!supportsAgentDashboardAuth(form.agentType)) {
return;
}
if (!form.dashboardUsername) {
@@ -411,7 +412,7 @@ const handleAgentTypeChange = async () => {
form.provider = '';
form.accountId = undefined as unknown as number;
form.baseURL = '';
- ensureHermesDashboardAuth();
+ ensureDashboardAuth();
if (form.agentType === 'openclaw') {
await loadSystemIP();
allowedOriginsAutoFilled.value = true;
@@ -487,8 +488,8 @@ const submit = async () => {
model: showModelConfig.value ? form.model : undefined,
accountId: showModelConfig.value ? form.accountId : undefined,
token: form.agentType === 'openclaw' ? form.token : undefined,
- dashboardUsername: form.agentType === 'hermes-agent' ? form.dashboardUsername : undefined,
- dashboardPassword: form.agentType === 'hermes-agent' ? form.dashboardPassword : undefined,
+ dashboardUsername: supportsAgentDashboardAuth(form.agentType) ? form.dashboardUsername : undefined,
+ dashboardPassword: supportsAgentDashboardAuth(form.agentType) ? form.dashboardPassword : undefined,
taskID: taskID,
advanced: form.advanced,
containerName: form.containerName,
@@ -536,7 +537,7 @@ const openDrawer = async (agentType?: AI.AgentType) => {
form.agentType = targetType;
setDefaultWebUIPort();
form.token = getRandomStr(32).toLowerCase();
- ensureHermesDashboardAuth();
+ ensureDashboardAuth();
if (form.agentType === 'copaw') {
form.allowedOrigins = '';
lastAutoAllowedOrigins.value = '';
diff --git a/frontend/src/views/ai/agents/agent/config/index.vue b/frontend/src/views/ai/agents/agent/config/index.vue
index 3f73e5e7d862..f97af999e7f8 100644
--- a/frontend/src/views/ai/agents/agent/config/index.vue
+++ b/frontend/src/views/ai/agents/agent/config/index.vue
@@ -9,7 +9,7 @@
>
-
+
@@ -26,7 +26,7 @@
@@ -48,6 +48,7 @@ import AgentTab from './tabs/agents/index.vue';
import SkillsTab from './tabs/skills.vue';
import PluginsTab from './tabs/plugins.vue';
import SettingsTab from './tabs/settings.vue';
+import { supportsAgentModelConfig } from '@/utils/agent';
const { t } = useI18n();
const emit = defineEmits(['updated']);
@@ -165,13 +166,13 @@ const openDrawer = async (agent: AI.AgentItem) => {
configPath.value = agent.configPath;
agentType.value = agent.agentType;
header.value = `${agent.name} - ${t('menu.config')}`;
- activeTab.value = agent.agentType === 'openclaw' || agent.agentType === 'hermes-agent' ? 'channels' : 'model';
+ activeTab.value = agent.agentType === 'copaw' ? 'settings' : 'channels';
open.value = true;
if (agent.agentType === 'openclaw' || agent.agentType === 'hermes-agent') {
await loadChannels();
return;
}
- await loadModel();
+ await loadSettings();
};
defineExpose({
diff --git a/frontend/src/views/ai/agents/agent/config/tabs/settings/other.vue b/frontend/src/views/ai/agents/agent/config/tabs/settings/other.vue
index 2c430721aba3..49735508d70f 100644
--- a/frontend/src/views/ai/agents/agent/config/tabs/settings/other.vue
+++ b/frontend/src/views/ai/agents/agent/config/tabs/settings/other.vue
@@ -9,10 +9,10 @@
{{ t('aiTools.agents.npmRegistryHelper') }}
-
+
-
+
@@ -33,7 +33,9 @@
{{
agentType === 'hermes-agent'
? t('aiTools.agents.dashboardAuthAutoRebuildHelper')
- : t('aiTools.agents.channelAutoRestartHelper')
+ : agentType === 'copaw'
+ ? t('aiTools.agents.dashboardAuthImmediateHelper')
+ : t('aiTools.agents.channelAutoRestartHelper')
}}
@@ -47,6 +49,7 @@ import { Rules } from '@/global/form-rules';
import { AI } from '@/api/interface/ai';
import { getAgentOtherConfig, updateAgentOtherConfig } from '@/api/modules/ai';
import { MsgSuccess } from '@/utils/message';
+import { supportsAgentDashboardAuth } from '@/utils/agent';
const { t } = useI18n();
const loading = ref(false);
@@ -71,6 +74,16 @@ const npmRegistryOptions = [
'https://repo.huaweicloud.com/repository/npm/',
];
+const resetForm = () => {
+ Object.assign(form, {
+ userTimezone: '',
+ browserEnabled: true,
+ npmRegistry: defaultNPMRegistry,
+ dashboardUsername: 'admin',
+ dashboardPassword: '',
+ });
+};
+
const validateNPMRegistry = (_rule: any, value: string, callback: (error?: Error) => void) => {
if (!value) {
callback(new Error(t('commons.rule.requiredInput')));
@@ -93,11 +106,12 @@ const rules = reactive({
const load = async (params: { agentId: number; agentType: AI.AgentType }) => {
agentId.value = params.agentId;
agentType.value = params.agentType;
+ resetForm();
loading.value = true;
try {
const res = await getAgentOtherConfig({ agentId: params.agentId });
Object.assign(form, res.data || {});
- if (params.agentType === 'hermes-agent' && !form.dashboardUsername) {
+ if (supportsAgentDashboardAuth(params.agentType) && !form.dashboardUsername) {
form.dashboardUsername = 'admin';
}
} finally {
@@ -114,11 +128,11 @@ const saveConfig = async () => {
try {
await updateAgentOtherConfig({
agentId: agentId.value,
- userTimezone: form.userTimezone,
+ userTimezone: agentType.value === 'copaw' ? undefined : form.userTimezone,
browserEnabled: form.browserEnabled,
npmRegistry: agentType.value === 'openclaw' ? form.npmRegistry : defaultNPMRegistry,
- dashboardUsername: agentType.value === 'hermes-agent' ? form.dashboardUsername : undefined,
- dashboardPassword: agentType.value === 'hermes-agent' ? form.dashboardPassword : undefined,
+ dashboardUsername: supportsAgentDashboardAuth(agentType.value) ? form.dashboardUsername : undefined,
+ dashboardPassword: supportsAgentDashboardAuth(agentType.value) ? form.dashboardPassword : undefined,
});
MsgSuccess(t('aiTools.agents.saveSuccess'));
} finally {
diff --git a/frontend/src/views/ai/agents/agent/index.vue b/frontend/src/views/ai/agents/agent/index.vue
index 356d3c27f5cd..c9b29fa28e9d 100644
--- a/frontend/src/views/ai/agents/agent/index.vue
+++ b/frontend/src/views/ai/agents/agent/index.vue
@@ -173,7 +173,7 @@
openConfig(row),
- show: (row: AI.AgentItem) => supportsAgentModelConfig(row.agentType),
+ show: (row: AI.AgentItem) =>
+ supportsAgentModelConfig(row.agentType) || supportsAgentDashboardAuth(row.agentType),
disabled: (row: AI.AgentItem) => row.status !== 'Running',
},
{