Files
Javier Martinez 42a6c047d0 feat: add validation skill endpoint + skill prompt (#2272)
* feat: add skill validator endpoint

* fix: skills

* feat: add skill prompt

(cherry picked from commit c36d27f008)

# Conflicts:
#	private_gpt/chat/input_models.py
#	private_gpt/components/prompts/prompt_builder.py
#	private_gpt/server/chat/interceptors/platform_guidelines_interceptor.py

* fix: test

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: clarify skill visibility comment

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: rename has_loaded_non_eager variable to snake_case

* test: cover skill validation route

* test: fix invalid skill validation case

* test: cover skill tool visibility states

* feat: improve skill tools + prompt

* fix: mypy

* feat: allow to limit the skill maximum size

* feat: add validation error codes

* fix: tests

* fix: invalid frontmatter

* fix: edge cases

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-25 15:35:26 +02:00

57 lines
1.7 KiB
Python

"""Typed errors for the skills component."""
from enum import StrEnum
class SkillErrorCode(StrEnum):
"""Stable error codes for skill validation failures."""
# Upload / file-level
MISSING_FILES = "MISSING_FILES"
MISSING_SKILL_MD = "MISSING_SKILL_MD"
INVALID_ZIP = "INVALID_ZIP"
EMPTY_ZIP = "EMPTY_ZIP"
UNSAFE_PATH_ABSOLUTE = "UNSAFE_PATH_ABSOLUTE"
UNSAFE_PATH_TRAVERSAL = "UNSAFE_PATH_TRAVERSAL"
MIME_TYPE_UNKNOWN = "MIME_TYPE_UNKNOWN"
# Bundle-level
BUNDLE_TOO_LARGE = "BUNDLE_TOO_LARGE"
# Parse / frontmatter
MISSING_FRONTMATTER = "MISSING_FRONTMATTER"
INVALID_FRONTMATTER = "INVALID_FRONTMATTER"
# Frontmatter field validation
NAME_REQUIRED = "NAME_REQUIRED"
NAME_TOO_LONG = "NAME_TOO_LONG"
NAME_INVALID_FORMAT = "NAME_INVALID_FORMAT"
NAME_CONSECUTIVE_HYPHENS = "NAME_CONSECUTIVE_HYPHENS"
DESCRIPTION_REQUIRED = "DESCRIPTION_REQUIRED"
DESCRIPTION_TOO_LONG = "DESCRIPTION_TOO_LONG"
METADATA_EMPTY_KEY = "METADATA_EMPTY_KEY"
METADATA_INVALID_VALUE = "METADATA_INVALID_VALUE"
class SkillDomainError(Exception):
"""Typed skill domain error with stable code and human-readable message."""
def __init__(
self,
code: SkillErrorCode,
message: str,
params: dict[str, str] | None = None,
) -> None:
self.code = code
self.message = message
self.params = params
super().__init__(message)
class SkillValidationErrors(Exception):
"""Aggregates multiple SkillDomainErrors from a single validation pass."""
def __init__(self, errors: list[SkillDomainError]) -> None:
self.errors = errors
super().__init__("; ".join(e.message for e in errors))