// internal/skills/retrospective/handlers.go package retrospective import ( "context" "encoding/json" "fmt" "time" iexec "github.com/mathiasbq/supervisor/internal/exec" "github.com/mathiasbq/supervisor/internal/session" ) type retroArgs struct { SessionID string `json:"session_id"` Model string `json:"model,omitempty"` } // Handle dispatches the retrospective tool call. func (s *Skill) Handle(ctx context.Context, tool string, args json.RawMessage) (json.RawMessage, error) { if tool != "retrospective" { return nil, fmt.Errorf("unknown retrospective tool: %s", tool) } var a retroArgs if err := json.Unmarshal(args, &a); err != nil { return nil, fmt.Errorf("parse args: %w", err) } if a.SessionID == "" { return nil, fmt.Errorf("session_id is required") } model := a.Model if model == "" { model = s.cfg.DefaultModel } // Read session log entries (empty slice if no log exists yet). entries, err := session.Read(s.cfg.SessionsDir, a.SessionID) if err != nil { return nil, fmt.Errorf("read session log: %w", err) } logJSON, err := json.MarshalIndent(entries, "", " ") if err != nil { return nil, fmt.Errorf("marshal session log: %w", err) } taskPrompt := fmt.Sprintf( "SESSION_ID: %s\n\nSESSION_LOG:\n%s\n\nReview this session log. Identify what is novel or worth preserving as organizational knowledge. Write structured entries to brain/raw/ via brain_write. Return JSON result when done.", a.SessionID, string(logJSON), ) if s.cfg.ExecutorFn == nil { return nil, fmt.Errorf("no executor configured") } t0 := time.Now() result, err := s.cfg.ExecutorFn(ctx, iexec.Request{ SkillPrompt: s.cfg.SkillPrompt, TaskPrompt: taskPrompt, Model: model, Tools: "Bash,Read,Write", }) if err != nil { return nil, fmt.Errorf("retrospective worker: %w", err) } _ = session.Append(s.cfg.SessionsDir, a.SessionID, session.Entry{ SessionID: a.SessionID, Timestamp: time.Now(), Skill: "retrospective", Phase: "retrospective", Attempts: session.AttemptsFrom(result.Attempts), FinalStatus: result.Status, ModelUsed: result.ModelUsed, DurationMs: time.Since(t0).Milliseconds(), Message: result.Message, }) b, err := json.Marshal(result) if err != nil { return nil, fmt.Errorf("marshal result: %w", err) } return b, nil }