""" Stage adapters - Bridge existing components to the Stage interface. This module provides adapters that wrap existing components (DataSource) as Stage implementations. """ from typing import Any from engine.data_sources import SourceItem from engine.pipeline.core import DataType, PipelineContext, Stage class DataSourceStage(Stage): """Adapter wrapping DataSource as a Stage.""" def __init__(self, data_source, name: str = "headlines"): self._source = data_source self.name = name self.category = "source" self.optional = False @property def capabilities(self) -> set[str]: return {f"source.{self.name}"} @property def dependencies(self) -> set[str]: return set() @property def inlet_types(self) -> set: return {DataType.NONE} # Sources don't take input @property def outlet_types(self) -> set: return {DataType.SOURCE_ITEMS} def process(self, data: Any, ctx: PipelineContext) -> Any: """Fetch data from source.""" if hasattr(self._source, "get_items"): return self._source.get_items() return data class PassthroughStage(Stage): """Simple stage that passes data through unchanged. Used for sources that already provide the data in the correct format (e.g., pipeline introspection that outputs text directly). """ def __init__(self, name: str = "passthrough"): self.name = name self.category = "render" self.optional = True @property def stage_type(self) -> str: return "render" @property def capabilities(self) -> set[str]: return {"render.output"} @property def dependencies(self) -> set[str]: return {"source"} @property def inlet_types(self) -> set: return {DataType.SOURCE_ITEMS} @property def outlet_types(self) -> set: return {DataType.SOURCE_ITEMS} def process(self, data: Any, ctx: PipelineContext) -> Any: """Pass data through unchanged.""" return data class SourceItemsToBufferStage(Stage): """Convert SourceItem objects to text buffer. Takes a list of SourceItem objects and extracts their content, splitting on newlines to create a proper text buffer for display. """ def __init__(self, name: str = "items-to-buffer"): self.name = name self.category = "render" self.optional = True @property def stage_type(self) -> str: return "render" @property def capabilities(self) -> set[str]: return {"render.output"} @property def dependencies(self) -> set[str]: return {"source"} @property def inlet_types(self) -> set: return {DataType.SOURCE_ITEMS} @property def outlet_types(self) -> set: return {DataType.TEXT_BUFFER} def process(self, data: Any, ctx: PipelineContext) -> Any: """Convert SourceItem list to text buffer.""" if data is None: return [] # If already a list of strings, return as-is if isinstance(data, list) and data and isinstance(data[0], str): return data # If it's a list of SourceItem, extract content if isinstance(data, list): result = [] for item in data: if isinstance(item, SourceItem): # Split content by newline to get individual lines lines = item.content.split("\n") result.extend(lines) elif hasattr(item, "content"): # Has content attribute lines = str(item.content).split("\n") result.extend(lines) else: result.append(str(item)) return result # Single item if isinstance(data, SourceItem): return data.content.split("\n") return [str(data)]