package main import ( "context" "errors" "log/slog" "net/http" "os" "os/signal" "syscall" "github.com/prometheus/client_golang/prometheus/promhttp" "l-ai-agent-kaya/internal/config" "l-ai-agent-kaya/internal/inference" "l-ai-agent-kaya/internal/profile" "l-ai-agent-kaya/internal/tasksboard" ) func main() { if err := run(); err != nil { slog.Error("kaya stopped", "error", err) os.Exit(1) } } func run() error { cfg, err := config.Load() if err != nil { return err } prof, err := profile.Load(cfg.ProfilePath) if err != nil { return err } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() core, err := inference.DialCore(cfg.CoreEndpoint, cfg.CoreToken, cfg.CoreInsecure) if err != nil { return err } defer core.Close() go serveHTTP(cfg.MetricsListenAddr, promhttp.Handler()) go serveHTTP(cfg.HealthListenAddr, healthHandler()) loop := &tasksboard.Loop{ WSURL: cfg.TasksWSURL, Token: cfg.TasksAgentToken, REST: &tasksboard.Client{BaseURL: cfg.TasksAPIURL, Token: cfg.TasksAgentToken}, Core: core, Profile: prof, Model: cfg.Model, ResponseTimeout: cfg.ResponseTimeout, Log: slog.Default(), } go loop.Run(ctx) <-ctx.Done() shutdown, cancel := context.WithTimeout(context.Background(), cfg.ShutdownTimeout) defer cancel() <-shutdown.Done() if errors.Is(ctx.Err(), context.Canceled) { return nil } return ctx.Err() } func serveHTTP(addr string, h http.Handler) { if addr == "" { return } if err := http.ListenAndServe(addr, h); err != nil && !errors.Is(err, http.ErrServerClosed) { slog.Error("http server stopped", "addr", addr, "error", err) } } func healthHandler() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("ok\n")) }) return mux }