// Package workflow 保存已装载的工作流定义。它只依赖 core,执行器在 runtime。 package workflow import ( "encoding/json" "sync" core "git-ssh.u1680832.nyat.app/weichen/Agent-System-Core.git" ) // ScriptKey 是脚本正文的索引。同一个相对路径可以出现在不同工作流里。 func ScriptKey(workflowID, path string) string { return workflowID + "\n" + path } // Registry 是当前装载集合的快照。Set 整体替换,不增量合并。 type Registry struct { mu sync.RWMutex byID map[string]core.WorkflowDef byIntent map[string]string scripts map[string]string } func NewRegistry() *Registry { return &Registry{ byID: map[string]core.WorkflowDef{}, byIntent: map[string]string{}, scripts: map[string]string{}, } } // Set 用这一批定义替换注册表。同 ID 或同意图以后出现的为准。 // scripts 的键是 ScriptKey。定义会被拷贝,调用方之后的修改不影响已注册的副本。 func (r *Registry) Set(defs []core.WorkflowDef, scripts map[string]string) { byID := map[string]core.WorkflowDef{} byIntent := map[string]string{} for _, def := range defs { cloned := cloneDef(def) byID[cloned.ID] = cloned if cloned.IntentID != "" { byIntent[cloned.IntentID] = cloned.ID } } copied := map[string]string{} for k, v := range scripts { copied[k] = v } r.mu.Lock() r.byID, r.byIntent, r.scripts = byID, byIntent, copied r.mu.Unlock() } func (r *Registry) Get(id string) (core.WorkflowDef, bool) { r.mu.RLock() defer r.mu.RUnlock() def, ok := r.byID[id] if !ok { return core.WorkflowDef{}, false } return cloneDef(def), true } func (r *Registry) ByIntent(intentID string) (core.WorkflowDef, bool) { r.mu.RLock() defer r.mu.RUnlock() id, ok := r.byIntent[intentID] if !ok { return core.WorkflowDef{}, false } return cloneDef(r.byID[id]), true } func (r *Registry) Script(workflowID, path string) (string, bool) { r.mu.RLock() defer r.mu.RUnlock() body, ok := r.scripts[ScriptKey(workflowID, path)] return body, ok } // SlotQuestion 是启动工作流时还没填上的必填槽位。 type SlotQuestion struct { Key string Question string } // Launch 是一次工作流 run 启动时的副本。之后插件卸载不能改到它。 type Launch struct { Def core.WorkflowDef Slots map[string]string Missing []SlotQuestion Scripts map[string]string // 键是步骤里的相对路径,值是当时读到的脚本正文 } // Clone 拷贝定义,调用方之后的修改不影响副本。 func Clone(def core.WorkflowDef) core.WorkflowDef { return cloneDef(def) } func cloneDef(def core.WorkflowDef) core.WorkflowDef { raw, err := json.Marshal(def) if err != nil { return def } var out core.WorkflowDef if err := json.Unmarshal(raw, &out); err != nil { return def } return out }