// internal/skills/trainer/skill.go package trainer import ( "context" "encoding/json" iexec "github.com/mathiasbq/supervisor/internal/exec" "github.com/mathiasbq/supervisor/internal/registry" ) // ExecutorFn is the function signature for running a worker subprocess. type ExecutorFn func(ctx context.Context, req iexec.Request) (iexec.Result, error) // Config holds dependencies for the trainer skill. type Config struct { ReaderPrompt string WriterPrompt string DefaultModel string ExecutorFn ExecutorFn SessionsDir string BrainDir string // root of brain/ directory; writer writes to BrainDir/training-data/ } // Skill implements the trainer MCP tool. type Skill struct{ cfg Config } // New creates a new trainer Skill. func New(cfg Config) *Skill { return &Skill{cfg: cfg} } // Name returns the skill identifier. func (s *Skill) Name() string { return "trainer" } // Tools returns the MCP tool definitions for this skill. func (s *Skill) Tools() []registry.ToolDef { schema := func(required []string, props map[string]any) json.RawMessage { b, _ := json.Marshal(map[string]any{"type": "object", "required": required, "properties": props}) return b } return []registry.ToolDef{ { Name: "trainer", Description: "Extract SFT and DPO training pairs from a session log. Runs a reader→writer chain: reader identifies learning moments, writer formats and writes pairs to brain/training-data/.", InputSchema: schema( []string{"session_id"}, map[string]any{ "session_id": map[string]any{"type": "string"}, "model": map[string]any{"type": "string"}, }, ), }, } }