fix(skills): reject unsupported native operations

This commit is contained in:
ymuichiro 2026-08-23 14:26:32 +09:00
parent 5c426208b1
commit 80f05a8e7b
2 changed files with 24 additions and 1 deletions

View file

@ -49,6 +49,7 @@ _NATIVE_SKILL_OPERATIONS: Final = MappingProxyType(
"version_content": ("skills.versions.content.retrieve", ("skill_id", "version")),
}
)
_NATIVE_ONLY_SKILL_OPERATIONS: Final = frozenset(_NATIVE_SKILL_OPERATIONS) - {"create", "list", "get", "delete"}
# Initialize LiteLLM skills handler (lazy - only used when custom_llm_provider="litellm")
_litellm_skills_handler = None
@ -70,6 +71,11 @@ def _azure_skills_api_base(api_base: str | None) -> str | None:
return str(url.copy_with(path=path[: -len(suffix)] if suffix else path, query=None)).rstrip("/")
def _validate_skill_operation(operation: str, custom_llm_provider: str) -> None:
if operation in _NATIVE_ONLY_SKILL_OPERATIONS and custom_llm_provider not in _NATIVE_SKILL_PROVIDERS:
raise ValueError(f"{operation} skills operation is only supported for OpenAI and Azure OpenAI")
def _native_skill_request(
operation: str,
request_data: dict[str, Any], # mutable-ok: logging and SDK dispatch consume request data
@ -274,6 +280,7 @@ def create_skill(
# Determine provider
if custom_llm_provider is None:
custom_llm_provider = "anthropic"
_validate_skill_operation(kwargs.get("_skill_operation", "create"), custom_llm_provider)
# Build create request
create_request: Final[CreateSkillRequest] = {}
@ -474,6 +481,7 @@ def list_skills(
# Determine provider
if custom_llm_provider is None:
custom_llm_provider = "anthropic"
_validate_skill_operation(kwargs.get("_skill_operation", "list"), custom_llm_provider)
# Route to LiteLLM DB if custom_llm_provider="litellm_proxy"
if custom_llm_provider == LlmProviders.LITELLM_PROXY.value:
@ -658,6 +666,7 @@ def get_skill(
# Determine provider
if custom_llm_provider is None:
custom_llm_provider = "anthropic"
_validate_skill_operation(kwargs.get("_skill_operation", "get"), custom_llm_provider)
# Route to LiteLLM DB if custom_llm_provider="litellm_proxy"
if custom_llm_provider == LlmProviders.LITELLM_PROXY.value:
@ -833,6 +842,7 @@ def delete_skill(
# Determine provider
if custom_llm_provider is None:
custom_llm_provider = "anthropic"
_validate_skill_operation(kwargs.get("_skill_operation", "delete"), custom_llm_provider)
# Route to LiteLLM DB if custom_llm_provider="litellm_proxy"
if custom_llm_provider == LlmProviders.LITELLM_PROXY.value:

View file

@ -23,7 +23,11 @@ from litellm.proxy.anthropic_endpoints.skills_endpoints import (
)
from litellm.proxy.openai_files_endpoints.common_utils import extract_model_param
from litellm.router import Router
from litellm.skills.main import _azure_skills_api_base, _native_skill_request
from litellm.skills.main import (
_azure_skills_api_base,
_native_skill_request,
_validate_skill_operation,
)
from litellm.types.router import GenericLiteLLMParams
SKILL = {
@ -448,6 +452,15 @@ def test_native_skill_request_rejects_uninitialized_openai_client() -> None:
)
@pytest.mark.parametrize(
"operation",
["update", "content", "create_version", "list_versions", "version", "delete_version", "version_content"],
)
def test_native_only_skill_operations_reject_non_native_providers(operation: str) -> None:
with pytest.raises(ValueError, match="only supported for OpenAI and Azure OpenAI"):
_validate_skill_operation(operation, "anthropic")
def test_extract_model_param_ignores_non_string_body_model() -> None:
request = Request(
{