ollie/fs/session_node.go

130 lines
2.9 KiB
Go

package fs
import (
"context"
"strings"
"sync"
"time"
"ollie/agent"
"ollie/session"
"ollie/toolsrv"
)
// SessionNode wraps session.Session for 9P handlers.
// It adds AgentLogs (9P chat streaming state) and models cache.
type SessionNode struct {
Core *session.Session
// AgentLogs for chat streaming, keyed by agent ID.
mu sync.RWMutex
AgentLogs map[string]*AgentLog
// Cached model list (expensive API call; refreshed every 24h).
modelsMu sync.Mutex
modelsCache string
modelsCacheAt time.Time
}
// NewSessionNode creates a SessionNode wrapping a session.
func NewSessionNode(core *session.Session) *SessionNode {
return &SessionNode{Core: core, AgentLogs: make(map[string]*AgentLog)}
}
// --- Delegation to Core ---
func (s *SessionNode) ID() string { return s.Core.ID }
func (s *SessionNode) Name() string { return s.Core.Name() }
func (s *SessionNode) SetName(n string) { s.Core.SetName(n) }
func (s *SessionNode) Uname() string { return s.Core.Uname }
func (s *SessionNode) Cancel() { if s.Core.Cancel != nil { s.Core.Cancel() } }
func (s *SessionNode) IsPaused() bool { return s.Core.IsPaused() }
func (s *SessionNode) IsConnected() bool { return s.Core.IsConnected() }
func (s *SessionNode) Pause() error {
err := s.Core.Pause()
if err == nil {
session.PublishEvent("session."+s.Core.ID+".pause", "")
}
return err
}
func (s *SessionNode) Resume() error {
err := s.Core.Resume()
if err == nil {
session.PublishEvent("session."+s.Core.ID+".resume", "")
}
return err
}
func (s *SessionNode) LoadTool(name string, ag *agent.Agent) error {
return s.Core.LoadTool(name, ag)
}
func (s *SessionNode) Ctx() context.Context {
return s.Core.Ctx
}
func (s *SessionNode) ToolsConn() *toolsrv.Conn {
return s.Core.ToolsConn()
}
// --- AgentLog management ---
func (s *SessionNode) AgentLog() *AgentLog {
s.mu.RLock()
defer s.mu.RUnlock()
for _, al := range s.AgentLogs {
return al
}
return nil
}
func (s *SessionNode) AgentLogFor(agentID string) *AgentLog {
s.mu.RLock()
defer s.mu.RUnlock()
return s.AgentLogs[agentID]
}
func (s *SessionNode) SetAgentLog(agentID string, al *AgentLog) {
s.mu.Lock()
defer s.mu.Unlock()
if s.AgentLogs == nil {
s.AgentLogs = make(map[string]*AgentLog)
}
s.AgentLogs[agentID] = al
}
// --- Models cache ---
const modelsCacheTTL = 24 * time.Hour
func (s *SessionNode) CachedListModels() string {
s.modelsMu.Lock()
if s.modelsCache != "" && time.Since(s.modelsCacheAt) < modelsCacheTTL {
result := s.modelsCache
s.modelsMu.Unlock()
return result
}
s.modelsMu.Unlock()
agents := s.Core.Agents()
if len(agents) == 0 {
return ""
}
models := agents[0].ListModels()
result := strings.Join(models, "\n")
s.modelsMu.Lock()
s.modelsCache = result
s.modelsCacheAt = time.Now()
s.modelsMu.Unlock()
return result
}
func (s *SessionNode) InvalidateModelsCache() {
s.modelsMu.Lock()
s.modelsCache = ""
s.modelsCacheAt = time.Time{}
s.modelsMu.Unlock()
}