diff --git a/examples/05_skills_and_plugins/01_loading_agentskills/main.py b/examples/05_skills_and_plugins/01_loading_agentskills/main.py index 7079cb8450..6b1371d168 100644 --- a/examples/05_skills_and_plugins/01_loading_agentskills/main.py +++ b/examples/05_skills_and_plugins/01_loading_agentskills/main.py @@ -27,7 +27,7 @@ from pydantic import SecretStr from openhands.sdk import LLM, Agent, AgentContext, Conversation -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( discover_skill_resources, load_skills_from_dir, ) diff --git a/openhands-agent-server/openhands/agent_server/skills_router.py b/openhands-agent-server/openhands/agent_server/skills_router.py index b01c21b893..0c2e214301 100644 --- a/openhands-agent-server/openhands/agent_server/skills_router.py +++ b/openhands-agent-server/openhands/agent_server/skills_router.py @@ -14,7 +14,7 @@ load_all_skills, sync_public_skills, ) -from openhands.sdk.context.skills.skill import DEFAULT_MARKETPLACE_PATH +from openhands.sdk.skills.skill import DEFAULT_MARKETPLACE_PATH skills_router = APIRouter(prefix="/skills", tags=["Skills"]) diff --git a/openhands-agent-server/openhands/agent_server/skills_service.py b/openhands-agent-server/openhands/agent_server/skills_service.py index 68bc390512..43b66d448c 100644 --- a/openhands-agent-server/openhands/agent_server/skills_service.py +++ b/openhands-agent-server/openhands/agent_server/skills_service.py @@ -20,21 +20,21 @@ from dataclasses import dataclass from pathlib import Path -from openhands.sdk.context.skills import ( +from openhands.sdk.logger import get_logger +from openhands.sdk.skills import ( Skill, load_available_skills, ) -from openhands.sdk.context.skills.skill import ( +from openhands.sdk.skills.skill import ( DEFAULT_MARKETPLACE_PATH, PUBLIC_SKILLS_BRANCH, PUBLIC_SKILLS_REPO, load_skills_from_dir, ) -from openhands.sdk.context.skills.utils import ( +from openhands.sdk.skills.utils import ( get_skills_cache_dir, update_skills_repository, ) -from openhands.sdk.logger import get_logger from openhands.sdk.utils import sanitized_env diff --git a/openhands-sdk/openhands/sdk/__init__.py b/openhands-sdk/openhands/sdk/__init__.py index 4aae71e5a2..a509bfa58e 100644 --- a/openhands-sdk/openhands/sdk/__init__.py +++ b/openhands-sdk/openhands/sdk/__init__.py @@ -5,12 +5,7 @@ AgentBase, ) from openhands.sdk.banner import _print_banner -from openhands.sdk.context import ( - AgentContext, - load_project_skills, - load_skills_from_dir, - load_user_skills, -) +from openhands.sdk.context import AgentContext from openhands.sdk.context.condenser import ( LLMSummarizingCondenser, ) @@ -65,6 +60,11 @@ SettingsSectionMetadata, field_meta, ) +from openhands.sdk.skills import ( + load_project_skills, + load_skills_from_dir, + load_user_skills, +) from openhands.sdk.subagent import ( agent_definition_to_factory, load_agents_from_dir, diff --git a/openhands-sdk/openhands/sdk/context/__init__.py b/openhands-sdk/openhands/sdk/context/__init__.py index 5343cf20b7..b1bdb11fe6 100644 --- a/openhands-sdk/openhands/sdk/context/__init__.py +++ b/openhands-sdk/openhands/sdk/context/__init__.py @@ -1,6 +1,8 @@ from openhands.sdk.context.agent_context import AgentContext from openhands.sdk.context.prompts import render_template -from openhands.sdk.context.skills import ( + +# Import from canonical location (openhands.sdk.skills) +from openhands.sdk.skills import ( BaseTrigger, KeywordTrigger, Skill, diff --git a/openhands-sdk/openhands/sdk/context/agent_context.py b/openhands-sdk/openhands/sdk/context/agent_context.py index 9c07613321..27a72b0e86 100644 --- a/openhands-sdk/openhands/sdk/context/agent_context.py +++ b/openhands-sdk/openhands/sdk/context/agent_context.py @@ -7,17 +7,17 @@ from pydantic import BaseModel, Field, field_validator, model_validator from openhands.sdk.context.prompts import render_template -from openhands.sdk.context.skills import ( +from openhands.sdk.llm import Message, TextContent +from openhands.sdk.llm.utils.model_prompt_spec import get_model_prompt_spec +from openhands.sdk.logger import get_logger +from openhands.sdk.secret import SecretSource, SecretValue +from openhands.sdk.skills import ( Skill, SkillKnowledge, load_available_skills, to_prompt, ) -from openhands.sdk.context.skills.skill import DEFAULT_MARKETPLACE_PATH -from openhands.sdk.llm import Message, TextContent -from openhands.sdk.llm.utils.model_prompt_spec import get_model_prompt_spec -from openhands.sdk.logger import get_logger -from openhands.sdk.secret import SecretSource, SecretValue +from openhands.sdk.skills.skill import DEFAULT_MARKETPLACE_PATH logger = get_logger(__name__) diff --git a/openhands-sdk/openhands/sdk/context/skills/__init__.py b/openhands-sdk/openhands/sdk/context/skills/__init__.py index 940ffbc479..5c0d15581b 100644 --- a/openhands-sdk/openhands/sdk/context/skills/__init__.py +++ b/openhands-sdk/openhands/sdk/context/skills/__init__.py @@ -1,42 +1,124 @@ -from openhands.sdk.context.skills.exceptions import SkillValidationError -from openhands.sdk.context.skills.skill import ( - Skill, - SkillResources, - load_available_skills, - load_project_skills, - load_public_skills, - load_skills_from_dir, - load_user_skills, - to_prompt, -) -from openhands.sdk.context.skills.trigger import ( - BaseTrigger, - KeywordTrigger, - TaskTrigger, -) -from openhands.sdk.context.skills.types import SkillKnowledge -from openhands.sdk.context.skills.utils import ( - RESOURCE_DIRECTORIES, - discover_skill_resources, - validate_skill_name, -) +"""Deprecated: Use openhands.sdk.skills instead. + +This module is deprecated and will be removed in a future version. +All skill-related imports should come from `openhands.sdk.skills`. + +Migration guide: + # Old (deprecated): + from openhands.sdk.context.skills import Skill, load_skills_from_dir + + # New: + from openhands.sdk.skills import Skill, load_skills_from_dir +""" + +from openhands.sdk.utils.deprecation import warn_deprecated + + +def __getattr__(name: str): + """Lazily import from openhands.sdk.skills with deprecation warning.""" + # Import the canonical module + from openhands.sdk import skills as _skills + + # List of valid exports that we re-export with deprecation warning + _VALID_EXPORTS = { + # Exceptions + "SkillError", + "SkillValidationError", + # Core skill model and loading + "Skill", + "SkillInfo", + "SkillResources", + "load_skills_from_dir", + "load_project_skills", + "load_user_skills", + "load_public_skills", + "load_available_skills", + "to_prompt", + # Triggers + "BaseTrigger", + "KeywordTrigger", + "TaskTrigger", + # Types + "SkillKnowledge", + "InputMetadata", + "SkillResponse", + "SkillContentResponse", + # Utilities + "discover_skill_resources", + "RESOURCE_DIRECTORIES", + "validate_skill_name", + } + + if name in _VALID_EXPORTS: + warn_deprecated( + f"Importing '{name}' from 'openhands.sdk.context.skills'", + deprecated_in="1.16.0", + removed_in="1.20.0", + details=f"Use 'from openhands.sdk.skills import {name}' instead.", + stacklevel=3, + ) + return getattr(_skills, name) + + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +def __dir__(): + """List available attributes for tab-completion.""" + return [ + # Exceptions + "SkillError", + "SkillValidationError", + # Core skill model and loading + "Skill", + "SkillInfo", + "SkillResources", + "load_skills_from_dir", + "load_project_skills", + "load_user_skills", + "load_public_skills", + "load_available_skills", + "to_prompt", + # Triggers + "BaseTrigger", + "KeywordTrigger", + "TaskTrigger", + # Types + "SkillKnowledge", + "InputMetadata", + "SkillResponse", + "SkillContentResponse", + # Utilities + "discover_skill_resources", + "RESOURCE_DIRECTORIES", + "validate_skill_name", + ] __all__ = [ + # Exceptions + "SkillError", + "SkillValidationError", + # Core skill model and loading "Skill", + "SkillInfo", "SkillResources", + "load_skills_from_dir", + "load_project_skills", + "load_user_skills", + "load_public_skills", + "load_available_skills", + "to_prompt", + # Triggers "BaseTrigger", "KeywordTrigger", "TaskTrigger", + # Types "SkillKnowledge", - "load_available_skills", - "load_skills_from_dir", - "load_user_skills", - "load_project_skills", - "load_public_skills", - "SkillValidationError", + "InputMetadata", + "SkillResponse", + "SkillContentResponse", + # Utilities "discover_skill_resources", "RESOURCE_DIRECTORIES", - "to_prompt", "validate_skill_name", ] diff --git a/openhands-sdk/openhands/sdk/plugin/plugin.py b/openhands-sdk/openhands/sdk/plugin/plugin.py index dfd47fa777..d90d110da1 100644 --- a/openhands-sdk/openhands/sdk/plugin/plugin.py +++ b/openhands-sdk/openhands/sdk/plugin/plugin.py @@ -8,12 +8,6 @@ from pydantic import BaseModel, Field -from openhands.sdk.context.skills import Skill -from openhands.sdk.context.skills.utils import ( - discover_skill_resources, - find_skill_md, - load_mcp_config, -) from openhands.sdk.hooks import HookConfig from openhands.sdk.logger import get_logger from openhands.sdk.plugin.fetch import fetch_plugin @@ -22,6 +16,12 @@ PluginAuthor, PluginManifest, ) +from openhands.sdk.skills.skill import Skill +from openhands.sdk.skills.utils import ( + discover_skill_resources, + find_skill_md, + load_mcp_config, +) from openhands.sdk.subagent.schema import AgentDefinition diff --git a/openhands-sdk/openhands/sdk/plugin/types.py b/openhands-sdk/openhands/sdk/plugin/types.py index 8ff2e904d3..29030e0254 100644 --- a/openhands-sdk/openhands/sdk/plugin/types.py +++ b/openhands-sdk/openhands/sdk/plugin/types.py @@ -188,7 +188,7 @@ def to_plugin_source(self) -> PluginSource: if TYPE_CHECKING: - from openhands.sdk.context.skills import Skill + from openhands.sdk.skills.skill import Skill class PluginAuthor(BaseModel): @@ -335,8 +335,8 @@ def to_skill(self, plugin_name: str) -> Skill: - Trigger keyword: "/city-weather:now" - When user types "/city-weather:now Tokyo", the skill activates """ - from openhands.sdk.context.skills import Skill - from openhands.sdk.context.skills.trigger import KeywordTrigger + from openhands.sdk.skills.skill import Skill + from openhands.sdk.skills.trigger import KeywordTrigger # Build the trigger keyword in Claude Code namespace format trigger_keyword = f"/{plugin_name}:{self.name}" diff --git a/openhands-sdk/openhands/sdk/skills/__init__.py b/openhands-sdk/openhands/sdk/skills/__init__.py index 1625ba3693..66e9645324 100644 --- a/openhands-sdk/openhands/sdk/skills/__init__.py +++ b/openhands-sdk/openhands/sdk/skills/__init__.py @@ -1,6 +1,44 @@ -"""Skill management utilities for OpenHands SDK.""" +"""Skill management for OpenHands SDK. +This module provides the unified API for working with skills: + +**Core Skill Model & Loading:** +- `Skill` - The skill data model +- `SkillResources` - Resource directories for a skill (scripts/, references/, assets/) +- `load_skills_from_dir` - Load skills from a directory +- `load_project_skills` - Load skills from project's .agents/skills/ +- `load_user_skills` - Load skills from ~/.openhands/skills/ +- `load_public_skills` - Load skills from the public OpenHands extensions repo +- `load_available_skills` - Load and merge skills from multiple sources + +**Triggers:** +- `BaseTrigger`, `KeywordTrigger`, `TaskTrigger` - Skill activation triggers + +**Installed Skills Management:** +- `install_skill` - Install a skill from a source +- `uninstall_skill` - Uninstall a skill +- `list_installed_skills` - List all installed skills +- `load_installed_skills` - Load enabled installed skills +- `enable_skill`, `disable_skill` - Toggle skill enabled state +- `update_skill` - Update an installed skill + +**Types:** +- `SkillKnowledge` - Represents knowledge from a triggered skill +- `InputMetadata` - Metadata for task skill inputs + +**Utilities:** +- `discover_skill_resources` - Discover resource directories in a skill +- `validate_skill_name` - Validate skill name per AgentSkills spec +- `to_prompt` - Generate XML prompt block for available skills +""" + +# Exceptions +from openhands.sdk.skills.exceptions import SkillError, SkillValidationError + +# Fetch utilities from openhands.sdk.skills.fetch import SkillFetchError, fetch_skill_with_resolution + +# Installed skills management from openhands.sdk.skills.installed import ( InstalledSkillInfo, InstalledSkillsMetadata, @@ -16,10 +54,50 @@ update_skill, ) +# Core skill model and loading +from openhands.sdk.skills.skill import ( + Skill, + SkillInfo, + SkillResources, + load_available_skills, + load_project_skills, + load_public_skills, + load_skills_from_dir, + load_user_skills, + to_prompt, +) + +# Triggers +from openhands.sdk.skills.trigger import ( + BaseTrigger, + KeywordTrigger, + TaskTrigger, +) + +# Types +from openhands.sdk.skills.types import ( + InputMetadata, + SkillContentResponse, + SkillKnowledge, + SkillResponse, +) + +# Utilities +from openhands.sdk.skills.utils import ( + RESOURCE_DIRECTORIES, + discover_skill_resources, + validate_skill_name, +) + __all__ = [ + # Exceptions + "SkillError", + "SkillValidationError", + # Fetch "SkillFetchError", "fetch_skill_with_resolution", + # Installed skills management "InstalledSkillInfo", "InstalledSkillsMetadata", "install_skill", @@ -32,4 +110,27 @@ "enable_skill", "disable_skill", "update_skill", + # Core skill model and loading + "Skill", + "SkillInfo", + "SkillResources", + "load_skills_from_dir", + "load_project_skills", + "load_user_skills", + "load_public_skills", + "load_available_skills", + "to_prompt", + # Triggers + "BaseTrigger", + "KeywordTrigger", + "TaskTrigger", + # Types + "SkillKnowledge", + "InputMetadata", + "SkillResponse", + "SkillContentResponse", + # Utilities + "discover_skill_resources", + "RESOURCE_DIRECTORIES", + "validate_skill_name", ] diff --git a/openhands-sdk/openhands/sdk/context/skills/exceptions.py b/openhands-sdk/openhands/sdk/skills/exceptions.py similarity index 100% rename from openhands-sdk/openhands/sdk/context/skills/exceptions.py rename to openhands-sdk/openhands/sdk/skills/exceptions.py diff --git a/openhands-sdk/openhands/sdk/context/skills/execute.py b/openhands-sdk/openhands/sdk/skills/execute.py similarity index 100% rename from openhands-sdk/openhands/sdk/context/skills/execute.py rename to openhands-sdk/openhands/sdk/skills/execute.py diff --git a/openhands-sdk/openhands/sdk/skills/installed.py b/openhands-sdk/openhands/sdk/skills/installed.py index 896327ab0a..ed25ad8463 100644 --- a/openhands-sdk/openhands/sdk/skills/installed.py +++ b/openhands-sdk/openhands/sdk/skills/installed.py @@ -13,11 +13,11 @@ from pydantic import BaseModel, Field -from openhands.sdk.context.skills.exceptions import SkillError, SkillValidationError -from openhands.sdk.context.skills.skill import Skill, load_skills_from_dir -from openhands.sdk.context.skills.utils import find_skill_md, validate_skill_name from openhands.sdk.logger import get_logger +from openhands.sdk.skills.exceptions import SkillError, SkillValidationError from openhands.sdk.skills.fetch import fetch_skill_with_resolution +from openhands.sdk.skills.skill import Skill, load_skills_from_dir +from openhands.sdk.skills.utils import find_skill_md, validate_skill_name logger = get_logger(__name__) diff --git a/openhands-sdk/openhands/sdk/context/skills/skill.py b/openhands-sdk/openhands/sdk/skills/skill.py similarity index 99% rename from openhands-sdk/openhands/sdk/context/skills/skill.py rename to openhands-sdk/openhands/sdk/skills/skill.py index d431dbf781..cb0cdb837c 100644 --- a/openhands-sdk/openhands/sdk/context/skills/skill.py +++ b/openhands-sdk/openhands/sdk/skills/skill.py @@ -11,14 +11,15 @@ from fastmcp.mcp_config import MCPConfig from pydantic import BaseModel, Field, field_validator, model_validator -from openhands.sdk.context.skills.exceptions import SkillError, SkillValidationError -from openhands.sdk.context.skills.execute import render_content_with_commands -from openhands.sdk.context.skills.trigger import ( +from openhands.sdk.logger import get_logger +from openhands.sdk.skills.exceptions import SkillError, SkillValidationError +from openhands.sdk.skills.execute import render_content_with_commands +from openhands.sdk.skills.trigger import ( KeywordTrigger, TaskTrigger, ) -from openhands.sdk.context.skills.types import InputMetadata -from openhands.sdk.context.skills.utils import ( +from openhands.sdk.skills.types import InputMetadata +from openhands.sdk.skills.utils import ( discover_skill_resources, find_mcp_config, find_regular_md_files, @@ -30,7 +31,6 @@ update_skills_repository, validate_skill_name, ) -from openhands.sdk.logger import get_logger from openhands.sdk.utils import DEFAULT_TRUNCATE_NOTICE, maybe_truncate @@ -981,7 +981,7 @@ def load_public_skills( Example: >>> from openhands.sdk.context import AgentContext - >>> from openhands.sdk.context.skills import load_public_skills + >>> from openhands.sdk.skills import load_public_skills >>> >>> # Load public skills >>> public_skills = load_public_skills() diff --git a/openhands-sdk/openhands/sdk/context/skills/trigger.py b/openhands-sdk/openhands/sdk/skills/trigger.py similarity index 100% rename from openhands-sdk/openhands/sdk/context/skills/trigger.py rename to openhands-sdk/openhands/sdk/skills/trigger.py diff --git a/openhands-sdk/openhands/sdk/context/skills/types.py b/openhands-sdk/openhands/sdk/skills/types.py similarity index 100% rename from openhands-sdk/openhands/sdk/context/skills/types.py rename to openhands-sdk/openhands/sdk/skills/types.py diff --git a/openhands-sdk/openhands/sdk/context/skills/utils.py b/openhands-sdk/openhands/sdk/skills/utils.py similarity index 97% rename from openhands-sdk/openhands/sdk/context/skills/utils.py rename to openhands-sdk/openhands/sdk/skills/utils.py index dc0615b127..4d4fc00be1 100644 --- a/openhands-sdk/openhands/sdk/context/skills/utils.py +++ b/openhands-sdk/openhands/sdk/skills/utils.py @@ -10,13 +10,13 @@ from fastmcp.mcp_config import MCPConfig -from openhands.sdk.context.skills.exceptions import SkillValidationError from openhands.sdk.git.cached_repo import try_cached_clone_or_update from openhands.sdk.logger import get_logger +from openhands.sdk.skills.exceptions import SkillValidationError if TYPE_CHECKING: - from openhands.sdk.context.skills.skill import Skill, SkillResources + from openhands.sdk.skills.skill import Skill, SkillResources logger = get_logger(__name__) @@ -297,7 +297,7 @@ def load_and_categorize( agent_skills: Dictionary for AgentSkills standard SKILL.md files. """ # Import here to avoid circular dependency - from openhands.sdk.context.skills.skill import Skill + from openhands.sdk.skills.skill import Skill skill = Skill.load(path, skill_base_dir) @@ -360,7 +360,7 @@ def discover_skill_resources(skill_dir: Path) -> SkillResources: SkillResources with lists of files in each resource directory. """ # Import here to avoid circular dependency - from openhands.sdk.context.skills.skill import SkillResources + from openhands.sdk.skills.skill import SkillResources resources = SkillResources(skill_root=str(skill_dir.resolve())) diff --git a/openhands-sdk/openhands/sdk/subagent/registry.py b/openhands-sdk/openhands/sdk/subagent/registry.py index 1996469fd9..0722914875 100644 --- a/openhands-sdk/openhands/sdk/subagent/registry.py +++ b/openhands-sdk/openhands/sdk/subagent/registry.py @@ -189,7 +189,7 @@ def agent_definition_to_factory( # Priority: project skills override user skills (handled by load_available_skills). resolved_skills: list = [] if agent_def.skills: - from openhands.sdk.context.skills import load_available_skills + from openhands.sdk.skills import load_available_skills available = load_available_skills( work_dir, include_user=True, include_project=True, include_public=False diff --git a/tests/agent_server/test_skills_router.py b/tests/agent_server/test_skills_router.py index 96f0b9886b..da1ae2dd0c 100644 --- a/tests/agent_server/test_skills_router.py +++ b/tests/agent_server/test_skills_router.py @@ -7,7 +7,7 @@ from openhands.agent_server.api import api from openhands.agent_server.skills_service import SkillLoadResult -from openhands.sdk.context.skills import KeywordTrigger, Skill +from openhands.sdk.skills import KeywordTrigger, Skill @pytest.fixture diff --git a/tests/agent_server/test_skills_service.py b/tests/agent_server/test_skills_service.py index e5daf00962..f5471d4b5b 100644 --- a/tests/agent_server/test_skills_service.py +++ b/tests/agent_server/test_skills_service.py @@ -14,7 +14,7 @@ merge_skills, sync_public_skills, ) -from openhands.sdk.context.skills import Skill +from openhands.sdk.skills import Skill class TestExposedUrlData: diff --git a/tests/sdk/context/skill/__init__.py b/tests/sdk/context/skill/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/sdk/context/test_agent_context.py b/tests/sdk/context/test_agent_context.py index 402a24dc9b..ea584e8ecd 100644 --- a/tests/sdk/context/test_agent_context.py +++ b/tests/sdk/context/test_agent_context.py @@ -4,12 +4,12 @@ from pydantic import SecretStr from openhands.sdk.context.agent_context import AgentContext -from openhands.sdk.context.skills import ( +from openhands.sdk.llm import Message, TextContent +from openhands.sdk.secret import LookupSecret, StaticSecret +from openhands.sdk.skills import ( KeywordTrigger, Skill, ) -from openhands.sdk.llm import Message, TextContent -from openhands.sdk.secret import LookupSecret, StaticSecret class TestAgentContext: diff --git a/tests/sdk/context/test_agent_context_model_specific.py b/tests/sdk/context/test_agent_context_model_specific.py index 764fa323a1..8b2f0269ae 100644 --- a/tests/sdk/context/test_agent_context_model_specific.py +++ b/tests/sdk/context/test_agent_context_model_specific.py @@ -3,7 +3,7 @@ import pytest from openhands.sdk.context.agent_context import AgentContext -from openhands.sdk.context.skills import load_project_skills +from openhands.sdk.skills import load_project_skills _REPO_BASELINE_TEXT = ( diff --git a/tests/sdk/context/test_agent_context_serialization.py b/tests/sdk/context/test_agent_context_serialization.py index c5b3f47168..cd34ea650f 100644 --- a/tests/sdk/context/test_agent_context_serialization.py +++ b/tests/sdk/context/test_agent_context_serialization.py @@ -3,12 +3,12 @@ import json from openhands.sdk.context.agent_context import AgentContext -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( KeywordTrigger, Skill, TaskTrigger, ) -from openhands.sdk.context.skills.types import InputMetadata +from openhands.sdk.skills.types import InputMetadata def test_agent_context_serialization_roundtrip(): diff --git a/tests/sdk/conversation/test_repo_root_project_skills.py b/tests/sdk/conversation/test_repo_root_project_skills.py index 578cc1f9c1..052b3f247d 100644 --- a/tests/sdk/conversation/test_repo_root_project_skills.py +++ b/tests/sdk/conversation/test_repo_root_project_skills.py @@ -4,10 +4,10 @@ from openhands.sdk.agent import Agent from openhands.sdk.context.agent_context import AgentContext -from openhands.sdk.context.skills import load_project_skills from openhands.sdk.conversation.impl.local_conversation import LocalConversation from openhands.sdk.event import SystemPromptEvent from openhands.sdk.llm import Message, TextContent +from openhands.sdk.skills import load_project_skills from openhands.sdk.testing import TestLLM diff --git a/tests/sdk/llm/test_prompt_caching_cross_conversation.py b/tests/sdk/llm/test_prompt_caching_cross_conversation.py index a2ec3f9699..3d842e1617 100644 --- a/tests/sdk/llm/test_prompt_caching_cross_conversation.py +++ b/tests/sdk/llm/test_prompt_caching_cross_conversation.py @@ -11,8 +11,8 @@ from pydantic import SecretStr from openhands.sdk import LLM, Agent, AgentContext -from openhands.sdk.context.skills import Skill from openhands.sdk.llm import Message, TextContent +from openhands.sdk.skills import Skill def test_static_system_message_is_constant_across_different_contexts(): diff --git a/tests/sdk/plugin/test_plugin_loader.py b/tests/sdk/plugin/test_plugin_loader.py index 7f6a01d205..f8aa8e9fde 100644 --- a/tests/sdk/plugin/test_plugin_loader.py +++ b/tests/sdk/plugin/test_plugin_loader.py @@ -8,7 +8,6 @@ from openhands.sdk import LLM, Agent from openhands.sdk.context import AgentContext -from openhands.sdk.context.skills import Skill from openhands.sdk.hooks import HookConfig from openhands.sdk.hooks.config import HookDefinition, HookMatcher from openhands.sdk.plugin import ( @@ -16,6 +15,7 @@ PluginSource, load_plugins, ) +from openhands.sdk.skills import Skill @pytest.fixture diff --git a/tests/sdk/plugin/test_plugin_loading.py b/tests/sdk/plugin/test_plugin_loading.py index 71fd791820..6657cf20c5 100644 --- a/tests/sdk/plugin/test_plugin_loading.py +++ b/tests/sdk/plugin/test_plugin_loading.py @@ -280,7 +280,7 @@ def test_load_plugin_without_entry_command(self, tmp_path: Path): def test_command_to_skill_conversion(self, tmp_path: Path): """Test converting a command to a keyword-triggered skill.""" - from openhands.sdk.context.skills.trigger import KeywordTrigger + from openhands.sdk.skills.trigger import KeywordTrigger plugin_dir = tmp_path / "city-weather" plugin_dir.mkdir() @@ -327,7 +327,7 @@ def test_command_to_skill_conversion(self, tmp_path: Path): def test_get_all_skills_with_commands(self, tmp_path: Path): """Test get_all_skills returns both skills and command-derived skills.""" - from openhands.sdk.context.skills.trigger import KeywordTrigger + from openhands.sdk.skills.trigger import KeywordTrigger plugin_dir = tmp_path / "test-plugin" plugin_dir.mkdir() diff --git a/tests/sdk/plugin/test_plugin_merging.py b/tests/sdk/plugin/test_plugin_merging.py index aba370ed2a..b1eb0d85e6 100644 --- a/tests/sdk/plugin/test_plugin_merging.py +++ b/tests/sdk/plugin/test_plugin_merging.py @@ -3,8 +3,8 @@ import pytest from openhands.sdk.context import AgentContext -from openhands.sdk.context.skills import Skill from openhands.sdk.plugin import Plugin, PluginManifest +from openhands.sdk.skills import Skill class TestPluginAddSkillsTo: diff --git a/tests/sdk/context/skill/test_agentskills_fields.py b/tests/sdk/skills/test_agentskills_fields.py similarity index 97% rename from tests/sdk/context/skill/test_agentskills_fields.py rename to tests/sdk/skills/test_agentskills_fields.py index 97f32b461f..d137178042 100644 --- a/tests/sdk/context/skill/test_agentskills_fields.py +++ b/tests/sdk/skills/test_agentskills_fields.py @@ -3,7 +3,7 @@ import pytest from pydantic import ValidationError -from openhands.sdk.context.skills import Skill, SkillValidationError +from openhands.sdk.skills import Skill, SkillValidationError def test_skill_with_agentskills_fields(tmp_path) -> None: diff --git a/tests/sdk/context/skill/test_extensions_ref.py b/tests/sdk/skills/test_extensions_ref.py similarity index 88% rename from tests/sdk/context/skill/test_extensions_ref.py rename to tests/sdk/skills/test_extensions_ref.py index 612135fb4f..992afff82f 100644 --- a/tests/sdk/context/skill/test_extensions_ref.py +++ b/tests/sdk/skills/test_extensions_ref.py @@ -34,7 +34,7 @@ def test_extensions_ref_default(): import os if "EXTENSIONS_REF" in os.environ: del os.environ["EXTENSIONS_REF"] -from openhands.sdk.context.skills.skill import PUBLIC_SKILLS_BRANCH +from openhands.sdk.skills.skill import PUBLIC_SKILLS_BRANCH assert PUBLIC_SKILLS_BRANCH == "main", ( f"Expected 'main' but got '{PUBLIC_SKILLS_BRANCH}'" ) @@ -45,7 +45,7 @@ def test_extensions_ref_default(): def test_extensions_ref_custom_branch(): """PUBLIC_SKILLS_BRANCH should use EXTENSIONS_REF when set.""" code = """ -from openhands.sdk.context.skills.skill import PUBLIC_SKILLS_BRANCH +from openhands.sdk.skills.skill import PUBLIC_SKILLS_BRANCH assert PUBLIC_SKILLS_BRANCH == "feature-branch", ( f"Expected 'feature-branch' but got '{PUBLIC_SKILLS_BRANCH}'" ) @@ -57,7 +57,7 @@ def test_extensions_ref_with_load_public_skills(): """load_public_skills should respect EXTENSIONS_REF environment variable.""" code = """ from unittest import mock -from openhands.sdk.context.skills.skill import ( +from openhands.sdk.skills.skill import ( PUBLIC_SKILLS_BRANCH, load_public_skills, ) @@ -65,7 +65,7 @@ def test_extensions_ref_with_load_public_skills(): f"Expected 'test-branch' but got '{PUBLIC_SKILLS_BRANCH}'" ) with mock.patch( - "openhands.sdk.context.skills.skill.update_skills_repository" + "openhands.sdk.skills.skill.update_skills_repository" ) as mock_update: mock_update.return_value = None load_public_skills() @@ -82,7 +82,7 @@ def test_extensions_ref_with_load_public_skills(): def test_extensions_ref_empty_string(): """Empty EXTENSIONS_REF should fall back to 'main'.""" code = """ -from openhands.sdk.context.skills.skill import PUBLIC_SKILLS_BRANCH +from openhands.sdk.skills.skill import PUBLIC_SKILLS_BRANCH # Empty string returns empty string per os.environ.get behavior assert PUBLIC_SKILLS_BRANCH == "", ( f"Expected '' but got '{PUBLIC_SKILLS_BRANCH}'" diff --git a/tests/sdk/skills/test_installed_skills.py b/tests/sdk/skills/test_installed_skills.py index 43dc6de198..02b2b3086a 100644 --- a/tests/sdk/skills/test_installed_skills.py +++ b/tests/sdk/skills/test_installed_skills.py @@ -7,7 +7,6 @@ import pytest -from openhands.sdk.context.skills.exceptions import SkillValidationError from openhands.sdk.skills import ( InstalledSkillsMetadata, disable_skill, @@ -20,6 +19,7 @@ uninstall_skill, update_skill, ) +from openhands.sdk.skills.exceptions import SkillValidationError def _create_skill_dir( diff --git a/tests/sdk/context/skill/test_load_project_skills.py b/tests/sdk/skills/test_load_project_skills.py similarity index 99% rename from tests/sdk/context/skill/test_load_project_skills.py rename to tests/sdk/skills/test_load_project_skills.py index 1ce3c62369..e8f89f83d5 100644 --- a/tests/sdk/context/skill/test_load_project_skills.py +++ b/tests/sdk/skills/test_load_project_skills.py @@ -1,6 +1,6 @@ """Tests for load_project_skills functionality.""" -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( KeywordTrigger, load_project_skills, ) diff --git a/tests/sdk/context/skill/test_load_public_skills.py b/tests/sdk/skills/test_load_public_skills.py similarity index 91% rename from tests/sdk/context/skill/test_load_public_skills.py rename to tests/sdk/skills/test_load_public_skills.py index ff474395ec..e3dc62692d 100644 --- a/tests/sdk/context/skill/test_load_public_skills.py +++ b/tests/sdk/skills/test_load_public_skills.py @@ -7,13 +7,13 @@ import pytest from openhands.sdk.context.agent_context import AgentContext -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( KeywordTrigger, Skill, load_public_skills, ) -from openhands.sdk.context.skills.skill import load_marketplace_skill_names -from openhands.sdk.context.skills.utils import update_skills_repository +from openhands.sdk.skills.skill import load_marketplace_skill_names +from openhands.sdk.skills.utils import update_skills_repository @pytest.fixture @@ -148,11 +148,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -179,11 +179,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -202,11 +202,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -236,11 +236,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -371,11 +371,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -396,11 +396,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -434,11 +434,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -464,11 +464,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -489,11 +489,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -512,11 +512,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -549,11 +549,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -727,11 +727,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -753,11 +753,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -776,11 +776,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -812,11 +812,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): @@ -865,11 +865,11 @@ def mock_update_repo(repo_url, branch, cache_dir): with ( patch( - "openhands.sdk.context.skills.skill.update_skills_repository", + "openhands.sdk.skills.skill.update_skills_repository", side_effect=mock_update_repo, ), patch( - "openhands.sdk.context.skills.skill.get_skills_cache_dir", + "openhands.sdk.skills.skill.get_skills_cache_dir", return_value=tmp_path, ), ): diff --git a/tests/sdk/context/skill/test_load_user_skills.py b/tests/sdk/skills/test_load_user_skills.py similarity index 94% rename from tests/sdk/context/skill/test_load_user_skills.py rename to tests/sdk/skills/test_load_user_skills.py index f4de2cc921..895706708d 100644 --- a/tests/sdk/context/skill/test_load_user_skills.py +++ b/tests/sdk/skills/test_load_user_skills.py @@ -6,7 +6,7 @@ import pytest from openhands.sdk.context.agent_context import AgentContext -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( KeywordTrigger, Skill, load_user_skills, @@ -46,7 +46,7 @@ def temp_microagents_dir(): def test_load_user_skills_no_directories(tmp_path): """Test load_user_skills when no user skills directories exist.""" # Point USER_SKILLS_DIRS to non-existent directories - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -70,7 +70,7 @@ def test_load_user_skills_with_agents_directory(temp_user_skills_dir): "---\nname: agent_skill\ntriggers:\n - agent\n---\nAgent skill content." ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -94,7 +94,7 @@ def test_load_user_skills_with_skills_directory(temp_user_skills_dir): "---\nname: test_skill\ntriggers:\n - test\n---\nThis is a test skill." ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -123,7 +123,7 @@ def test_load_user_skills_with_microagents_directory(temp_microagents_dir): "This is a legacy microagent skill." ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -155,7 +155,7 @@ def test_load_user_skills_priority_order(tmp_path): "---\nname: duplicate\n---\nFrom .openhands/microagents." ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -187,7 +187,7 @@ def test_load_user_skills_merges_all_directories(tmp_path): "---\nname: skill2\n---\nSkill 2 content." ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -213,7 +213,7 @@ def test_load_user_skills_handles_errors_gracefully(temp_user_skills_dir): "Invalid skill." ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -233,7 +233,7 @@ def test_agent_context_loads_user_skills_by_default(temp_user_skills_dir): skill_file = skills_dir / "auto_skill.md" skill_file.write_text("---\nname: auto_skill\n---\nAutomatically loaded skill.") - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -266,7 +266,7 @@ def test_agent_context_merges_explicit_and_user_skills(temp_user_skills_dir): trigger=None, ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: @@ -295,7 +295,7 @@ def test_agent_context_explicit_skill_takes_precedence(temp_user_skills_dir): trigger=None, ) - from openhands.sdk.context.skills import skill + from openhands.sdk.skills import skill original_dirs = skill.USER_SKILLS_DIRS try: diff --git a/tests/sdk/context/skill/test_mcp_json.py b/tests/sdk/skills/test_mcp_json.py similarity index 98% rename from tests/sdk/context/skill/test_mcp_json.py rename to tests/sdk/skills/test_mcp_json.py index d33dbc5dae..a4dee72ef6 100644 --- a/tests/sdk/context/skill/test_mcp_json.py +++ b/tests/sdk/skills/test_mcp_json.py @@ -13,7 +13,7 @@ import pytest -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( Skill, SkillValidationError, load_skills_from_dir, diff --git a/tests/sdk/context/skill/test_resource_directories.py b/tests/sdk/skills/test_resource_directories.py similarity index 98% rename from tests/sdk/context/skill/test_resource_directories.py rename to tests/sdk/skills/test_resource_directories.py index f51bdf82f0..496960e759 100644 --- a/tests/sdk/context/skill/test_resource_directories.py +++ b/tests/sdk/skills/test_resource_directories.py @@ -2,7 +2,7 @@ from pathlib import Path -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( RESOURCE_DIRECTORIES, Skill, SkillResources, diff --git a/tests/sdk/context/skill/test_skill_commands.py b/tests/sdk/skills/test_skill_commands.py similarity index 98% rename from tests/sdk/context/skill/test_skill_commands.py rename to tests/sdk/skills/test_skill_commands.py index a410a7b549..e6f9c70b92 100644 --- a/tests/sdk/context/skill/test_skill_commands.py +++ b/tests/sdk/skills/test_skill_commands.py @@ -17,8 +17,8 @@ import pytest -from openhands.sdk.context.skills import Skill -from openhands.sdk.context.skills.execute import ( +from openhands.sdk.skills import Skill +from openhands.sdk.skills.execute import ( MAX_OUTPUT_SIZE, _execute_inline_command, render_content_with_commands, diff --git a/tests/sdk/context/skill/test_skill_info.py b/tests/sdk/skills/test_skill_info.py similarity index 98% rename from tests/sdk/context/skill/test_skill_info.py rename to tests/sdk/skills/test_skill_info.py index 9c6544b7a4..d390146443 100644 --- a/tests/sdk/context/skill/test_skill_info.py +++ b/tests/sdk/skills/test_skill_info.py @@ -2,12 +2,12 @@ from typing import Literal, get_args -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( KeywordTrigger, Skill, TaskTrigger, ) -from openhands.sdk.context.skills.skill import SkillInfo +from openhands.sdk.skills.skill import SkillInfo SkillType = Literal["repo", "knowledge", "agentskills"] diff --git a/tests/sdk/context/skill/test_skill_md_convention.py b/tests/sdk/skills/test_skill_md_convention.py similarity index 98% rename from tests/sdk/context/skill/test_skill_md_convention.py rename to tests/sdk/skills/test_skill_md_convention.py index 4e6f971f1f..0d4b3f71b1 100644 --- a/tests/sdk/context/skill/test_skill_md_convention.py +++ b/tests/sdk/skills/test_skill_md_convention.py @@ -4,12 +4,12 @@ import pytest -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( Skill, SkillValidationError, load_skills_from_dir, ) -from openhands.sdk.context.skills.utils import ( +from openhands.sdk.skills.utils import ( find_skill_md, validate_skill_name, ) diff --git a/tests/sdk/context/skill/test_skill_no_header.py b/tests/sdk/skills/test_skill_no_header.py similarity index 100% rename from tests/sdk/context/skill/test_skill_no_header.py rename to tests/sdk/skills/test_skill_no_header.py diff --git a/tests/sdk/context/skill/test_skill_serialization.py b/tests/sdk/skills/test_skill_serialization.py similarity index 98% rename from tests/sdk/context/skill/test_skill_serialization.py rename to tests/sdk/skills/test_skill_serialization.py index 3c2a22603a..9f6dd8a589 100644 --- a/tests/sdk/context/skill/test_skill_serialization.py +++ b/tests/sdk/skills/test_skill_serialization.py @@ -4,12 +4,12 @@ from pydantic import BaseModel, Field -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( KeywordTrigger, Skill, TaskTrigger, ) -from openhands.sdk.context.skills.types import InputMetadata +from openhands.sdk.skills.types import InputMetadata from openhands.sdk.utils.models import OpenHandsModel diff --git a/tests/sdk/context/skill/test_skill_utils.py b/tests/sdk/skills/test_skill_utils.py similarity index 99% rename from tests/sdk/context/skill/test_skill_utils.py rename to tests/sdk/skills/test_skill_utils.py index 89e8d9c2ae..1c658e1356 100644 --- a/tests/sdk/context/skill/test_skill_utils.py +++ b/tests/sdk/skills/test_skill_utils.py @@ -13,7 +13,7 @@ load_project_skills, load_skills_from_dir, ) -from openhands.sdk.context.skills.utils import find_third_party_files +from openhands.sdk.skills.utils import find_third_party_files CONTENT = "# dummy header\ndummy content\n## dummy subheader\ndummy subcontent\n" diff --git a/tests/sdk/context/skill/test_task_skill.py b/tests/sdk/skills/test_task_skill.py similarity index 92% rename from tests/sdk/context/skill/test_task_skill.py rename to tests/sdk/skills/test_task_skill.py index 016d0355ed..0beac5914f 100644 --- a/tests/sdk/context/skill/test_task_skill.py +++ b/tests/sdk/skills/test_task_skill.py @@ -1,5 +1,5 @@ -from openhands.sdk.context.skills import Skill, TaskTrigger -from openhands.sdk.context.skills.types import InputMetadata +from openhands.sdk.skills import Skill, TaskTrigger +from openhands.sdk.skills.types import InputMetadata def test_task_skill_prompt_appending(): diff --git a/tests/sdk/context/skill/test_validation_improvements.py b/tests/sdk/skills/test_validation_improvements.py similarity index 96% rename from tests/sdk/context/skill/test_validation_improvements.py rename to tests/sdk/skills/test_validation_improvements.py index a1ffeb37c3..fcd2f91c18 100644 --- a/tests/sdk/context/skill/test_validation_improvements.py +++ b/tests/sdk/skills/test_validation_improvements.py @@ -1,6 +1,6 @@ """Tests for skill validation improvements.""" -from openhands.sdk.context.skills import Skill +from openhands.sdk.skills import Skill from openhands.sdk.utils import DEFAULT_TRUNCATE_NOTICE diff --git a/tests/sdk/context/skill/test_validation_prompt.py b/tests/sdk/skills/test_validation_prompt.py similarity index 98% rename from tests/sdk/context/skill/test_validation_prompt.py rename to tests/sdk/skills/test_validation_prompt.py index 2e05dc8e14..3c566f3e12 100644 --- a/tests/sdk/context/skill/test_validation_prompt.py +++ b/tests/sdk/skills/test_validation_prompt.py @@ -1,6 +1,6 @@ """Tests for prompt generation utilities (Issue #1478).""" -from openhands.sdk.context.skills import ( +from openhands.sdk.skills import ( Skill, to_prompt, ) diff --git a/tests/sdk/subagent/test_subagent_registry.py b/tests/sdk/subagent/test_subagent_registry.py index f15f9f0f50..9a3708b97e 100644 --- a/tests/sdk/subagent/test_subagent_registry.py +++ b/tests/sdk/subagent/test_subagent_registry.py @@ -346,7 +346,7 @@ def test_agent_definition_to_factory_skills_project_over_user(tmp_path: Path) -> skills=["shared-skill"], ) - with patch("openhands.sdk.context.skills.skill.Path.home", return_value=user_home): + with patch("openhands.sdk.skills.skill.Path.home", return_value=user_home): factory = agent_definition_to_factory(agent_def, work_dir=tmp_path) llm = _make_test_llm()