package rpc import ( "errors" "fmt" "os" "strings" ) var ErrApprovedWorkerRequired = errors.New("approved call worker is required") // NewApprovedAgentServer binds the control RPC and one-shot originate callback // to the same task-call registry. The separate legacy hooks are not accepted // on either explicitly selected entry: otherwise a control could confirm while // a call started by a different adapter remains active. func NewApprovedAgentServer(options ServerOptions, worker *ApprovedCallWorker) (*Server, error) { if worker == nil { return nil, ErrApprovedWorkerRequired } if (options.Mode != "mock" && options.Mode != "nonprod-real") || options.StatePath == "" || options.Status == nil || options.Status.AgentId == "" || options.Status.CellId == "" || options.Status.BootId == "" || strings.TrimSpace(options.ApprovedDispatcherID) == "" || options.LoadedSIP == nil { return nil, errors.New("approved Agent requires an explicit supported mode, durable state, Agent and Dispatcher identity, and observed SIP") } if worker.Lifecycle == nil || worker.Calls == nil || worker.Prepare == nil || worker.OnFailure == nil { return nil, errors.New("approved Agent requires a process lifecycle, task calls, runner and failure reporting") } if _, err := os.Lstat(options.StatePath + ".executions"); err == nil { return nil, errors.New("legacy Agent execution state requires operator disposition") } else if !errors.Is(err, os.ErrNotExist) { return nil, fmt.Errorf("inspect legacy Agent execution state: %w", err) } if options.MockApprovedOriginate != nil || options.NonprodRealOriginate != nil || options.ApprovedTaskCalls != nil { return nil, errors.New("approved Agent cannot use competing call or control adapters") } // Copy the configuration so later mutation of worker fields cannot cause // ExecuteApproved and task controls to observe different registries. frozen := *worker if options.Mode == "mock" { options.MockApprovedOriginate = frozen.Originate } else { options.NonprodRealOriginate = frozen.Originate } options.ApprovedTaskCalls = frozen.Calls return NewServer(options), nil }