package persona import ( "context" "fmt" "os" "path/filepath" "strings" "github.com/VictorVargas/rony-llm-agent/pkg/llm" ) // Persona defines the personality and behavior of the agent. type Persona struct { ID string Name string Tone string Style string Language string Constraints []string FewShot []llm.Message } // Loader loads personas from files. type Loader interface { Load(ctx context.Context, configPath string) (Persona, error) Discover(ctx context.Context, workdir string) (Persona, error) } // ErrPersonaNotFound is returned when a persona file is not found. var ErrPersonaNotFound = fmt.Errorf("persona not found") // DefaultPersona returns a basic persona with sensible defaults. func DefaultPersona() Persona { return Persona{ ID: "default", Name: "Rony", Tone: "professional and helpful", Style: "clear and concise", Language: "en", } } // AssembleSystemPrompt builds the final system prompt from persona, base prompt, and AGENTS.md. func AssembleSystemPrompt(p Persona, agentsMD string) string { var parts []string // Base system prompt parts = append(parts, "You are an AI agent. Be helpful, accurate, and safe.") // Persona instructions if p.Name != "" { parts = append(parts, fmt.Sprintf("Your name is %s.", p.Name)) } if p.Tone != "" { parts = append(parts, fmt.Sprintf("Use a %s tone.", p.Tone)) } if p.Style != "" { parts = append(parts, fmt.Sprintf("Write in a %s style.", p.Style)) } if p.Language != "" { parts = append(parts, fmt.Sprintf("Respond in %s.", p.Language)) } for _, c := range p.Constraints { parts = append(parts, fmt.Sprintf("CONSTRAINT: %s", c)) } // AGENTS.md content if agentsMD != "" { parts = append(parts, "---") parts = append(parts, "Project instructions:") parts = append(parts, agentsMD) } return strings.Join(parts, "\n\n") } // discoverAgentsMD walks up the directory tree looking for AGENTS.md files. func discoverAgentsMD(root string) string { var parts []string current := root for { agentsPath := filepath.Join(current, "AGENTS.md") if _, err := os.Stat(agentsPath); err == nil { data, err := os.ReadFile(agentsPath) if err == nil { parts = append(parts, string(data)) } } parent := filepath.Dir(current) if parent == current || parent == "." { break } current = parent } // Also check ~/.config/rony/AGENTS.md home, err := os.UserHomeDir() if err == nil { globalPath := filepath.Join(home, ".config", "rony", "AGENTS.md") if data, err := os.ReadFile(globalPath); err == nil { parts = append(parts, string(data)) } } return strings.Join(parts, "\n\n") }