mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-29 14:10:50 +02:00
feat: persist hitl default config
This commit is contained in:
@@ -315,12 +315,13 @@ func (h *AgentHandler) SetHitlToolWhitelistSaver(s HitlToolWhitelistSaver) {
|
||||
h.hitlWhitelistSaver = s
|
||||
}
|
||||
|
||||
// HitlDefaultReviewerSaver 持久化全局默认审批方到 config.yaml。
|
||||
// HitlDefaultReviewerSaver 持久化全局默认人机协同配置到 config.yaml。
|
||||
type HitlDefaultReviewerSaver interface {
|
||||
UpdateHitlDefaultConfig(mode, reviewer string, timeoutSeconds int) error
|
||||
UpdateHitlDefaultReviewer(reviewer string) error
|
||||
}
|
||||
|
||||
// SetHitlDefaultReviewerSaver 设置 HITL 默认审批方落盘。
|
||||
// SetHitlDefaultReviewerSaver 设置 HITL 默认配置落盘。
|
||||
func (h *AgentHandler) SetHitlDefaultReviewerSaver(s HitlDefaultReviewerSaver) {
|
||||
h.hitlDefaultReviewerSaver = s
|
||||
}
|
||||
@@ -332,6 +333,35 @@ func (h *AgentHandler) hitlEffectiveDefaultReviewer() string {
|
||||
return "human"
|
||||
}
|
||||
|
||||
func (h *AgentHandler) hitlEffectiveDefaultMode() string {
|
||||
if h != nil && h.config != nil {
|
||||
return normalizeHitlDefaultMode(h.config.Hitl.EffectiveDefaultMode())
|
||||
}
|
||||
return "off"
|
||||
}
|
||||
|
||||
func (h *AgentHandler) hitlEffectiveDefaultTimeoutSeconds() int {
|
||||
if h != nil && h.config != nil {
|
||||
timeout := h.config.Hitl.EffectiveDefaultTimeoutSeconds()
|
||||
if timeout < 0 {
|
||||
return 0
|
||||
}
|
||||
return timeout
|
||||
}
|
||||
return 300
|
||||
}
|
||||
|
||||
func (h *AgentHandler) hitlEffectiveDefaultRequest() *HITLRequest {
|
||||
mode := h.hitlEffectiveDefaultMode()
|
||||
return &HITLRequest{
|
||||
Enabled: mode != "off",
|
||||
Mode: mode,
|
||||
Reviewer: h.hitlEffectiveDefaultReviewer(),
|
||||
SensitiveTools: []string{},
|
||||
TimeoutSeconds: h.hitlEffectiveDefaultTimeoutSeconds(),
|
||||
}
|
||||
}
|
||||
|
||||
// HITLNeedsToolApproval 供 C2 危险任务门控:与会话侧人机协同及免审批白名单判定一致。
|
||||
func (h *AgentHandler) HITLNeedsToolApproval(conversationID, toolName string) bool {
|
||||
if h == nil || h.hitlManager == nil {
|
||||
|
||||
@@ -891,7 +891,14 @@ func (h *ConfigHandler) UpdateConfig(c *gin.Context) {
|
||||
if req.Hitl != nil {
|
||||
h.config.Hitl.AuditModel = req.Hitl.AuditModel
|
||||
h.config.Hitl.ToolWhitelist = mergeHitlToolWhitelistSlice(nil, req.Hitl.ToolWhitelist)
|
||||
if strings.TrimSpace(req.Hitl.DefaultMode) != "" {
|
||||
h.config.Hitl.DefaultMode = req.Hitl.EffectiveDefaultMode()
|
||||
}
|
||||
h.config.Hitl.DefaultReviewer = req.Hitl.EffectiveDefaultReviewer()
|
||||
if req.Hitl.DefaultTimeoutSeconds != nil {
|
||||
v := req.Hitl.EffectiveDefaultTimeoutSeconds()
|
||||
h.config.Hitl.DefaultTimeoutSeconds = &v
|
||||
}
|
||||
h.config.Hitl.AuditAgentPrompt = strings.TrimSpace(req.Hitl.AuditAgentPrompt)
|
||||
h.config.Hitl.AuditAgentPromptReviewEdit = strings.TrimSpace(req.Hitl.AuditAgentPromptReviewEdit)
|
||||
if req.Hitl.RetentionDays != nil {
|
||||
@@ -2141,12 +2148,35 @@ func updateHitlConfig(doc *yaml.Node, cfg config.HitlConfig) {
|
||||
setStringInMap(auditModelNode, "model", cfg.AuditModel.Model)
|
||||
// flow 样式 [a, b, c] 单行展示,工具多时比块序列省行数
|
||||
setFlowStringSliceInMap(hitlNode, "tool_whitelist", cfg.ToolWhitelist)
|
||||
setStringInMap(hitlNode, "default_mode", cfg.EffectiveDefaultMode())
|
||||
setStringInMap(hitlNode, "default_reviewer", cfg.EffectiveDefaultReviewer())
|
||||
setIntInMap(hitlNode, "default_timeout_seconds", cfg.EffectiveDefaultTimeoutSeconds())
|
||||
setIntInMap(hitlNode, "retention_days", cfg.RetentionDaysEffective())
|
||||
setStringInMap(hitlNode, "audit_agent_prompt", cfg.AuditAgentPrompt)
|
||||
setStringInMap(hitlNode, "audit_agent_prompt_review_edit", cfg.AuditAgentPromptReviewEdit)
|
||||
}
|
||||
|
||||
// UpdateHitlDefaultConfig 更新全局默认人机协同配置并写入 config.yaml。
|
||||
func (h *ConfigHandler) UpdateHitlDefaultConfig(mode, reviewer string, timeoutSeconds int) error {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.config.Hitl.DefaultMode = config.HitlConfig{DefaultMode: mode}.EffectiveDefaultMode()
|
||||
h.config.Hitl.DefaultReviewer = config.HitlConfig{DefaultReviewer: reviewer}.EffectiveDefaultReviewer()
|
||||
if timeoutSeconds < 0 {
|
||||
timeoutSeconds = 0
|
||||
}
|
||||
h.config.Hitl.DefaultTimeoutSeconds = &timeoutSeconds
|
||||
if err := h.saveConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.logger.Info("HITL 全局默认配置已写入配置文件",
|
||||
zap.String("default_mode", h.config.Hitl.DefaultMode),
|
||||
zap.String("default_reviewer", h.config.Hitl.DefaultReviewer),
|
||||
zap.Int("default_timeout_seconds", timeoutSeconds),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateHitlDefaultReviewer 更新全局默认审批方并写入 config.yaml。
|
||||
func (h *ConfigHandler) UpdateHitlDefaultReviewer(reviewer string) error {
|
||||
h.mu.Lock()
|
||||
|
||||
@@ -289,6 +289,18 @@ func normalizeHitlMode(mode string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeHitlDefaultMode(mode string) string {
|
||||
v := strings.ToLower(strings.TrimSpace(mode))
|
||||
switch v {
|
||||
case "feedback", "followup":
|
||||
return "approval"
|
||||
case "approval", "review_edit":
|
||||
return v
|
||||
default:
|
||||
return "off"
|
||||
}
|
||||
}
|
||||
|
||||
func (m *HITLManager) ActivateConversation(conversationID string, req *HITLRequest) {
|
||||
if req == nil || !req.Enabled {
|
||||
m.DeactivateConversation(conversationID)
|
||||
@@ -629,7 +641,7 @@ func (h *AgentHandler) loadHITLConversationConfig(conversationID string) (*HITLR
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
cfg.Reviewer = h.hitlEffectiveDefaultReviewer()
|
||||
return h.hitlEffectiveDefaultRequest(), nil
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -994,7 +1006,9 @@ func (h *AgentHandler) GetHITLConversationConfig(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"conversationId": conversationID,
|
||||
"hitl": cfg,
|
||||
"defaultMode": h.hitlEffectiveDefaultMode(),
|
||||
"defaultReviewer": h.hitlEffectiveDefaultReviewer(),
|
||||
"defaultTimeoutSeconds": h.hitlEffectiveDefaultTimeoutSeconds(),
|
||||
"hitlGlobalToolWhitelist": h.hitlConfigGlobalToolWhitelist(),
|
||||
})
|
||||
}
|
||||
@@ -1051,11 +1065,64 @@ type setHitlDefaultReviewerReq struct {
|
||||
Reviewer string `json:"reviewer"`
|
||||
}
|
||||
|
||||
type setHitlDefaultConfigReq struct {
|
||||
Mode string `json:"mode"`
|
||||
Reviewer string `json:"reviewer"`
|
||||
TimeoutSeconds int `json:"timeoutSeconds"`
|
||||
}
|
||||
|
||||
func (h *AgentHandler) hitlDefaultConfigResponse() gin.H {
|
||||
return gin.H{
|
||||
"defaultMode": h.hitlEffectiveDefaultMode(),
|
||||
"defaultReviewer": h.hitlEffectiveDefaultReviewer(),
|
||||
"defaultTimeoutSeconds": h.hitlEffectiveDefaultTimeoutSeconds(),
|
||||
"hitlGlobalToolWhitelist": h.hitlConfigGlobalToolWhitelist(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetHITLDefaultConfig 返回 config.yaml 中的全局默认人机协同配置。
|
||||
func (h *AgentHandler) GetHITLDefaultConfig(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, h.hitlDefaultConfigResponse())
|
||||
}
|
||||
|
||||
// UpdateHITLDefaultConfig 将全局默认人机协同配置写入 config.yaml。
|
||||
func (h *AgentHandler) UpdateHITLDefaultConfig(c *gin.Context) {
|
||||
if h.hitlDefaultReviewerSaver == nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "HITL 配置持久化不可用"})
|
||||
return
|
||||
}
|
||||
var req setHitlDefaultConfigReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
mode := normalizeHitlDefaultMode(req.Mode)
|
||||
reviewer := normalizeHitlReviewer(req.Reviewer)
|
||||
timeoutSeconds := req.TimeoutSeconds
|
||||
if timeoutSeconds < 0 {
|
||||
timeoutSeconds = 0
|
||||
}
|
||||
if err := h.hitlDefaultReviewerSaver.UpdateHitlDefaultConfig(mode, reviewer, timeoutSeconds); err != nil {
|
||||
h.logger.Warn("写入 HITL 默认配置到 config.yaml 失败", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if h.config != nil {
|
||||
h.config.Hitl.DefaultMode = mode
|
||||
h.config.Hitl.DefaultReviewer = reviewer
|
||||
h.config.Hitl.DefaultTimeoutSeconds = &timeoutSeconds
|
||||
}
|
||||
if h.audit != nil {
|
||||
h.audit.RecordOK(c, "hitl", "default_config_update", "HITL 全局默认配置更新", "hitl_config", "default", nil)
|
||||
}
|
||||
out := h.hitlDefaultConfigResponse()
|
||||
out["ok"] = true
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
// GetHITLDefaultReviewer 返回 config.yaml 中的全局默认审批方。
|
||||
func (h *AgentHandler) GetHITLDefaultReviewer(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"defaultReviewer": h.hitlEffectiveDefaultReviewer(),
|
||||
})
|
||||
c.JSON(http.StatusOK, h.hitlDefaultConfigResponse())
|
||||
}
|
||||
|
||||
// UpdateHITLDefaultReviewer 将全局默认审批方写入 config.yaml(未选会话时切换审批方)。
|
||||
@@ -1081,10 +1148,9 @@ func (h *AgentHandler) UpdateHITLDefaultReviewer(c *gin.Context) {
|
||||
if h.audit != nil {
|
||||
h.audit.RecordOK(c, "hitl", "default_reviewer_update", "HITL 全局默认审批方更新", "hitl_config", "default_reviewer", nil)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"ok": true,
|
||||
"defaultReviewer": reviewer,
|
||||
})
|
||||
out := h.hitlDefaultConfigResponse()
|
||||
out["ok"] = true
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
// SetHITLGlobalToolWhitelist 整表替换 config.yaml 中的全局免审批工具白名单。
|
||||
|
||||
Reference in New Issue
Block a user