Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions agent/app/api/v2/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 11 additions & 2 deletions agent/app/dto/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -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"`
Expand Down Expand Up @@ -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"`
Expand Down
2 changes: 2 additions & 0 deletions agent/app/service/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 44 additions & 5 deletions agent/app/service/agents_channels.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down
78 changes: 72 additions & 6 deletions agent/app/service/agents_hermes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 == "" {
Expand Down Expand Up @@ -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")
}
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 nil
return err
}
Loading
Loading