diff --git a/.env.example b/.env.example index d083cd0..a46d5ef 100644 --- a/.env.example +++ b/.env.example @@ -6,3 +6,12 @@ SUPERVISOR_MODELS_FILE=./config/models.yaml # LiteLLM gateway (iguana) LITELLM_BASE_URL=http://iguana:4000 LITELLM_API_KEY=your-litellm-master-key + +# Ingestion server +INGEST_BASE_URL=http://localhost:3300 +INGEST_PORT=3300 +INGEST_BRAIN_DIR=./brain + +# Brain directories +SUPERVISOR_SESSIONS_DIR=./brain/sessions +SUPERVISOR_BRAIN_DIR=./brain diff --git a/cmd/supervisor/main.go b/cmd/supervisor/main.go index d3d61c7..a57494c 100644 --- a/cmd/supervisor/main.go +++ b/cmd/supervisor/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "log/slog" "net/http" "os" @@ -9,7 +10,12 @@ import ( iexec "github.com/mathiasbq/supervisor/internal/exec" "github.com/mathiasbq/supervisor/internal/mcp" "github.com/mathiasbq/supervisor/internal/registry" + "github.com/mathiasbq/supervisor/internal/skills/brain" + "github.com/mathiasbq/supervisor/internal/skills/org" + "github.com/mathiasbq/supervisor/internal/skills/retrospective" + "github.com/mathiasbq/supervisor/internal/skills/sessionlog" "github.com/mathiasbq/supervisor/internal/skills/tdd" + "github.com/mathiasbq/supervisor/internal/tier" ) func main() { @@ -39,12 +45,22 @@ func main() { os.Exit(1) } + retroPrompt, err := os.ReadFile(cfg.ConfigDir + "/retrospective.md") + if err != nil { + logger.Error("read retrospective.md", "path", cfg.ConfigDir+"/retrospective.md", "err", err) + os.Exit(1) + } + executor := iexec.New(iexec.Config{ SystemPrompt: string(systemPrompt), LiteLLMBaseURL: cfg.LiteLLMBaseURL, LiteLLMAPIKey: cfg.LiteLLMAPIKey, }) + tierFn := func(ctx context.Context) tier.Info { + return tier.Detect(ctx, "https://api.anthropic.com", cfg.LiteLLMBaseURL) + } + reg := registry.New() reg.Register(tdd.New(tdd.Config{ SystemPrompt: string(systemPrompt), @@ -52,6 +68,21 @@ func main() { DefaultModel: models.Resolve("tdd", ""), ExecutorFn: executor.Run, })) + reg.Register(brain.New(brain.Config{ + IngestBaseURL: cfg.IngestBaseURL, + })) + reg.Register(org.New(org.Config{ + TierFn: tierFn, + })) + reg.Register(sessionlog.New(sessionlog.Config{ + SessionsDir: cfg.SessionsDir, + })) + reg.Register(retrospective.New(retrospective.Config{ + SkillPrompt: string(retroPrompt), + DefaultModel: models.Resolve("retrospective", ""), + SessionsDir: cfg.SessionsDir, + ExecutorFn: executor.Run, + })) srv := mcp.NewServer(reg) mux := http.NewServeMux() diff --git a/config/models.yaml b/config/models.yaml index cc3d63c..f26fb9b 100644 --- a/config/models.yaml +++ b/config/models.yaml @@ -5,6 +5,7 @@ default: ollama/qwen3-coder-30b-tuned skills: - tdd: ollama/qwen3-coder-30b-tuned - review: ollama/devstral-tuned - debug: ollama/deepseek-r1-tuned + tdd: ollama/qwen3-coder-30b-tuned + review: ollama/devstral-tuned + debug: ollama/deepseek-r1-tuned + retrospective: ollama/qwen3-coder-30b-tuned diff --git a/internal/config/config.go b/internal/config/config.go index d788d0a..2a7ff3f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,6 +8,9 @@ type Config struct { LiteLLMAPIKey string // LITELLM_API_KEY ConfigDir string // SUPERVISOR_CONFIG_DIR, default ./config/supervisor ModelsFile string // SUPERVISOR_MODELS_FILE, default /../models.yaml + IngestBaseURL string // INGEST_BASE_URL, default http://localhost:3300 + SessionsDir string // SUPERVISOR_SESSIONS_DIR, default ./brain/sessions + BrainDir string // SUPERVISOR_BRAIN_DIR, default ./brain } func Load() (Config, error) { @@ -18,6 +21,9 @@ func Load() (Config, error) { ConfigDir: envOr("SUPERVISOR_CONFIG_DIR", "./config/supervisor"), } cfg.ModelsFile = envOr("SUPERVISOR_MODELS_FILE", cfg.ConfigDir+"/../models.yaml") + cfg.IngestBaseURL = envOr("INGEST_BASE_URL", "http://localhost:3300") + cfg.SessionsDir = envOr("SUPERVISOR_SESSIONS_DIR", "./brain/sessions") + cfg.BrainDir = envOr("SUPERVISOR_BRAIN_DIR", "./brain") return cfg, nil } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 1b9ac32..f3c7ec9 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -13,12 +13,18 @@ func TestLoadDefaults(t *testing.T) { t.Setenv("LITELLM_BASE_URL", "") t.Setenv("LITELLM_API_KEY", "") t.Setenv("SUPERVISOR_CONFIG_DIR", "") + t.Setenv("INGEST_BASE_URL", "") + t.Setenv("SUPERVISOR_SESSIONS_DIR", "") + t.Setenv("SUPERVISOR_BRAIN_DIR", "") cfg, err := config.Load() require.NoError(t, err) assert.Equal(t, "3200", cfg.Port) assert.Equal(t, "http://iguana:4000", cfg.LiteLLMBaseURL) assert.Equal(t, "./config/supervisor", cfg.ConfigDir) + assert.Equal(t, "http://localhost:3300", cfg.IngestBaseURL) + assert.Equal(t, "./brain/sessions", cfg.SessionsDir) + assert.Equal(t, "./brain", cfg.BrainDir) } func TestLoadFromEnv(t *testing.T) {