Skip to content

Events

All event classes, enums, and core types. See Events for the conceptual guide and lifecycle ordering.

hother.streamblocks.core.types

Core types and enums for StreamBlocks.

BaseContent

Bases: BaseModel

Base content model with raw content field.

All custom content models should inherit from this class and optionally override the parse() method to add custom parsing logic. The raw_content field always preserves the original unparsed text.

Example

Simple content model that just stores raw text

class SimpleContent(BaseContent): ... pass ... content = SimpleContent.parse("Hello, world!") content.raw_content 'Hello, world!'

Content model with custom parsing

class ItemsContent(BaseContent): ... items: list[str] = [] ... ... @classmethod ... def parse(cls, raw_text: str) -> Self: ... items = [line.strip() for line in raw_text.split("\n") if line.strip()] ... return cls(raw_content=raw_text, items=items) ... content = ItemsContent.parse("apple\nbanana\norange") content.items ['apple', 'banana', 'orange'] content.raw_content # Original text preserved 'apple\nbanana\norange'

Source code in src/hother/streamblocks/core/types.py
class BaseContent(BaseModel):
    """Base content model with raw content field.

    All custom content models should inherit from this class and optionally
    override the parse() method to add custom parsing logic. The raw_content
    field always preserves the original unparsed text.

    Example:
        >>> # Simple content model that just stores raw text
        >>> class SimpleContent(BaseContent):
        ...     pass
        ...
        >>> content = SimpleContent.parse("Hello, world!")
        >>> content.raw_content
        'Hello, world!'
        >>>
        >>> # Content model with custom parsing
        >>> class ItemsContent(BaseContent):
        ...     items: list[str] = []
        ...
        ...     @classmethod
        ...     def parse(cls, raw_text: str) -> Self:
        ...         items = [line.strip() for line in raw_text.split("\\n") if line.strip()]
        ...         return cls(raw_content=raw_text, items=items)
        ...
        >>> content = ItemsContent.parse("apple\\nbanana\\norange")
        >>> content.items
        ['apple', 'banana', 'orange']
        >>> content.raw_content  # Original text preserved
        'apple\\nbanana\\norange'
    """

    raw_content: str = Field(..., description="Raw unparsed content from the block")

    # Format marker set by the @parse_as_json / @parse_as_yaml decorators.
    # Used by prompt generation to describe the expected content format without
    # fragile source/bytecode introspection. None means "no declared format".
    __content_format__: ClassVar[str | None] = None

    @classmethod
    def parse(cls, raw_text: str) -> Self:
        """Default parse method that just stores raw content.

        Override this in subclasses to add custom parsing logic.
        """
        return cls(raw_content=raw_text)

raw_content class-attribute instance-attribute

raw_content: str = Field(
    ..., description="Raw unparsed content from the block"
)

parse classmethod

parse(raw_text: str) -> Self

Default parse method that just stores raw content.

Override this in subclasses to add custom parsing logic.

Source code in src/hother/streamblocks/core/types.py
@classmethod
def parse(cls, raw_text: str) -> Self:
    """Default parse method that just stores raw content.

    Override this in subclasses to add custom parsing logic.
    """
    return cls(raw_content=raw_text)

BaseEvent

Bases: BaseModel

Base class for all StreamBlocks events.

Attributes:

Name Type Description
type

Event type discriminator (defined in subclasses)

timestamp int

Unix timestamp in milliseconds (auto-generated)

event_id str

Unique event identifier (auto-generated)

raw_event Any | None

Original provider event (preserved by adapters)

Source code in src/hother/streamblocks/core/types.py
class BaseEvent(BaseModel):
    """Base class for all StreamBlocks events.

    Attributes:
        type: Event type discriminator (defined in subclasses)
        timestamp: Unix timestamp in milliseconds (auto-generated)
        event_id: Unique event identifier (auto-generated)
        raw_event: Original provider event (preserved by adapters)
    """

    model_config = ConfigDict(frozen=True)

    timestamp: int = Field(default_factory=lambda: int(time.time() * 1000))
    event_id: str = Field(default_factory=lambda: str(uuid4()))
    raw_event: Any | None = None

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

BaseMetadata

Bases: BaseModel

Base metadata model with standard fields.

All custom metadata models should inherit from this class and add their domain-specific fields.

Example

Define custom metadata for a patch block

class PatchMetadata(BaseMetadata): ... file_path: str ... operation: Literal["create", "update", "delete"] ...

Create instance with required base fields

metadata = PatchMetadata( ... id="patch_001", ... block_type="patch", ... file_path="src/main.py", ... operation="update" ... ) metadata.id 'patch_001' metadata.file_path 'src/main.py'

Source code in src/hother/streamblocks/core/types.py
class BaseMetadata(BaseModel):
    """Base metadata model with standard fields.

    All custom metadata models should inherit from this class and add
    their domain-specific fields.

    Example:
        >>> # Define custom metadata for a patch block
        >>> class PatchMetadata(BaseMetadata):
        ...     file_path: str
        ...     operation: Literal["create", "update", "delete"]
        ...
        >>> # Create instance with required base fields
        >>> metadata = PatchMetadata(
        ...     id="patch_001",
        ...     block_type="patch",
        ...     file_path="src/main.py",
        ...     operation="update"
        ... )
        >>> metadata.id
        'patch_001'
        >>> metadata.file_path
        'src/main.py'
    """

    id: str = Field(..., description="Block identifier")
    block_type: str = Field(..., description="Type of the block")

block_type class-attribute instance-attribute

block_type: str = Field(
    ..., description="Type of the block"
)

id class-attribute instance-attribute

id: str = Field(..., description='Block identifier')

BlockContentDeltaEvent

Bases: _BlockDeltaBase

Delta event for block content section.

Emitted when content is added to the content section of a block. This is the main body content after any metadata.

Source code in src/hother/streamblocks/core/types.py
class BlockContentDeltaEvent(_BlockDeltaBase):
    """Delta event for block content section.

    Emitted when content is added to the content section of a block.
    This is the main body content after any metadata.
    """

    type: Literal[EventType.BLOCK_CONTENT_DELTA] = EventType.BLOCK_CONTENT_DELTA

accumulated_size instance-attribute

accumulated_size: int

block_id instance-attribute

block_id: str

current_line instance-attribute

current_line: int

delta instance-attribute

delta: str

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

BlockContentEndEvent

Bases: BaseEvent

Emitted when content section completes (before BlockEndEvent).

This event signals that all content has been received and parsed. Enables early validation and processing before final block extraction.

Source code in src/hother/streamblocks/core/types.py
class BlockContentEndEvent(BaseEvent):
    """Emitted when content section completes (before BlockEndEvent).

    This event signals that all content has been received and parsed.
    Enables early validation and processing before final block extraction.
    """

    type: Literal[EventType.BLOCK_CONTENT_END] = EventType.BLOCK_CONTENT_END
    block_id: str
    syntax: str
    start_line: int
    end_line: int
    raw_content: str
    parsed_content: dict[str, Any] | None = None
    validation_passed: bool = True
    validation_error: str | None = None

block_id instance-attribute

block_id: str

end_line instance-attribute

end_line: int

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

parsed_content class-attribute instance-attribute

parsed_content: dict[str, Any] | None = None

raw_content instance-attribute

raw_content: str

raw_event class-attribute instance-attribute

raw_event: Any | None = None

start_line instance-attribute

start_line: int

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

validation_error class-attribute instance-attribute

validation_error: str | None = None

validation_passed class-attribute instance-attribute

validation_passed: bool = True

BlockEndEvent

Bases: BaseEvent

Block successfully extracted and validated.

Emitted when a block is fully parsed, validated, and ready for use. Contains the complete extracted content.

Source code in src/hother/streamblocks/core/types.py
class BlockEndEvent(BaseEvent):
    """Block successfully extracted and validated.

    Emitted when a block is fully parsed, validated, and ready for use.
    Contains the complete extracted content.
    """

    model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)

    type: Literal[EventType.BLOCK_END] = EventType.BLOCK_END
    block_id: str
    block_type: str
    syntax: str
    start_line: int
    end_line: int

    # Extracted content as dicts for serialization
    metadata: dict[str, Any]
    content: dict[str, Any]
    raw_content: str

    # Hash for deduplication/caching
    hash_id: str

    # Typed block reference (not serialized)
    _block: ExtractedBlock[Any, Any] | None = PrivateAttr(default=None)

    def get_block(self) -> ExtractedBlock[Any, Any] | None:
        """Get the typed ExtractedBlock if available."""
        return self._block

block_id instance-attribute

block_id: str

block_type instance-attribute

block_type: str

content instance-attribute

content: dict[str, Any]

end_line instance-attribute

end_line: int

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

hash_id instance-attribute

hash_id: str

metadata instance-attribute

metadata: dict[str, Any]

model_config class-attribute instance-attribute

model_config = ConfigDict(
    frozen=True, arbitrary_types_allowed=True
)

raw_content instance-attribute

raw_content: str

raw_event class-attribute instance-attribute

raw_event: Any | None = None

start_line instance-attribute

start_line: int

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

get_block

get_block() -> ExtractedBlock[Any, Any] | None

Get the typed ExtractedBlock if available.

Source code in src/hother/streamblocks/core/types.py
def get_block(self) -> ExtractedBlock[Any, Any] | None:
    """Get the typed ExtractedBlock if available."""
    return self._block

BlockErrorCode

Bases: StrEnum

Standard error codes for BlockErrorEvent.

These codes categorize why a block extraction failed, enabling appropriate error handling and recovery strategies.

Values
Example

Handle different error codes appropriately

async for event in processor.process_stream(stream): ... if isinstance(event, BlockErrorEvent): ... if event.error_code == BlockErrorCode.SIZE_EXCEEDED: ... logger.warning(f"Block too large: {event.reason}") ... elif event.error_code == BlockErrorCode.VALIDATION_FAILED: ... logger.error(f"Validation failed: {event.reason}") ... elif event.error_code == BlockErrorCode.UNCLOSED_BLOCK: ... logger.info(f"Incomplete block at stream end: {event.reason}")

Source code in src/hother/streamblocks/core/types.py
class BlockErrorCode(StrEnum):
    """Standard error codes for BlockErrorEvent.

    These codes categorize why a block extraction failed, enabling
    appropriate error handling and recovery strategies.

    Values:
        VALIDATION_FAILED: Block failed validator function checks (syntax or registry validation).
            Indicates the block structure is valid but business rules were violated.
        SIZE_EXCEEDED: Block exceeded max_block_size limit.
            Prevents memory exhaustion from maliciously large blocks.
        UNCLOSED_BLOCK: Block opened but never closed (stream ended).
            Indicates incomplete block at end of stream.
        UNKNOWN_TYPE: block_type not registered in registry.
            The syntax extracted a type that hasn't been registered.
        PARSE_FAILED: Block parsing failed (malformed YAML, invalid structure).
            The syntax couldn't parse the block content into metadata/content.
        MISSING_METADATA: Required metadata section missing.
            Parse succeeded but returned None for metadata.
        MISSING_CONTENT: Required content section missing.
            Parse succeeded but returned None for content.
        SYNTAX_ERROR: Syntax-specific error (custom validation).
            Used for syntax-specific validation failures.

    Example:
        >>> # Handle different error codes appropriately
        >>> async for event in processor.process_stream(stream):
        ...     if isinstance(event, BlockErrorEvent):
        ...         if event.error_code == BlockErrorCode.SIZE_EXCEEDED:
        ...             logger.warning(f"Block too large: {event.reason}")
        ...         elif event.error_code == BlockErrorCode.VALIDATION_FAILED:
        ...             logger.error(f"Validation failed: {event.reason}")
        ...         elif event.error_code == BlockErrorCode.UNCLOSED_BLOCK:
        ...             logger.info(f"Incomplete block at stream end: {event.reason}")
    """

    VALIDATION_FAILED = "VALIDATION_FAILED"
    SIZE_EXCEEDED = "SIZE_EXCEEDED"
    UNCLOSED_BLOCK = "UNCLOSED_BLOCK"
    UNKNOWN_TYPE = "UNKNOWN_TYPE"
    PARSE_FAILED = "PARSE_FAILED"
    MISSING_METADATA = "MISSING_METADATA"
    MISSING_CONTENT = "MISSING_CONTENT"
    SYNTAX_ERROR = "SYNTAX_ERROR"

MISSING_CONTENT class-attribute instance-attribute

MISSING_CONTENT = 'MISSING_CONTENT'

MISSING_METADATA class-attribute instance-attribute

MISSING_METADATA = 'MISSING_METADATA'

PARSE_FAILED class-attribute instance-attribute

PARSE_FAILED = 'PARSE_FAILED'

SIZE_EXCEEDED class-attribute instance-attribute

SIZE_EXCEEDED = 'SIZE_EXCEEDED'

SYNTAX_ERROR class-attribute instance-attribute

SYNTAX_ERROR = 'SYNTAX_ERROR'

UNCLOSED_BLOCK class-attribute instance-attribute

UNCLOSED_BLOCK = 'UNCLOSED_BLOCK'

UNKNOWN_TYPE class-attribute instance-attribute

UNKNOWN_TYPE = 'UNKNOWN_TYPE'

VALIDATION_FAILED class-attribute instance-attribute

VALIDATION_FAILED = 'VALIDATION_FAILED'

BlockErrorEvent

Bases: BaseEvent

Block extraction failed.

Emitted when a block cannot be extracted due to validation failure, size limits, missing closing marker, or other errors.

Source code in src/hother/streamblocks/core/types.py
class BlockErrorEvent(BaseEvent):
    """Block extraction failed.

    Emitted when a block cannot be extracted due to validation failure,
    size limits, missing closing marker, or other errors.
    """

    model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)

    type: Literal[EventType.BLOCK_ERROR] = EventType.BLOCK_ERROR
    block_id: str | None = None
    reason: str
    error_code: BlockErrorCode | None = None
    syntax: str
    start_line: int
    end_line: int | None = None
    exception: Exception | None = Field(default=None, exclude=True)

block_id class-attribute instance-attribute

block_id: str | None = None

end_line class-attribute instance-attribute

end_line: int | None = None

error_code class-attribute instance-attribute

error_code: BlockErrorCode | None = None

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

exception class-attribute instance-attribute

exception: Exception | None = Field(
    default=None, exclude=True
)

model_config class-attribute instance-attribute

model_config = ConfigDict(
    frozen=True, arbitrary_types_allowed=True
)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

reason instance-attribute

reason: str

start_line instance-attribute

start_line: int

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

BlockHeaderDeltaEvent

Bases: _BlockDeltaBase

Delta event for block header section.

Emitted when content is added to the header section of a block. May include inline metadata parsed from the header.

Source code in src/hother/streamblocks/core/types.py
class BlockHeaderDeltaEvent(_BlockDeltaBase):
    """Delta event for block header section.

    Emitted when content is added to the header section of a block.
    May include inline metadata parsed from the header.
    """

    type: Literal[EventType.BLOCK_HEADER_DELTA] = EventType.BLOCK_HEADER_DELTA
    inline_metadata: dict[str, Any] | None = None

accumulated_size instance-attribute

accumulated_size: int

block_id instance-attribute

block_id: str

current_line instance-attribute

current_line: int

delta instance-attribute

delta: str

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

inline_metadata class-attribute instance-attribute

inline_metadata: dict[str, Any] | None = None

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

BlockMetadataDeltaEvent

Bases: _BlockDeltaBase

Delta event for block metadata section.

Emitted when content is added to the metadata section of a block. The is_boundary flag indicates if this delta contains a section boundary marker.

Source code in src/hother/streamblocks/core/types.py
class BlockMetadataDeltaEvent(_BlockDeltaBase):
    """Delta event for block metadata section.

    Emitted when content is added to the metadata section of a block.
    The is_boundary flag indicates if this delta contains a section boundary marker.
    """

    type: Literal[EventType.BLOCK_METADATA_DELTA] = EventType.BLOCK_METADATA_DELTA
    is_boundary: bool = False

accumulated_size instance-attribute

accumulated_size: int

block_id instance-attribute

block_id: str

current_line instance-attribute

current_line: int

delta instance-attribute

delta: str

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

is_boundary class-attribute instance-attribute

is_boundary: bool = False

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

BlockMetadataEndEvent

Bases: BaseEvent

Emitted when metadata section completes (before content begins).

This event signals that all metadata has been received and parsed. Enables early validation and processing before content accumulation.

Source code in src/hother/streamblocks/core/types.py
class BlockMetadataEndEvent(BaseEvent):
    """Emitted when metadata section completes (before content begins).

    This event signals that all metadata has been received and parsed.
    Enables early validation and processing before content accumulation.
    """

    type: Literal[EventType.BLOCK_METADATA_END] = EventType.BLOCK_METADATA_END
    block_id: str
    syntax: str
    start_line: int
    end_line: int
    raw_metadata: str
    parsed_metadata: dict[str, Any] | None = None
    validation_passed: bool = True
    validation_error: str | None = None

block_id instance-attribute

block_id: str

end_line instance-attribute

end_line: int

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

parsed_metadata class-attribute instance-attribute

parsed_metadata: dict[str, Any] | None = None

raw_event class-attribute instance-attribute

raw_event: Any | None = None

raw_metadata instance-attribute

raw_metadata: str

start_line instance-attribute

start_line: int

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

validation_error class-attribute instance-attribute

validation_error: str | None = None

validation_passed class-attribute instance-attribute

validation_passed: bool = True

BlockStartEvent

Bases: BaseEvent

Block opening detected - begins block lifecycle.

Emitted when a block opening marker is detected, before content accumulation. Useful for UIs to prepare display elements.

Source code in src/hother/streamblocks/core/types.py
class BlockStartEvent(BaseEvent):
    """Block opening detected - begins block lifecycle.

    Emitted when a block opening marker is detected, before content
    accumulation. Useful for UIs to prepare display elements.
    """

    type: Literal[EventType.BLOCK_START] = EventType.BLOCK_START
    block_id: str
    block_type: str | None = None  # May not be known until parsed
    syntax: str
    start_line: int
    inline_metadata: dict[str, Any] | None = None

block_id instance-attribute

block_id: str

block_type class-attribute instance-attribute

block_type: str | None = None

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

inline_metadata class-attribute instance-attribute

inline_metadata: dict[str, Any] | None = None

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

start_line instance-attribute

start_line: int

syntax instance-attribute

syntax: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

BlockState

Bases: StrEnum

Internal state of block detection.

Source code in src/hother/streamblocks/core/types.py
class BlockState(StrEnum):
    """Internal state of block detection."""

    SEARCHING = "searching"
    HEADER_DETECTED = "header_detected"
    ACCUMULATING_METADATA = "accumulating_metadata"
    ACCUMULATING_CONTENT = "accumulating_content"
    CLOSING_DETECTED = "closing_detected"
    REJECTED = "rejected"
    COMPLETED = "completed"

ACCUMULATING_CONTENT class-attribute instance-attribute

ACCUMULATING_CONTENT = 'accumulating_content'

ACCUMULATING_METADATA class-attribute instance-attribute

ACCUMULATING_METADATA = 'accumulating_metadata'

CLOSING_DETECTED class-attribute instance-attribute

CLOSING_DETECTED = 'closing_detected'

COMPLETED class-attribute instance-attribute

COMPLETED = 'completed'

HEADER_DETECTED class-attribute instance-attribute

HEADER_DETECTED = 'header_detected'

REJECTED class-attribute instance-attribute

REJECTED = 'rejected'

SEARCHING class-attribute instance-attribute

SEARCHING = 'searching'

CustomEvent

Bases: BaseEvent

Application-specific custom events.

Source code in src/hother/streamblocks/core/types.py
class CustomEvent(BaseEvent):
    """Application-specific custom events."""

    type: Literal[EventType.CUSTOM] = EventType.CUSTOM
    name: str
    value: dict[str, Any] = Field(default_factory=dict)

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

name instance-attribute

name: str

raw_event class-attribute instance-attribute

raw_event: Any | None = None

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

value class-attribute instance-attribute

value: dict[str, Any] = Field(default_factory=dict)

DetectionResult

Bases: BaseModel

Result from syntax detection attempt.

Source code in src/hother/streamblocks/core/types.py
class DetectionResult(BaseModel):
    """Result from syntax detection attempt."""

    is_opening: bool = False
    is_closing: bool = False
    is_metadata_boundary: bool = False
    metadata: dict[str, Any] | None = None

is_closing class-attribute instance-attribute

is_closing: bool = False

is_metadata_boundary class-attribute instance-attribute

is_metadata_boundary: bool = False

is_opening class-attribute instance-attribute

is_opening: bool = False

metadata class-attribute instance-attribute

metadata: dict[str, Any] | None = None

EventType

Bases: StrEnum

Event types emitted during stream processing.

Source code in src/hother/streamblocks/core/types.py
class EventType(StrEnum):
    """Event types emitted during stream processing."""

    # Lifecycle events
    STREAM_STARTED = "STREAM_STARTED"
    STREAM_FINISHED = "STREAM_FINISHED"
    STREAM_ERROR = "STREAM_ERROR"

    # Text events
    TEXT_CONTENT = "TEXT_CONTENT"
    TEXT_DELTA = "TEXT_DELTA"

    # Block lifecycle events
    BLOCK_START = "BLOCK_START"
    BLOCK_HEADER_DELTA = "BLOCK_HEADER_DELTA"
    BLOCK_METADATA_DELTA = "BLOCK_METADATA_DELTA"
    BLOCK_CONTENT_DELTA = "BLOCK_CONTENT_DELTA"
    BLOCK_METADATA_END = "BLOCK_METADATA_END"
    BLOCK_CONTENT_END = "BLOCK_CONTENT_END"
    BLOCK_END = "BLOCK_END"
    BLOCK_ERROR = "BLOCK_ERROR"

    # Custom events
    CUSTOM = "CUSTOM"

BLOCK_CONTENT_DELTA class-attribute instance-attribute

BLOCK_CONTENT_DELTA = 'BLOCK_CONTENT_DELTA'

BLOCK_CONTENT_END class-attribute instance-attribute

BLOCK_CONTENT_END = 'BLOCK_CONTENT_END'

BLOCK_END class-attribute instance-attribute

BLOCK_END = 'BLOCK_END'

BLOCK_ERROR class-attribute instance-attribute

BLOCK_ERROR = 'BLOCK_ERROR'

BLOCK_HEADER_DELTA class-attribute instance-attribute

BLOCK_HEADER_DELTA = 'BLOCK_HEADER_DELTA'

BLOCK_METADATA_DELTA class-attribute instance-attribute

BLOCK_METADATA_DELTA = 'BLOCK_METADATA_DELTA'

BLOCK_METADATA_END class-attribute instance-attribute

BLOCK_METADATA_END = 'BLOCK_METADATA_END'

BLOCK_START class-attribute instance-attribute

BLOCK_START = 'BLOCK_START'

CUSTOM class-attribute instance-attribute

CUSTOM = 'CUSTOM'

STREAM_ERROR class-attribute instance-attribute

STREAM_ERROR = 'STREAM_ERROR'

STREAM_FINISHED class-attribute instance-attribute

STREAM_FINISHED = 'STREAM_FINISHED'

STREAM_STARTED class-attribute instance-attribute

STREAM_STARTED = 'STREAM_STARTED'

TEXT_CONTENT class-attribute instance-attribute

TEXT_CONTENT = 'TEXT_CONTENT'

TEXT_DELTA class-attribute instance-attribute

TEXT_DELTA = 'TEXT_DELTA'

ParseResult

Bases: BaseModel

Result from parsing attempt.

Source code in src/hother/streamblocks/core/types.py
class ParseResult[TMetadata: BaseMetadata, TContent: BaseContent](BaseModel):
    """Result from parsing attempt."""

    model_config = ConfigDict(arbitrary_types_allowed=True)

    success: bool
    metadata: TMetadata | None = None
    content: TContent | None = None
    error: str | None = None
    exception: Exception | None = None

content class-attribute instance-attribute

content: TContent | None = None

error class-attribute instance-attribute

error: str | None = None

exception class-attribute instance-attribute

exception: Exception | None = None

metadata class-attribute instance-attribute

metadata: TMetadata | None = None

model_config class-attribute instance-attribute

model_config = ConfigDict(arbitrary_types_allowed=True)

success instance-attribute

success: bool

SectionType

Bases: StrEnum

Block section types during accumulation.

These represent the different phases of block parsing as content is accumulated line by line.

Source code in src/hother/streamblocks/core/types.py
class SectionType(StrEnum):
    """Block section types during accumulation.

    These represent the different phases of block parsing as content
    is accumulated line by line.
    """

    HEADER = "header"  # Block opening line(s) with inline metadata
    METADATA = "metadata"  # Dedicated metadata section (e.g., YAML frontmatter)
    CONTENT = "content"  # Main block content

CONTENT class-attribute instance-attribute

CONTENT = 'content'

HEADER class-attribute instance-attribute

HEADER = 'header'

METADATA class-attribute instance-attribute

METADATA = 'metadata'

StreamErrorEvent

Bases: BaseEvent

Emitted when stream processing fails.

Source code in src/hother/streamblocks/core/types.py
class StreamErrorEvent(BaseEvent):
    """Emitted when stream processing fails."""

    type: Literal[EventType.STREAM_ERROR] = EventType.STREAM_ERROR
    stream_id: str
    error: str
    error_code: str | None = None

error instance-attribute

error: str

error_code class-attribute instance-attribute

error_code: str | None = None

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

stream_id instance-attribute

stream_id: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

StreamFinishedEvent

Bases: BaseEvent

Emitted when stream processing completes successfully.

Source code in src/hother/streamblocks/core/types.py
class StreamFinishedEvent(BaseEvent):
    """Emitted when stream processing completes successfully."""

    type: Literal[EventType.STREAM_FINISHED] = EventType.STREAM_FINISHED
    stream_id: str
    blocks_extracted: int = 0
    blocks_rejected: int = 0
    total_events: int = 0
    duration_ms: int | None = None

blocks_extracted class-attribute instance-attribute

blocks_extracted: int = 0

blocks_rejected class-attribute instance-attribute

blocks_rejected: int = 0

duration_ms class-attribute instance-attribute

duration_ms: int | None = None

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

stream_id instance-attribute

stream_id: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

total_events class-attribute instance-attribute

total_events: int = 0

type class-attribute instance-attribute

StreamStartedEvent

Bases: BaseEvent

Emitted when stream processing begins.

Source code in src/hother/streamblocks/core/types.py
class StreamStartedEvent(BaseEvent):
    """Emitted when stream processing begins."""

    type: Literal[EventType.STREAM_STARTED] = EventType.STREAM_STARTED
    stream_id: str
    registry_name: str | None = None

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

registry_name class-attribute instance-attribute

registry_name: str | None = None

stream_id instance-attribute

stream_id: str

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

TextContentEvent

Bases: BaseEvent

Complete line of text outside any block.

Source code in src/hother/streamblocks/core/types.py
class TextContentEvent(BaseEvent):
    """Complete line of text outside any block."""

    type: Literal[EventType.TEXT_CONTENT] = EventType.TEXT_CONTENT
    content: str
    line_number: int

content instance-attribute

content: str

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

line_number instance-attribute

line_number: int

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute

TextDeltaEvent

Bases: BaseEvent

Real-time text chunk (character/token level).

Emitted immediately when text is received from stream, before line completion. Enables live streaming UIs and real-time text display.

Source code in src/hother/streamblocks/core/types.py
class TextDeltaEvent(BaseEvent):
    """Real-time text chunk (character/token level).

    Emitted immediately when text is received from stream, before line
    completion. Enables live streaming UIs and real-time text display.
    """

    type: Literal[EventType.TEXT_DELTA] = EventType.TEXT_DELTA
    delta: str
    inside_block: bool = False
    block_id: str | None = None
    section: str | None = None  # "header", "metadata", "content"

block_id class-attribute instance-attribute

block_id: str | None = None

delta instance-attribute

delta: str

event_id class-attribute instance-attribute

event_id: str = Field(default_factory=lambda: str(uuid4()))

inside_block class-attribute instance-attribute

inside_block: bool = False

model_config class-attribute instance-attribute

model_config = ConfigDict(frozen=True)

raw_event class-attribute instance-attribute

raw_event: Any | None = None

section class-attribute instance-attribute

section: str | None = None

timestamp class-attribute instance-attribute

timestamp: int = Field(
    default_factory=lambda: int(time() * 1000)
)

type class-attribute instance-attribute