Files
LocalAI/core/services/studio/agents/json.go
T
Ettore Di Giacinto b15905e90f fix: restore the files that the previous commit removed by mistake
The previous commit was made on a stale base and so reverted work that
landed on master before it. This commit puts every file back to the
state of its parent's parent. The permission enforcement of the
previous commit stays.

Assisted-by: Claude:claude-sonnet-5-5 go
2026-11-03 14:33:05 +00:00

155 lines
3.3 KiB
Go

package agents
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
"sync"
"github.com/mudler/LocalAI/pkg/atomicfile"
)
// jsonStore keeps the agents in memory and, with a directory, in the file
// agents.json (rewritten atomically after every change). One process owns the
// directory.
// A cluster uses GORM.
type jsonStore struct {
mu sync.Mutex
path string // empty: memory only
byID map[string]Agent
}
// NewJSON returns a Store. With an empty dir it keeps everything in memory.
// With a directory it creates it and loads what is there.
func NewJSON(dir string) (Store, error) {
s := &jsonStore{byID: map[string]Agent{}}
if dir == "" {
return s, nil
}
if err := os.MkdirAll(dir, 0o700); err != nil {
return nil, err
}
s.path = filepath.Join(dir, "agents.json")
raw, err := os.ReadFile(s.path)
if os.IsNotExist(err) {
return s, nil
}
if err != nil {
return nil, err
}
var all []Agent
if err := json.Unmarshal(raw, &all); err != nil {
return nil, fmt.Errorf("agents: read %s: %w", s.path, err)
}
for _, a := range all {
s.byID[a.ID] = a.clone()
}
return s, nil
}
func (s *jsonStore) save() error {
if s.path == "" {
return nil
}
all := make([]Agent, 0, len(s.byID))
for _, a := range s.byID {
all = append(all, a)
}
sort.Slice(all, func(i, j int) bool { return all[i].ID < all[j].ID })
return atomicfile.WriteJSON(s.path, all, 0o600)
}
func (s *jsonStore) Put(_ context.Context, a Agent) error {
s.mu.Lock()
defer s.mu.Unlock()
old, exists := s.byID[a.ID]
if exists && old.Principal != a.Principal {
return ErrNotFound
}
key := NameKey(a.Name)
for _, o := range s.byID {
if o.ID != a.ID && o.Principal == a.Principal && NameKey(o.Name) == key {
return ErrNameTaken
}
}
if exists {
a.Created = old.Created
}
s.byID[a.ID] = a.clone()
if err := s.save(); err != nil {
if exists {
s.byID[a.ID] = old
} else {
delete(s.byID, a.ID)
}
return err
}
return nil
}
func (s *jsonStore) Get(_ context.Context, principal, id string) (Agent, error) {
s.mu.Lock()
defer s.mu.Unlock()
a, ok := s.byID[id]
if !ok || a.Principal != principal {
return Agent{}, ErrNotFound
}
return a.clone(), nil
}
func (s *jsonStore) List(_ context.Context, principal string) ([]Agent, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []Agent
for _, a := range s.byID {
if a.Principal == principal {
out = append(out, a.clone())
}
}
sort.Slice(out, func(i, j int) bool {
ki, kj := NameKey(out[i].Name), NameKey(out[j].Name)
if ki != kj {
return ki < kj
}
return out[i].ID < out[j].ID
})
return out, nil
}
func (s *jsonStore) ListAll(context.Context) ([]Agent, error) {
s.mu.Lock()
defer s.mu.Unlock()
out := make([]Agent, 0, len(s.byID))
for _, a := range s.byID {
out = append(out, a.clone())
}
sort.Slice(out, func(i, j int) bool {
if out[i].Principal != out[j].Principal {
return out[i].Principal < out[j].Principal
}
if ki, kj := NameKey(out[i].Name), NameKey(out[j].Name); ki != kj {
return ki < kj
}
return out[i].ID < out[j].ID
})
return out, nil
}
func (s *jsonStore) Delete(_ context.Context, principal, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
a, ok := s.byID[id]
if !ok || a.Principal != principal {
return ErrNotFound
}
delete(s.byID, id)
if err := s.save(); err != nil {
s.byID[id] = a
return err
}
return nil
}