Skip to content

Commit 066301a

Browse files
committed
refactorings
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 6c0afb5 commit 066301a

134 files changed

Lines changed: 3250 additions & 3063 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ COPY ./.git ./.git
319319
# Some of the Go backends use libs from the main src, we could further optimize the caching by building the CPP backends before here
320320
COPY ./pkg/grpc ./pkg/grpc
321321
COPY ./pkg/utils ./pkg/utils
322-
COPY ./pkg/langchain ./pkg/langchain
323322

324323
RUN ls -l ./
325324
RUN make protogen-go

core/application/agent_jobs.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package application
33
import (
44
"time"
55

6-
"github.com/mudler/LocalAI/core/services"
6+
"github.com/mudler/LocalAI/core/services/agentpool"
77
"github.com/mudler/xlog"
88
)
99

@@ -22,13 +22,21 @@ func (a *Application) RestartAgentJobService() error {
2222
}
2323

2424
// Create new service instance
25-
agentJobService := services.NewAgentJobService(
25+
agentJobService := agentpool.NewAgentJobService(
2626
a.ApplicationConfig(),
2727
a.ModelLoader(),
2828
a.ModelConfigLoader(),
2929
a.TemplatesEvaluator(),
3030
)
3131

32+
// Re-apply distributed wiring if available (matches startup.go logic)
33+
if a.jobDispatcher != nil {
34+
agentJobService.SetDistributedBackends(a.jobDispatcher)
35+
}
36+
if a.jobStore != nil {
37+
agentJobService.SetDistributedJobStore(a.jobStore)
38+
}
39+
3240
// Start the service
3341
err := agentJobService.Start(a.ApplicationConfig().Context)
3442
if err != nil {

core/application/application.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import (
88

99
"github.com/mudler/LocalAI/core/config"
1010
mcpTools "github.com/mudler/LocalAI/core/http/endpoints/mcp"
11-
"github.com/mudler/LocalAI/core/services"
1211
"github.com/mudler/LocalAI/core/services/agents"
12+
"github.com/mudler/LocalAI/core/services/agentpool"
13+
"github.com/mudler/LocalAI/core/services/galleryop"
1314
"github.com/mudler/LocalAI/core/services/distributed"
1415
"github.com/mudler/LocalAI/core/services/jobs"
1516
"github.com/mudler/LocalAI/core/services/messaging"
@@ -27,9 +28,9 @@ type Application struct {
2728
applicationConfig *config.ApplicationConfig
2829
startupConfig *config.ApplicationConfig // Stores original config from env vars (before file loading)
2930
templatesEvaluator *templates.Evaluator
30-
galleryService *services.GalleryService
31-
agentJobService *services.AgentJobService
32-
agentPoolService atomic.Pointer[services.AgentPoolService]
31+
galleryService *galleryop.GalleryService
32+
agentJobService *agentpool.AgentJobService
33+
agentPoolService atomic.Pointer[agentpool.AgentPoolService]
3334
authDB *gorm.DB
3435
watchdogMutex sync.Mutex
3536
watchdogStop chan bool
@@ -84,15 +85,15 @@ func (a *Application) TemplatesEvaluator() *templates.Evaluator {
8485
return a.templatesEvaluator
8586
}
8687

87-
func (a *Application) GalleryService() *services.GalleryService {
88+
func (a *Application) GalleryService() *galleryop.GalleryService {
8889
return a.galleryService
8990
}
9091

91-
func (a *Application) AgentJobService() *services.AgentJobService {
92+
func (a *Application) AgentJobService() *agentpool.AgentJobService {
9293
return a.agentJobService
9394
}
9495

95-
func (a *Application) AgentPoolService() *services.AgentPoolService {
96+
func (a *Application) AgentPoolService() *agentpool.AgentPoolService {
9697
return a.agentPoolService.Load()
9798
}
9899

@@ -169,7 +170,7 @@ func (a *Application) IsDistributed() bool {
169170
// waitForHealthyWorker blocks until at least one healthy backend worker is registered.
170171
// This prevents the agent pool from failing during startup when workers haven't connected yet.
171172
func (a *Application) waitForHealthyWorker() {
172-
const maxWait = 5 * time.Minute
173+
maxWait := a.applicationConfig.Distributed.WorkerWaitTimeoutOrDefault()
173174
const pollInterval = 2 * time.Second
174175

175176
xlog.Info("Waiting for at least one healthy backend worker before starting agent pool")
@@ -200,7 +201,7 @@ func (a *Application) InstanceID() string {
200201
}
201202

202203
func (a *Application) start() error {
203-
galleryService := services.NewGalleryService(a.ApplicationConfig(), a.ModelLoader())
204+
galleryService := galleryop.NewGalleryService(a.ApplicationConfig(), a.ModelLoader())
204205
err := galleryService.Start(a.ApplicationConfig().Context, a.ModelConfigLoader(), a.ApplicationConfig().SystemState)
205206
if err != nil {
206207
return err
@@ -209,7 +210,7 @@ func (a *Application) start() error {
209210
a.galleryService = galleryService
210211

211212
// Initialize agent job service (Start() is deferred to after distributed wiring)
212-
agentJobService := services.NewAgentJobService(
213+
agentJobService := agentpool.NewAgentJobService(
213214
a.ApplicationConfig(),
214215
a.ModelLoader(),
215216
a.ModelConfigLoader(),
@@ -228,7 +229,7 @@ func (a *Application) StartAgentPool() {
228229
if !a.applicationConfig.AgentPool.Enabled {
229230
return
230231
}
231-
aps, err := services.NewAgentPoolService(a.applicationConfig)
232+
aps, err := agentpool.NewAgentPoolService(a.applicationConfig)
232233
if err != nil {
233234
xlog.Error("Failed to create agent pool service", "error", err)
234235
return
@@ -262,7 +263,7 @@ func (a *Application) StartAgentPool() {
262263
}
263264

264265
// Wire per-user scoped services so collections, skills, and jobs are isolated per user
265-
usm := services.NewUserServicesManager(
266+
usm := agentpool.NewUserServicesManager(
266267
aps.UserStorage(),
267268
a.applicationConfig,
268269
a.modelLoader,

core/application/distributed.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,18 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
7070
}
7171
xlog.Info("Connected to NATS", "url", cfg.Distributed.NatsURL)
7272

73+
// Ensure NATS is closed if any subsequent initialization step fails.
74+
success := false
75+
defer func() {
76+
if !success {
77+
natsClient.Close()
78+
}
79+
}()
80+
7381
// Initialize object storage
7482
var store storage.ObjectStore
7583
if cfg.Distributed.StorageURL != "" {
7684
if cfg.Distributed.StorageBucket == "" {
77-
natsClient.Close()
7885
return nil, fmt.Errorf("distributed storage bucket must be set when storage URL is configured")
7986
}
8087
s3Store, err := storage.NewS3Store(storage.S3Config{
@@ -86,7 +93,6 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
8693
ForcePathStyle: true, // required for MinIO
8794
})
8895
if err != nil {
89-
natsClient.Close()
9096
return nil, fmt.Errorf("initializing S3 storage: %w", err)
9197
}
9298
xlog.Info("Object storage initialized (S3)", "endpoint", cfg.Distributed.StorageURL, "bucket", cfg.Distributed.StorageBucket)
@@ -95,7 +101,6 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
95101
// Fallback to filesystem storage in distributed mode (useful for single-node testing)
96102
fsStore, err := storage.NewFilesystemStore(cfg.DataPath + "/objectstore")
97103
if err != nil {
98-
natsClient.Close()
99104
return nil, fmt.Errorf("initializing filesystem storage: %w", err)
100105
}
101106
xlog.Info("Object storage initialized (filesystem fallback)", "path", cfg.DataPath+"/objectstore")
@@ -104,13 +109,11 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
104109

105110
// Initialize node registry (requires the auth DB which is PostgreSQL)
106111
if authDB == nil {
107-
natsClient.Close()
108112
return nil, fmt.Errorf("distributed mode requires auth database to be initialized first")
109113
}
110114

111115
registry, err := nodes.NewNodeRegistry(authDB)
112116
if err != nil {
113-
natsClient.Close()
114117
return nil, fmt.Errorf("initializing node registry: %w", err)
115118
}
116119
xlog.Info("Node registry initialized")
@@ -122,12 +125,14 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
122125
if galleriesJSON, err := json.Marshal(cfg.BackendGalleries); err == nil {
123126
router.SetGalleriesJSON(string(galleriesJSON))
124127
}
125-
healthMon := nodes.NewHealthMonitor(registry, authDB)
128+
healthMon := nodes.NewHealthMonitor(registry, authDB,
129+
cfg.Distributed.HealthCheckIntervalOrDefault(),
130+
cfg.Distributed.StaleNodeThresholdOrDefault(),
131+
)
126132

127133
// Initialize job store
128134
jobStore, err := jobs.NewJobStore(authDB)
129135
if err != nil {
130-
natsClient.Close()
131136
return nil, fmt.Errorf("initializing job store: %w", err)
132137
}
133138
xlog.Info("Distributed job store initialized")
@@ -138,7 +143,6 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
138143
// Initialize agent store
139144
agentStore, err := agents.NewAgentStore(authDB)
140145
if err != nil {
141-
natsClient.Close()
142146
return nil, fmt.Errorf("initializing agent store: %w", err)
143147
}
144148
xlog.Info("Distributed agent store initialized")
@@ -149,15 +153,13 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
149153
// Initialize Phase 4 stores (MCP, Gallery, FineTune, Skills)
150154
distStores, err := distributed.InitStores(authDB)
151155
if err != nil {
152-
natsClient.Close()
153156
return nil, fmt.Errorf("initializing distributed stores: %w", err)
154157
}
155158

156159
// Initialize file manager with local cache
157160
cacheDir := cfg.DataPath + "/cache"
158161
fileMgr, err := storage.NewFileManager(store, cacheDir)
159162
if err != nil {
160-
natsClient.Close()
161163
return nil, fmt.Errorf("initializing file manager: %w", err)
162164
}
163165
xlog.Info("File manager initialized", "cacheDir", cacheDir)
@@ -185,6 +187,7 @@ func initDistributed(cfg *config.ApplicationConfig, authDB *gorm.DB) (*distribut
185187
// Create ModelRouterAdapter to wire into ModelLoader
186188
modelAdapter := nodes.NewModelRouterAdapter(router)
187189

190+
success = true
188191
return &distributedServices{
189192
nats: natsClient,
190193
store: store,

core/application/p2p.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/mudler/LocalAI/core/gallery"
1212
"github.com/mudler/LocalAI/core/p2p"
1313
"github.com/mudler/LocalAI/core/schema"
14-
"github.com/mudler/LocalAI/core/services"
14+
"github.com/mudler/LocalAI/core/services/galleryop"
1515

1616
"github.com/mudler/edgevpn/pkg/node"
1717
"github.com/mudler/xlog"
@@ -146,22 +146,14 @@ func (a *Application) RestartP2P() error {
146146
return fmt.Errorf("P2P token is not set")
147147
}
148148

149-
// Create new context for P2P
150-
ctx, cancel := context.WithCancel(appConfig.Context)
151-
a.p2pCtx = ctx
152-
a.p2pCancel = cancel
153-
154-
// Get API address from config
155-
address := appConfig.APIAddress
156-
if address == "" {
157-
address = "127.0.0.1:8080" // default
158-
}
159-
160149
// Start P2P stack in a goroutine
150+
// Note: StartP2P creates its own context and assigns a.p2pCtx/a.p2pCancel
161151
go func() {
162152
if err := a.StartP2P(); err != nil {
163153
xlog.Error("Failed to start P2P stack", "error", err)
164-
cancel() // Cancel context on error
154+
if a.p2pCancel != nil {
155+
a.p2pCancel()
156+
}
165157
}
166158
}()
167159
xlog.Info("P2P stack restarted with new settings")
@@ -228,7 +220,7 @@ func syncState(ctx context.Context, n *node.Node, app *Application) error {
228220
continue
229221
}
230222

231-
app.GalleryService().ModelGalleryChannel <- services.ManagementOp[gallery.GalleryModel, gallery.ModelConfig]{
223+
app.GalleryService().ModelGalleryChannel <- galleryop.ManagementOp[gallery.GalleryModel, gallery.ModelConfig]{
232224
ID: uuid.String(),
233225
GalleryElementName: model,
234226
Galleries: app.ApplicationConfig().Galleries,

core/application/startup.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/mudler/LocalAI/core/config"
1414
"github.com/mudler/LocalAI/core/gallery"
1515
"github.com/mudler/LocalAI/core/http/auth"
16-
"github.com/mudler/LocalAI/core/services"
16+
"github.com/mudler/LocalAI/core/services/galleryop"
1717
"github.com/mudler/LocalAI/core/services/jobs"
1818
"github.com/mudler/LocalAI/core/services/nodes"
1919
"github.com/mudler/LocalAI/core/services/storage"
@@ -223,7 +223,7 @@ func New(opts ...config.AppOption) (*Application, error) {
223223
}
224224

225225
for _, backend := range options.ExternalBackends {
226-
if err := services.InstallExternalBackend(options.Context, options.BackendGalleries, options.SystemState, application.ModelLoader(), nil, backend, "", ""); err != nil {
226+
if err := galleryop.InstallExternalBackend(options.Context, options.BackendGalleries, options.SystemState, application.ModelLoader(), nil, backend, "", ""); err != nil {
227227
xlog.Error("error installing external backend", "error", err)
228228
}
229229
}
@@ -249,13 +249,13 @@ func New(opts ...config.AppOption) (*Application, error) {
249249
}
250250

251251
if options.PreloadJSONModels != "" {
252-
if err := services.ApplyGalleryFromString(options.SystemState, application.ModelLoader(), options.EnforcePredownloadScans, options.AutoloadBackendGalleries, options.Galleries, options.BackendGalleries, options.PreloadJSONModels); err != nil {
252+
if err := galleryop.ApplyGalleryFromString(options.SystemState, application.ModelLoader(), options.EnforcePredownloadScans, options.AutoloadBackendGalleries, options.Galleries, options.BackendGalleries, options.PreloadJSONModels); err != nil {
253253
return nil, err
254254
}
255255
}
256256

257257
if options.PreloadModelsFromPath != "" {
258-
if err := services.ApplyGalleryFromFile(options.SystemState, application.ModelLoader(), options.EnforcePredownloadScans, options.AutoloadBackendGalleries, options.Galleries, options.BackendGalleries, options.PreloadModelsFromPath); err != nil {
258+
if err := galleryop.ApplyGalleryFromFile(options.SystemState, application.ModelLoader(), options.EnforcePredownloadScans, options.AutoloadBackendGalleries, options.Galleries, options.BackendGalleries, options.PreloadModelsFromPath); err != nil {
259259
return nil, err
260260
}
261261
}

core/backend/llm.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
"github.com/mudler/LocalAI/core/config"
1616
"github.com/mudler/LocalAI/core/trace"
1717
"github.com/mudler/LocalAI/core/schema"
18-
"github.com/mudler/LocalAI/core/services"
18+
"github.com/mudler/LocalAI/core/services/galleryop"
1919

2020
"github.com/mudler/LocalAI/core/gallery"
2121
"github.com/mudler/LocalAI/pkg/grpc/proto"
@@ -47,7 +47,7 @@ func ModelInference(ctx context.Context, s string, messages schema.Messages, ima
4747

4848
// Check if the modelFile exists, if it doesn't try to load it from the gallery
4949
if o.AutoloadGalleries { // experimental
50-
modelNames, err := services.ListModels(cl, loader, nil, services.SKIP_ALWAYS)
50+
modelNames, err := galleryop.ListModels(cl, loader, nil, galleryop.SKIP_ALWAYS)
5151
if err != nil {
5252
return nil, err
5353
}

core/cli/agent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
cliContext "github.com/mudler/LocalAI/core/cli/context"
1212
"github.com/mudler/LocalAI/core/config"
13-
"github.com/mudler/LocalAI/core/services"
13+
"github.com/mudler/LocalAI/core/services/agentpool"
1414
"github.com/mudler/LocalAGI/core/state"
1515
coreTypes "github.com/mudler/LocalAGI/core/types"
1616
"github.com/mudler/xlog"
@@ -59,7 +59,7 @@ func (r *AgentRunCMD) Run(ctx *cliContext.Context) error {
5959

6060
appConfig := r.buildAppConfig()
6161

62-
poolService, err := services.NewAgentPoolService(appConfig)
62+
poolService, err := agentpool.NewAgentPoolService(appConfig)
6363
if err != nil {
6464
return fmt.Errorf("failed to create agent pool service: %w", err)
6565
}

0 commit comments

Comments
 (0)