mirror of
https://github.com/mudler/LocalAI.git
synced 2026-04-01 05:36:49 -04:00
* feat: add distributed mode (experimental) Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix data races, mutexes, transactions Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactorings Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fixups Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix events and tool stream in agent chat Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * use ginkgo Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(cron): compute correctly time boundaries avoiding re-triggering Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * enhancements, refactorings Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * do not flood of healthy checks Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * do not list obvious backends as text backends Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * tests fixups Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Drop redundant healthcheck Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * enhancements, refactorings Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
package distributed
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// SkillMetadataRecord tracks skill metadata in PostgreSQL.
|
|
type SkillMetadataRecord struct {
|
|
ID string `gorm:"primaryKey;size:36" json:"id"`
|
|
UserID string `gorm:"index;size:36" json:"user_id,omitempty"`
|
|
Name string `gorm:"index;size:255" json:"name"`
|
|
Definition string `gorm:"type:text" json:"definition,omitempty"` // SKILL.md content or YAML
|
|
SourceType string `gorm:"size:32" json:"source_type"` // "inline", "git"
|
|
SourceURL string `gorm:"size:512" json:"source_url,omitempty"`
|
|
Version string `gorm:"size:64" json:"version,omitempty"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func (SkillMetadataRecord) TableName() string { return "skills_metadata" }
|
|
|
|
// SkillStore manages skill metadata in PostgreSQL.
|
|
type SkillStore struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewSkillStore creates a new SkillStore and auto-migrates.
|
|
func NewSkillStore(db *gorm.DB) (*SkillStore, error) {
|
|
if err := db.AutoMigrate(&SkillMetadataRecord{}); err != nil {
|
|
return nil, fmt.Errorf("migrating skills_metadata: %w", err)
|
|
}
|
|
return &SkillStore{db: db}, nil
|
|
}
|
|
|
|
// Save creates or updates a skill metadata record.
|
|
func (s *SkillStore) Save(rec *SkillMetadataRecord) error {
|
|
if rec.ID == "" {
|
|
rec.ID = uuid.New().String()
|
|
}
|
|
rec.UpdatedAt = time.Now()
|
|
if rec.CreatedAt.IsZero() {
|
|
rec.CreatedAt = rec.UpdatedAt
|
|
}
|
|
|
|
var existing SkillMetadataRecord
|
|
err := s.db.Where("user_id = ? AND name = ?", rec.UserID, rec.Name).First(&existing).Error
|
|
if err == nil {
|
|
rec.ID = existing.ID
|
|
rec.CreatedAt = existing.CreatedAt
|
|
return s.db.Model(&existing).Updates(rec).Error
|
|
}
|
|
return s.db.Create(rec).Error
|
|
}
|
|
|
|
// Get retrieves a skill by user and name.
|
|
func (s *SkillStore) Get(userID, name string) (*SkillMetadataRecord, error) {
|
|
var rec SkillMetadataRecord
|
|
q := s.db.Where("name = ?", name)
|
|
if userID != "" {
|
|
q = q.Where("user_id = ?", userID)
|
|
}
|
|
if err := q.First(&rec).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &rec, nil
|
|
}
|
|
|
|
// List returns skills for a user.
|
|
func (s *SkillStore) List(userID string) ([]SkillMetadataRecord, error) {
|
|
var recs []SkillMetadataRecord
|
|
q := s.db.Order("name")
|
|
if userID != "" {
|
|
q = q.Where("user_id = ?", userID)
|
|
}
|
|
return recs, q.Find(&recs).Error
|
|
}
|
|
|
|
// Delete removes a skill metadata record.
|
|
func (s *SkillStore) Delete(userID, name string) error {
|
|
q := s.db.Where("name = ?", name)
|
|
if userID != "" {
|
|
q = q.Where("user_id = ?", userID)
|
|
}
|
|
return q.Delete(&SkillMetadataRecord{}).Error
|
|
}
|
|
|
|
// ListGitSkills returns skills sourced from git repos (for sync jobs).
|
|
func (s *SkillStore) ListGitSkills() ([]SkillMetadataRecord, error) {
|
|
var recs []SkillMetadataRecord
|
|
return recs, s.db.Where("source_type = ? AND enabled = true", "git").Find(&recs).Error
|
|
}
|