From 810c6fd232c83bae75ae3ca4158b068ba80f0499 Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Tue, 21 Apr 2026 16:35:24 +0800 Subject: [PATCH] feat: change hermes channel logic (#12551) --- agent/app/api/v2/agents.go | 41 ++++++ agent/app/dto/agents.go | 13 +- agent/app/service/agents.go | 2 + agent/app/service/agents_channels.go | 49 ++++++- agent/app/service/agents_hermes.go | 78 +++++++++++- agent/app/service/agents_hermes_channels.go | 115 ++++++++++++++++- agent/i18n/lang/en.yaml | 1 + agent/i18n/lang/es-ES.yaml | 1 + agent/i18n/lang/ja.yaml | 1 + agent/i18n/lang/ko.yaml | 1 + agent/i18n/lang/ms.yaml | 1 + agent/i18n/lang/pt-BR.yaml | 1 + agent/i18n/lang/ru.yaml | 1 + agent/i18n/lang/tr.yaml | 1 + agent/i18n/lang/zh-Hant.yaml | 1 + agent/i18n/lang/zh.yaml | 1 + agent/router/ro_ai.go | 2 + frontend/src/api/interface/ai.ts | 15 ++- frontend/src/api/modules/ai.ts | 8 ++ frontend/src/components/log/task/index.vue | 3 +- frontend/src/lang/modules/en.ts | 3 + frontend/src/lang/modules/es-es.ts | 3 + frontend/src/lang/modules/ja.ts | 3 + frontend/src/lang/modules/ko.ts | 3 + frontend/src/lang/modules/ms.ts | 3 + frontend/src/lang/modules/pt-br.ts | 3 + frontend/src/lang/modules/ru.ts | 3 + frontend/src/lang/modules/tr.ts | 3 + frontend/src/lang/modules/zh-Hant.ts | 3 + frontend/src/lang/modules/zh.ts | 3 + .../src/views/ai/agents/agent/add/index.vue | 12 +- .../config/tabs/channels/hermes/dingtalk.vue | 120 ++++++++++++++++-- .../config/tabs/channels/hermes/discord.vue | 43 ++++++- .../config/tabs/channels/hermes/feishu.vue | 52 ++++++-- .../agent/config/tabs/channels/hermes/qq.vue | 52 ++++++-- .../config/tabs/channels/hermes/telegram.vue | 43 ++++++- .../config/tabs/channels/hermes/wecom.vue | 64 +++++++--- .../config/tabs/channels/hermes/weixin.vue | 42 +++++- frontend/src/views/ai/agents/agent/index.vue | 27 +++- 39 files changed, 730 insertions(+), 91 deletions(-) diff --git a/agent/app/api/v2/agents.go b/agent/app/api/v2/agents.go index 5492a64ec..b6c9c3c7b 100644 --- a/agent/app/api/v2/agents.go +++ b/agent/app/api/v2/agents.go @@ -864,6 +864,27 @@ func (b *BaseApi) UpdateAgentDingTalkConfig(c *gin.Context) { helper.Success(c) } +// @Tags AI +// @Summary Get Agent Weixin channel config +// @Accept json +// @Param request body dto.AgentIDReq true "request" +// @Success 200 {object} dto.AgentWeixinConfig +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /ai/agents/channel/weixin/get [post] +func (b *BaseApi) GetAgentWeixinConfig(c *gin.Context) { + var req dto.AgentIDReq + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + data, err := agentService.GetWeixinConfig(req) + if err != nil { + helper.BadRequest(c, err) + return + } + helper.SuccessWithData(c, data) +} + // @Tags AI // @Summary Get Agent QQ Bot channel config // @Accept json @@ -905,6 +926,26 @@ func (b *BaseApi) UpdateAgentQQBotConfig(c *gin.Context) { helper.Success(c) } +// @Tags AI +// @Summary Delete Agent channel config +// @Accept json +// @Param request body dto.AgentChannelDeleteReq true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /ai/agents/channel/delete [post] +func (b *BaseApi) DeleteAgentChannelConfig(c *gin.Context) { + var req dto.AgentChannelDeleteReq + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + if err := agentService.DeleteChannelConfig(req); err != nil { + helper.BadRequest(c, err) + return + } + helper.Success(c) +} + // @Tags AI // @Summary Install Agent plugin // @Accept json diff --git a/agent/app/dto/agents.go b/agent/app/dto/agents.go index 56af9e1fd..d73d9a1d7 100644 --- a/agent/app/dto/agents.go +++ b/agent/app/dto/agents.go @@ -376,11 +376,16 @@ type AgentTelegramConfig struct { type AgentChannelPairingApproveReq struct { AgentID uint `json:"agentId" validate:"required"` - Type string `json:"type" validate:"required,oneof=feishu telegram discord wecom qqbot"` + Type string `json:"type" validate:"required,oneof=feishu telegram discord wecom qqbot dingtalk"` PairingCode string `json:"pairingCode" validate:"required"` AccountID string `json:"accountId"` } +type AgentChannelDeleteReq struct { + AgentID uint `json:"agentId" validate:"required"` + Type string `json:"type" validate:"required,oneof=feishu telegram discord wecom qqbot dingtalk weixin"` +} + type AgentWecomConfigUpdateReq struct { AgentID uint `json:"agentId" validate:"required"` Enabled bool `json:"enabled"` @@ -406,7 +411,7 @@ type AgentWecomConfig struct { type AgentDingTalkConfigUpdateReq struct { AgentID uint `json:"agentId" validate:"required"` Enabled bool `json:"enabled"` - DmPolicy string `json:"dmPolicy" validate:"required,oneof=allowlist open disabled"` + DmPolicy string `json:"dmPolicy" validate:"required,oneof=pairing allowlist open disabled"` AllowFrom []string `json:"allowFrom"` GroupPolicy string `json:"groupPolicy" validate:"required,oneof=open allowlist disabled"` GroupAllowFrom []string `json:"groupAllowFrom"` @@ -438,6 +443,10 @@ type AgentWeixinLoginReq struct { TaskID string `json:"taskID" validate:"required"` } +type AgentWeixinConfig struct { + Enabled bool `json:"enabled"` +} + type AgentQQBotConfigUpdateReq struct { AgentID uint `json:"agentId" validate:"required"` Enabled bool `json:"enabled"` diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go index a4c551b0b..a1eecacef 100644 --- a/agent/app/service/agents.go +++ b/agent/app/service/agents.go @@ -86,9 +86,11 @@ type IAgentService interface { UpdateWecomConfig(req dto.AgentWecomConfigUpdateReq) error GetDingTalkConfig(req dto.AgentIDReq) (*dto.AgentDingTalkConfig, error) UpdateDingTalkConfig(req dto.AgentDingTalkConfigUpdateReq) error + GetWeixinConfig(req dto.AgentIDReq) (*dto.AgentWeixinConfig, error) LoginWeixinChannel(req dto.AgentWeixinLoginReq) error GetQQBotConfig(req dto.AgentIDReq) (*dto.AgentQQBotConfig, error) UpdateQQBotConfig(req dto.AgentQQBotConfigUpdateReq) error + DeleteChannelConfig(req dto.AgentChannelDeleteReq) error InstallPlugin(req dto.AgentPluginInstallReq) error UpgradePlugin(req dto.AgentPluginUpgradeReq) error UninstallPlugin(req dto.AgentPluginUninstallReq) error diff --git a/agent/app/service/agents_channels.go b/agent/app/service/agents_channels.go index f0a1ff223..3fe1bb8e4 100644 --- a/agent/app/service/agents_channels.go +++ b/agent/app/service/agents_channels.go @@ -306,6 +306,17 @@ func (a AgentService) GetDingTalkConfig(req dto.AgentIDReq) (*dto.AgentDingTalkC return &result, nil } +func (a AgentService) GetWeixinConfig(req dto.AgentIDReq) (*dto.AgentWeixinConfig, error) { + agent, _, err := a.loadAgentAndInstall(req.AgentID) + if err != nil { + return nil, err + } + if agent.AgentType == constant.AppHermesAgent { + return readHermesWeixinChannelConfig(path.Dir(agent.ConfigPath)) + } + return nil, fmt.Errorf("%s does not support", agent.AgentType) +} + func (a AgentService) UpdateDingTalkConfig(req dto.AgentDingTalkConfigUpdateReq) error { agent, install, err := a.loadAgentAndInstall(req.AgentID) if err != nil { @@ -495,6 +506,36 @@ func (a AgentService) LoginWeixinChannel(req dto.AgentWeixinLoginReq) error { return nil } +func (a AgentService) DeleteChannelConfig(req dto.AgentChannelDeleteReq) error { + agent, install, err := a.loadAgentAndInstall(req.AgentID) + if err != nil { + return err + } + if agent.AgentType != constant.AppHermesAgent { + return fmt.Errorf("%s does not support", agent.AgentType) + } + return updateHermesChannelConfig(agent, install, func(confDir string) error { + switch req.Type { + case "telegram": + return deleteHermesTelegramChannelConfig(confDir) + case "discord": + return deleteHermesDiscordChannelConfig(confDir) + case "qqbot": + return deleteHermesQQBotChannelConfig(confDir) + case "wecom": + return deleteHermesWecomChannelConfig(confDir) + case "dingtalk": + return deleteHermesDingTalkChannelConfig(confDir) + case "feishu": + return deleteHermesFeishuChannelConfig(confDir) + case "weixin": + return deleteHermesWeixinChannelConfig(confDir) + default: + return fmt.Errorf("unsupported channel type: %s", req.Type) + } + }) +} + func (a AgentService) CheckPlugin(req dto.AgentPluginCheckReq) (*dto.AgentPluginStatus, error) { _, install, err := a.loadAgentAndInstall(req.AgentID) if err != nil { @@ -535,14 +576,12 @@ func (a AgentService) ApproveChannelPairing(req dto.AgentChannelPairingApproveRe return err } if agent.AgentType == constant.AppHermesAgent { - output, err := cmd.NewCommandMgr(cmd.WithTimeout(20*time.Second)).RunWithStdout( + mgr := cmd.NewCommandMgr(cmd.WithTimeout(20 * time.Second)) + output, err := mgr.RunWithStdout( "docker", buildHermesDockerExecArgs(install.ContainerName, "pairing", "approve", req.Type, req.PairingCode)..., ) - if err != nil { - return err - } - return validateHermesPairingApproveOutput(output) + return validateHermesPairingApproveResult(output, err) } if req.AccountID != "" { return cmd.RunDefaultBashCf( diff --git a/agent/app/service/agents_hermes.go b/agent/app/service/agents_hermes.go index e50b55ed4..902c70fa3 100644 --- a/agent/app/service/agents_hermes.go +++ b/agent/app/service/agents_hermes.go @@ -326,6 +326,64 @@ func writeHermesDiscordChannelConfig(confDir string, config dto.AgentDiscordConf return writeHermesConfigMap(configPath, cfg) } +func deleteHermesEnvKeys(confDir string, keys ...string) error { + envPath := path.Join(confDir, ".env") + envMap, err := readHermesEnvMap(envPath) + if err != nil { + return err + } + for _, key := range keys { + delete(envMap, key) + } + return writeHermesEnvMap(envPath, envMap, keys) +} + +func deleteHermesConfigSections(confDir string, topLevelKeys []string, platformKeys []string) error { + configPath := path.Join(confDir, "config.yaml") + cfg, err := readHermesConfigMap(configPath) + if err != nil { + return err + } + for _, key := range topLevelKeys { + delete(cfg, key) + } + if len(platformKeys) > 0 { + if platforms, ok := cfg["platforms"].(map[string]interface{}); ok { + for _, key := range platformKeys { + delete(platforms, key) + } + if len(platforms) == 0 { + delete(cfg, "platforms") + } + } + } + return writeHermesConfigMap(configPath, cfg) +} + +func deleteHermesTelegramChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "TELEGRAM_BOT_TOKEN", + "TELEGRAM_ALLOWED_USERS", + "TELEGRAM_ALLOW_ALL_USERS", + "TELEGRAM_HOME_CHANNEL", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, []string{"telegram"}, []string{"telegram"}) +} + +func deleteHermesDiscordChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "DISCORD_BOT_TOKEN", + "DISCORD_ALLOWED_USERS", + "DISCORD_ALLOW_ALL_USERS", + "DISCORD_HOME_CHANNEL", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, []string{"discord"}, []string{"discord"}) +} + func normalizeHermesTimezone(timezone string) string { timezone = strings.TrimSpace(timezone) if timezone == "" { @@ -566,13 +624,21 @@ func extractHermesEnvBool(envMap map[string]string, key string, defaultValue boo return strings.EqualFold(value, "true") } -func validateHermesPairingApproveOutput(output string) error { - text := strings.TrimSpace(output) - if text == "" { +func validateHermesPairingApproveResult(output string, err error) error { + if strings.Contains(output, "Approved!") { return nil } - if strings.Contains(text, "not found or expired for platform") { - return errors.New(text) + if strings.Contains(output, "not found or expired for platform") { + return buserr.New("ErrHermesPairingCodeUnavailable") } - return nil + if err == nil { + if strings.TrimSpace(output) == "" { + return fmt.Errorf("unexpected hermes pairing approve result") + } + return errors.New(strings.TrimSpace(output)) + } + if strings.Contains(err.Error(), "not found or expired for platform") { + return buserr.New("ErrHermesPairingCodeUnavailable") + } + return err } diff --git a/agent/app/service/agents_hermes_channels.go b/agent/app/service/agents_hermes_channels.go index 6b03fc3a8..dde2618f7 100644 --- a/agent/app/service/agents_hermes_channels.go +++ b/agent/app/service/agents_hermes_channels.go @@ -137,6 +137,23 @@ func writeHermesQQBotChannelConfig(confDir string, config dto.AgentQQBotConfig) return writeHermesConfigMap(configPath, cfg) } +func deleteHermesQQBotChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "QQ_APP_ID", + "QQ_CLIENT_SECRET", + "QQ_ALLOW_ALL_USERS", + "QQ_ALLOWED_USERS", + "QQ_HOME_CHANNEL", + "QQ_HOME_CHANNEL_NAME", + "QQ_STT_API_KEY", + "QQ_STT_BASE_URL", + "QQ_STT_MODEL", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, nil, []string{"qq"}) +} + func readHermesWecomChannelConfig(confDir string) (*dto.AgentWecomConfig, error) { envMap, err := readHermesEnvMap(path.Join(confDir, ".env")) if err != nil { @@ -243,6 +260,19 @@ func writeHermesWecomChannelConfig(confDir string, config dto.AgentWecomConfig) return writeHermesConfigMap(configPath, cfg) } +func deleteHermesWecomChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "WECOM_BOT_ID", + "WECOM_SECRET", + "WECOM_ALLOW_ALL_USERS", + "WECOM_ALLOWED_USERS", + "WECOM_HOME_CHANNEL", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, nil, []string{"wecom"}) +} + func readHermesDingTalkChannelConfig(confDir string) (*dto.AgentDingTalkConfig, error) { envMap, err := readHermesEnvMap(path.Join(confDir, ".env")) if err != nil { @@ -254,10 +284,15 @@ func readHermesDingTalkChannelConfig(confDir string) (*dto.AgentDingTalkConfig, } platform := childMap(childMap(cfg, "platforms"), "dingtalk") + extra := childMap(platform, "extra") allowFrom := splitHermesEnvList(envMap["DINGTALK_ALLOWED_USERS"]) - dmPolicy := "open" - if len(allowFrom) > 0 { + dmPolicy := "pairing" + if extractHermesEnvBool(envMap, "DINGTALK_ALLOW_ALL_USERS", false) { + dmPolicy = "open" + } else if len(allowFrom) > 0 { dmPolicy = "allowlist" + } else if extractStringValue(extra["unauthorized_dm_behavior"]) == "ignore" { + dmPolicy = "disabled" } clientID := envMap["DINGTALK_CLIENT_ID"] clientSecret := envMap["DINGTALK_CLIENT_SECRET"] @@ -292,25 +327,29 @@ func writeHermesDingTalkChannelConfig(confDir string, config dto.AgentDingTalkCo return err } clientID, clientSecret := firstHermesDingTalkBotCredentials(config.Bots) - if clientID != "" { + if config.Enabled && clientID != "" { envMap["DINGTALK_CLIENT_ID"] = clientID } else { delete(envMap, "DINGTALK_CLIENT_ID") } - if clientSecret != "" { + if config.Enabled && clientSecret != "" { envMap["DINGTALK_CLIENT_SECRET"] = clientSecret } else { delete(envMap, "DINGTALK_CLIENT_SECRET") } delete(envMap, "DINGTALK_ALLOWED_USERS") + delete(envMap, "DINGTALK_ALLOW_ALL_USERS") if config.DmPolicy == "allowlist" { if allow := joinHermesEnvList(config.AllowFrom); allow != "" { envMap["DINGTALK_ALLOWED_USERS"] = allow } + } else if config.DmPolicy == "open" { + envMap["DINGTALK_ALLOW_ALL_USERS"] = "true" } if err := writeHermesEnvMap(envPath, envMap, []string{ "DINGTALK_CLIENT_ID", "DINGTALK_CLIENT_SECRET", + "DINGTALK_ALLOW_ALL_USERS", "DINGTALK_ALLOWED_USERS", }); err != nil { return err @@ -323,9 +362,31 @@ func writeHermesDingTalkChannelConfig(confDir string, config dto.AgentDingTalkCo } platform := ensureChildMap(ensureChildMap(cfg, "platforms"), "dingtalk") platform["enabled"] = config.Enabled && clientID != "" && clientSecret != "" + extra := ensureChildMap(platform, "extra") + switch config.DmPolicy { + case "pairing": + extra["unauthorized_dm_behavior"] = "pair" + case "disabled": + extra["unauthorized_dm_behavior"] = "ignore" + default: + delete(extra, "unauthorized_dm_behavior") + } return writeHermesConfigMap(configPath, cfg) } +func deleteHermesDingTalkChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "DINGTALK_CLIENT_ID", + "DINGTALK_CLIENT_SECRET", + "DINGTALK_ALLOW_ALL_USERS", + "DINGTALK_ALLOWED_USERS", + "DINGTALK_HOME_CHANNEL", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, nil, []string{"dingtalk"}) +} + func readHermesFeishuChannelConfig(confDir string) (*dto.AgentFeishuConfig, error) { envMap, err := readHermesEnvMap(path.Join(confDir, ".env")) if err != nil { @@ -432,6 +493,52 @@ func writeHermesFeishuChannelConfig(confDir string, config dto.AgentFeishuConfig return writeHermesConfigMap(configPath, cfg) } +func deleteHermesFeishuChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "FEISHU_APP_ID", + "FEISHU_APP_SECRET", + "FEISHU_DOMAIN", + "FEISHU_CONNECTION_MODE", + "FEISHU_ALLOW_ALL_USERS", + "FEISHU_ALLOWED_USERS", + "FEISHU_GROUP_POLICY", + "FEISHU_HOME_CHANNEL", + "FEISHU_VERIFICATION_TOKEN", + "FEISHU_ENCRYPT_KEY", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, nil, []string{"feishu"}) +} + +func readHermesWeixinChannelConfig(confDir string) (*dto.AgentWeixinConfig, error) { + envMap, err := readHermesEnvMap(path.Join(confDir, ".env")) + if err != nil { + return nil, err + } + return &dto.AgentWeixinConfig{ + Enabled: envMap["WEIXIN_ACCOUNT_ID"] != "" || envMap["WEIXIN_TOKEN"] != "", + }, nil +} + +func deleteHermesWeixinChannelConfig(confDir string) error { + if err := deleteHermesEnvKeys(confDir, + "WEIXIN_ACCOUNT_ID", + "WEIXIN_TOKEN", + "WEIXIN_BASE_URL", + "WEIXIN_CDN_BASE_URL", + "WEIXIN_DM_POLICY", + "WEIXIN_ALLOW_ALL_USERS", + "WEIXIN_ALLOWED_USERS", + "WEIXIN_GROUP_POLICY", + "WEIXIN_GROUP_ALLOWED_USERS", + "WEIXIN_HOME_CHANNEL", + ); err != nil { + return err + } + return deleteHermesConfigSections(confDir, nil, []string{"weixin"}) +} + func firstHermesDingTalkBotCredentials(bots []dto.AgentDingTalkBot) (string, string) { for _, bot := range bots { if bot.IsDefault || bot.AccountID == "default" { diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index 7074f506d..3d6c04b5b 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -65,6 +65,7 @@ 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' +ErrHermesPairingCodeUnavailable: 'The pairing code is temporarily unavailable in Hermes, possibly due to network issues. Please try again later.' #backup Localhost: 'Local' diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml index 5b19c222c..11f94a34f 100644 --- a/agent/i18n/lang/es-ES.yaml +++ b/agent/i18n/lang/es-ES.yaml @@ -60,6 +60,7 @@ 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' +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.' Localhost: 'Máquina local' ErrBackupInUsed: 'Cuenta de respaldo en uso por tarea programada' ErrBackupCheck: 'Conexión de respaldo falló: {{ .err }}' diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 98f051448..8f130061b 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'このエージェントはすでにサイトに関連付 ErrAgentWebsiteTypeUnsupported: '関連付けできるのはプロキシサイトまたは静的サイトのみです' ErrAgentWebsiteInUse: 'このサイトはすでに別のエージェントに関連付けられています' ErrAgentWebsiteUnbindUnsupported: 'ワンクリックデプロイのサイトは手動で関連解除できません' +ErrHermesPairingCodeUnavailable: 'Hermes でペアリングコードが一時的に見つかりません。ネットワーク要因の可能性があるため、しばらくしてから再試行してください。' Localhost: 'ローカルマシン' ErrBackupInUsed: 'バックアップアカウントがスケジュールで使用中' ErrBackupCheck: '接続テストに失敗しました: {{ .err }}' diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index 61ceaa98a..caafa8510 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -60,6 +60,7 @@ ErrAgentWebsiteBound: '이 에이전트는 이미 웹사이트에 연결되어 ErrAgentWebsiteTypeUnsupported: '프록시 또는 정적 웹사이트만 연결할 수 있습니다' ErrAgentWebsiteInUse: '이 웹사이트는 이미 다른 에이전트에 연결되어 있습니다' ErrAgentWebsiteUnbindUnsupported: '원클릭 배포 웹사이트는 수동으로 연결 해제할 수 없습니다' +ErrHermesPairingCodeUnavailable: 'Hermes에서 페어링 코드가 일시적으로 존재하지 않습니다. 네트워크 문제일 수 있으니 잠시 후 다시 시도해 주세요.' Localhost: '로컬 머신' ErrBackupInUsed: '백업 계정이 예약에 사용 중' ErrBackupCheck: '연결 테스트 실패: {{ .err }}' diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index d925a1d8b..55b3c03a1 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -60,6 +60,7 @@ 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' +ErrHermesPairingCodeUnavailable: 'Kod pasangan buat sementara waktu tidak wujud dalam Hermes, mungkin disebabkan masalah rangkaian. Sila cuba lagi sebentar nanti.' Localhost: 'Mesin Tempatan' ErrBackupInUsed: 'Akaun sandaran sedang digunakan oleh tugas' ErrBackupCheck: 'Ujian sambungan gagal: {{ .err }}' diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 453471362..af1e0cf4b 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -60,6 +60,7 @@ 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' +ErrHermesPairingCodeUnavailable: 'O código de pareamento está temporariamente indisponível no Hermes, possivelmente por causa de rede. Tente novamente mais tarde.' Localhost: 'Máquina Local' ErrBackupInUsed: 'Conta de backup em uso por tarefa' ErrBackupCheck: 'Teste de conexão falhou: {{ .err }}' diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 32ff57aec..9f9dc266d 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'Этот агент уже связан с сайтом' ErrAgentWebsiteTypeUnsupported: 'Можно связывать только proxy- или static-сайты' ErrAgentWebsiteInUse: 'Этот сайт уже связан с другим агентом' ErrAgentWebsiteUnbindUnsupported: 'Сайты one-click deployment нельзя отвязать вручную' +ErrHermesPairingCodeUnavailable: 'Код сопряжения временно недоступен в Hermes, возможно из-за проблем с сетью. Повторите попытку позже.' Localhost: 'Локальная машина' ErrBackupInUsed: 'Аккаунт бэкапа занят задачей' ErrBackupCheck: 'Проверка подключения не удалась: {{ .err }}' diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index 04fe9cb99..a2bfd83fa 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -60,6 +60,7 @@ 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' +ErrHermesPairingCodeUnavailable: 'Eşleştirme kodu Hermes içinde geçici olarak bulunamıyor; bu durum ağ kaynaklı olabilir. Lütfen daha sonra tekrar deneyin.' Localhost: 'Yerel Makine' ErrBackupInUsed: 'Yedek hesabı görevde kullanılıyor' ErrBackupCheck: 'Bağlantı testi başarısız: {{ .err }}' diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index 371244a8c..0b11e1a28 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -60,6 +60,7 @@ ErrAgentWebsiteBound: '該智能體已關聯網站' ErrAgentWebsiteTypeUnsupported: '只能關聯反向代理或靜態網站' ErrAgentWebsiteInUse: '該網站已被其他智能體關聯' ErrAgentWebsiteUnbindUnsupported: '一鍵部署網站不支援手動解綁' +ErrHermesPairingCodeUnavailable: '配對碼在 Hermes 中暫時不存在,可能是由於網路原因,請稍後再試' Localhost: '本機' ErrBackupInUsed: '此備份帳號已在排程任務中使用,無法刪除' ErrBackupCheck: '備份帳號測試連線失敗{{ .err }}' diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 850bea827..acf1450da 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -65,6 +65,7 @@ ErrAgentWebsiteBound: "该智能体已关联网站" ErrAgentWebsiteTypeUnsupported: "只能关联反向代理或静态网站" ErrAgentWebsiteInUse: "该网站已被其他智能体关联" ErrAgentWebsiteUnbindUnsupported: "一键部署网站不支持手动解绑" +ErrHermesPairingCodeUnavailable: "配对码在 hermes 中暂时不存在,可能是由于网络原因,请稍后尝试" #backup Localhost: '本机' diff --git a/agent/router/ro_ai.go b/agent/router/ro_ai.go index a33f3e19e..1304f9b7e 100644 --- a/agent/router/ro_ai.go +++ b/agent/router/ro_ai.go @@ -82,9 +82,11 @@ func (a *AIToolsRouter) InitRouter(Router *gin.RouterGroup) { aiToolsRouter.POST("/agents/channel/wecom/update", baseApi.UpdateAgentWecomConfig) aiToolsRouter.POST("/agents/channel/dingtalk/get", baseApi.GetAgentDingTalkConfig) aiToolsRouter.POST("/agents/channel/dingtalk/update", baseApi.UpdateAgentDingTalkConfig) + aiToolsRouter.POST("/agents/channel/weixin/get", baseApi.GetAgentWeixinConfig) aiToolsRouter.POST("/agents/channel/weixin/login", baseApi.LoginAgentWeixinChannel) aiToolsRouter.POST("/agents/channel/qqbot/get", baseApi.GetAgentQQBotConfig) aiToolsRouter.POST("/agents/channel/qqbot/update", baseApi.UpdateAgentQQBotConfig) + aiToolsRouter.POST("/agents/channel/delete", baseApi.DeleteAgentChannelConfig) aiToolsRouter.POST("/agents/plugin/install", baseApi.InstallAgentPlugin) aiToolsRouter.POST("/agents/plugin/upgrade", baseApi.UpgradeAgentPlugin) aiToolsRouter.POST("/agents/plugin/uninstall", baseApi.UninstallAgentPlugin) diff --git a/frontend/src/api/interface/ai.ts b/frontend/src/api/interface/ai.ts index 821134855..f0ddec8ac 100644 --- a/frontend/src/api/interface/ai.ts +++ b/frontend/src/api/interface/ai.ts @@ -626,7 +626,7 @@ export namespace AI { export interface AgentChannelPairingApproveReq { agentId: number; - type: 'feishu' | 'telegram' | 'discord' | 'wecom' | 'qqbot'; + type: 'feishu' | 'telegram' | 'discord' | 'wecom' | 'qqbot' | 'dingtalk'; pairingCode: string; accountId?: string; } @@ -670,7 +670,7 @@ export namespace AI { export interface AgentDingTalkConfig { enabled: boolean; - dmPolicy: 'allowlist' | 'open' | 'disabled'; + dmPolicy: 'pairing' | 'allowlist' | 'open' | 'disabled'; allowFrom: string[]; groupPolicy: 'open' | 'allowlist' | 'disabled'; groupAllowFrom: string[]; @@ -686,7 +686,7 @@ export namespace AI { export interface AgentDingTalkConfigUpdateReq { agentId: number; enabled: boolean; - dmPolicy: 'allowlist' | 'open' | 'disabled'; + dmPolicy: 'pairing' | 'allowlist' | 'open' | 'disabled'; allowFrom: string[]; groupPolicy: 'open' | 'allowlist' | 'disabled'; groupAllowFrom: string[]; @@ -703,6 +703,15 @@ export namespace AI { taskID: string; } + export interface AgentWeixinConfig { + enabled: boolean; + } + + export interface AgentChannelDeleteReq { + agentId: number; + type: 'feishu' | 'telegram' | 'discord' | 'wecom' | 'qqbot' | 'dingtalk' | 'weixin'; + } + export interface AgentQQBotConfigReq { agentId: number; } diff --git a/frontend/src/api/modules/ai.ts b/frontend/src/api/modules/ai.ts index e1bda0810..af6505cbd 100644 --- a/frontend/src/api/modules/ai.ts +++ b/frontend/src/api/modules/ai.ts @@ -262,6 +262,10 @@ export const updateAgentDingTalkConfig = (req: AI.AgentDingTalkConfigUpdateReq) return http.post(`/ai/agents/channel/dingtalk/update`, req); }; +export const getAgentWeixinConfig = (req: AI.AgentIDReq) => { + return http.post(`/ai/agents/channel/weixin/get`, req); +}; + export const loginAgentWeixinChannel = (req: AI.AgentWeixinLoginReq) => { return http.post(`/ai/agents/channel/weixin/login`, req); }; @@ -274,6 +278,10 @@ export const updateAgentQQBotConfig = (req: AI.AgentQQBotConfigUpdateReq) => { return http.post(`/ai/agents/channel/qqbot/update`, req); }; +export const deleteAgentChannelConfig = (req: AI.AgentChannelDeleteReq) => { + return http.post(`/ai/agents/channel/delete`, req); +}; + export const installAgentPlugin = (req: AI.AgentPluginInstallReq) => { return http.post(`/ai/agents/plugin/install`, req); }; diff --git a/frontend/src/components/log/task/index.vue b/frontend/src/components/log/task/index.vue index 7dc084f80..91e5bb564 100644 --- a/frontend/src/components/log/task/index.vue +++ b/frontend/src/components/log/task/index.vue @@ -1,5 +1,5 @@