tightening
This commit is contained in:
@@ -107,7 +107,6 @@ def build_skill_detail_payload(registry: DocsRegistry, skill_id: str) -> dict[st
|
||||
"description": skill.description,
|
||||
"version": skill.version,
|
||||
"tags": list(skill.tags),
|
||||
"depends_on": list(skill.depends_on),
|
||||
"capabilities": list(skill.capabilities),
|
||||
"resources": {
|
||||
"document": skill.document_uri,
|
||||
|
||||
+3
-20
@@ -88,22 +88,6 @@ def _render_prompt_markdown(content: str, arguments: dict[str, Any]) -> str:
|
||||
return rendered
|
||||
|
||||
|
||||
def _python_type(prompt_arg_type: str) -> type[Any]:
|
||||
if prompt_arg_type == "string":
|
||||
return str
|
||||
if prompt_arg_type == "number":
|
||||
return float
|
||||
if prompt_arg_type == "integer":
|
||||
return int
|
||||
if prompt_arg_type == "boolean":
|
||||
return bool
|
||||
if prompt_arg_type == "array":
|
||||
return list
|
||||
if prompt_arg_type == "object":
|
||||
return dict
|
||||
return str
|
||||
|
||||
|
||||
def _make_prompt_handler(content: str):
|
||||
def prompt_handler(**kwargs: Any) -> str:
|
||||
return _render_prompt_markdown(content, kwargs)
|
||||
@@ -118,15 +102,14 @@ def _register_prompt_objects() -> None:
|
||||
params: list[Parameter] = []
|
||||
|
||||
for arg_name, arg in sorted(prompt.arguments.items()):
|
||||
arg_type = _python_type(arg.type)
|
||||
annotations[arg_name] = arg_type
|
||||
default = Parameter.empty if arg.required else arg.default
|
||||
annotations[arg_name] = str
|
||||
default = Parameter.empty if arg.required else None
|
||||
params.append(
|
||||
Parameter(
|
||||
arg_name,
|
||||
kind=Parameter.KEYWORD_ONLY,
|
||||
default=default,
|
||||
annotation=arg_type,
|
||||
annotation=str,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ def _build_skill_record(
|
||||
version=metadata.version,
|
||||
tags=tuple(metadata.tags),
|
||||
capabilities=tuple(metadata.capabilities),
|
||||
depends_on=tuple(metadata.depends_on),
|
||||
document_uri=f"resource://skills/{metadata.id}/document",
|
||||
document_relpath=stored.relpath.as_posix(),
|
||||
document_content=stored.content,
|
||||
@@ -160,11 +159,6 @@ def load_docs_registry(*, package_anchor: str, docs_root: str = "docs") -> DocsR
|
||||
prompts_by_id[record.prompt_id] = record
|
||||
prompts_in_load_order.append(record.prompt_id)
|
||||
|
||||
for skill_id, skill in skills_by_id.items():
|
||||
for dependency in skill.depends_on:
|
||||
if dependency not in skills_by_id:
|
||||
raise ValueError(f"skill '{skill_id}' depends_on unknown skill '{dependency}'")
|
||||
|
||||
skills_in_order_tuple = tuple(skills_in_load_order)
|
||||
prompts_in_order_tuple = tuple(prompts_in_load_order)
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import re
|
||||
from collections.abc import Mapping
|
||||
from pathlib import PurePosixPath
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Any
|
||||
from typing import Literal
|
||||
|
||||
import yaml
|
||||
from pydantic import Field
|
||||
@@ -18,31 +16,13 @@ from .common import frozen_mapping
|
||||
if TYPE_CHECKING:
|
||||
from personal_mcp.registry.ingest.prompt import PromptFilesBundle
|
||||
|
||||
type PromptArgumentType = Literal[
|
||||
"string",
|
||||
"number",
|
||||
"integer",
|
||||
"boolean",
|
||||
"array",
|
||||
"object",
|
||||
]
|
||||
|
||||
|
||||
class PromptArgumentEntry(StrictFrozenModel):
|
||||
"""Schema for a single prompt argument definition."""
|
||||
|
||||
type: PromptArgumentType
|
||||
title: str | None = None
|
||||
description: str | None = None
|
||||
required: bool = False
|
||||
default: Any | None = None
|
||||
enum: tuple[str, ...] | None = None
|
||||
|
||||
@field_validator("enum")
|
||||
@classmethod
|
||||
def validate_enum(cls, value: tuple[str, ...] | None) -> tuple[str, ...] | None:
|
||||
if value is not None and not value:
|
||||
raise ValueError("enum must contain at least one value when provided")
|
||||
return value
|
||||
|
||||
|
||||
class PromptMetadata(StrictFrozenModel):
|
||||
|
||||
@@ -28,7 +28,6 @@ class SkillRecord(StrictFrozenModel):
|
||||
version: str
|
||||
tags: tuple[str, ...]
|
||||
capabilities: tuple[str, ...]
|
||||
depends_on: tuple[str, ...]
|
||||
document_uri: str
|
||||
document_relpath: str
|
||||
document_content: str
|
||||
@@ -116,7 +115,6 @@ class SkillPatternPayload(StrictFrozenModel):
|
||||
version: str
|
||||
description: str
|
||||
tags: list[str]
|
||||
depends_on: list[str]
|
||||
capabilities: list[str]
|
||||
resources: list[str]
|
||||
|
||||
@@ -128,7 +126,6 @@ class SkillPatternPayload(StrictFrozenModel):
|
||||
version=record.version,
|
||||
description=record.description,
|
||||
tags=list(record.tags),
|
||||
depends_on=list(record.depends_on),
|
||||
capabilities=list(record.capabilities),
|
||||
resources=list(record.capabilities),
|
||||
)
|
||||
|
||||
@@ -12,17 +12,14 @@ from .common import ReferenceEntry
|
||||
from .common import StrictFrozenModel
|
||||
from .common import frozen_mapping
|
||||
|
||||
type ToolSelector = str | tuple[str, ...]
|
||||
|
||||
|
||||
class SkillMetadata(StrictFrozenModel):
|
||||
"""Canonical metadata describing a skill and its dependencies."""
|
||||
"""Canonical metadata describing a skill."""
|
||||
|
||||
id: str
|
||||
version: str
|
||||
tags: tuple[str, ...] = ()
|
||||
capabilities: tuple[str, ...] = Field(min_length=1)
|
||||
depends_on: tuple[str, ...] = ()
|
||||
references: Mapping[str, ReferenceEntry] = Field(default_factory=frozen_mapping)
|
||||
|
||||
@field_validator("id")
|
||||
@@ -47,14 +44,6 @@ class SkillMetadata(StrictFrozenModel):
|
||||
raise ValueError(f"invalid tag: {tag}")
|
||||
return value
|
||||
|
||||
@field_validator("depends_on")
|
||||
@classmethod
|
||||
def validate_depends_on(cls, value: tuple[str, ...]) -> tuple[str, ...]:
|
||||
for dep in value:
|
||||
if not SKILL_ID_RE.fullmatch(dep):
|
||||
raise ValueError(f"invalid depends_on skill id: {dep}")
|
||||
return value
|
||||
|
||||
@field_validator("references", mode="before")
|
||||
@classmethod
|
||||
def freeze_references(cls, value: Mapping[str, ReferenceEntry] | None) -> Mapping[str, ReferenceEntry]:
|
||||
@@ -74,31 +63,8 @@ class SkillFrontmatter(StrictFrozenModel):
|
||||
|
||||
name: str = Field(min_length=1, max_length=64)
|
||||
description: str = Field(min_length=1, max_length=1024)
|
||||
when_to_use: str | None = None
|
||||
allowed_tools: ToolSelector | None = Field(default=None, alias="allowed-tools")
|
||||
disallowed_tools: ToolSelector | None = Field(
|
||||
default=None,
|
||||
alias="disallowed-tools",
|
||||
)
|
||||
disable_model_invocation: bool | None = Field(
|
||||
default=None,
|
||||
alias="disable-model-invocation",
|
||||
)
|
||||
user_invocable: bool | None = Field(default=None, alias="user-invocable")
|
||||
argument_hint: str | None = Field(default=None, alias="argument-hint")
|
||||
arguments: ToolSelector | None = None
|
||||
license: str | None = None
|
||||
compatibility: str | None = None
|
||||
metadata: Mapping[str, str] | None = None
|
||||
x_personal_mcp: SkillMetadata = Field(alias="x-personal-mcp")
|
||||
|
||||
@field_validator("metadata", mode="before")
|
||||
@classmethod
|
||||
def freeze_metadata(cls, value: Mapping[str, str] | None) -> Mapping[str, str] | None:
|
||||
if value is None:
|
||||
return None
|
||||
return frozen_mapping(value)
|
||||
|
||||
@field_validator("name")
|
||||
@classmethod
|
||||
def validate_name(cls, value: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user