Skip to content

karenina.integrations.adele.parser

parser

Parser for ADeLe (Annotated Demand Levels) rubric text files.

ADeLe rubrics define 6 levels (0-5) for evaluating various cognitive and processing dimensions. Each level has a label, description, and examples.

ADeLe rubrics from Zhou et al. (2025), arXiv:2503.06378. https://kinds-of-intelligence-cfi.github.io/ADELE/

Classes

AdeleLevel dataclass

A single level in an ADeLe rubric (0-5).

Source code in src/karenina/integrations/adele/parser.py
@dataclass
class AdeleLevel:
    """A single level in an ADeLe rubric (0-5)."""

    index: int
    label: str
    description: str
    examples: list[str] = field(default_factory=list)

    def to_class_description(self) -> str:
        """Format level as a single class description string for LLMRubricTrait.

        Format: "Level N: Label. Description\nExamples:\n* example1\n* example2"
        """
        parts = [f"Level {self.index}: {self.label}. {self.description}"]
        if self.examples:
            parts.append("Examples:")
            for example in self.examples:
                parts.append(f"* {example}")
        return "\n".join(parts)
Functions
to_class_description
to_class_description() -> str

Format level as a single class description string for LLMRubricTrait.

    Format: "Level N: Label. Description

Examples: * example1 * example2"

Source code in src/karenina/integrations/adele/parser.py
def to_class_description(self) -> str:
    """Format level as a single class description string for LLMRubricTrait.

    Format: "Level N: Label. Description\nExamples:\n* example1\n* example2"
    """
    parts = [f"Level {self.index}: {self.label}. {self.description}"]
    if self.examples:
        parts.append("Examples:")
        for example in self.examples:
            parts.append(f"* {example}")
    return "\n".join(parts)

AdeleRubric dataclass

A parsed ADeLe rubric with optional header and 6 levels.

Source code in src/karenina/integrations/adele/parser.py
@dataclass
class AdeleRubric:
    """A parsed ADeLe rubric with optional header and 6 levels."""

    code: str
    header: str | None
    levels: list[AdeleLevel]

    def __post_init__(self) -> None:
        """Validate rubric structure."""
        if len(self.levels) != 6:
            raise ValueError(f"ADeLe rubric must have exactly 6 levels, got {len(self.levels)}")

        for i, level in enumerate(self.levels):
            if level.index != i:
                raise ValueError(f"Level at position {i} has index {level.index}, expected {i}")

Functions

parse_adele_file

parse_adele_file(content: str, code: str) -> AdeleRubric

Parse ADeLe rubric text content into structured format.

Parameters:

Name Type Description Default
content
str

Raw text content of the rubric file

required
code
str

File code/identifier (e.g., "AS", "AT", "CEc")

required

Returns:

Type Description
AdeleRubric

Parsed AdeleRubric with header (if present) and 6 levels

Raises:

Type Description
ValueError

If parsing fails or rubric structure is invalid

Source code in src/karenina/integrations/adele/parser.py
def parse_adele_file(content: str, code: str) -> AdeleRubric:
    """Parse ADeLe rubric text content into structured format.

    Args:
        content: Raw text content of the rubric file
        code: File code/identifier (e.g., "AS", "AT", "CEc")

    Returns:
        Parsed AdeleRubric with header (if present) and 6 levels

    Raises:
        ValueError: If parsing fails or rubric structure is invalid
    """
    # Normalize line endings
    content = content.replace("\r\n", "\n").replace("\r", "\n")

    # Find all level markers
    level_matches = list(LEVEL_PATTERN.finditer(content))

    if len(level_matches) != 6:
        raise ValueError(f"Expected 6 levels in rubric {code}, found {len(level_matches)}")

    # Extract header (content before Level 0)
    first_level_start = level_matches[0].start()
    header_content = content[:first_level_start].strip()
    header = header_content if header_content else None

    # Parse each level
    levels: list[AdeleLevel] = []

    for i, match in enumerate(level_matches):
        level_index = int(match.group(1))
        label = match.group(2).strip()
        first_line_desc = match.group(3).strip()

        # Determine where this level's content ends
        level_end = level_matches[i + 1].start() if i + 1 < len(level_matches) else len(content)

        # Extract full level content (after the matched line)
        level_content = content[match.end() : level_end].strip()

        # Combine first line description with continuation
        full_description, examples = _parse_level_content(first_line_desc, level_content)

        levels.append(
            AdeleLevel(
                index=level_index,
                label=label,
                description=full_description,
                examples=examples,
            )
        )

    return AdeleRubric(code=code, header=header, levels=levels)