11import pathlib
22
3- from pydantic import BaseModel , Field , field_validator
3+ from pydantic import BaseModel , Field , field_validator , model_validator
44
55from openhands .sdk .context .prompts import render_template
66from openhands .sdk .context .skills import (
77 Skill ,
88 SkillKnowledge ,
9+ load_user_skills ,
910)
1011from openhands .sdk .llm import Message , TextContent
1112from openhands .sdk .logger import get_logger
@@ -48,6 +49,13 @@ class AgentContext(BaseModel):
4849 user_message_suffix : str | None = Field (
4950 default = None , description = "Optional suffix to append to the user's message."
5051 )
52+ load_user_skills : bool = Field (
53+ default = False ,
54+ description = (
55+ "Whether to automatically load user skills from ~/.openhands/skills/ "
56+ "and ~/.openhands/microagents/ (for backward compatibility). "
57+ ),
58+ )
5159
5260 @field_validator ("skills" )
5361 @classmethod
@@ -62,6 +70,29 @@ def _validate_skills(cls, v: list[Skill], _info):
6270 seen_names .add (skill .name )
6371 return v
6472
73+ @model_validator (mode = "after" )
74+ def _load_user_skills (self ):
75+ """Load user skills from home directory if enabled."""
76+ if not self .load_user_skills :
77+ return self
78+
79+ try :
80+ user_skills = load_user_skills ()
81+ # Merge user skills with explicit skills, avoiding duplicates
82+ existing_names = {skill .name for skill in self .skills }
83+ for user_skill in user_skills :
84+ if user_skill .name not in existing_names :
85+ self .skills .append (user_skill )
86+ else :
87+ logger .warning (
88+ f"Skipping user skill '{ user_skill .name } ' "
89+ f"(already in explicit skills)"
90+ )
91+ except Exception as e :
92+ logger .warning (f"Failed to load user skills: { str (e )} " )
93+
94+ return self
95+
6596 def get_system_message_suffix (self ) -> str | None :
6697 """Get the system message with repo skill content and custom suffix.
6798
0 commit comments