Adapters
Input/output adapter protocols, auto-detection, and event categories. See Adapters for the conceptual guide.
hother.streamblocks.adapters.protocols
Protocol definitions for bidirectional stream adapters.
BidirectionalAdapter
Bases: Protocol[TInput, TOutput]
Combined bidirectional adapter for full protocol transformation.
This is a convenience pattern - users can also use separate adapters.
Example
class MyBidirectionalAdapter: ... def init(self): ... self._input = MyInputAdapter() ... self._output = MyOutputAdapter() ... ... @property ... def input_adapter(self) -> MyInputAdapter: ... return self._input ... ... @property ... def output_adapter(self) -> MyOutputAdapter: ... return self._output
Source code in src/hother/streamblocks/adapters/protocols.py
HasNativeModulePrefix
Bases: Protocol
Protocol for adapters that can identify native events by module prefix.
Adapters implementing this protocol can help the processor determine which events are "native" to their protocol and should be passed through.
Example
class OpenAIInputAdapter: ... native_module_prefix: ClassVar[str] = "openai.types" ... ...
Source code in src/hother/streamblocks/adapters/protocols.py
InputProtocolAdapter
Protocol for transforming input events for StreamBlocks processing.
Handles any input format: chunks (OpenAI), events (AG-UI), or custom.
Example
class MyInputAdapter: ... def categorize(self, event: MyEvent) -> EventCategory: ... if event.has_text: ... return EventCategory.TEXT_CONTENT ... return EventCategory.PASSTHROUGH ... ... def extract_text(self, event: MyEvent) -> str | None: ... return event.text
Source code in src/hother/streamblocks/adapters/protocols.py
categorize
categorize(event: TInput) -> EventCategory
Categorize event for routing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
TInput
|
Input event to categorize |
required |
Returns:
| Type | Description |
|---|---|
EventCategory
|
|
EventCategory
|
|
EventCategory
|
|
Source code in src/hother/streamblocks/adapters/protocols.py
extract_text
Extract text content from TEXT_CONTENT events.
Only called for events categorized as TEXT_CONTENT.
This method can perform any complex extraction/computation: - Simple field access: return event.text - Nested extraction: return event.data.content.text - Multiple fields: return f"{event.prefix}{event.body}" - Decoding: return base64.decode(event.encoded_text) - JSON extraction: return json.loads(event.payload)["message"]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
TInput
|
Input event to extract text from |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
Extracted text, or None if no text available |
Source code in src/hother/streamblocks/adapters/protocols.py
get_metadata
OutputProtocolAdapter
Protocol for transforming StreamBlocks events to output format.
Can emit to any protocol: AG-UI, custom events, plain text, etc.
Example
class MyOutputAdapter: ... def to_protocol_event(self, event: BaseEvent) -> MyEvent | None: ... if isinstance(event, BlockEndEvent): ... return MyEvent(type="block", data=event.get_block()) ... return None ... ... def passthrough(self, original_event: Any) -> MyEvent | None: ... return MyEvent(type="passthrough", data=original_event)
Source code in src/hother/streamblocks/adapters/protocols.py
passthrough
Handle passthrough events.
Called for events categorized as PASSTHROUGH by the input adapter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_event
|
Any
|
Original input event to pass through |
required |
Returns:
| Type | Description |
|---|---|
TOutput | None
|
|
TOutput | None
|
|
Source code in src/hother/streamblocks/adapters/protocols.py
to_protocol_event
Convert a StreamBlocks event to output protocol event(s).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
BaseEvent
|
StreamBlocks event to convert |
required |
Returns:
| Type | Description |
|---|---|
TOutput | list[TOutput] | None
|
|
TOutput | list[TOutput] | None
|
|
TOutput | list[TOutput] | None
|
|
Source code in src/hother/streamblocks/adapters/protocols.py
hother.streamblocks.adapters.detection
Automatic adapter detection for stream chunks.
HasContent
Bases: Protocol
Protocol for objects with a content attribute.
Source code in src/hother/streamblocks/adapters/detection.py
HasText
InputAdapterRegistry
Registry for input adapter auto-detection.
Uses module prefix matching and attribute-based fallback detection. Extensions register themselves when imported.
Example
Register via decorator
@InputAdapterRegistry.register(module_prefix="openai.") ... class OpenAIInputAdapter: ... def categorize(self, event) -> EventCategory: ... return EventCategory.TEXT_CONTENT ... def extract_text(self, event) -> str | None: ... return event.choices[0].delta.content
Register via method
InputAdapterRegistry.register_module("mycompany.api", MyCustomAdapter)
Detect adapter from sample
adapter = InputAdapterRegistry.detect(sample_chunk)
Source code in src/hother/streamblocks/adapters/detection.py
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | |
clear
classmethod
detect
classmethod
detect(chunk: Any) -> InputProtocolAdapter[Any] | None
Detect and instantiate appropriate adapter from chunk.
Detection order: 1. String → IdentityInputAdapter 2. Module prefix match 3. Attribute pattern match 4. Fallback to text/content attribute 5. None if no match
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chunk
|
Any
|
Sample chunk from stream |
required |
Returns:
| Type | Description |
|---|---|
InputProtocolAdapter[Any] | None
|
Adapter instance if detected, None otherwise |
Source code in src/hother/streamblocks/adapters/detection.py
get_registered_modules
classmethod
get_registered_modules() -> dict[
str, type[InputProtocolAdapter[Any]]
]
Get all registered module prefixes.
Returns:
| Type | Description |
|---|---|
dict[str, type[InputProtocolAdapter[Any]]]
|
Copy of module prefix registry |
get_registered_patterns
classmethod
register
classmethod
register(
*,
module_prefix: str | None = None,
attributes: list[str] | None = None,
) -> Callable[
[type[InputProtocolAdapter[Any]]],
type[InputProtocolAdapter[Any]],
]
Decorator to register an adapter for auto-detection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_prefix
|
str | None
|
Module path prefix to match (e.g., "openai.types") |
None
|
attributes
|
list[str] | None
|
Required attributes for attribute-based detection |
None
|
Returns:
| Type | Description |
|---|---|
Callable[[type[InputProtocolAdapter[Any]]], type[InputProtocolAdapter[Any]]]
|
Decorator function |
Example
@InputAdapterRegistry.register(module_prefix="openai.") ... class OpenAIInputAdapter: ... ...
@InputAdapterRegistry.register(attributes=["text", "candidates"]) ... class GeminiInputAdapter: ... ...
Source code in src/hother/streamblocks/adapters/detection.py
register_module
classmethod
register_module(
prefix: str,
adapter_class: type[InputProtocolAdapter[Any]],
) -> None
Register adapter by module prefix (non-decorator form).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix
|
str
|
Module path prefix to match |
required |
adapter_class
|
type[InputProtocolAdapter[Any]]
|
Adapter class to instantiate when matched |
required |
Source code in src/hother/streamblocks/adapters/detection.py
register_pattern
classmethod
register_pattern(
attrs: list[str],
adapter_class: type[InputProtocolAdapter[Any]],
) -> None
Register adapter by attribute pattern (non-decorator form).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
attrs
|
list[str]
|
Required attributes for detection |
required |
adapter_class
|
type[InputProtocolAdapter[Any]]
|
Adapter class to instantiate when matched |
required |
Source code in src/hother/streamblocks/adapters/detection.py
detect_input_adapter
detect_input_adapter(
sample: Any,
) -> InputProtocolAdapter[Any]
Detect input adapter from sample event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample
|
Any
|
A sample event from the stream |
required |
Returns:
| Type | Description |
|---|---|
InputProtocolAdapter[Any]
|
Detected adapter instance |
Raises:
| Type | Description |
|---|---|
AdapterDetectionError
|
If no adapter matches the sample |
Source code in src/hother/streamblocks/adapters/detection.py
hother.streamblocks.adapters.categories
Event categories for protocol adapter routing.
EventCategory
Bases: StrEnum
Semantic categorization of protocol events.
These three categories are EXHAUSTIVE - every protocol event falls into one:
- TEXT_CONTENT: Event contains text that should be processed by StreamBlocks
- PASSTHROUGH: Event should pass through unchanged to output
- SKIP: Event should not be emitted in output at all
Source code in src/hother/streamblocks/adapters/categories.py
PASSTHROUGH
class-attribute
instance-attribute
Event has no text content and should pass through unchanged to output.
SKIP
class-attribute
instance-attribute
Event should not be included in output at all.