Fix build blockers and rewrite README with authorized-use warning.
Restore server/agent compile fixes, wire remote actions end-to-end, harden run.bat, and document AetherForge with a severity-ranked audit in PROBLEMS.md.
This commit is contained in:
@@ -23,13 +23,18 @@ import (
|
||||
// AIHandler manages AI autonomy endpoints.
|
||||
type AIHandler struct {
|
||||
db *db.Database
|
||||
engines map[string]*ollama.Engine // agentID -> engine (each agent can have its own Ollama config)
|
||||
reports []ollama.Report // recent tool execution reports
|
||||
engines map[string]*agentEngine // agentID -> engine wrapper
|
||||
reports []ollama.Report // recent tool execution reports
|
||||
activity map[string]AIActivityEntry
|
||||
onEvent func(AIActivityEntry)
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
type agentEngine struct {
|
||||
engine *ollama.Engine
|
||||
lastUsed time.Time
|
||||
}
|
||||
|
||||
// AIActivityEntry summarizes recent AI cycles per agent.
|
||||
type AIActivityEntry struct {
|
||||
AgentID string `json:"agent_id"`
|
||||
@@ -44,12 +49,34 @@ type AIActivityEntry struct {
|
||||
|
||||
// NewAIHandler creates a new AI handler.
|
||||
func NewAIHandler(database *db.Database) *AIHandler {
|
||||
return &AIHandler{
|
||||
h := &AIHandler{
|
||||
db: database,
|
||||
engines: make(map[string]*ollama.Engine),
|
||||
engines: make(map[string]*agentEngine),
|
||||
reports: make([]ollama.Report, 0, 1000),
|
||||
activity: make(map[string]AIActivityEntry),
|
||||
}
|
||||
go h.runCleanupLoop()
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *AIHandler) runCleanupLoop() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
h.mu.Lock()
|
||||
now := time.Now()
|
||||
for id, eng := range h.engines {
|
||||
if now.Sub(eng.lastUsed) > 1*time.Hour {
|
||||
delete(h.engines, id)
|
||||
}
|
||||
}
|
||||
for id, act := range h.activity {
|
||||
if now.Sub(act.LastReportAt) > 24*time.Hour && now.Sub(act.LastDecideAt) > 24*time.Hour {
|
||||
delete(h.activity, id)
|
||||
}
|
||||
}
|
||||
h.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AIHandler) SetEventBroadcaster(fn func(AIActivityEntry)) {
|
||||
@@ -71,7 +98,10 @@ func (h *AIHandler) SetEngineForAgent(agentID, ollamaEndpoint, model string) {
|
||||
model = "llama3.2"
|
||||
}
|
||||
|
||||
h.engines[agentID] = ollama.NewEngine(ollamaEndpoint, model)
|
||||
h.engines[agentID] = &agentEngine{
|
||||
engine: ollama.NewEngine(ollamaEndpoint, model),
|
||||
lastUsed: time.Now(),
|
||||
}
|
||||
log.Printf("[AI] Engine set for agent %s (endpoint=%s, model=%s)", agentID, ollamaEndpoint, model)
|
||||
}
|
||||
|
||||
@@ -86,7 +116,15 @@ func (h *AIHandler) RemoveEngine(agentID string) {
|
||||
func (h *AIHandler) GetEngine(agentID string) *ollama.Engine {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
return h.engines[agentID]
|
||||
if entry, ok := h.engines[agentID]; ok {
|
||||
h.mu.RUnlock() // Briefly unlock to update timestamp
|
||||
h.mu.Lock()
|
||||
entry.lastUsed = time.Now()
|
||||
h.mu.Unlock()
|
||||
h.mu.RLock()
|
||||
return entry.engine
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleDecide handles POST /api/v1/agent/decide
|
||||
|
||||
@@ -203,6 +203,8 @@ func sanitizeFilename(name string) string {
|
||||
// Trim spaces and dots
|
||||
name = strings.TrimSpace(name)
|
||||
name = strings.Trim(name, ".")
|
||||
// Prevent explicit traversal sequences
|
||||
name = strings.ReplaceAll(name, "..", "")
|
||||
// Limit length
|
||||
if len(name) > 100 {
|
||||
name = name[:100]
|
||||
|
||||
@@ -189,6 +189,7 @@ func (h *WSHub) HandleAgentWS(w http.ResponseWriter, r *http.Request) {
|
||||
h.mu.Lock()
|
||||
delete(h.agents, agentID)
|
||||
delete(h.agentConfigs, agentID)
|
||||
delete(h.agentLogs, agentID)
|
||||
h.mu.Unlock()
|
||||
if h.aiHandler != nil {
|
||||
h.aiHandler.RemoveEngine(agentID)
|
||||
@@ -629,3 +630,15 @@ func (h *WSHub) BroadcastPoolStatus(status interface{}) {
|
||||
func (h *WSHub) BroadcastAIActivity(entry interface{}) {
|
||||
h.broadcastDashboard(Message{Type: "ai_activity", Payload: mustMarshal(entry)})
|
||||
}
|
||||
|
||||
// BroadcastServerLog streams a server log line to connected dashboards.
|
||||
func (h *WSHub) BroadcastServerLog(line string) {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
return
|
||||
}
|
||||
h.broadcastDashboard(Message{
|
||||
Type: "server_log",
|
||||
Payload: mustMarshal(map[string]string{"line": line}),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user