feat: Agent CLI 与终端审计回放全面优化
- Agent CLI: 多轮对话、SSH 长连接、流式推理、Evolver 按用户隔离、历史侧栏 - 终端审计: 回放播放器、命令书签、筛选分页导出、命令输出统计、录制落盘修复 - 修复 session_commands 表迁移、Kill 竞态导致录制丢失、无录制会话回放提示 - 审计历史页只读(移除删除),移除回放弹框录制搜索
This commit is contained in:
1 parent
9a3dd304f7
commit
1acb0c49af
81 files changed
+3916
-1655
No files matched your search
@@ -42,6 +42,7 @@ type EvolveResult struct {
|
||||
LearnedHint string `json:"learned_hint"`
|
||||
ToolSequence []string `json:"tool_sequence"`
|
||||
ExperienceAdded bool `json:"experience_added"`
|
||||
SkillAdded bool `json:"skill_added"`
|
||||
Consolidated bool `json:"consolidated"`
|
||||
}
|
||||
|
||||
@@ -107,6 +108,21 @@ func (e *EvolverEngine) Evolve(ctx context.Context, exec *TaskExecution) *Evolve
|
||||
go e.memorizeFact(ctx, exec) // 异步,不阻塞进化主流程
|
||||
}
|
||||
|
||||
// Step 6: PROCEDURAL —— 成功任务沉淀程序记忆(工具命令序列) // Logan.Li
|
||||
if exec.Success {
|
||||
if steps := extractSSHSteps(exec.ToolCalls); len(steps) >= 2 {
|
||||
skill := SkillEntry{
|
||||
Name: result.TaskType + "标准流程",
|
||||
When: result.TaskType,
|
||||
Steps: steps,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
if err := e.mem.AddSkill(skill); err == nil {
|
||||
result.SkillAdded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -194,6 +210,12 @@ func (e *EvolverEngine) GetContextForPrompt(query string) string {
|
||||
if hosts := e.mem.Hosts(); len(hosts) > 0 {
|
||||
sb.WriteString(fmt.Sprintf(" 【已知主机】%s\n", strings.Join(hosts, ", ")))
|
||||
}
|
||||
if skills := e.mem.FindSkills(taskType, 2); len(skills) > 0 {
|
||||
sb.WriteString(" 【推荐流程】\n")
|
||||
for _, sk := range skills {
|
||||
sb.WriteString(fmt.Sprintf(" - %s: %s\n", sk.Name, strings.Join(sk.Steps, " → ")))
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
@@ -258,6 +280,20 @@ func resultToolNames(calls []ToolCallRecord) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// extractSSHSteps 从工具调用记录提取 ssh_execute 命令序列 // Logan.Li
|
||||
func extractSSHSteps(calls []ToolCallRecord) []string {
|
||||
out := make([]string, 0, len(calls))
|
||||
for _, c := range calls {
|
||||
if c.ToolName != "ssh_execute" {
|
||||
continue
|
||||
}
|
||||
if cmd, ok := c.Args["command"].(string); ok && strings.TrimSpace(cmd) != "" {
|
||||
out = append(out, strings.TrimSpace(cmd))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func uniqueStrings(in []string) []string {
|
||||
seen := make(map[string]bool)
|
||||
out := make([]string, 0, len(in))
|
||||
|
||||
@@ -235,6 +235,21 @@ func (m *Memories) Hosts() []string {
|
||||
return readJSON(m.envPath, KnownHosts{}).Hosts
|
||||
}
|
||||
|
||||
// FindSkills 按任务类型查找程序记忆(运维流程,最多 n 条) // Logan.Li
|
||||
func (m *Memories) FindSkills(taskType string, n int) []SkillEntry {
|
||||
all := readJSONL[SkillEntry](m.sklPath)
|
||||
var matched []SkillEntry
|
||||
for _, s := range all {
|
||||
if taskType == "" || s.When == taskType {
|
||||
matched = append(matched, s)
|
||||
}
|
||||
}
|
||||
if len(matched) > n {
|
||||
matched = matched[len(matched)-n:]
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
// CountStats 统计各层记忆条目数 // Logan.Li
|
||||
func (m *Memories) CountStats() map[string]int {
|
||||
return map[string]int{
|
||||
|
||||
Reference in new issue
Block a user