- Agent CLI: 多轮对话、SSH 长连接、流式推理、Evolver 按用户隔离、历史侧栏 - 终端审计: 回放播放器、命令书签、筛选分页导出、命令输出统计、录制落盘修复 - 修复 session_commands 表迁移、Kill 竞态导致录制丢失、无录制会话回放提示 - 审计历史页只读(移除删除),移除回放弹框录制搜索
181 lines
4.4 KiB
Go
181 lines
4.4 KiB
Go
// Package tools 提供 Agent CLI 引擎的工具注册中心与工具接口。 // Logan.Li
|
||
// 设计参考 opsxcli/internal/agent/tools,剥离 CLI 专属工具(local_bash 本地执行、scp)。
|
||
// Web 版聚焦远程运维:ssh_execute(目标主机执行)+ analyze_output(输出分析)。
|
||
// 风险评估逻辑(黑名单 + AssessBashRisk)置于本包,避免与 safety 包形成循环依赖。
|
||
package tools
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"sync"
|
||
|
||
"ezops/pkg/agentcli/llm"
|
||
)
|
||
|
||
// RiskLevel 工具风险等级 // Logan.Li
|
||
type RiskLevel int
|
||
|
||
const (
|
||
RiskSafe RiskLevel = iota // 只读操作(cat/grep/df/ps)
|
||
RiskLow // 低风险(mkdir/touch)
|
||
RiskMedium // 中风险(chmod/文件修改)
|
||
RiskHigh // 高风险(远程服务控制/reboot)
|
||
RiskCritical // 危险操作(rm -rf //mkfs/dd)
|
||
)
|
||
|
||
// String 返回风险等级字符串 // Logan.Li
|
||
func (r RiskLevel) String() string {
|
||
switch r {
|
||
case RiskSafe:
|
||
return "safe"
|
||
case RiskLow:
|
||
return "low"
|
||
case RiskMedium:
|
||
return "medium"
|
||
case RiskHigh:
|
||
return "high"
|
||
case RiskCritical:
|
||
return "critical"
|
||
default:
|
||
return "unknown"
|
||
}
|
||
}
|
||
|
||
// Display 返回风险等级中文显示 // Logan.Li
|
||
func (r RiskLevel) Display() string {
|
||
switch r {
|
||
case RiskSafe:
|
||
return "安全"
|
||
case RiskLow:
|
||
return "低风险"
|
||
case RiskMedium:
|
||
return "中风险"
|
||
case RiskHigh:
|
||
return "高风险"
|
||
case RiskCritical:
|
||
return "危险"
|
||
default:
|
||
return "未知"
|
||
}
|
||
}
|
||
|
||
// Result 工具执行结果 // Logan.Li
|
||
type Result struct {
|
||
Success bool `json:"success"`
|
||
Output string `json:"output"`
|
||
Error string `json:"error,omitempty"`
|
||
}
|
||
|
||
// Tool 核心工具接口(5 方法) // Logan.Li
|
||
type Tool interface {
|
||
Name() string // 工具名
|
||
Description() string // 给 LLM 看的描述
|
||
Parameters() map[string]interface{} // JSON Schema 参数定义
|
||
RiskLevel() RiskLevel // 静态风险等级
|
||
Execute(ctx context.Context, args map[string]interface{}) (*Result, error)
|
||
}
|
||
|
||
// DynamicRiskTool 动态风险评估接口 // Logan.Li
|
||
// 工具可额外实现此接口,依据运行时参数动态计算风险(如 ssh_execute 看具体命令)。
|
||
// 安全控制器 Check 时优先调用此接口。
|
||
type DynamicRiskTool interface {
|
||
Tool
|
||
RiskLevelForArgs(args map[string]interface{}) RiskLevel
|
||
}
|
||
|
||
// Registry 工具注册中心(线程安全) // Logan.Li
|
||
type Registry struct {
|
||
tools map[string]Tool
|
||
mu sync.RWMutex
|
||
}
|
||
|
||
// NewRegistry 创建空注册中心 // Logan.Li
|
||
func NewRegistry() *Registry {
|
||
return &Registry{tools: make(map[string]Tool)}
|
||
}
|
||
|
||
// Register 注册工具 // Logan.Li
|
||
func (r *Registry) Register(tool Tool) {
|
||
r.mu.Lock()
|
||
defer r.mu.Unlock()
|
||
r.tools[tool.Name()] = tool
|
||
}
|
||
|
||
// Get 按名获取工具 // Logan.Li
|
||
func (r *Registry) Get(name string) (Tool, error) {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
t, ok := r.tools[name]
|
||
if !ok {
|
||
return nil, fmt.Errorf("工具未找到: %s", name)
|
||
}
|
||
return t, nil
|
||
}
|
||
|
||
// List 列出所有工具 // Logan.Li
|
||
func (r *Registry) List() []Tool {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
list := make([]Tool, 0, len(r.tools))
|
||
for _, t := range r.tools {
|
||
list = append(list, t)
|
||
}
|
||
return list
|
||
}
|
||
|
||
// ToLLMTools 转换为 LLM function calling 格式 // Logan.Li
|
||
func (r *Registry) ToLLMTools() []llm.Tool {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
out := make([]llm.Tool, 0, len(r.tools))
|
||
for _, t := range r.tools {
|
||
out = append(out, llm.Tool{
|
||
Type: "function",
|
||
Function: llm.ToolFunction{
|
||
Name: t.Name(),
|
||
Description: t.Description(),
|
||
Parameters: t.Parameters(),
|
||
},
|
||
})
|
||
}
|
||
return out
|
||
}
|
||
|
||
// ---- 参数解析辅助 ---- // Logan.Li
|
||
|
||
// StringParam 取字符串参数 // Logan.Li
|
||
func StringParam(args map[string]interface{}, key string) string {
|
||
if v, ok := args[key]; ok {
|
||
if s, ok := v.(string); ok {
|
||
return s
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// Close 关闭所有实现了 Close() 的工具(如 ssh_execute 长连接) // Logan.Li
|
||
func (r *Registry) Close() {
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
for _, t := range r.tools {
|
||
if c, ok := t.(interface{ Close() error }); ok {
|
||
_ = c.Close()
|
||
}
|
||
}
|
||
}
|
||
|
||
// IntParam 取整型参数(兼容 int/float64/int64) // Logan.Li
|
||
func IntParam(args map[string]interface{}, key string) int {
|
||
if v, ok := args[key]; ok {
|
||
switch val := v.(type) {
|
||
case int:
|
||
return val
|
||
case float64:
|
||
return int(val)
|
||
case int64:
|
||
return int(val)
|
||
}
|
||
}
|
||
return 0
|
||
}
|