Skip to content

Commit 2cb2058

Browse files
feat: support edit config file (#12313)
1 parent 8533dd1 commit 2cb2058

19 files changed

Lines changed: 233 additions & 0 deletions

File tree

agent/app/api/v2/agents.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,47 @@ func (b *BaseApi) UpdateAgentOtherConfig(c *gin.Context) {
680680
helper.Success(c)
681681
}
682682

683+
// @Tags AI
684+
// @Summary Get Agent config file
685+
// @Accept json
686+
// @Param request body dto.AgentConfigFileReq true "request"
687+
// @Success 200 {object} dto.AgentConfigFile
688+
// @Security ApiKeyAuth
689+
// @Security Timestamp
690+
// @Router /ai/agents/config-file/get [post]
691+
func (b *BaseApi) GetAgentConfigFile(c *gin.Context) {
692+
var req dto.AgentConfigFileReq
693+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
694+
return
695+
}
696+
data, err := agentService.GetConfigFile(req)
697+
if err != nil {
698+
helper.BadRequest(c, err)
699+
return
700+
}
701+
helper.SuccessWithData(c, data)
702+
}
703+
704+
// @Tags AI
705+
// @Summary Update Agent config file
706+
// @Accept json
707+
// @Param request body dto.AgentConfigFileUpdateReq true "request"
708+
// @Success 200
709+
// @Security ApiKeyAuth
710+
// @Security Timestamp
711+
// @Router /ai/agents/config-file/update [post]
712+
func (b *BaseApi) UpdateAgentConfigFile(c *gin.Context) {
713+
var req dto.AgentConfigFileUpdateReq
714+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
715+
return
716+
}
717+
if err := agentService.UpdateConfigFile(req); err != nil {
718+
helper.BadRequest(c, err)
719+
return
720+
}
721+
helper.Success(c)
722+
}
723+
683724
// @Tags AI
684725
// @Summary List Agent skills
685726
// @Accept json

agent/app/dto/agents.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,19 @@ type AgentOtherConfig struct {
354354
NPMRegistry string `json:"npmRegistry"`
355355
}
356356

357+
type AgentConfigFileReq struct {
358+
AgentID uint `json:"agentId" validate:"required"`
359+
}
360+
361+
type AgentConfigFileUpdateReq struct {
362+
AgentID uint `json:"agentId" validate:"required"`
363+
Content string `json:"content" validate:"required"`
364+
}
365+
366+
type AgentConfigFile struct {
367+
Content string `json:"content"`
368+
}
369+
357370
type AgentSkillsReq struct {
358371
AgentID uint `json:"agentId" validate:"required"`
359372
}

agent/app/service/agents.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"os"
78
"path"
89
"sort"
910
"strings"
@@ -33,6 +34,8 @@ type IAgentService interface {
3334
UpdateSecurityConfig(req dto.AgentSecurityConfigUpdateReq) error
3435
GetOtherConfig(req dto.AgentOtherConfigReq) (*dto.AgentOtherConfig, error)
3536
UpdateOtherConfig(req dto.AgentOtherConfigUpdateReq) error
37+
GetConfigFile(req dto.AgentConfigFileReq) (*dto.AgentConfigFile, error)
38+
UpdateConfigFile(req dto.AgentConfigFileUpdateReq) error
3639
ListSkills(req dto.AgentSkillsReq) ([]dto.AgentSkillItem, error)
3740
UpdateSkill(req dto.AgentSkillUpdateReq) error
3841

@@ -717,6 +720,46 @@ func (a AgentService) UpdateOtherConfig(req dto.AgentOtherConfigUpdateReq) error
717720
return setOpenclawNPMRegistry(install.ContainerName, req.NPMRegistry)
718721
}
719722

723+
func (a AgentService) GetConfigFile(req dto.AgentConfigFileReq) (*dto.AgentConfigFile, error) {
724+
agent, _, err := a.loadAgentAndInstall(req.AgentID)
725+
if err != nil {
726+
return nil, err
727+
}
728+
if agent.AgentType == constant.AppCopaw {
729+
return nil, fmt.Errorf("copaw does not support config file")
730+
}
731+
content, err := os.ReadFile(agent.ConfigPath)
732+
if err != nil {
733+
return nil, err
734+
}
735+
return &dto.AgentConfigFile{Content: string(content)}, nil
736+
}
737+
738+
func (a AgentService) UpdateConfigFile(req dto.AgentConfigFileUpdateReq) error {
739+
agent, install, err := a.loadAgentAndInstall(req.AgentID)
740+
if err != nil {
741+
return err
742+
}
743+
if agent.AgentType == constant.AppCopaw {
744+
return fmt.Errorf("copaw does not support config file")
745+
}
746+
var payload interface{}
747+
if err := json.Unmarshal([]byte(req.Content), &payload); err != nil {
748+
return err
749+
}
750+
info, err := os.Stat(agent.ConfigPath)
751+
if err != nil {
752+
return err
753+
}
754+
if err := os.WriteFile(agent.ConfigPath, []byte(req.Content), info.Mode()); err != nil {
755+
return err
756+
}
757+
return NewIAppInstalledService().Operate(request.AppInstalledOperate{
758+
InstallId: install.ID,
759+
Operate: constant.Restart,
760+
})
761+
}
762+
720763
func getOpenclawNPMRegistry(containerName string) (string, error) {
721764
registry, err := cmd.RunDefaultWithStdoutBashCfAndTimeOut("docker exec %s npm get registry", 20*time.Second, containerName)
722765
if err != nil {

agent/app/service/agents_channels.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,13 +540,15 @@ func setDingTalkConfig(conf map[string]interface{}, config dto.AgentDingTalkConf
540540
func setQQBotConfig(conf map[string]interface{}, config dto.AgentQQBotConfig) {
541541
channels := ensureChildMap(conf, "channels")
542542
qqbot := ensureChildMap(channels, "qqbot")
543+
delete(qqbot, "dmPolicy")
543544
qqbot["enabled"] = config.Enabled
544545
qqbot["allowFrom"] = []string{"*"}
545546
qqbot["appId"] = strings.TrimSpace(config.AppID)
546547
qqbot["clientSecret"] = strings.TrimSpace(config.ClientSecret)
547548

548549
plugins := ensureChildMap(conf, "plugins")
549550
entries := ensureChildMap(plugins, "entries")
551+
delete(entries, "qqbot")
550552
qqbotEntry := ensureChildMap(entries, "openclaw-qqbot")
551553
qqbotEntry["enabled"] = config.Enabled
552554
}

agent/router/ro_ai.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ func (a *AIToolsRouter) InitRouter(Router *gin.RouterGroup) {
7474
aiToolsRouter.POST("/agents/security/update", baseApi.UpdateAgentSecurityConfig)
7575
aiToolsRouter.POST("/agents/other/get", baseApi.GetAgentOtherConfig)
7676
aiToolsRouter.POST("/agents/other/update", baseApi.UpdateAgentOtherConfig)
77+
aiToolsRouter.POST("/agents/config-file/get", baseApi.GetAgentConfigFile)
78+
aiToolsRouter.POST("/agents/config-file/update", baseApi.UpdateAgentConfigFile)
7779
aiToolsRouter.POST("/agents/skills/list", baseApi.ListAgentSkills)
7880
aiToolsRouter.POST("/agents/skills/update", baseApi.UpdateAgentSkill)
7981
aiToolsRouter.POST("/agents/channel/pairing/approve", baseApi.ApproveAgentChannelPairing)

frontend/src/api/interface/ai.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,19 @@ export namespace AI {
588588
npmRegistry: string;
589589
}
590590

591+
export interface AgentConfigFileReq {
592+
agentId: number;
593+
}
594+
595+
export interface AgentConfigFile {
596+
content: string;
597+
}
598+
599+
export interface AgentConfigFileUpdateReq {
600+
agentId: number;
601+
content: string;
602+
}
603+
591604
export interface AgentSkillsReq {
592605
agentId: number;
593606
}

frontend/src/api/modules/ai.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ export const updateAgentOtherConfig = (req: AI.AgentOtherConfigUpdateReq) => {
229229
return http.post(`/ai/agents/other/update`, req);
230230
};
231231

232+
export const getAgentConfigFile = (req: AI.AgentConfigFileReq) => {
233+
return http.post<AI.AgentConfigFile>(`/ai/agents/config-file/get`, req);
234+
};
235+
236+
export const updateAgentConfigFile = (req: AI.AgentConfigFileUpdateReq) => {
237+
return http.post(`/ai/agents/config-file/update`, req);
238+
};
239+
232240
export const listAgentSkills = (req: AI.AgentSkillsReq) => {
233241
return http.post<AI.AgentSkillItem[]>(`/ai/agents/skills/list`, req);
234242
};

frontend/src/lang/modules/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,8 @@ const message = {
715715
skillsGroupWorkspace: 'Workspace',
716716
switchModelSuccess: 'Model switched successfully',
717717
channelsTab: 'Channels',
718+
configFileRestartHelper:
719+
'Saving the config file requires immediately restarting the container to take effect.',
718720
weixin: 'Weixin',
719721
wecom: 'WeCom',
720722
dingtalk: 'DingTalk',

frontend/src/lang/modules/es-es.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,8 @@ const message = {
723723
skillsGroupWorkspace: 'Workspace',
724724
switchModelSuccess: 'Model switched successfully',
725725
channelsTab: 'Channels',
726+
configFileRestartHelper:
727+
'Saving the config file requires immediately restarting the container to take effect.',
726728
weixin: 'Weixin',
727729
wecom: 'WeCom',
728730
dingtalk: 'DingTalk',

frontend/src/lang/modules/ja.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,8 @@ const message = {
716716
skillsGroupWorkspace: 'Workspace',
717717
switchModelSuccess: 'Model switched successfully',
718718
channelsTab: 'Channels',
719+
configFileRestartHelper:
720+
'Saving the config file requires immediately restarting the container to take effect.',
719721
weixin: 'Weixin',
720722
wecom: 'WeCom',
721723
dingtalk: 'DingTalk',

0 commit comments

Comments
 (0)